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