attribute-manager: Pass the full IKE_SA to provider methods
[strongswan.git] / src / libcharon / sa / ikev2 / tasks / ike_config.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "ike_config.h"
18
19 #include <daemon.h>
20 #include <encoding/payloads/cp_payload.h>
21
22 typedef struct private_ike_config_t private_ike_config_t;
23
24 /**
25 * Private members of a ike_config_t task.
26 */
27 struct private_ike_config_t {
28
29 /**
30 * Public methods and task_t interface.
31 */
32 ike_config_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 * Received list of virtual IPs, host_t*
46 */
47 linked_list_t *vips;
48
49 /**
50 * list of attributes requested and its handler, entry_t
51 */
52 linked_list_t *requested;
53 };
54
55 /**
56 * Entry for a requested attribute and the requesting handler
57 */
58 typedef struct {
59 /** attribute requested */
60 configuration_attribute_type_t type;
61 /** handler requesting this attribute */
62 attribute_handler_t *handler;
63 } entry_t;
64
65 /**
66 * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip
67 */
68 static configuration_attribute_t *build_vip(host_t *vip)
69 {
70 configuration_attribute_type_t type;
71 chunk_t chunk, prefix;
72
73 if (vip->get_family(vip) == AF_INET)
74 {
75 type = INTERNAL_IP4_ADDRESS;
76 if (vip->is_anyaddr(vip))
77 {
78 chunk = chunk_empty;
79 }
80 else
81 {
82 chunk = vip->get_address(vip);
83 }
84 }
85 else
86 {
87 type = INTERNAL_IP6_ADDRESS;
88 if (vip->is_anyaddr(vip))
89 {
90 chunk = chunk_empty;
91 }
92 else
93 {
94 prefix = chunk_alloca(1);
95 *prefix.ptr = 64;
96 chunk = vip->get_address(vip);
97 chunk = chunk_cata("cc", chunk, prefix);
98 }
99 }
100 return configuration_attribute_create_chunk(PLV2_CONFIGURATION_ATTRIBUTE,
101 type, chunk);
102 }
103
104 /**
105 * Handle a received attribute as initiator
106 */
107 static void handle_attribute(private_ike_config_t *this,
108 configuration_attribute_t *ca)
109 {
110 attribute_handler_t *handler = NULL;
111 enumerator_t *enumerator;
112 entry_t *entry;
113
114 /* find the handler which requested this attribute */
115 enumerator = this->requested->create_enumerator(this->requested);
116 while (enumerator->enumerate(enumerator, &entry))
117 {
118 if (entry->type == ca->get_type(ca))
119 {
120 handler = entry->handler;
121 this->requested->remove_at(this->requested, enumerator);
122 free(entry);
123 break;
124 }
125 }
126 enumerator->destroy(enumerator);
127
128 /* and pass it to the handle function */
129 handler = charon->attributes->handle(charon->attributes,
130 this->ike_sa->get_other_id(this->ike_sa), handler,
131 ca->get_type(ca), ca->get_chunk(ca));
132 this->ike_sa->add_configuration_attribute(this->ike_sa,
133 handler, ca->get_type(ca), ca->get_chunk(ca));
134 }
135
136 /**
137 * process a single configuration attribute
138 */
139 static void process_attribute(private_ike_config_t *this,
140 configuration_attribute_t *ca)
141 {
142 host_t *ip;
143 chunk_t addr;
144 int family = AF_INET6;
145
146 switch (ca->get_type(ca))
147 {
148 case INTERNAL_IP4_ADDRESS:
149 family = AF_INET;
150 /* fall */
151 case INTERNAL_IP6_ADDRESS:
152 {
153 addr = ca->get_chunk(ca);
154 if (addr.len == 0)
155 {
156 ip = host_create_any(family);
157 }
158 else
159 {
160 /* skip prefix byte in IPv6 payload*/
161 if (family == AF_INET6)
162 {
163 addr.len--;
164 }
165 ip = host_create_from_chunk(family, addr, 0);
166 }
167 if (ip)
168 {
169 this->vips->insert_last(this->vips, ip);
170 }
171 break;
172 }
173 case INTERNAL_IP4_SERVER:
174 case INTERNAL_IP6_SERVER:
175 /* assume it's a Windows client if we see proprietary attributes */
176 this->ike_sa->enable_extension(this->ike_sa, EXT_MS_WINDOWS);
177 /* fall */
178 default:
179 {
180 if (this->initiator)
181 {
182 handle_attribute(this, ca);
183 }
184 }
185 }
186 }
187
188 /**
189 * Scan for configuration payloads and attributes
190 */
191 static void process_payloads(private_ike_config_t *this, message_t *message)
192 {
193 enumerator_t *enumerator, *attributes;
194 payload_t *payload;
195
196 enumerator = message->create_payload_enumerator(message);
197 while (enumerator->enumerate(enumerator, &payload))
198 {
199 if (payload->get_type(payload) == PLV2_CONFIGURATION)
200 {
201 cp_payload_t *cp = (cp_payload_t*)payload;
202 configuration_attribute_t *ca;
203
204 switch (cp->get_type(cp))
205 {
206 case CFG_REQUEST:
207 case CFG_REPLY:
208 {
209 attributes = cp->create_attribute_enumerator(cp);
210 while (attributes->enumerate(attributes, &ca))
211 {
212 DBG2(DBG_IKE, "processing %N attribute",
213 configuration_attribute_type_names, ca->get_type(ca));
214 process_attribute(this, ca);
215 }
216 attributes->destroy(attributes);
217 break;
218 }
219 default:
220 DBG1(DBG_IKE, "ignoring %N config payload",
221 config_type_names, cp->get_type(cp));
222 break;
223 }
224 }
225 }
226 enumerator->destroy(enumerator);
227 }
228
229 METHOD(task_t, build_i, status_t,
230 private_ike_config_t *this, message_t *message)
231 {
232 if (message->get_message_id(message) == 1)
233 { /* in first IKE_AUTH only */
234 cp_payload_t *cp = NULL;
235 enumerator_t *enumerator;
236 attribute_handler_t *handler;
237 peer_cfg_t *config;
238 configuration_attribute_type_t type;
239 chunk_t data;
240 linked_list_t *vips;
241 host_t *host;
242
243 vips = linked_list_create();
244
245 /* reuse virtual IP if we already have one */
246 enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa,
247 TRUE);
248 while (enumerator->enumerate(enumerator, &host))
249 {
250 vips->insert_last(vips, host);
251 }
252 enumerator->destroy(enumerator);
253
254 if (vips->get_count(vips) == 0)
255 {
256 config = this->ike_sa->get_peer_cfg(this->ike_sa);
257 enumerator = config->create_virtual_ip_enumerator(config);
258 while (enumerator->enumerate(enumerator, &host))
259 {
260 vips->insert_last(vips, host);
261 }
262 enumerator->destroy(enumerator);
263 }
264
265 if (vips->get_count(vips))
266 {
267 cp = cp_payload_create_type(PLV2_CONFIGURATION, CFG_REQUEST);
268 enumerator = vips->create_enumerator(vips);
269 while (enumerator->enumerate(enumerator, &host))
270 {
271 cp->add_attribute(cp, build_vip(host));
272 }
273 enumerator->destroy(enumerator);
274 }
275
276 enumerator = charon->attributes->create_initiator_enumerator(
277 charon->attributes,
278 this->ike_sa->get_other_id(this->ike_sa), vips);
279 while (enumerator->enumerate(enumerator, &handler, &type, &data))
280 {
281 configuration_attribute_t *ca;
282 entry_t *entry;
283
284 /* create configuration attribute */
285 DBG2(DBG_IKE, "building %N attribute",
286 configuration_attribute_type_names, type);
287 ca = configuration_attribute_create_chunk(PLV2_CONFIGURATION_ATTRIBUTE,
288 type, data);
289 if (!cp)
290 {
291 cp = cp_payload_create_type(PLV2_CONFIGURATION, CFG_REQUEST);
292 }
293 cp->add_attribute(cp, ca);
294
295 /* save handler along with requested type */
296 entry = malloc_thing(entry_t);
297 entry->type = type;
298 entry->handler = handler;
299
300 this->requested->insert_last(this->requested, entry);
301 }
302 enumerator->destroy(enumerator);
303
304 vips->destroy(vips);
305
306 if (cp)
307 {
308 message->add_payload(message, (payload_t*)cp);
309 }
310 }
311 return NEED_MORE;
312 }
313
314 METHOD(task_t, process_r, status_t,
315 private_ike_config_t *this, message_t *message)
316 {
317 if (message->get_message_id(message) == 1)
318 { /* in first IKE_AUTH only */
319 process_payloads(this, message);
320 }
321 return NEED_MORE;
322 }
323
324 METHOD(task_t, build_r, status_t,
325 private_ike_config_t *this, message_t *message)
326 {
327 if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
328 { /* in last IKE_AUTH exchange */
329 enumerator_t *enumerator;
330 configuration_attribute_type_t type;
331 chunk_t value;
332 cp_payload_t *cp = NULL;
333 peer_cfg_t *config;
334 identification_t *id;
335 linked_list_t *vips, *pools;
336 host_t *requested;
337
338 id = this->ike_sa->get_other_eap_id(this->ike_sa);
339 config = this->ike_sa->get_peer_cfg(this->ike_sa);
340 vips = linked_list_create();
341 pools = linked_list_create_from_enumerator(
342 config->create_pool_enumerator(config));
343
344 this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
345
346 enumerator = this->vips->create_enumerator(this->vips);
347 while (enumerator->enumerate(enumerator, &requested))
348 {
349 host_t *found = NULL;
350
351 /* query all pools until we get an address */
352 DBG1(DBG_IKE, "peer requested virtual IP %H", requested);
353
354 found = charon->attributes->acquire_address(charon->attributes,
355 pools, this->ike_sa, requested);
356 if (found)
357 {
358 DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
359 this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
360 if (!cp)
361 {
362 cp = cp_payload_create_type(PLV2_CONFIGURATION, CFG_REPLY);
363 }
364 cp->add_attribute(cp, build_vip(found));
365 vips->insert_last(vips, found);
366 }
367 else
368 {
369 DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'",
370 requested, id);
371 }
372 }
373 enumerator->destroy(enumerator);
374
375 if (this->vips->get_count(this->vips) && !vips->get_count(vips))
376 {
377 DBG1(DBG_IKE, "no virtual IP found, sending %N",
378 notify_type_names, INTERNAL_ADDRESS_FAILURE);
379 charon->bus->alert(charon->bus, ALERT_VIP_FAILURE, this->vips);
380 message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE,
381 chunk_empty);
382 vips->destroy_offset(vips, offsetof(host_t, destroy));
383 pools->destroy(pools);
384 return SUCCESS;
385 }
386 charon->bus->assign_vips(charon->bus, this->ike_sa, TRUE);
387
388 if (pools->get_count(pools) && !this->vips->get_count(this->vips))
389 {
390 DBG1(DBG_IKE, "expected a virtual IP request, sending %N",
391 notify_type_names, FAILED_CP_REQUIRED);
392 charon->bus->alert(charon->bus, ALERT_VIP_FAILURE, this->vips);
393 message->add_notify(message, FALSE, FAILED_CP_REQUIRED, chunk_empty);
394 vips->destroy_offset(vips, offsetof(host_t, destroy));
395 pools->destroy(pools);
396 return SUCCESS;
397 }
398
399 /* query registered providers for additional attributes to include */
400 enumerator = charon->attributes->create_responder_enumerator(
401 charon->attributes, pools, this->ike_sa, vips);
402 while (enumerator->enumerate(enumerator, &type, &value))
403 {
404 if (!cp)
405 {
406 cp = cp_payload_create_type(PLV2_CONFIGURATION, CFG_REPLY);
407 }
408 DBG2(DBG_IKE, "building %N attribute",
409 configuration_attribute_type_names, type);
410 cp->add_attribute(cp,
411 configuration_attribute_create_chunk(PLV2_CONFIGURATION_ATTRIBUTE,
412 type, value));
413 }
414 enumerator->destroy(enumerator);
415 vips->destroy_offset(vips, offsetof(host_t, destroy));
416 pools->destroy(pools);
417
418 if (cp)
419 {
420 message->add_payload(message, (payload_t*)cp);
421 }
422 return SUCCESS;
423 }
424 return NEED_MORE;
425 }
426
427 METHOD(task_t, process_i, status_t,
428 private_ike_config_t *this, message_t *message)
429 {
430 if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
431 { /* in last IKE_AUTH exchange */
432 enumerator_t *enumerator;
433 host_t *host;
434
435 process_payloads(this, message);
436
437 this->ike_sa->clear_virtual_ips(this->ike_sa, TRUE);
438
439 enumerator = this->vips->create_enumerator(this->vips);
440 while (enumerator->enumerate(enumerator, &host))
441 {
442 if (!host->is_anyaddr(host))
443 {
444 this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host);
445 }
446 }
447 enumerator->destroy(enumerator);
448
449 charon->bus->handle_vips(charon->bus, this->ike_sa, TRUE);
450 return SUCCESS;
451 }
452 return NEED_MORE;
453 }
454
455 METHOD(task_t, get_type, task_type_t,
456 private_ike_config_t *this)
457 {
458 return TASK_IKE_CONFIG;
459 }
460
461 METHOD(task_t, migrate, void,
462 private_ike_config_t *this, ike_sa_t *ike_sa)
463 {
464 this->ike_sa = ike_sa;
465 this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
466 this->vips = linked_list_create();
467 this->requested->destroy_function(this->requested, free);
468 this->requested = linked_list_create();
469 }
470
471 METHOD(task_t, destroy, void,
472 private_ike_config_t *this)
473 {
474 this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
475 this->requested->destroy_function(this->requested, free);
476 free(this);
477 }
478
479 /*
480 * Described in header.
481 */
482 ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator)
483 {
484 private_ike_config_t *this;
485
486 INIT(this,
487 .public = {
488 .task = {
489 .get_type = _get_type,
490 .migrate = _migrate,
491 .destroy = _destroy,
492 },
493 },
494 .initiator = initiator,
495 .ike_sa = ike_sa,
496 .vips = linked_list_create(),
497 .requested = linked_list_create(),
498 );
499
500 if (initiator)
501 {
502 this->public.task.build = _build_i;
503 this->public.task.process = _process_i;
504 }
505 else
506 {
507 this->public.task.build = _build_r;
508 this->public.task.process = _process_r;
509 }
510
511 return &this->public;
512 }