Annotation of embedaddon/strongswan/src/libcharon/plugins/stroke/stroke_config.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2012-2014 Tobias Brunner
3: * Copyright (C) 2008 Martin Willi
4: * HSR 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 "stroke_config.h"
18:
19: #include <daemon.h>
20: #include <threading/mutex.h>
21: #include <utils/lexparser.h>
22:
23: #include <netdb.h>
24:
25: typedef struct private_stroke_config_t private_stroke_config_t;
26:
27: /**
28: * private data of stroke_config
29: */
30: struct private_stroke_config_t {
31:
32: /**
33: * public functions
34: */
35: stroke_config_t public;
36:
37: /**
38: * list of peer_cfg_t
39: */
40: linked_list_t *list;
41:
42: /**
43: * mutex to lock config list
44: */
45: mutex_t *mutex;
46:
47: /**
48: * ca sections
49: */
50: stroke_ca_t *ca;
51:
52: /**
53: * credentials
54: */
55: stroke_cred_t *cred;
56:
57: /**
58: * Virtual IP pool / DNS backend
59: */
60: stroke_attribute_t *attributes;
61: };
62:
63: METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
64: private_stroke_config_t *this, identification_t *me, identification_t *other)
65: {
66: this->mutex->lock(this->mutex);
67: return enumerator_create_cleaner(this->list->create_enumerator(this->list),
68: (void*)this->mutex->unlock, this->mutex);
69: }
70:
71: CALLBACK(ike_filter, bool,
72: void *data, enumerator_t *orig, va_list args)
73: {
74: peer_cfg_t *cfg;
75: ike_cfg_t **out;
76:
77: VA_ARGS_VGET(args, out);
78:
79: if (orig->enumerate(orig, &cfg))
80: {
81: *out = cfg->get_ike_cfg(cfg);
82: return TRUE;
83: }
84: return FALSE;
85: }
86:
87: METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
88: private_stroke_config_t *this, host_t *me, host_t *other)
89: {
90: this->mutex->lock(this->mutex);
91: return enumerator_create_filter(this->list->create_enumerator(this->list),
92: ike_filter, this->mutex,
93: (void*)this->mutex->unlock);
94: }
95:
96: METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
97: private_stroke_config_t *this, char *name)
98: {
99: enumerator_t *e1, *e2;
100: peer_cfg_t *current, *found = NULL;
101: child_cfg_t *child;
102:
103: this->mutex->lock(this->mutex);
104: e1 = this->list->create_enumerator(this->list);
105: while (e1->enumerate(e1, ¤t))
106: {
107: /* compare peer_cfgs name first */
108: if (streq(current->get_name(current), name))
109: {
110: found = current;
111: found->get_ref(found);
112: break;
113: }
114: /* compare all child_cfg names otherwise */
115: e2 = current->create_child_cfg_enumerator(current);
116: while (e2->enumerate(e2, &child))
117: {
118: if (streq(child->get_name(child), name))
119: {
120: found = current;
121: found->get_ref(found);
122: break;
123: }
124: }
125: e2->destroy(e2);
126: if (found)
127: {
128: break;
129: }
130: }
131: e1->destroy(e1);
132: this->mutex->unlock(this->mutex);
133: return found;
134: }
135:
136: /**
137: * parse a proposal string, either into ike_cfg or child_cfg
138: */
139: static bool add_proposals(private_stroke_config_t *this, char *string,
140: ike_cfg_t *ike_cfg, child_cfg_t *child_cfg, protocol_id_t proto)
141: {
142: if (string)
143: {
144: char *single;
145: char *strict;
146: proposal_t *proposal;
147:
148: strict = string + strlen(string) - 1;
149: if (*strict == '!')
150: {
151: *strict = '\0';
152: }
153: else
154: {
155: strict = NULL;
156: }
157: while ((single = strsep(&string, ",")))
158: {
159: proposal = proposal_create_from_string(proto, single);
160: if (proposal)
161: {
162: if (ike_cfg)
163: {
164: ike_cfg->add_proposal(ike_cfg, proposal);
165: }
166: else
167: {
168: child_cfg->add_proposal(child_cfg, proposal);
169: }
170: continue;
171: }
172: DBG1(DBG_CFG, "skipped invalid proposal string: %s", single);
173: return FALSE;
174: }
175: if (strict)
176: {
177: return TRUE;
178: }
179: /* add default proposal to the end if not strict */
180: }
181: if (ike_cfg)
182: {
183: ike_cfg->add_proposal(ike_cfg, proposal_create_default(proto));
184: ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(proto));
185: }
186: else
187: {
188: child_cfg->add_proposal(child_cfg, proposal_create_default(proto));
189: child_cfg->add_proposal(child_cfg, proposal_create_default_aead(proto));
190: }
191: return TRUE;
192: }
193:
194: /**
195: * Check if any addresses in the given string are local
196: */
197: static bool is_local(char *address, bool any_allowed)
198: {
199: enumerator_t *enumerator;
200: host_t *host;
201: char *token;
202: bool found = FALSE;
203:
204: enumerator = enumerator_create_token(address, ",", " ");
205: while (enumerator->enumerate(enumerator, &token))
206: {
207: if (!strchr(token, '/'))
208: {
209: host = host_create_from_dns(token, 0, 0);
210: if (host)
211: {
212: if (charon->kernel->get_interface(charon->kernel, host, NULL))
213: {
214: found = TRUE;
215: }
216: else if (any_allowed && host->is_anyaddr(host))
217: {
218: found = TRUE;
219: }
220: host->destroy(host);
221: if (found)
222: {
223: break;
224: }
225: }
226: }
227: }
228: enumerator->destroy(enumerator);
229: return found;
230: }
231:
232: /**
233: * Swap ends if indicated by left|right
234: */
235: static void swap_ends(stroke_msg_t *msg)
236: {
237: if (!lib->settings->get_bool(lib->settings, "%s.plugins.stroke.allow_swap",
238: TRUE, lib->ns))
239: {
240: return;
241: }
242:
243: if (is_local(msg->add_conn.other.address, FALSE))
244: {
245: stroke_end_t tmp_end;
246:
247: DBG2(DBG_CFG, "left is other host, swapping ends");
248: tmp_end = msg->add_conn.me;
249: msg->add_conn.me = msg->add_conn.other;
250: msg->add_conn.other = tmp_end;
251: }
252: else if (!is_local(msg->add_conn.me.address, TRUE))
253: {
254: DBG1(DBG_CFG, "left nor right host is our side, assuming left=local");
255: }
256: }
257:
258: /**
259: * Build an IKE config from a stroke message
260: */
261: static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg)
262: {
263: ike_cfg_create_t ike;
264: ike_cfg_t *ike_cfg;
265: char me[256], other[256];
266:
267: swap_ends(msg);
268:
269: ike = (ike_cfg_create_t){
270: .version = msg->add_conn.version,
271: .local = msg->add_conn.me.address,
272: .local_port = msg->add_conn.me.ikeport,
273: .remote = msg->add_conn.other.address,
274: .remote_port = msg->add_conn.other.ikeport,
275: .no_certreq = msg->add_conn.other.sendcert == CERT_NEVER_SEND,
276: .force_encap = msg->add_conn.force_encap,
277: .fragmentation = msg->add_conn.fragmentation,
278: .dscp = msg->add_conn.ikedscp,
279: };
280: if (msg->add_conn.me.allow_any)
281: {
282: snprintf(me, sizeof(me), "%s,0.0.0.0/0,::/0",
283: msg->add_conn.me.address);
284: ike.local = me;
285: }
286: if (msg->add_conn.other.allow_any)
287: {
288: snprintf(other, sizeof(other), "%s,0.0.0.0/0,::/0",
289: msg->add_conn.other.address);
290: ike.remote = other;
291: }
292: if (ike.local_port == IKEV2_UDP_PORT)
293: {
294: ike.local_port = charon->socket->get_port(charon->socket, FALSE);
295: }
296: ike_cfg = ike_cfg_create(&ike);
297:
298: if (!add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg,
299: NULL, PROTO_IKE))
300: {
301: ike_cfg->destroy(ike_cfg);
302: return NULL;
303: }
304: return ike_cfg;
305: }
306:
307: /**
308: * Add CRL constraint to config
309: */
310: static void build_crl_policy(auth_cfg_t *cfg, bool local, int policy)
311: {
312: /* CRL/OCSP policy, for remote config only */
313: if (!local)
314: {
315: switch (policy)
316: {
317: case CRL_STRICT_YES:
318: /* if yes, we require a GOOD validation */
319: cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
320: break;
321: case CRL_STRICT_IFURI:
322: /* for ifuri, a SKIPPED validation is sufficient */
323: cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_SKIPPED);
324: break;
325: default:
326: break;
327: }
328: }
329: }
330:
331: /**
332: * build authentication config
333: */
334: static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
335: stroke_msg_t *msg, bool local, bool primary)
336: {
337: identification_t *identity;
338: certificate_t *certificate;
339: char *auth, *id, *pubkey, *cert, *ca, *groups;
340: stroke_end_t *end, *other_end;
341: auth_cfg_t *cfg;
342: bool loose = FALSE;
343:
344: /* select strings */
345: if (local)
346: {
347: end = &msg->add_conn.me;
348: other_end = &msg->add_conn.other;
349: }
350: else
351: {
352: end = &msg->add_conn.other;
353: other_end = &msg->add_conn.me;
354: }
355: if (primary)
356: {
357: auth = end->auth;
358: id = end->id;
359: if (!id)
360: { /* leftid/rightid fallback to address */
361: id = end->address;
362: }
363: cert = end->cert;
364: ca = end->ca;
365: if (ca && streq(ca, "%same"))
366: {
367: ca = other_end->ca;
368: }
369: }
370: else
371: {
372: auth = end->auth2;
373: id = end->id2;
374: if (local && !id)
375: { /* leftid2 falls back to leftid */
376: id = end->id;
377: }
378: cert = end->cert2;
379: ca = end->ca2;
380: if (ca && streq(ca, "%same"))
381: {
382: ca = other_end->ca2;
383: }
384: }
385: if (id && *id == '%' && !streq(id, "%any") && !streq(id, "%any6"))
386: { /* has only an effect on rightid/2 */
387: loose = !local;
388: id++;
389: }
390:
391: if (!auth)
392: {
393: if (primary)
394: {
395: auth = "pubkey";
396: }
397: else
398: { /* no second authentication round, fine. But load certificates
399: * for other purposes (EAP-TLS) */
400: if (cert)
401: {
402: certificate = this->cred->load_peer(this->cred, cert);
403: if (certificate)
404: {
405: certificate->destroy(certificate);
406: }
407: }
408: return NULL;
409: }
410: }
411:
412: cfg = auth_cfg_create();
413:
414: /* add identity and peer certificate */
415: identity = identification_create_from_string(id);
416: if (cert)
417: {
418: enumerator_t *enumerator;
419: bool has_subject = FALSE;
420: certificate_t *first = NULL;
421:
422: enumerator = enumerator_create_token(cert, ",", " ");
423: while (enumerator->enumerate(enumerator, &cert))
424: {
425: certificate = this->cred->load_peer(this->cred, cert);
426: if (certificate)
427: {
428: cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
429: if (!first)
430: {
431: first = certificate;
432: }
433: if (identity->get_type(identity) != ID_ANY &&
434: certificate->has_subject(certificate, identity))
435: {
436: has_subject = TRUE;
437: }
438: }
439: }
440: enumerator->destroy(enumerator);
441:
442: if (first && !has_subject)
443: {
444: DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, "
445: "defaulting to '%Y'", identity, first->get_subject(first));
446: identity->destroy(identity);
447: identity = first->get_subject(first);
448: identity = identity->clone(identity);
449: }
450: }
451: /* add raw RSA public key */
452: pubkey = end->rsakey;
453: if (pubkey && !streq(pubkey, "") && !streq(pubkey, "%cert"))
454: {
455: certificate = this->cred->load_pubkey(this->cred, pubkey, identity);
456: if (certificate)
457: {
458: cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
459: }
460: }
461: if (identity->get_type(identity) != ID_ANY)
462: {
463: cfg->add(cfg, AUTH_RULE_IDENTITY, identity);
464: if (loose)
465: {
466: cfg->add(cfg, AUTH_RULE_IDENTITY_LOOSE, TRUE);
467: }
468: }
469: else
470: {
471: identity->destroy(identity);
472: }
473:
474: /* CA constraint */
475: if (ca)
476: {
477: identity = identification_create_from_string(ca);
478: certificate = lib->credmgr->get_cert(lib->credmgr, CERT_X509,
479: KEY_ANY, identity, TRUE);
480: identity->destroy(identity);
481: if (certificate)
482: {
483: cfg->add(cfg, AUTH_RULE_CA_CERT, certificate);
484: }
485: else
486: {
487: DBG1(DBG_CFG, "CA certificate \"%s\" not found, discarding CA "
488: "constraint", ca);
489: }
490: }
491:
492: /* groups */
493: groups = primary ? end->groups : end->groups2;
494: if (groups)
495: {
496: enumerator_t *enumerator;
497: char *group;
498:
499: enumerator = enumerator_create_token(groups, ",", " ");
500: while (enumerator->enumerate(enumerator, &group))
501: {
502: cfg->add(cfg, AUTH_RULE_GROUP,
503: identification_create_from_string(group));
504: }
505: enumerator->destroy(enumerator);
506: }
507:
508: /* certificatePolicies */
509: if (end->cert_policy)
510: {
511: enumerator_t *enumerator;
512: char *policy;
513:
514: enumerator = enumerator_create_token(end->cert_policy, ",", " ");
515: while (enumerator->enumerate(enumerator, &policy))
516: {
517: cfg->add(cfg, AUTH_RULE_CERT_POLICY, strdup(policy));
518: }
519: enumerator->destroy(enumerator);
520: }
521:
522: /* authentication method (class, actually) */
523: if (strpfx(auth, "ike:") ||
524: strpfx(auth, "pubkey") ||
525: strpfx(auth, "rsa") ||
526: strpfx(auth, "ecdsa") ||
527: strpfx(auth, "bliss"))
528: {
529: cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
530: build_crl_policy(cfg, local, msg->add_conn.crl_policy);
531: cfg->add_pubkey_constraints(cfg, auth, TRUE);
532: }
533: else if (streq(auth, "psk") || streq(auth, "secret"))
534: {
535: cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
536: }
537: else if (strpfx(auth, "xauth"))
538: {
539: char *pos;
540:
541: pos = strchr(auth, '-');
542: if (pos)
543: {
544: cfg->add(cfg, AUTH_RULE_XAUTH_BACKEND, strdup(++pos));
545: }
546: cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
547: if (msg->add_conn.xauth_identity)
548: {
549: cfg->add(cfg, AUTH_RULE_XAUTH_IDENTITY,
550: identification_create_from_string(msg->add_conn.xauth_identity));
551: }
552: }
553: else if (strpfx(auth, "eap"))
554: {
555: eap_vendor_type_t *type;
556: char *pos;
557:
558: cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
559: /* check for public key constraints for EAP-TLS etc. */
560: pos = strchr(auth, ':');
561: if (pos)
562: {
563: *pos = 0;
564: cfg->add_pubkey_constraints(cfg, pos + 1, FALSE);
565: }
566: type = eap_vendor_type_from_string(auth);
567: if (type)
568: {
569: cfg->add(cfg, AUTH_RULE_EAP_TYPE, type->type);
570: if (type->vendor)
571: {
572: cfg->add(cfg, AUTH_RULE_EAP_VENDOR, type->vendor);
573: }
574: free(type);
575: }
576:
577: if (msg->add_conn.eap_identity)
578: {
579: if (streq(msg->add_conn.eap_identity, "%identity"))
580: {
581: identity = identification_create_from_encoding(ID_ANY,
582: chunk_empty);
583: }
584: else
585: {
586: identity = identification_create_from_string(
587: msg->add_conn.eap_identity);
588: }
589: cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, identity);
590: }
591: if (msg->add_conn.aaa_identity)
592: {
593: cfg->add(cfg, AUTH_RULE_AAA_IDENTITY,
594: identification_create_from_string(msg->add_conn.aaa_identity));
595: }
596: }
597: else
598: {
599: if (!streq(auth, "any"))
600: {
601: DBG1(DBG_CFG, "authentication method %s unknown, fallback to any",
602: auth);
603: }
604: build_crl_policy(cfg, local, msg->add_conn.crl_policy);
605: }
606: return cfg;
607: }
608:
609: /**
610: * build a mem_pool_t from an address range
611: */
612: static mem_pool_t *create_pool_range(char *str)
613: {
614: mem_pool_t *pool;
615: host_t *from, *to;
616:
617: if (!host_create_from_range(str, &from, &to))
618: {
619: return NULL;
620: }
621: pool = mem_pool_create_range(str, from, to);
622: from->destroy(from);
623: to->destroy(to);
624: return pool;
625: }
626:
627: /**
628: * build a peer_cfg from a stroke msg
629: */
630: static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
631: stroke_msg_t *msg, ike_cfg_t *ike_cfg)
632: {
633: peer_cfg_t *peer_cfg;
634: auth_cfg_t *auth_cfg;
635: peer_cfg_create_t peer = {
636: .cert_policy = msg->add_conn.me.sendcert,
637: .keyingtries = msg->add_conn.rekey.tries,
638: .no_mobike = !msg->add_conn.mobike,
639: .aggressive = msg->add_conn.aggressive,
640: .push_mode = msg->add_conn.pushmode,
641: .dpd = msg->add_conn.dpd.delay,
642: .dpd_timeout = msg->add_conn.dpd.timeout,
643: };
644:
645: #ifdef ME
646: if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by)
647: {
648: DBG1(DBG_CFG, "a mediation connection cannot be a mediated connection "
649: "at the same time, aborting");
650: return NULL;
651: }
652:
653: if (msg->add_conn.ikeme.mediation)
654: {
655: peer.mediation = TRUE;
656: /* force unique connections for mediation connections */
657: msg->add_conn.unique = 1;
658: }
659: else if (msg->add_conn.ikeme.mediated_by)
660: {
661: peer.mediated_by = msg->add_conn.ikeme.mediated_by;
662: if (msg->add_conn.ikeme.peerid)
663: {
664: peer.peer_id = identification_create_from_string(
665: msg->add_conn.ikeme.peerid);
666: }
667: else if (msg->add_conn.other.id)
668: {
669: peer.peer_id = identification_create_from_string(
670: msg->add_conn.other.id);
671: }
672: }
673: #endif /* ME */
674:
675: peer.jitter_time = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
676: peer.over_time = msg->add_conn.rekey.margin;
677: if (msg->add_conn.rekey.reauth)
678: {
679: peer.reauth_time = msg->add_conn.rekey.ike_lifetime - peer.over_time;
680: }
681: else
682: {
683: peer.rekey_time = msg->add_conn.rekey.ike_lifetime - peer.over_time;
684: }
685: switch (msg->add_conn.unique)
686: {
687: case 1: /* yes */
688: case 2: /* replace */
689: peer.unique = UNIQUE_REPLACE;
690: break;
691: case 3: /* keep */
692: peer.unique = UNIQUE_KEEP;
693: break;
694: case 4: /* never */
695: peer.unique = UNIQUE_NEVER;
696: break;
697: default: /* no */
698: peer.unique = UNIQUE_NO;
699: break;
700: }
701: if (msg->add_conn.dpd.action == 0)
702: { /* dpdaction=none disables DPD */
703: peer.dpd = 0;
704: }
705:
706: /* other.sourceip is managed in stroke_attributes. If it is set, we define
707: * the pool name as the connection name, which the attribute provider
708: * uses to serve pool addresses. */
709: peer_cfg = peer_cfg_create(msg->add_conn.name, ike_cfg, &peer);
710:
711: if (msg->add_conn.other.sourceip)
712: {
713: enumerator_t *enumerator;
714: char *token;
715:
716: enumerator = enumerator_create_token(msg->add_conn.other.sourceip,
717: ",", " ");
718: while (enumerator->enumerate(enumerator, &token))
719: {
720: if (streq(token, "%modeconfig") || streq(token, "%modecfg") ||
721: streq(token, "%config") || streq(token, "%cfg") ||
722: streq(token, "%config4") || streq(token, "%config6"))
723: {
724: /* empty pool, uses connection name */
725: this->attributes->add_pool(this->attributes,
726: mem_pool_create(msg->add_conn.name, NULL, 0));
727: peer_cfg->add_pool(peer_cfg, msg->add_conn.name);
728: }
729: else if (*token == '%')
730: {
731: /* external named pool */
732: peer_cfg->add_pool(peer_cfg, token + 1);
733: }
734: else
735: {
736: /* in-memory pool, using range or CIDR notation */
737: mem_pool_t *pool;
738: host_t *base;
739: int bits;
740:
741: pool = create_pool_range(token);
742: if (!pool)
743: {
744: base = host_create_from_subnet(token, &bits);
745: if (base)
746: {
747: pool = mem_pool_create(token, base, bits);
748: base->destroy(base);
749: }
750: }
751: if (pool)
752: {
753: this->attributes->add_pool(this->attributes, pool);
754: peer_cfg->add_pool(peer_cfg, token);
755: }
756: else
757: {
758: DBG1(DBG_CFG, "IP pool %s invalid, ignored", token);
759: }
760: }
761: }
762: enumerator->destroy(enumerator);
763: }
764:
765: if (msg->add_conn.me.sourceip && msg->add_conn.other.sourceip)
766: {
767: DBG1(DBG_CFG, "'%s' has both left- and rightsourceip, but IKE can "
768: "negotiate one virtual IP only, ignoring local virtual IP",
769: msg->add_conn.name);
770: }
771: else if (msg->add_conn.me.sourceip)
772: {
773: enumerator_t *enumerator;
774: char *token;
775:
776: enumerator = enumerator_create_token(msg->add_conn.me.sourceip, ",", " ");
777: while (enumerator->enumerate(enumerator, &token))
778: {
779: host_t *vip = NULL;
780:
781: if (streq(token, "%modeconfig") || streq(token, "%modecfg") ||
782: streq(token, "%config") || streq(token, "%cfg"))
783: { /* try to deduce an address family */
784: if (msg->add_conn.me.subnets)
785: { /* use the same family as in local subnet, if any */
786: if (strchr(msg->add_conn.me.subnets, '.'))
787: {
788: vip = host_create_any(AF_INET);
789: }
790: else
791: {
792: vip = host_create_any(AF_INET6);
793: }
794: }
795: else if (msg->add_conn.other.subnets)
796: { /* use the same family as in remote subnet, if any */
797: if (strchr(msg->add_conn.other.subnets, '.'))
798: {
799: vip = host_create_any(AF_INET);
800: }
801: else
802: {
803: vip = host_create_any(AF_INET6);
804: }
805: }
806: else
807: {
808: char *addr, *next, *hit;
809:
810: /* guess virtual IP family based on local address. If
811: * multiple addresses are specified, we look at the first
812: * only, as with leftallowany a ::/0 is always appended. */
813: addr = ike_cfg->get_my_addr(ike_cfg);
814: next = strchr(addr, ',');
815: hit = strchr(addr, ':');
816: if (hit && (!next || hit < next))
817: {
818: vip = host_create_any(AF_INET6);
819: }
820: else
821: {
822: vip = host_create_any(AF_INET);
823: }
824: }
825: }
826: else if (streq(token, "%config4"))
827: {
828: vip = host_create_any(AF_INET);
829: }
830: else if (streq(token, "%config6"))
831: {
832: vip = host_create_any(AF_INET6);
833: }
834: else
835: {
836: vip = host_create_from_string(token, 0);
837: if (!vip)
838: {
839: DBG1(DBG_CFG, "ignored invalid subnet token: %s", token);
840: }
841: }
842:
843: if (vip)
844: {
845: peer_cfg->add_virtual_ip(peer_cfg, vip);
846: }
847: }
848: enumerator->destroy(enumerator);
849: }
850:
851: /* build leftauth= */
852: auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE);
853: if (auth_cfg)
854: {
855: peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
856: }
857: else
858: { /* we require at least one config on our side */
859: peer_cfg->destroy(peer_cfg);
860: return NULL;
861: }
862: /* build leftauth2= */
863: auth_cfg = build_auth_cfg(this, msg, TRUE, FALSE);
864: if (auth_cfg)
865: {
866: peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
867: }
868: /* build rightauth= */
869: auth_cfg = build_auth_cfg(this, msg, FALSE, TRUE);
870: if (auth_cfg)
871: {
872: peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
873: }
874: /* build rightauth2= */
875: auth_cfg = build_auth_cfg(this, msg, FALSE, FALSE);
876: if (auth_cfg)
877: {
878: peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
879: }
880: return peer_cfg;
881: }
882:
883: /**
884: * Parse a protoport specifier
885: */
886: static bool parse_protoport(char *token, uint16_t *from_port,
887: uint16_t *to_port, uint8_t *protocol)
888: {
889: char *sep, *port = "", *endptr;
890: struct protoent *proto;
891: struct servent *svc;
892: long int p;
893:
894: sep = strrchr(token, ']');
895: if (!sep)
896: {
897: return FALSE;
898: }
899: *sep = '\0';
900:
901: sep = strchr(token, '/');
902: if (sep)
903: { /* protocol/port */
904: *sep = '\0';
905: port = sep + 1;
906: }
907:
908: if (streq(token, "%any"))
909: {
910: *protocol = 0;
911: }
912: else
913: {
914: proto = getprotobyname(token);
915: if (proto)
916: {
917: *protocol = proto->p_proto;
918: }
919: else
920: {
921: p = strtol(token, &endptr, 0);
922: if ((*token && *endptr) || p < 0 || p > 0xff)
923: {
924: return FALSE;
925: }
926: *protocol = (uint8_t)p;
927: }
928: }
929: if (streq(port, "%any"))
930: {
931: *from_port = 0;
932: *to_port = 0xffff;
933: }
934: else if (streq(port, "%opaque"))
935: {
936: *from_port = 0xffff;
937: *to_port = 0;
938: }
939: else if (*port)
940: {
941: svc = getservbyname(port, NULL);
942: if (svc)
943: {
944: *from_port = *to_port = ntohs(svc->s_port);
945: }
946: else
947: {
948: p = strtol(port, &endptr, 0);
949: if (p < 0 || p > 0xffff)
950: {
951: return FALSE;
952: }
953: *from_port = p;
954: if (*endptr == '-')
955: {
956: port = endptr + 1;
957: p = strtol(port, &endptr, 0);
958: if (p < 0 || p > 0xffff)
959: {
960: return FALSE;
961: }
962: }
963: *to_port = p;
964: if (*endptr)
965: {
966: return FALSE;
967: }
968: }
969: }
970: return TRUE;
971: }
972:
973: /**
974: * build a traffic selector from a stroke_end
975: */
976: static void add_ts(private_stroke_config_t *this,
977: stroke_end_t *end, child_cfg_t *child_cfg, bool local)
978: {
979: traffic_selector_t *ts;
980: bool ts_added = FALSE;
981:
982: if (end->subnets)
983: {
984: enumerator_t *enumerator;
985: char *subnet, *pos;
986: uint16_t from_port, to_port;
987: uint8_t proto;
988:
989: enumerator = enumerator_create_token(end->subnets, ",", " ");
990: while (enumerator->enumerate(enumerator, &subnet))
991: {
992: from_port = end->from_port;
993: to_port = end->to_port;
994: proto = end->protocol;
995:
996: pos = strchr(subnet, '[');
997: if (pos)
998: {
999: *(pos++) = '\0';
1000: if (!parse_protoport(pos, &from_port, &to_port, &proto))
1001: {
1002: DBG1(DBG_CFG, "invalid proto/port: %s, skipped subnet",
1003: pos);
1004: continue;
1005: }
1006: }
1007: if (streq(subnet, "%dynamic"))
1008: {
1009: ts = traffic_selector_create_dynamic(proto,
1010: from_port, to_port);
1011: }
1012: else
1013: {
1014: ts = traffic_selector_create_from_cidr(subnet, proto,
1015: from_port, to_port);
1016: }
1017: if (ts)
1018: {
1019: child_cfg->add_traffic_selector(child_cfg, local, ts);
1020: ts_added = TRUE;
1021: }
1022: else
1023: {
1024: DBG1(DBG_CFG, "invalid subnet: %s, skipped", subnet);
1025: }
1026: }
1027: enumerator->destroy(enumerator);
1028: }
1029: if (!ts_added)
1030: {
1031: ts = traffic_selector_create_dynamic(end->protocol,
1032: end->from_port, end->to_port);
1033: child_cfg->add_traffic_selector(child_cfg, local, ts);
1034: }
1035: }
1036:
1037: /**
1038: * map starter magic values to our action type
1039: */
1040: static action_t map_action(int starter_action)
1041: {
1042: switch (starter_action)
1043: {
1044: case 2: /* =hold */
1045: return ACTION_ROUTE;
1046: case 3: /* =restart */
1047: return ACTION_RESTART;
1048: default:
1049: return ACTION_NONE;
1050: }
1051: }
1052:
1053: /**
1054: * build a child config from the stroke message
1055: */
1056: static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
1057: stroke_msg_t *msg)
1058: {
1059: child_cfg_t *child_cfg;
1060: bool success;
1061: child_cfg_create_t child = {
1062: .lifetime = {
1063: .time = {
1064: .life = msg->add_conn.rekey.ipsec_lifetime,
1065: .rekey = msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
1066: .jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100
1067: },
1068: .bytes = {
1069: .life = msg->add_conn.rekey.life_bytes,
1070: .rekey = msg->add_conn.rekey.life_bytes - msg->add_conn.rekey.margin_bytes,
1071: .jitter = msg->add_conn.rekey.margin_bytes * msg->add_conn.rekey.fuzz / 100
1072: },
1073: .packets = {
1074: .life = msg->add_conn.rekey.life_packets,
1075: .rekey = msg->add_conn.rekey.life_packets - msg->add_conn.rekey.margin_packets,
1076: .jitter = msg->add_conn.rekey.margin_packets * msg->add_conn.rekey.fuzz / 100
1077: },
1078: },
1079: .mark_in = {
1080: .value = msg->add_conn.mark_in.value,
1081: .mask = msg->add_conn.mark_in.mask
1082: },
1083: .mark_out = {
1084: .value = msg->add_conn.mark_out.value,
1085: .mask = msg->add_conn.mark_out.mask
1086: },
1087: .reqid = msg->add_conn.reqid,
1088: .mode = msg->add_conn.mode,
1089: .options = (msg->add_conn.proxy_mode ? OPT_PROXY_MODE : 0) |
1090: (msg->add_conn.ipcomp ? OPT_IPCOMP : 0) |
1091: (msg->add_conn.me.hostaccess ? OPT_HOSTACCESS : 0) |
1092: (msg->add_conn.install_policy ? 0 : OPT_NO_POLICIES) |
1093: (msg->add_conn.sha256_96 ? OPT_SHA256_96 : 0),
1094: .tfc = msg->add_conn.tfc,
1095: .inactivity = msg->add_conn.inactivity,
1096: .dpd_action = map_action(msg->add_conn.dpd.action),
1097: .close_action = map_action(msg->add_conn.close_action),
1098: .updown = msg->add_conn.me.updown,
1099: };
1100:
1101: child_cfg = child_cfg_create(msg->add_conn.name, &child);
1102: if (msg->add_conn.replay_window != -1)
1103: {
1104: child_cfg->set_replay_window(child_cfg, msg->add_conn.replay_window);
1105: }
1106: add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
1107: add_ts(this, &msg->add_conn.other, child_cfg, FALSE);
1108:
1109: if (msg->add_conn.algorithms.ah)
1110: {
1111: success = add_proposals(this, msg->add_conn.algorithms.ah,
1112: NULL, child_cfg, PROTO_AH);
1113: }
1114: else
1115: {
1116: success = add_proposals(this, msg->add_conn.algorithms.esp,
1117: NULL, child_cfg, PROTO_ESP);
1118: }
1119: if (!success)
1120: {
1121: child_cfg->destroy(child_cfg);
1122: return NULL;
1123: }
1124: return child_cfg;
1125: }
1126:
1127: METHOD(stroke_config_t, add, void,
1128: private_stroke_config_t *this, stroke_msg_t *msg)
1129: {
1130: ike_cfg_t *ike_cfg, *existing_ike;
1131: peer_cfg_t *peer_cfg, *existing;
1132: child_cfg_t *child_cfg;
1133: enumerator_t *enumerator;
1134: bool use_existing = FALSE;
1135:
1136: ike_cfg = build_ike_cfg(this, msg);
1137: if (!ike_cfg)
1138: {
1139: return;
1140: }
1141: peer_cfg = build_peer_cfg(this, msg, ike_cfg);
1142: if (!peer_cfg)
1143: {
1144: ike_cfg->destroy(ike_cfg);
1145: return;
1146: }
1147:
1148: enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
1149: while (enumerator->enumerate(enumerator, &existing))
1150: {
1151: existing_ike = existing->get_ike_cfg(existing);
1152: if (existing->equals(existing, peer_cfg) &&
1153: existing_ike->equals(existing_ike, peer_cfg->get_ike_cfg(peer_cfg)))
1154: {
1155: use_existing = TRUE;
1156: peer_cfg->destroy(peer_cfg);
1157: peer_cfg = existing;
1158: peer_cfg->get_ref(peer_cfg);
1159: DBG1(DBG_CFG, "added child to existing configuration '%s'",
1160: peer_cfg->get_name(peer_cfg));
1161: break;
1162: }
1163: }
1164: enumerator->destroy(enumerator);
1165:
1166: child_cfg = build_child_cfg(this, msg);
1167: if (!child_cfg)
1168: {
1169: peer_cfg->destroy(peer_cfg);
1170: return;
1171: }
1172: peer_cfg->add_child_cfg(peer_cfg, child_cfg);
1173:
1174: if (use_existing)
1175: {
1176: peer_cfg->destroy(peer_cfg);
1177: }
1178: else
1179: {
1180: /* add config to backend */
1181: DBG1(DBG_CFG, "added configuration '%s'", msg->add_conn.name);
1182: this->mutex->lock(this->mutex);
1183: this->list->insert_last(this->list, peer_cfg);
1184: this->mutex->unlock(this->mutex);
1185: }
1186: }
1187:
1188: METHOD(stroke_config_t, del, void,
1189: private_stroke_config_t *this, stroke_msg_t *msg)
1190: {
1191: enumerator_t *enumerator, *children;
1192: peer_cfg_t *peer;
1193: child_cfg_t *child;
1194: bool deleted = FALSE;
1195:
1196: this->mutex->lock(this->mutex);
1197: enumerator = this->list->create_enumerator(this->list);
1198: while (enumerator->enumerate(enumerator, &peer))
1199: {
1200: bool keep = FALSE;
1201:
1202: /* remove any child with such a name */
1203: children = peer->create_child_cfg_enumerator(peer);
1204: while (children->enumerate(children, &child))
1205: {
1206: if (streq(child->get_name(child), msg->del_conn.name))
1207: {
1208: peer->remove_child_cfg(peer, children);
1209: child->destroy(child);
1210: deleted = TRUE;
1211: }
1212: else
1213: {
1214: keep = TRUE;
1215: }
1216: }
1217: children->destroy(children);
1218:
1219: /* if peer config has no children anymore, remove it */
1220: if (!keep)
1221: {
1222: this->list->remove_at(this->list, enumerator);
1223: peer->destroy(peer);
1224: }
1225: }
1226: enumerator->destroy(enumerator);
1227: this->mutex->unlock(this->mutex);
1228:
1229: if (deleted)
1230: {
1231: DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name);
1232: }
1233: else
1234: {
1235: DBG1(DBG_CFG, "connection '%s' not found", msg->del_conn.name);
1236: }
1237: }
1238:
1239: METHOD(stroke_config_t, set_user_credentials, void,
1240: private_stroke_config_t *this, stroke_msg_t *msg, FILE *prompt)
1241: {
1242: enumerator_t *enumerator, *children, *remote_auth;
1243: peer_cfg_t *peer, *found = NULL;
1244: auth_cfg_t *auth_cfg, *remote_cfg;
1245: auth_class_t auth_class;
1246: child_cfg_t *child;
1247: identification_t *id, *identity, *gw = NULL;
1248: shared_key_type_t type = SHARED_ANY;
1249: chunk_t password = chunk_empty;
1250:
1251: this->mutex->lock(this->mutex);
1252: enumerator = this->list->create_enumerator(this->list);
1253: while (enumerator->enumerate(enumerator, (void**)&peer))
1254: { /* find the peer (or child) config with the given name */
1255: if (streq(peer->get_name(peer), msg->user_creds.name))
1256: {
1257: found = peer;
1258: }
1259: else
1260: {
1261: children = peer->create_child_cfg_enumerator(peer);
1262: while (children->enumerate(children, &child))
1263: {
1264: if (streq(child->get_name(child), msg->user_creds.name))
1265: {
1266: found = peer;
1267: break;
1268: }
1269: }
1270: children->destroy(children);
1271: }
1272:
1273: if (found)
1274: {
1275: break;
1276: }
1277: }
1278: enumerator->destroy(enumerator);
1279:
1280: if (!found)
1281: {
1282: DBG1(DBG_CFG, " no config named '%s'", msg->user_creds.name);
1283: fprintf(prompt, "no config named '%s'\n", msg->user_creds.name);
1284: this->mutex->unlock(this->mutex);
1285: return;
1286: }
1287:
1288: id = identification_create_from_string(msg->user_creds.username);
1289: if (strlen(msg->user_creds.username) == 0 ||
1290: !id || id->get_type(id) == ID_ANY)
1291: {
1292: DBG1(DBG_CFG, " invalid username '%s'", msg->user_creds.username);
1293: fprintf(prompt, "invalid username '%s'\n", msg->user_creds.username);
1294: this->mutex->unlock(this->mutex);
1295: DESTROY_IF(id);
1296: return;
1297: }
1298:
1299: /* replace/set the username in the first EAP/XAuth auth_cfg, also look for
1300: * a suitable remote ID.
1301: * note that adding the identity here is not fully thread-safe as the
1302: * peer_cfg and in turn the auth_cfg could be in use. for the default use
1303: * case (setting user credentials before upping the connection) this will
1304: * not be a problem, though. */
1305: enumerator = found->create_auth_cfg_enumerator(found, TRUE);
1306: remote_auth = found->create_auth_cfg_enumerator(found, FALSE);
1307: while (enumerator->enumerate(enumerator, (void**)&auth_cfg))
1308: {
1309: if (remote_auth->enumerate(remote_auth, (void**)&remote_cfg))
1310: { /* fall back on rightid, in case aaa_identity is not specified */
1311: identity = remote_cfg->get(remote_cfg, AUTH_RULE_IDENTITY);
1312: if (identity && identity->get_type(identity) != ID_ANY)
1313: {
1314: gw = identity;
1315: }
1316: }
1317:
1318: auth_class = (uintptr_t)auth_cfg->get(auth_cfg, AUTH_RULE_AUTH_CLASS);
1319: if (auth_class == AUTH_CLASS_EAP || auth_class == AUTH_CLASS_XAUTH)
1320: {
1321: if (auth_class == AUTH_CLASS_EAP)
1322: {
1323: auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id));
1324: /* if aaa_identity is specified use that as remote ID */
1325: identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY);
1326: if (identity && identity->get_type(identity) != ID_ANY)
1327: {
1328: gw = identity;
1329: }
1330: DBG1(DBG_CFG, " configured EAP-Identity %Y", id);
1331: }
1332: else
1333: {
1334: auth_cfg->add(auth_cfg, AUTH_RULE_XAUTH_IDENTITY,
1335: id->clone(id));
1336: DBG1(DBG_CFG, " configured XAuth username %Y", id);
1337: }
1338: type = SHARED_EAP;
1339: break;
1340: }
1341: }
1342: enumerator->destroy(enumerator);
1343: remote_auth->destroy(remote_auth);
1344: /* clone the gw ID before unlocking the mutex */
1345: if (gw)
1346: {
1347: gw = gw->clone(gw);
1348: }
1349: this->mutex->unlock(this->mutex);
1350:
1351: if (type == SHARED_ANY)
1352: {
1353: DBG1(DBG_CFG, " config '%s' unsuitable for user credentials",
1354: msg->user_creds.name);
1355: fprintf(prompt, "config '%s' unsuitable for user credentials\n",
1356: msg->user_creds.name);
1357: id->destroy(id);
1358: DESTROY_IF(gw);
1359: return;
1360: }
1361:
1362: if (msg->user_creds.password)
1363: {
1364: char *pass;
1365:
1366: pass = msg->user_creds.password;
1367: password = chunk_clone(chunk_create(pass, strlen(pass)));
1368: memwipe(pass, strlen(pass));
1369: }
1370: else
1371: { /* prompt the user for the password */
1372: char buf[256];
1373:
1374: fprintf(prompt, "Password:\n");
1375: if (fgets(buf, sizeof(buf), prompt))
1376: {
1377: password = chunk_clone(chunk_create(buf, strlen(buf)));
1378: if (password.len > 0)
1379: { /* trim trailing \n */
1380: password.len--;
1381: }
1382: memwipe(buf, sizeof(buf));
1383: }
1384: }
1385:
1386: if (password.len)
1387: {
1388: shared_key_t *shared;
1389: linked_list_t *owners;
1390:
1391: shared = shared_key_create(type, password);
1392:
1393: owners = linked_list_create();
1394: owners->insert_last(owners, id->clone(id));
1395: if (gw && gw->get_type(gw) != ID_ANY)
1396: {
1397: owners->insert_last(owners, gw->clone(gw));
1398: DBG1(DBG_CFG, " added %N secret for %Y %Y", shared_key_type_names,
1399: type, id, gw);
1400: }
1401: else
1402: {
1403: DBG1(DBG_CFG, " added %N secret for %Y", shared_key_type_names,
1404: type, id);
1405: }
1406: this->cred->add_shared(this->cred, shared, owners);
1407: DBG4(DBG_CFG, " secret: %#B", &password);
1408: }
1409: else
1410: { /* in case a user answers the password prompt by just pressing enter */
1411: chunk_clear(&password);
1412: }
1413: id->destroy(id);
1414: DESTROY_IF(gw);
1415: }
1416:
1417: METHOD(stroke_config_t, destroy, void,
1418: private_stroke_config_t *this)
1419: {
1420: this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy));
1421: this->mutex->destroy(this->mutex);
1422: free(this);
1423: }
1424:
1425: /*
1426: * see header file
1427: */
1428: stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred,
1429: stroke_attribute_t *attributes)
1430: {
1431: private_stroke_config_t *this;
1432:
1433: INIT(this,
1434: .public = {
1435: .backend = {
1436: .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
1437: .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
1438: .get_peer_cfg_by_name = _get_peer_cfg_by_name,
1439: },
1440: .add = _add,
1441: .del = _del,
1442: .set_user_credentials = _set_user_credentials,
1443: .destroy = _destroy,
1444: },
1445: .list = linked_list_create(),
1446: .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
1447: .ca = ca,
1448: .cred = cred,
1449: .attributes = attributes,
1450: );
1451:
1452: return &this->public;
1453: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>