483420b99a16e9f2ed4f4f7e32fff699a0604c59
[strongswan.git] / src / charon / processing / jobs / initiate_mediation_job.c
1 /*
2 * Copyright (C) 2007 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "initiate_mediation_job.h"
19
20 #include <sa/ike_sa.h>
21 #include <daemon.h>
22
23
24 typedef struct private_initiate_mediation_job_t private_initiate_mediation_job_t;
25
26 /**
27 * Private data of an initiate_mediation_job_t Object
28 */
29 struct private_initiate_mediation_job_t {
30 /**
31 * public initiate_mediation_job_t interface
32 */
33 initiate_mediation_job_t public;
34
35 /**
36 * ID of the IKE_SA of the mediated connection.
37 */
38 ike_sa_id_t *mediated_sa_id;
39
40 /**
41 * Child config of the CHILD_SA of the mediated connection.
42 */
43 child_cfg_t *mediated_child;
44
45 /**
46 * ID of the IKE_SA of the mediation connection.
47 */
48 ike_sa_id_t *mediation_sa_id;
49 };
50
51 /**
52 * Implements job_t.destroy.
53 */
54 static void destroy(private_initiate_mediation_job_t *this)
55 {
56 DESTROY_IF(this->mediation_sa_id);
57 DESTROY_IF(this->mediated_sa_id);
58 DESTROY_IF(this->mediated_child);
59 free(this);
60 }
61
62 /**
63 * Callback to handle initiation of mediation connection
64 */
65 static bool initiate_callback(private_initiate_mediation_job_t *this, signal_t signal, level_t level,
66 ike_sa_t *ike_sa, char *format, va_list args)
67 {
68 if (signal == CHILD_UP_SUCCESS)
69 {
70 /* mediation connection is up */
71 this->mediation_sa_id = ike_sa->get_id(ike_sa);
72 this->mediation_sa_id = this->mediation_sa_id->clone(this->mediation_sa_id);
73 return FALSE;
74 }
75 return TRUE;
76 }
77
78 /**
79 * Implementation of job_t.execute.
80 */
81 static void initiate(private_initiate_mediation_job_t *this)
82 { /* FIXME: check the logging */
83 ike_sa_t *mediated_sa, *mediation_sa;
84 peer_cfg_t *mediated_cfg, *mediation_cfg;
85
86 mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
87 this->mediated_sa_id);
88 if (mediated_sa)
89 {
90 mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
91 /* get_peer_cfg returns an internal object */
92 mediated_cfg->get_ref(mediated_cfg);
93
94 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
95
96 mediation_cfg = mediated_cfg->get_mediated_by(mediated_cfg);
97 mediation_cfg->get_ref(mediation_cfg);
98
99 if (charon->connect_manager->check_and_register(charon->connect_manager,
100 mediation_cfg->get_my_id(mediation_cfg),
101 mediated_cfg->get_peer_id(mediated_cfg),
102 this->mediated_sa_id, this->mediated_child))
103 {
104 mediated_cfg->destroy(mediated_cfg);
105 mediation_cfg->destroy(mediation_cfg);
106 /* this pointer should still be valid */
107 charon->bus->set_sa(charon->bus, mediated_sa);
108 DBG1(DBG_IKE, "mediation with the same peer is already in progress, queued");
109 destroy(this);
110 return;
111 }
112 /* we need an additional reference because initiate consumes one */
113 mediation_cfg->get_ref(mediation_cfg);
114
115 /* this function call blocks until the connection is up or failed
116 * we do not check the status, but NEED_MORE would be returned on success
117 * because the registered callback returns FALSE then
118 * this->mediation_sa_id is set in the callback */
119 charon->controller->initiate(charon->controller,
120 mediation_cfg, NULL, (controller_cb_t)initiate_callback, this);
121 if (!this->mediation_sa_id)
122 {
123 DBG1(DBG_JOB, "initiating mediation connection '%s' failed",
124 mediation_cfg->get_name(mediation_cfg));
125 mediation_cfg->destroy(mediation_cfg);
126 mediated_cfg->destroy(mediated_cfg);
127 charon->bus->set_sa(charon->bus, mediated_sa);
128 SIG(IKE_UP_FAILED, "mediation failed");
129 destroy(this);
130 return;
131 }
132 mediation_cfg->destroy(mediation_cfg);
133
134 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
135 this->mediation_sa_id);
136
137 if (mediation_sa)
138 {
139 if (mediation_sa->initiate_mediation(mediation_sa, mediated_cfg) != SUCCESS)
140 {
141 DBG1(DBG_JOB, "initiating mediated connection '%s' failed",
142 mediated_cfg->get_name(mediated_cfg));
143 mediated_cfg->destroy(mediated_cfg);
144 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, mediation_sa);
145
146 charon->bus->set_sa(charon->bus, mediated_sa);
147 SIG(IKE_UP_FAILED, "mediation failed");
148 destroy(this);
149 return;
150 }
151
152 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediation_sa);
153 }
154
155 mediated_cfg->destroy(mediated_cfg);
156 }
157 destroy(this);
158 }
159
160 /**
161 * Implementation of job_t.execute.
162 */
163 static void reinitiate(private_initiate_mediation_job_t *this)
164 { /* FIXME: check the logging */
165 ike_sa_t *mediated_sa, *mediation_sa;
166 peer_cfg_t *mediated_cfg;
167
168 mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
169 this->mediated_sa_id);
170 if (mediated_sa)
171 {
172 mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
173 mediated_cfg->get_ref(mediated_cfg);
174 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
175
176 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
177 this->mediation_sa_id);
178 if (mediation_sa)
179 {
180 if (mediation_sa->initiate_mediation(mediation_sa, mediated_cfg) != SUCCESS)
181 {
182 DBG1(DBG_JOB, "initiating mediated connection '%s' failed",
183 mediated_cfg->get_name(mediated_cfg));
184 mediated_cfg->destroy(mediated_cfg);
185 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, mediation_sa);
186
187 charon->bus->set_sa(charon->bus, mediated_sa);
188 SIG(IKE_UP_FAILED, "mediation failed");
189 destroy(this);
190 return;
191 }
192
193 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediation_sa);
194 }
195
196 mediated_cfg->destroy(mediated_cfg);
197 }
198 destroy(this);
199 }
200
201 /**
202 * Creates an empty job
203 */
204 static private_initiate_mediation_job_t *initiate_mediation_job_create_empty()
205 {
206 private_initiate_mediation_job_t *this = malloc_thing(private_initiate_mediation_job_t);
207
208 /* interface functions */
209 this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
210
211 /* private variables */
212 this->mediation_sa_id = NULL;
213 this->mediated_sa_id = NULL;
214 this->mediated_child = NULL;
215
216 return this;
217 }
218
219 /*
220 * Described in header
221 */
222 initiate_mediation_job_t *initiate_mediation_job_create(ike_sa_id_t *ike_sa_id,
223 child_cfg_t *child_cfg)
224 {
225 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
226
227 this->public.job_interface.execute = (void (*) (job_t *)) initiate;
228
229 this->mediated_sa_id = ike_sa_id->clone(ike_sa_id);
230 child_cfg->get_ref(child_cfg);
231 this->mediated_child = child_cfg;
232
233 return &this->public;
234 }
235
236 /*
237 * Described in header
238 */
239 initiate_mediation_job_t *reinitiate_mediation_job_create(ike_sa_id_t *mediation_sa_id,
240 ike_sa_id_t *mediated_sa_id)
241 {
242 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
243
244 this->public.job_interface.execute = (void (*) (job_t *)) reinitiate;
245
246 this->mediation_sa_id = mediation_sa_id->clone(mediation_sa_id);
247 this->mediated_sa_id = mediated_sa_id->clone(mediated_sa_id);
248
249 return &this->public;
250 }