610998d885ed758b1f3687323bec8e4c2c4aa038
[strongswan.git] / src / libcharon / 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
16 #include "initiate_mediation_job.h"
17
18 #include <sa/ike_sa.h>
19 #include <daemon.h>
20
21
22 typedef struct private_initiate_mediation_job_t private_initiate_mediation_job_t;
23
24 /**
25 * Private data of an initiate_mediation_job_t Object
26 */
27 struct private_initiate_mediation_job_t {
28 /**
29 * public initiate_mediation_job_t interface
30 */
31 initiate_mediation_job_t public;
32
33 /**
34 * ID of the IKE_SA of the mediated connection.
35 */
36 ike_sa_id_t *mediated_sa_id;
37
38 /**
39 * ID of the IKE_SA of the mediation connection.
40 */
41 ike_sa_id_t *mediation_sa_id;
42 };
43
44 METHOD(job_t, destroy, void,
45 private_initiate_mediation_job_t *this)
46 {
47 DESTROY_IF(this->mediation_sa_id);
48 DESTROY_IF(this->mediated_sa_id);
49 free(this);
50 }
51
52 /**
53 * Callback to handle initiation of mediation connection
54 */
55 static bool initiate_callback(private_initiate_mediation_job_t *this,
56 debug_t group, level_t level, ike_sa_t *ike_sa,
57 char *message)
58 {
59 if (ike_sa && !this->mediation_sa_id)
60 {
61 this->mediation_sa_id = ike_sa->get_id(ike_sa);
62 this->mediation_sa_id = this->mediation_sa_id->clone(this->mediation_sa_id);
63 }
64 return TRUE;
65 }
66
67 METHOD(job_t, initiate, void,
68 private_initiate_mediation_job_t *this)
69 {
70 ike_sa_t *mediated_sa, *mediation_sa;
71 peer_cfg_t *mediated_cfg, *mediation_cfg;
72 enumerator_t *enumerator;
73 auth_cfg_t *auth_cfg;
74
75 mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
76 this->mediated_sa_id);
77 if (mediated_sa)
78 {
79 DBG1(DBG_IKE, "initiating mediation connection");
80 mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
81 mediated_cfg->get_ref(mediated_cfg);
82
83 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
84
85 mediation_cfg = mediated_cfg->get_mediated_by(mediated_cfg);
86 mediation_cfg->get_ref(mediation_cfg);
87
88 enumerator = mediation_cfg->create_auth_cfg_enumerator(mediation_cfg,
89 TRUE);
90 if (!enumerator->enumerate(enumerator, &auth_cfg) ||
91 auth_cfg->get(auth_cfg, AUTH_RULE_IDENTITY) == NULL)
92 {
93 mediated_cfg->destroy(mediated_cfg);
94 mediation_cfg->destroy(mediation_cfg);
95 enumerator->destroy(enumerator);
96 destroy(this);
97 return;
98 }
99 enumerator->destroy(enumerator);
100
101 if (charon->connect_manager->check_and_register(charon->connect_manager,
102 auth_cfg->get(auth_cfg, AUTH_RULE_IDENTITY),
103 mediated_cfg->get_peer_id(mediated_cfg),
104 this->mediated_sa_id))
105 {
106 mediated_cfg->destroy(mediated_cfg);
107 mediation_cfg->destroy(mediation_cfg);
108
109 mediated_sa = charon->ike_sa_manager->checkout(
110 charon->ike_sa_manager, this->mediated_sa_id);
111 if (mediated_sa)
112 {
113 DBG1(DBG_IKE, "mediation with the same peer is already in "
114 "progress, queued");
115 charon->ike_sa_manager->checkin(
116 charon->ike_sa_manager, mediated_sa);
117 }
118 destroy(this);
119 return;
120 }
121 /* we need an additional reference because initiate consumes one */
122 mediation_cfg->get_ref(mediation_cfg);
123
124 if (charon->controller->initiate(charon->controller, mediation_cfg,
125 NULL, (controller_cb_t)initiate_callback, this, 0) != SUCCESS)
126 {
127 mediation_cfg->destroy(mediation_cfg);
128 mediated_cfg->destroy(mediated_cfg);
129 mediated_sa = charon->ike_sa_manager->checkout(
130 charon->ike_sa_manager, this->mediated_sa_id);
131 if (mediated_sa)
132 {
133 DBG1(DBG_IKE, "initiating mediation connection failed");
134 charon->ike_sa_manager->checkin_and_destroy(
135 charon->ike_sa_manager, mediated_sa);
136 }
137 destroy(this);
138 return;
139 }
140 mediation_cfg->destroy(mediation_cfg);
141
142 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
143 this->mediation_sa_id);
144 if (mediation_sa)
145 {
146 if (mediation_sa->initiate_mediation(mediation_sa,
147 mediated_cfg) != SUCCESS)
148 {
149 mediated_cfg->destroy(mediated_cfg);
150 charon->ike_sa_manager->checkin_and_destroy(
151 charon->ike_sa_manager, mediation_sa);
152 mediated_sa = charon->ike_sa_manager->checkout(
153 charon->ike_sa_manager, this->mediated_sa_id);
154 if (mediated_sa)
155 {
156 DBG1(DBG_IKE, "establishing mediation connection failed");
157 charon->ike_sa_manager->checkin_and_destroy(
158 charon->ike_sa_manager, mediated_sa);
159 }
160 destroy(this);
161 return;
162 }
163 charon->ike_sa_manager->checkin(charon->ike_sa_manager,
164 mediation_sa);
165 }
166 mediated_cfg->destroy(mediated_cfg);
167 }
168 destroy(this);
169 }
170
171 METHOD(job_t, reinitiate, void,
172 private_initiate_mediation_job_t *this)
173 {
174 ike_sa_t *mediated_sa, *mediation_sa;
175 peer_cfg_t *mediated_cfg;
176
177 mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
178 this->mediated_sa_id);
179 if (mediated_sa)
180 {
181 mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
182 mediated_cfg->get_ref(mediated_cfg);
183 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
184
185 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
186 this->mediation_sa_id);
187 if (mediation_sa)
188 {
189 if (mediation_sa->initiate_mediation(mediation_sa,
190 mediated_cfg) != SUCCESS)
191 {
192 DBG1(DBG_JOB, "initiating mediated connection '%s' failed",
193 mediated_cfg->get_name(mediated_cfg));
194 mediated_cfg->destroy(mediated_cfg);
195 charon->ike_sa_manager->checkin_and_destroy(
196 charon->ike_sa_manager,
197 mediation_sa);
198 mediated_sa = charon->ike_sa_manager->checkout(
199 charon->ike_sa_manager,
200 this->mediated_sa_id);
201 if (mediated_sa)
202 {
203 DBG1(DBG_IKE, "establishing mediation connection failed");
204 charon->ike_sa_manager->checkin_and_destroy(
205 charon->ike_sa_manager,
206 mediated_sa);
207 }
208 destroy(this);
209 return;
210 }
211 charon->ike_sa_manager->checkin(charon->ike_sa_manager,
212 mediation_sa);
213 }
214
215 mediated_cfg->destroy(mediated_cfg);
216 }
217 destroy(this);
218 }
219
220 METHOD(job_t, get_priority, job_priority_t,
221 private_initiate_mediation_job_t *this)
222 {
223 return JOB_PRIO_MEDIUM;
224 }
225
226 /**
227 * Creates an empty job
228 */
229 static private_initiate_mediation_job_t *initiate_mediation_job_create_empty()
230 {
231 private_initiate_mediation_job_t *this;
232 INIT(this,
233 .public = {
234 .job_interface = {
235 .get_priority = _get_priority,
236 .destroy = _destroy,
237 },
238 },
239 );
240 return this;
241 }
242
243 /*
244 * Described in header
245 */
246 initiate_mediation_job_t *initiate_mediation_job_create(ike_sa_id_t *ike_sa_id)
247 {
248 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
249
250 this->public.job_interface.execute = _initiate;
251 this->mediated_sa_id = ike_sa_id->clone(ike_sa_id);
252
253 return &this->public;
254 }
255
256 /*
257 * Described in header
258 */
259 initiate_mediation_job_t *reinitiate_mediation_job_create(ike_sa_id_t *mediation_sa_id,
260 ike_sa_id_t *mediated_sa_id)
261 {
262 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
263
264 this->public.job_interface.execute = _reinitiate;
265 this->mediation_sa_id = mediation_sa_id->clone(mediation_sa_id);
266 this->mediated_sa_id = mediated_sa_id->clone(mediated_sa_id);
267
268 return &this->public;
269 }