fixing mediation extension
[strongswan.git] / src / charon / processing / jobs / initiate_mediation_job.c
1 /*
2 * Copyright (C) 2007-2008 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 * ID of the IKE_SA of the mediation connection.
42 */
43 ike_sa_id_t *mediation_sa_id;
44 };
45
46 /**
47 * Implements job_t.destroy.
48 */
49 static void destroy(private_initiate_mediation_job_t *this)
50 {
51 DESTROY_IF(this->mediation_sa_id);
52 DESTROY_IF(this->mediated_sa_id);
53 free(this);
54 }
55
56 /**
57 * Callback to handle initiation of mediation connection
58 */
59 static bool initiate_callback(private_initiate_mediation_job_t *this,
60 debug_t group, level_t level, ike_sa_t *ike_sa,
61 char *format, va_list args)
62 {
63 if (ike_sa && !this->mediation_sa_id)
64 {
65 this->mediation_sa_id = ike_sa->get_id(ike_sa);
66 this->mediation_sa_id = this->mediation_sa_id->clone(this->mediation_sa_id);
67 }
68 return TRUE;
69 }
70
71 /**
72 * Implementation of job_t.execute.
73 */
74 static void initiate(private_initiate_mediation_job_t *this)
75 {
76 ike_sa_t *mediated_sa, *mediation_sa;
77 peer_cfg_t *mediated_cfg, *mediation_cfg;
78
79 mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
80 this->mediated_sa_id);
81 if (mediated_sa)
82 {
83 mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
84 mediated_cfg->get_ref(mediated_cfg);
85
86 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
87
88 mediation_cfg = mediated_cfg->get_mediated_by(mediated_cfg);
89 mediation_cfg->get_ref(mediation_cfg);
90
91 if (charon->connect_manager->check_and_register(charon->connect_manager,
92 mediation_cfg->get_my_id(mediation_cfg),
93 mediated_cfg->get_peer_id(mediated_cfg),
94 this->mediated_sa_id))
95 {
96 mediated_cfg->destroy(mediated_cfg);
97 mediation_cfg->destroy(mediation_cfg);
98
99 mediated_sa = charon->ike_sa_manager->checkout(
100 charon->ike_sa_manager, this->mediated_sa_id);
101 if (mediated_sa)
102 {
103 DBG1(DBG_IKE, "mediation with the same peer is already in "
104 "progress, queued");
105 charon->ike_sa_manager->checkin(
106 charon->ike_sa_manager, mediated_sa);
107 }
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 if (charon->controller->initiate(charon->controller, mediation_cfg,
115 NULL, (controller_cb_t)initiate_callback, this) != SUCCESS)
116 {
117 mediation_cfg->destroy(mediation_cfg);
118 mediated_cfg->destroy(mediated_cfg);
119 mediated_sa = charon->ike_sa_manager->checkout(
120 charon->ike_sa_manager, this->mediated_sa_id);
121 if (mediated_sa)
122 {
123 DBG1(DBG_IKE, "initiating mediation connection failed");
124 charon->ike_sa_manager->checkin_and_destroy(
125 charon->ike_sa_manager, mediated_sa);
126 }
127 destroy(this);
128 return;
129 }
130 mediation_cfg->destroy(mediation_cfg);
131
132 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
133 this->mediation_sa_id);
134
135 if (mediation_sa)
136 {
137 if (mediation_sa->initiate_mediation(mediation_sa,
138 mediated_cfg) != SUCCESS)
139 {
140 mediated_cfg->destroy(mediated_cfg);
141 charon->ike_sa_manager->checkin_and_destroy(
142 charon->ike_sa_manager, mediation_sa);
143 mediated_sa = charon->ike_sa_manager->checkout(
144 charon->ike_sa_manager, this->mediated_sa_id);
145 if (mediated_sa)
146 {
147 DBG1(DBG_IKE, "establishing mediation connection failed");
148 charon->ike_sa_manager->checkin_and_destroy(
149 charon->ike_sa_manager, mediated_sa);
150 }
151 destroy(this);
152 return;
153 }
154
155 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediation_sa);
156 }
157
158 mediated_cfg->destroy(mediated_cfg);
159 }
160 destroy(this);
161 }
162
163 /**
164 * Implementation of job_t.execute.
165 */
166 static void reinitiate(private_initiate_mediation_job_t *this)
167 {
168 ike_sa_t *mediated_sa, *mediation_sa;
169 peer_cfg_t *mediated_cfg;
170
171 mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
172 this->mediated_sa_id);
173 if (mediated_sa)
174 {
175 mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
176 mediated_cfg->get_ref(mediated_cfg);
177 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
178
179 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
180 this->mediation_sa_id);
181 if (mediation_sa)
182 {
183 if (mediation_sa->initiate_mediation(mediation_sa, mediated_cfg) != SUCCESS)
184 {
185 DBG1(DBG_JOB, "initiating mediated connection '%s' failed",
186 mediated_cfg->get_name(mediated_cfg));
187 mediated_cfg->destroy(mediated_cfg);
188 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, mediation_sa);
189 mediated_sa = charon->ike_sa_manager->checkout(
190 charon->ike_sa_manager, this->mediated_sa_id);
191 if (mediated_sa)
192 {
193 DBG1(DBG_IKE, "establishing mediation connection failed");
194 charon->ike_sa_manager->checkin_and_destroy(
195 charon->ike_sa_manager, mediated_sa);
196 }
197 destroy(this);
198 return;
199 }
200 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediation_sa);
201 }
202
203 mediated_cfg->destroy(mediated_cfg);
204 }
205 destroy(this);
206 }
207
208 /**
209 * Creates an empty job
210 */
211 static private_initiate_mediation_job_t *initiate_mediation_job_create_empty()
212 {
213 private_initiate_mediation_job_t *this = malloc_thing(private_initiate_mediation_job_t);
214
215 /* interface functions */
216 this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
217
218 /* private variables */
219 this->mediation_sa_id = NULL;
220 this->mediated_sa_id = NULL;
221
222 return this;
223 }
224
225 /*
226 * Described in header
227 */
228 initiate_mediation_job_t *initiate_mediation_job_create(ike_sa_id_t *ike_sa_id)
229 {
230 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
231
232 this->public.job_interface.execute = (void (*) (job_t *)) initiate;
233
234 this->mediated_sa_id = ike_sa_id->clone(ike_sa_id);
235
236 return &this->public;
237 }
238
239 /*
240 * Described in header
241 */
242 initiate_mediation_job_t *reinitiate_mediation_job_create(ike_sa_id_t *mediation_sa_id,
243 ike_sa_id_t *mediated_sa_id)
244 {
245 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
246
247 this->public.job_interface.execute = (void (*) (job_t *)) reinitiate;
248
249 this->mediation_sa_id = mediation_sa_id->clone(mediation_sa_id);
250 this->mediated_sa_id = mediated_sa_id->clone(mediated_sa_id);
251
252 return &this->public;
253 }