kernel-interface: Raise mapping event with a proto/SPI/dst tuple
[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, job_requeue_t,
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 return JOB_REQUEUE_NONE;
97 }
98 enumerator->destroy(enumerator);
99
100 if (charon->connect_manager->check_and_register(charon->connect_manager,
101 auth_cfg->get(auth_cfg, AUTH_RULE_IDENTITY),
102 mediated_cfg->get_peer_id(mediated_cfg),
103 this->mediated_sa_id))
104 {
105 mediated_cfg->destroy(mediated_cfg);
106 mediation_cfg->destroy(mediation_cfg);
107
108 mediated_sa = charon->ike_sa_manager->checkout(
109 charon->ike_sa_manager, this->mediated_sa_id);
110 if (mediated_sa)
111 {
112 DBG1(DBG_IKE, "mediation with the same peer is already in "
113 "progress, queued");
114 charon->ike_sa_manager->checkin(
115 charon->ike_sa_manager, mediated_sa);
116 }
117 return JOB_REQUEUE_NONE;
118 }
119 /* we need an additional reference because initiate consumes one */
120 mediation_cfg->get_ref(mediation_cfg);
121
122 if (charon->controller->initiate(charon->controller, mediation_cfg,
123 NULL, (controller_cb_t)initiate_callback, this, 0) != SUCCESS)
124 {
125 mediation_cfg->destroy(mediation_cfg);
126 mediated_cfg->destroy(mediated_cfg);
127 mediated_sa = charon->ike_sa_manager->checkout(
128 charon->ike_sa_manager, this->mediated_sa_id);
129 if (mediated_sa)
130 {
131 DBG1(DBG_IKE, "initiating mediation connection failed");
132 charon->ike_sa_manager->checkin_and_destroy(
133 charon->ike_sa_manager, mediated_sa);
134 }
135 return JOB_REQUEUE_NONE;
136 }
137 mediation_cfg->destroy(mediation_cfg);
138
139 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
140 this->mediation_sa_id);
141 if (mediation_sa)
142 {
143 if (mediation_sa->initiate_mediation(mediation_sa,
144 mediated_cfg) != SUCCESS)
145 {
146 mediated_cfg->destroy(mediated_cfg);
147 charon->ike_sa_manager->checkin_and_destroy(
148 charon->ike_sa_manager, mediation_sa);
149 mediated_sa = charon->ike_sa_manager->checkout(
150 charon->ike_sa_manager, this->mediated_sa_id);
151 if (mediated_sa)
152 {
153 DBG1(DBG_IKE, "establishing mediation connection failed");
154 charon->ike_sa_manager->checkin_and_destroy(
155 charon->ike_sa_manager, mediated_sa);
156 }
157 return JOB_REQUEUE_NONE;
158 }
159 charon->ike_sa_manager->checkin(charon->ike_sa_manager,
160 mediation_sa);
161 }
162 mediated_cfg->destroy(mediated_cfg);
163 }
164 return JOB_REQUEUE_NONE;
165 }
166
167 METHOD(job_t, reinitiate, job_requeue_t,
168 private_initiate_mediation_job_t *this)
169 {
170 ike_sa_t *mediated_sa, *mediation_sa;
171 peer_cfg_t *mediated_cfg;
172
173 mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
174 this->mediated_sa_id);
175 if (mediated_sa)
176 {
177 mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
178 mediated_cfg->get_ref(mediated_cfg);
179 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
180
181 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
182 this->mediation_sa_id);
183 if (mediation_sa)
184 {
185 if (mediation_sa->initiate_mediation(mediation_sa,
186 mediated_cfg) != SUCCESS)
187 {
188 DBG1(DBG_JOB, "initiating mediated connection '%s' failed",
189 mediated_cfg->get_name(mediated_cfg));
190 mediated_cfg->destroy(mediated_cfg);
191 charon->ike_sa_manager->checkin_and_destroy(
192 charon->ike_sa_manager,
193 mediation_sa);
194 mediated_sa = charon->ike_sa_manager->checkout(
195 charon->ike_sa_manager,
196 this->mediated_sa_id);
197 if (mediated_sa)
198 {
199 DBG1(DBG_IKE, "establishing mediation connection failed");
200 charon->ike_sa_manager->checkin_and_destroy(
201 charon->ike_sa_manager,
202 mediated_sa);
203 }
204 return JOB_REQUEUE_NONE;
205 }
206 charon->ike_sa_manager->checkin(charon->ike_sa_manager,
207 mediation_sa);
208 }
209
210 mediated_cfg->destroy(mediated_cfg);
211 }
212 return JOB_REQUEUE_NONE;
213 }
214
215 METHOD(job_t, get_priority, job_priority_t,
216 private_initiate_mediation_job_t *this)
217 {
218 return JOB_PRIO_MEDIUM;
219 }
220
221 /**
222 * Creates an empty job
223 */
224 static private_initiate_mediation_job_t *initiate_mediation_job_create_empty()
225 {
226 private_initiate_mediation_job_t *this;
227 INIT(this,
228 .public = {
229 .job_interface = {
230 .get_priority = _get_priority,
231 .destroy = _destroy,
232 },
233 },
234 );
235 return this;
236 }
237
238 /*
239 * Described in header
240 */
241 initiate_mediation_job_t *initiate_mediation_job_create(ike_sa_id_t *ike_sa_id)
242 {
243 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
244
245 this->public.job_interface.execute = _initiate;
246 this->mediated_sa_id = ike_sa_id->clone(ike_sa_id);
247
248 return &this->public;
249 }
250
251 /*
252 * Described in header
253 */
254 initiate_mediation_job_t *reinitiate_mediation_job_create(ike_sa_id_t *mediation_sa_id,
255 ike_sa_id_t *mediated_sa_id)
256 {
257 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
258
259 this->public.job_interface.execute = _reinitiate;
260 this->mediation_sa_id = mediation_sa_id->clone(mediation_sa_id);
261 this->mediated_sa_id = mediated_sa_id->clone(mediated_sa_id);
262
263 return &this->public;
264 }