ikev2: Fix segfault when reestablishing CHILD_SAs due to closeaction=restart|hold
[strongswan.git] / src / libcharon / sa / ikev2 / tasks / child_delete.c
1 /*
2 * Copyright (C) 2006-2007 Martin Willi
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 "child_delete.h"
17
18 #include <daemon.h>
19 #include <encoding/payloads/delete_payload.h>
20
21
22 typedef struct private_child_delete_t private_child_delete_t;
23
24 /**
25 * Private members of a child_delete_t task.
26 */
27 struct private_child_delete_t {
28
29 /**
30 * Public methods and task_t interface.
31 */
32 child_delete_t public;
33
34 /**
35 * Assigned IKE_SA.
36 */
37 ike_sa_t *ike_sa;
38
39 /**
40 * Are we the initiator?
41 */
42 bool initiator;
43
44 /**
45 * Protocol of CHILD_SA to delete
46 */
47 protocol_id_t protocol;
48
49 /**
50 * Inbound SPI of CHILD_SA to delete
51 */
52 u_int32_t spi;
53
54 /**
55 * whether to enforce delete action policy
56 */
57 bool check_delete_action;
58
59 /**
60 * is this delete exchange following a rekey?
61 */
62 bool rekeyed;
63
64 /**
65 * CHILD_SA already expired?
66 */
67 bool expired;
68
69 /**
70 * CHILD_SAs which get deleted
71 */
72 linked_list_t *child_sas;
73 };
74
75 /**
76 * build the delete payloads from the listed child_sas
77 */
78 static void build_payloads(private_child_delete_t *this, message_t *message)
79 {
80 delete_payload_t *ah = NULL, *esp = NULL;
81 enumerator_t *enumerator;
82 child_sa_t *child_sa;
83
84 enumerator = this->child_sas->create_enumerator(this->child_sas);
85 while (enumerator->enumerate(enumerator, (void**)&child_sa))
86 {
87 protocol_id_t protocol = child_sa->get_protocol(child_sa);
88 u_int32_t spi = child_sa->get_spi(child_sa, TRUE);
89
90 switch (protocol)
91 {
92 case PROTO_ESP:
93 if (esp == NULL)
94 {
95 esp = delete_payload_create(DELETE, PROTO_ESP);
96 message->add_payload(message, (payload_t*)esp);
97 }
98 esp->add_spi(esp, spi);
99 DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
100 protocol_id_names, protocol, ntohl(spi));
101 break;
102 case PROTO_AH:
103 if (ah == NULL)
104 {
105 ah = delete_payload_create(DELETE, PROTO_AH);
106 message->add_payload(message, (payload_t*)ah);
107 }
108 ah->add_spi(ah, spi);
109 DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
110 protocol_id_names, protocol, ntohl(spi));
111 break;
112 default:
113 break;
114 }
115 child_sa->set_state(child_sa, CHILD_DELETING);
116 }
117 enumerator->destroy(enumerator);
118 }
119
120 /**
121 * read in payloads and find the children to delete
122 */
123 static void process_payloads(private_child_delete_t *this, message_t *message)
124 {
125 enumerator_t *payloads, *spis;
126 payload_t *payload;
127 delete_payload_t *delete_payload;
128 u_int32_t spi;
129 protocol_id_t protocol;
130 child_sa_t *child_sa;
131
132 payloads = message->create_payload_enumerator(message);
133 while (payloads->enumerate(payloads, &payload))
134 {
135 if (payload->get_type(payload) == DELETE)
136 {
137 delete_payload = (delete_payload_t*)payload;
138 protocol = delete_payload->get_protocol_id(delete_payload);
139 if (protocol != PROTO_ESP && protocol != PROTO_AH)
140 {
141 continue;
142 }
143 spis = delete_payload->create_spi_enumerator(delete_payload);
144 while (spis->enumerate(spis, &spi))
145 {
146 child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
147 spi, FALSE);
148 if (child_sa == NULL)
149 {
150 DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x, "
151 "but no such SA", protocol_id_names, protocol, ntohl(spi));
152 continue;
153 }
154 DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
155 protocol_id_names, protocol, ntohl(spi));
156
157 switch (child_sa->get_state(child_sa))
158 {
159 case CHILD_REKEYING:
160 this->rekeyed = TRUE;
161 /* we reply as usual, rekeying will fail */
162 break;
163 case CHILD_DELETING:
164 /* we don't send back a delete if we initiated ourself */
165 if (!this->initiator)
166 {
167 this->ike_sa->destroy_child_sa(this->ike_sa,
168 protocol, spi);
169 continue;
170 }
171 /* fall through */
172 case CHILD_INSTALLED:
173 if (!this->initiator)
174 { /* reestablish installed children if required */
175 this->check_delete_action = TRUE;
176 }
177 default:
178 break;
179 }
180 if (this->child_sas->find_first(this->child_sas, NULL,
181 (void**)&child_sa) != SUCCESS)
182 {
183 this->child_sas->insert_last(this->child_sas, child_sa);
184 }
185 }
186 spis->destroy(spis);
187 }
188 }
189 payloads->destroy(payloads);
190 }
191
192 /**
193 * destroy the children listed in this->child_sas, reestablish by policy
194 */
195 static status_t destroy_and_reestablish(private_child_delete_t *this)
196 {
197 enumerator_t *enumerator;
198 child_sa_t *child_sa;
199 child_cfg_t *child_cfg;
200 protocol_id_t protocol;
201 u_int32_t spi, reqid;
202 action_t action;
203 status_t status = SUCCESS;
204
205 enumerator = this->child_sas->create_enumerator(this->child_sas);
206 while (enumerator->enumerate(enumerator, (void**)&child_sa))
207 {
208 /* signal child down event if we are not rekeying */
209 if (!this->rekeyed)
210 {
211 charon->bus->child_updown(charon->bus, child_sa, FALSE);
212 }
213 spi = child_sa->get_spi(child_sa, TRUE);
214 reqid = child_sa->get_reqid(child_sa);
215 protocol = child_sa->get_protocol(child_sa);
216 child_cfg = child_sa->get_config(child_sa);
217 child_cfg->get_ref(child_cfg);
218 action = child_sa->get_close_action(child_sa);
219 this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
220 if (this->check_delete_action)
221 { /* enforce child_cfg policy if deleted passively */
222 switch (action)
223 {
224 case ACTION_RESTART:
225 child_cfg->get_ref(child_cfg);
226 status = this->ike_sa->initiate(this->ike_sa, child_cfg,
227 reqid, NULL, NULL);
228 break;
229 case ACTION_ROUTE:
230 charon->traps->install(charon->traps,
231 this->ike_sa->get_peer_cfg(this->ike_sa), child_cfg,
232 reqid);
233 break;
234 default:
235 break;
236 }
237 }
238 child_cfg->destroy(child_cfg);
239 if (status != SUCCESS)
240 {
241 break;
242 }
243 }
244 enumerator->destroy(enumerator);
245 return status;
246 }
247
248 /**
249 * send closing signals for all CHILD_SAs over the bus
250 */
251 static void log_children(private_child_delete_t *this)
252 {
253 linked_list_t *my_ts, *other_ts;
254 enumerator_t *enumerator;
255 child_sa_t *child_sa;
256 u_int64_t bytes_in, bytes_out;
257
258 enumerator = this->child_sas->create_enumerator(this->child_sas);
259 while (enumerator->enumerate(enumerator, (void**)&child_sa))
260 {
261 my_ts = linked_list_create_from_enumerator(
262 child_sa->create_ts_enumerator(child_sa, TRUE));
263 other_ts = linked_list_create_from_enumerator(
264 child_sa->create_ts_enumerator(child_sa, FALSE));
265 if (this->expired)
266 {
267 DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
268 "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
269 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
270 ntohl(child_sa->get_spi(child_sa, TRUE)),
271 ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
272 }
273 else
274 {
275 child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in, NULL);
276 child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out, NULL);
277
278 DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs %.8x_i "
279 "(%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R",
280 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
281 ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
282 ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
283 my_ts, other_ts);
284 }
285 my_ts->destroy(my_ts);
286 other_ts->destroy(other_ts);
287 }
288 enumerator->destroy(enumerator);
289 }
290
291 METHOD(task_t, build_i, status_t,
292 private_child_delete_t *this, message_t *message)
293 {
294 child_sa_t *child_sa;
295
296 child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
297 this->spi, TRUE);
298 if (!child_sa)
299 { /* check if it is an outbound sa */
300 child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
301 this->spi, FALSE);
302 if (!child_sa)
303 { /* child does not exist anymore */
304 return SUCCESS;
305 }
306 /* we work only with the inbound SPI */
307 this->spi = child_sa->get_spi(child_sa, TRUE);
308 }
309 this->child_sas->insert_last(this->child_sas, child_sa);
310 if (child_sa->get_state(child_sa) == CHILD_REKEYING)
311 {
312 this->rekeyed = TRUE;
313 }
314 log_children(this);
315 build_payloads(this, message);
316 return NEED_MORE;
317 }
318
319 METHOD(task_t, process_i, status_t,
320 private_child_delete_t *this, message_t *message)
321 {
322 process_payloads(this, message);
323 DBG1(DBG_IKE, "CHILD_SA closed");
324 return destroy_and_reestablish(this);
325 }
326
327 METHOD(task_t, process_r, status_t,
328 private_child_delete_t *this, message_t *message)
329 {
330 process_payloads(this, message);
331 log_children(this);
332 return NEED_MORE;
333 }
334
335 METHOD(task_t, build_r, status_t,
336 private_child_delete_t *this, message_t *message)
337 {
338 /* if we are rekeying, we send an empty informational */
339 if (this->ike_sa->get_state(this->ike_sa) != IKE_REKEYING)
340 {
341 build_payloads(this, message);
342 }
343 DBG1(DBG_IKE, "CHILD_SA closed");
344 return destroy_and_reestablish(this);
345 }
346
347 METHOD(task_t, get_type, task_type_t,
348 private_child_delete_t *this)
349 {
350 return TASK_CHILD_DELETE;
351 }
352
353 METHOD(child_delete_t , get_child, child_sa_t*,
354 private_child_delete_t *this)
355 {
356 child_sa_t *child_sa = NULL;
357 this->child_sas->get_first(this->child_sas, (void**)&child_sa);
358 return child_sa;
359 }
360
361 METHOD(task_t, migrate, void,
362 private_child_delete_t *this, ike_sa_t *ike_sa)
363 {
364 this->check_delete_action = FALSE;
365 this->ike_sa = ike_sa;
366
367 this->child_sas->destroy(this->child_sas);
368 this->child_sas = linked_list_create();
369 }
370
371 METHOD(task_t, destroy, void,
372 private_child_delete_t *this)
373 {
374 this->child_sas->destroy(this->child_sas);
375 free(this);
376 }
377
378 /*
379 * Described in header.
380 */
381 child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
382 u_int32_t spi, bool expired)
383 {
384 private_child_delete_t *this;
385
386 INIT(this,
387 .public = {
388 .task = {
389 .get_type = _get_type,
390 .migrate = _migrate,
391 .destroy = _destroy,
392 },
393 .get_child = _get_child,
394 },
395 .ike_sa = ike_sa,
396 .child_sas = linked_list_create(),
397 .protocol = protocol,
398 .spi = spi,
399 .expired = expired,
400 );
401
402 if (protocol != PROTO_NONE)
403 {
404 this->public.task.build = _build_i;
405 this->public.task.process = _process_i;
406 this->initiator = TRUE;
407 }
408 else
409 {
410 this->public.task.build = _build_r;
411 this->public.task.process = _process_r;
412 this->initiator = FALSE;
413 }
414 return &this->public;
415 }