]> git.ipfire.org Git - people/ms/strongswan.git/blame - src/charon/sa/tasks/ike_config.c
Prefer EAP-Identity for provider attribute/address lookup
[people/ms/strongswan.git] / src / charon / sa / tasks / ike_config.c
CommitLineData
c60c7694
MW
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
22typedef struct private_ike_config_t private_ike_config_t;
23
24/**
25 * Private members of a ike_config_t task.
26 */
27struct private_ike_config_t {
7daf5226 28
c60c7694
MW
29 /**
30 * Public methods and task_t interface.
31 */
32 ike_config_t public;
7daf5226 33
c60c7694
MW
34 /**
35 * Assigned IKE_SA.
36 */
37 ike_sa_t *ike_sa;
7daf5226 38
c60c7694
MW
39 /**
40 * Are we the initiator?
41 */
42 bool initiator;
7daf5226 43
c60c7694
MW
44 /**
45 * virtual ip
46 */
47 host_t *virtual_ip;
b5a2055f
MW
48
49 /**
50 * list of attributes requested and its handler, entry_t
51 */
52 linked_list_t *requested;
c60c7694
MW
53};
54
55/**
b5a2055f
MW
56 * Entry for a requested attribute and the requesting handler
57 */
58typedef 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
c60c7694 67 */
b5a2055f 68static configuration_attribute_t *build_vip(host_t *vip)
c60c7694 69{
b5a2055f 70 configuration_attribute_type_t type;
c60c7694 71 chunk_t chunk, prefix;
7daf5226 72
7f56b494 73 if (vip->get_family(vip) == AF_INET)
c60c7694 74 {
b5a2055f 75 type = INTERNAL_IP4_ADDRESS;
7f56b494 76 if (vip->is_anyaddr(vip))
c60c7694
MW
77 {
78 chunk = chunk_empty;
79 }
80 else
81 {
7f56b494 82 chunk = vip->get_address(vip);
c60c7694
MW
83 }
84 }
85 else
86 {
b5a2055f 87 type = INTERNAL_IP6_ADDRESS;
7f56b494 88 if (vip->is_anyaddr(vip))
c60c7694
MW
89 {
90 chunk = chunk_empty;
91 }
92 else
93 {
94 prefix = chunk_alloca(1);
95 *prefix.ptr = 64;
7f56b494 96 chunk = vip->get_address(vip);
c60c7694
MW
97 chunk = chunk_cata("cc", chunk, prefix);
98 }
99 }
b5a2055f
MW
100 return configuration_attribute_create_value(type, chunk);
101}
102
103/**
104 * Handle a received attribute as initiator
105 */
106static void handle_attribute(private_ike_config_t *this,
107 configuration_attribute_t *ca)
108{
109 attribute_handler_t *handler = NULL;
110 enumerator_t *enumerator;
111 entry_t *entry;
112
113 /* find the handler which requested this attribute */
114 enumerator = this->requested->create_enumerator(this->requested);
115 while (enumerator->enumerate(enumerator, &entry))
116 {
117 if (entry->type == ca->get_type(ca))
118 {
119 handler = entry->handler;
120 this->requested->remove_at(this->requested, enumerator);
121 free(entry);
122 break;
123 }
124 }
1427c93f 125 enumerator->destroy(enumerator);
b5a2055f
MW
126
127 /* and pass it to the handle function */
128 handler = lib->attributes->handle(lib->attributes,
129 this->ike_sa->get_other_id(this->ike_sa), handler,
130 ca->get_type(ca), ca->get_value(ca));
131 if (handler)
132 {
133 this->ike_sa->add_configuration_attribute(this->ike_sa,
134 handler, ca->get_type(ca), ca->get_value(ca));
135 }
c60c7694
MW
136}
137
138/**
139 * process a single configuration attribute
140 */
141static void process_attribute(private_ike_config_t *this,
142 configuration_attribute_t *ca)
143{
144 host_t *ip;
145 chunk_t addr;
146 int family = AF_INET6;
7daf5226 147
c60c7694
MW
148 switch (ca->get_type(ca))
149 {
150 case INTERNAL_IP4_ADDRESS:
151 family = AF_INET;
152 /* fall */
153 case INTERNAL_IP6_ADDRESS:
154 {
155 addr = ca->get_value(ca);
156 if (addr.len == 0)
157 {
158 ip = host_create_any(family);
159 }
160 else
161 {
162 /* skip prefix byte in IPv6 payload*/
163 if (family == AF_INET6)
164 {
7daf5226 165 addr.len--;
c60c7694
MW
166 }
167 ip = host_create_from_chunk(family, addr, 0);
168 }
c60c7694
MW
169 if (ip)
170 {
7f56b494
MW
171 DESTROY_IF(this->virtual_ip);
172 this->virtual_ip = ip;
c60c7694
MW
173 }
174 break;
175 }
7f56b494 176 default:
b5a2055f 177 {
7f56b494 178 if (this->initiator)
2b1f5f34 179 {
b5a2055f 180 handle_attribute(this, ca);
2b1f5f34 181 }
b5a2055f 182 }
c60c7694
MW
183 }
184}
185
186/**
187 * Scan for configuration payloads and attributes
188 */
189static void process_payloads(private_ike_config_t *this, message_t *message)
190{
b5a2055f 191 enumerator_t *enumerator, *attributes;
c60c7694 192 payload_t *payload;
7daf5226 193
a44bb934
MW
194 enumerator = message->create_payload_enumerator(message);
195 while (enumerator->enumerate(enumerator, &payload))
c60c7694
MW
196 {
197 if (payload->get_type(payload) == CONFIGURATION)
198 {
199 cp_payload_t *cp = (cp_payload_t*)payload;
200 configuration_attribute_t *ca;
b5a2055f
MW
201
202 switch (cp->get_type(cp))
c60c7694
MW
203 {
204 case CFG_REQUEST:
205 case CFG_REPLY:
206 {
b5a2055f
MW
207 attributes = cp->create_attribute_enumerator(cp);
208 while (attributes->enumerate(attributes, &ca))
c60c7694 209 {
653da7c9
AS
210 DBG2(DBG_IKE, "processing %N config attribute",
211 configuration_attribute_type_names, ca->get_type(ca));
c60c7694
MW
212 process_attribute(this, ca);
213 }
214 attributes->destroy(attributes);
215 break;
216 }
217 default:
7daf5226 218 DBG1(DBG_IKE, "ignoring %N config payload",
b5a2055f 219 config_type_names, cp->get_type(cp));
c60c7694
MW
220 break;
221 }
222 }
223 }
a44bb934 224 enumerator->destroy(enumerator);
c60c7694
MW
225}
226
227/**
228 * Implementation of task_t.process for initiator
229 */
230static status_t build_i(private_ike_config_t *this, message_t *message)
231{
a44bb934
MW
232 if (message->get_message_id(message) == 1)
233 { /* in first IKE_AUTH only */
b5a2055f
MW
234 cp_payload_t *cp = NULL;
235 enumerator_t *enumerator;
236 attribute_handler_t *handler;
00ccb876 237 peer_cfg_t *config;
b5a2055f
MW
238 configuration_attribute_type_t type;
239 chunk_t data;
00ccb876 240 host_t *vip;
7daf5226 241
00ccb876
MW
242 /* reuse virtual IP if we already have one */
243 vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
cdcfe777 244 if (!vip)
00ccb876 245 {
cdcfe777
MW
246 config = this->ike_sa->get_peer_cfg(this->ike_sa);
247 vip = config->get_virtual_ip(config);
00ccb876 248 }
cdcfe777 249 if (vip)
00ccb876 250 {
b5a2055f
MW
251 cp = cp_payload_create_type(CFG_REQUEST);
252 cp->add_attribute(cp, build_vip(vip));
253 }
7daf5226 254
b5a2055f
MW
255 enumerator = lib->attributes->create_initiator_enumerator(lib->attributes,
256 this->ike_sa->get_other_id(this->ike_sa), vip);
257 while (enumerator->enumerate(enumerator, &handler, &type, &data))
258 {
259 configuration_attribute_t *ca;
260 entry_t *entry;
7daf5226 261
b5a2055f 262 /* create configuration attribute */
653da7c9
AS
263 DBG2(DBG_IKE, "building %N config attribute",
264 configuration_attribute_type_names, type);
b5a2055f
MW
265 ca = configuration_attribute_create_value(type, data);
266 if (!cp)
7f56b494 267 {
b5a2055f 268 cp = cp_payload_create_type(CFG_REQUEST);
7f56b494 269 }
b5a2055f
MW
270 cp->add_attribute(cp, ca);
271
272 /* save handler along with requested type */
273 entry = malloc_thing(entry_t);
274 entry->type = type;
275 entry->handler = handler;
276
277 this->requested->insert_last(this->requested, entry);
278 }
279 enumerator->destroy(enumerator);
280
281 if (cp)
282 {
7f56b494 283 message->add_payload(message, (payload_t*)cp);
00ccb876 284 }
c60c7694 285 }
c60c7694
MW
286 return NEED_MORE;
287}
288
289/**
290 * Implementation of task_t.process for responder
291 */
292static status_t process_r(private_ike_config_t *this, message_t *message)
293{
a44bb934
MW
294 if (message->get_message_id(message) == 1)
295 { /* in first IKE_AUTH only */
c60c7694
MW
296 process_payloads(this, message);
297 }
298 return NEED_MORE;
299}
300
5b4d0de7
MW
301/**
302 * Find a peer (EAP) identity to query provider for attributes
303 */
304static identification_t *get_peer_identity(private_ike_config_t *this)
305{
306 identification_t *id = NULL, *current;
307 enumerator_t *enumerator;
308 auth_cfg_t *cfg;
309
310 enumerator = this->ike_sa->create_auth_cfg_enumerator(this->ike_sa, FALSE);
311 while (enumerator->enumerate(enumerator, &cfg))
312 {
313 /* prefer EAP-Identity of last round */
314 current = cfg->get(cfg, AUTH_RULE_EAP_IDENTITY);
315 if (!current || current->get_type(current) == ID_ANY)
316 {
317 current = cfg->get(cfg, AUTH_RULE_IDENTITY);
318 }
319 if (current && current->get_type(current) != ID_ANY)
320 {
321 id = current;
322 continue;
323 }
324 }
325 enumerator->destroy(enumerator);
326 if (!id)
327 { /* fallback, should not happen */
328 id = this->ike_sa->get_other_id(this->ike_sa);
329 }
330 return id;
331}
332
c60c7694
MW
333/**
334 * Implementation of task_t.build for responder
335 */
336static status_t build_r(private_ike_config_t *this, message_t *message)
337{
a44bb934
MW
338 if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
339 { /* in last IKE_AUTH exchange */
b5a2055f
MW
340 enumerator_t *enumerator;
341 configuration_attribute_type_t type;
342 chunk_t value;
343 host_t *vip = NULL;
344 cp_payload_t *cp = NULL;
345 peer_cfg_t *config;
5b4d0de7
MW
346 identification_t *id;
347
348 id = get_peer_identity(this);
7daf5226 349
b5a2055f 350 config = this->ike_sa->get_peer_cfg(this->ike_sa);
e0fe7651 351 if (config && this->virtual_ip)
c60c7694 352 {
c60c7694 353 DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
45819d7d
MW
354 if (config->get_pool(config))
355 {
930443af 356 vip = lib->attributes->acquire_address(lib->attributes,
5b4d0de7 357 config->get_pool(config), id, this->virtual_ip);
45819d7d 358 }
7f56b494 359 if (vip == NULL)
c60c7694 360 {
d510eaea
MW
361 DBG1(DBG_IKE, "no virtual IP found, sending %N",
362 notify_type_names, INTERNAL_ADDRESS_FAILURE);
363 message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE,
364 chunk_empty);
c60c7694
MW
365 return SUCCESS;
366 }
7f56b494
MW
367 DBG1(DBG_IKE, "assigning virtual IP %H to peer", vip);
368 this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip);
7daf5226 369
b5a2055f
MW
370 cp = cp_payload_create_type(CFG_REPLY);
371 cp->add_attribute(cp, build_vip(vip));
372 }
7daf5226 373
b5a2055f
MW
374 /* query registered providers for additional attributes to include */
375 enumerator = lib->attributes->create_responder_enumerator(
5b4d0de7 376 lib->attributes, id, vip);
b5a2055f
MW
377 while (enumerator->enumerate(enumerator, &type, &value))
378 {
379 if (!cp)
7f56b494 380 {
b5a2055f 381 cp = cp_payload_create_type(CFG_REPLY);
7f56b494 382 }
b5a2055f
MW
383 cp->add_attribute(cp,
384 configuration_attribute_create_value(type, value));
385 }
386 enumerator->destroy(enumerator);
7daf5226 387
b5a2055f
MW
388 if (cp)
389 {
7f56b494 390 message->add_payload(message, (payload_t*)cp);
c60c7694 391 }
b5a2055f 392 DESTROY_IF(vip);
c60c7694
MW
393 return SUCCESS;
394 }
395 return NEED_MORE;
396}
397
398/**
399 * Implementation of task_t.process for initiator
400 */
401static status_t process_i(private_ike_config_t *this, message_t *message)
402{
a44bb934
MW
403 if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
404 { /* in last IKE_AUTH exchange */
7daf5226 405
c60c7694 406 process_payloads(this, message);
7daf5226 407
7f56b494 408 if (this->virtual_ip)
c60c7694
MW
409 {
410 this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
c60c7694
MW
411 }
412 return SUCCESS;
413 }
414 return NEED_MORE;
415}
416
417/**
418 * Implementation of task_t.get_type
419 */
420static task_type_t get_type(private_ike_config_t *this)
421{
422 return IKE_CONFIG;
423}
424
425/**
426 * Implementation of task_t.migrate
427 */
428static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa)
429{
430 DESTROY_IF(this->virtual_ip);
7daf5226 431
c60c7694
MW
432 this->ike_sa = ike_sa;
433 this->virtual_ip = NULL;
b5a2055f
MW
434 this->requested->destroy_function(this->requested, free);
435 this->requested = linked_list_create();
c60c7694
MW
436}
437
438/**
439 * Implementation of task_t.destroy
440 */
441static void destroy(private_ike_config_t *this)
442{
443 DESTROY_IF(this->virtual_ip);
b5a2055f 444 this->requested->destroy_function(this->requested, free);
c60c7694
MW
445 free(this);
446}
447
448/*
449 * Described in header.
450 */
e0fe7651 451ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator)
c60c7694
MW
452{
453 private_ike_config_t *this = malloc_thing(private_ike_config_t);
7daf5226 454
c60c7694
MW
455 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
456 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
457 this->public.task.destroy = (void(*)(task_t*))destroy;
7daf5226 458
48f9a22b
AS
459 this->initiator = initiator;
460 this->ike_sa = ike_sa;
461 this->virtual_ip = NULL;
b5a2055f 462 this->requested = linked_list_create();
7daf5226 463
e0fe7651 464 if (initiator)
c60c7694
MW
465 {
466 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
467 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
c60c7694
MW
468 }
469 else
470 {
471 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
472 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
c60c7694 473 }
7daf5226 474
c60c7694
MW
475 return &this->public;
476}
7f56b494 477