two small fixes
[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
98 if (charon->connect_manager->check_and_register(charon->connect_manager,
99 mediation_cfg->get_my_id(mediation_cfg),
100 mediated_cfg->get_peer_id(mediated_cfg),
101 this->mediated_sa_id, this->mediated_child))
102 {
103 mediated_cfg->destroy(mediated_cfg);
104 mediation_cfg->destroy(mediation_cfg);
105 /* this pointer should still be valid */
106 charon->bus->set_sa(charon->bus, mediated_sa);
107 DBG1(DBG_IKE, "mediation with the same peer is already in progress, queued");
108 destroy(this);
109 return;
110 }
111 /* we need an additional reference because initiate consumes one */
112 mediation_cfg->get_ref(mediation_cfg);
113
114 /* this function call blocks until the connection is up or failed
115 * we do not check the status, but NEED_MORE would be returned on success
116 * because the registered callback returns FALSE then
117 * this->mediation_sa_id is set in the callback */
118 charon->controller->initiate(charon->controller,
119 mediation_cfg, NULL, (controller_cb_t)initiate_callback, this);
120 if (!this->mediation_sa_id)
121 {
122 DBG1(DBG_JOB, "initiating mediation connection '%s' failed",
123 mediation_cfg->get_name(mediation_cfg));
124 mediation_cfg->destroy(mediation_cfg);
125 mediated_cfg->destroy(mediated_cfg);
126 charon->bus->set_sa(charon->bus, mediated_sa);
127 SIG(IKE_UP_FAILED, "mediation failed");
128 destroy(this);
129 return;
130 }
131 mediation_cfg->destroy(mediation_cfg);
132
133 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
134 this->mediation_sa_id);
135
136 if (mediation_sa)
137 {
138 if (mediation_sa->initiate_mediation(mediation_sa, mediated_cfg) != SUCCESS)
139 {
140 DBG1(DBG_JOB, "initiating mediated connection '%s' failed",
141 mediated_cfg->get_name(mediated_cfg));
142 mediated_cfg->destroy(mediated_cfg);
143 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, mediation_sa);
144
145 charon->bus->set_sa(charon->bus, mediated_sa);
146 SIG(IKE_UP_FAILED, "mediation failed");
147 destroy(this);
148 return;
149 }
150
151 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediation_sa);
152 }
153
154 mediated_cfg->destroy(mediated_cfg);
155 }
156 destroy(this);
157 }
158
159 /**
160 * Implementation of job_t.execute.
161 */
162 static void reinitiate(private_initiate_mediation_job_t *this)
163 { /* FIXME: check the logging */
164 ike_sa_t *mediated_sa, *mediation_sa;
165 peer_cfg_t *mediated_cfg;
166
167 mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
168 this->mediated_sa_id);
169 if (mediated_sa)
170 {
171 mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
172 mediated_cfg->get_ref(mediated_cfg);
173 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
174
175 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
176 this->mediation_sa_id);
177 if (mediation_sa)
178 {
179 if (mediation_sa->initiate_mediation(mediation_sa, mediated_cfg) != SUCCESS)
180 {
181 DBG1(DBG_JOB, "initiating mediated connection '%s' failed",
182 mediated_cfg->get_name(mediated_cfg));
183 mediated_cfg->destroy(mediated_cfg);
184 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, mediation_sa);
185
186 charon->bus->set_sa(charon->bus, mediated_sa);
187 SIG(IKE_UP_FAILED, "mediation failed");
188 destroy(this);
189 return;
190 }
191
192 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediation_sa);
193 }
194
195 mediated_cfg->destroy(mediated_cfg);
196 }
197 destroy(this);
198 }
199
200 /**
201 * Creates an empty job
202 */
203 static private_initiate_mediation_job_t *initiate_mediation_job_create_empty()
204 {
205 private_initiate_mediation_job_t *this = malloc_thing(private_initiate_mediation_job_t);
206
207 /* interface functions */
208 this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
209
210 /* private variables */
211 this->mediation_sa_id = NULL;
212 this->mediated_sa_id = NULL;
213 this->mediated_child = NULL;
214
215 return this;
216 }
217
218 /*
219 * Described in header
220 */
221 initiate_mediation_job_t *initiate_mediation_job_create(ike_sa_id_t *ike_sa_id,
222 child_cfg_t *child_cfg)
223 {
224 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
225
226 this->public.job_interface.execute = (void (*) (job_t *)) initiate;
227
228 this->mediated_sa_id = ike_sa_id->clone(ike_sa_id);
229 child_cfg->get_ref(child_cfg);
230 this->mediated_child = child_cfg;
231
232 return &this->public;
233 }
234
235 /*
236 * Described in header
237 */
238 initiate_mediation_job_t *reinitiate_mediation_job_create(ike_sa_id_t *mediation_sa_id,
239 ike_sa_id_t *mediated_sa_id)
240 {
241 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
242
243 this->public.job_interface.execute = (void (*) (job_t *)) reinitiate;
244
245 this->mediation_sa_id = mediation_sa_id->clone(mediation_sa_id);
246 this->mediated_sa_id = mediated_sa_id->clone(mediated_sa_id);
247
248 return &this->public;
249 }