starter: Parse authby as string.
[strongswan.git] / src / starter / args.c
1 /* automatic handling of confread struct arguments
2 * Copyright (C) 2006 Andreas Steffen
3 * Hochschule fuer Technik Rapperswil, Switzerland
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 <stddef.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include <library.h>
21 #include <debug.h>
22
23 #include "../pluto/constants.h"
24 #include "../pluto/defs.h"
25
26 #include "keywords.h"
27 #include "confread.h"
28 #include "args.h"
29
30 /* argument types */
31
32 typedef enum {
33 ARG_NONE,
34 ARG_ENUM,
35 ARG_UINT,
36 ARG_TIME,
37 ARG_ULNG,
38 ARG_ULLI,
39 ARG_PCNT,
40 ARG_STR,
41 ARG_LST,
42 ARG_MISC
43 } arg_t;
44
45 /* various keyword lists */
46
47 static const char *LST_bool[] = {
48 "no",
49 "yes",
50 NULL
51 };
52
53 static const char *LST_sendcert[] = {
54 "always",
55 "ifasked",
56 "never",
57 "yes",
58 "no",
59 NULL
60 };
61
62 static const char *LST_unique[] = {
63 "no",
64 "yes",
65 "replace",
66 "keep",
67 NULL
68 };
69
70 static const char *LST_strict[] = {
71 "no",
72 "yes",
73 "ifuri",
74 NULL
75 };
76 static const char *LST_dpd_action[] = {
77 "none",
78 "clear",
79 "hold",
80 "restart",
81 NULL
82 };
83
84 static const char *LST_startup[] = {
85 "ignore",
86 "add",
87 "route",
88 "start",
89 NULL
90 };
91
92 static const char *LST_packetdefault[] = {
93 "drop",
94 "reject",
95 "pass",
96 NULL
97 };
98
99 static const char *LST_keyexchange[] = {
100 "ike",
101 "ikev1",
102 "ikev2",
103 NULL
104 };
105
106 static const char *LST_pfsgroup[] = {
107 "modp1024",
108 "modp1536",
109 "modp2048",
110 "modp3072",
111 "modp4096",
112 "modp6144",
113 "modp8192",
114 "ecp192",
115 "ecp224",
116 "ecp256",
117 "ecp384",
118 "ecp521",
119 NULL
120 };
121
122 static const char *LST_plutodebug[] = {
123 "none",
124 "all",
125 "raw",
126 "crypt",
127 "parsing",
128 "emitting",
129 "control",
130 "lifecycle",
131 "klips",
132 "kernel",
133 "dns",
134 "natt",
135 "oppo",
136 "controlmore",
137 "private",
138 NULL
139 };
140
141 static const char *LST_klipsdebug[] = {
142 "tunnel",
143 "tunnel-xmit",
144 "pfkey",
145 "xform",
146 "eroute",
147 "spi",
148 "radij",
149 "esp",
150 "ah",
151 "ipcomp",
152 "verbose",
153 "all",
154 "none",
155 NULL
156 };
157
158 static const char *LST_authby[] = {
159 "psk",
160 "secret",
161 "pubkey",
162 "rsa",
163 "rsasig",
164 "ecdsa",
165 "ecdsasig",
166 "xauthpsk",
167 "xauthrsasig",
168 "never",
169 NULL
170 };
171
172 typedef struct {
173 arg_t type;
174 size_t offset;
175 const char **list;
176 } token_info_t;
177
178 static const token_info_t token_info[] =
179 {
180 /* config setup keywords */
181 { ARG_LST, offsetof(starter_config_t, setup.interfaces), NULL },
182 { ARG_STR, offsetof(starter_config_t, setup.dumpdir), NULL },
183 { ARG_ENUM, offsetof(starter_config_t, setup.charonstart), LST_bool },
184 { ARG_ENUM, offsetof(starter_config_t, setup.plutostart), LST_bool },
185
186 /* pluto/charon keywords */
187 { ARG_LST, offsetof(starter_config_t, setup.plutodebug), LST_plutodebug },
188 { ARG_STR, offsetof(starter_config_t, setup.charondebug), NULL },
189 { ARG_STR, offsetof(starter_config_t, setup.prepluto), NULL },
190 { ARG_STR, offsetof(starter_config_t, setup.postpluto), NULL },
191 { ARG_STR, offsetof(starter_config_t, setup.plutostderrlog), NULL },
192 { ARG_ENUM, offsetof(starter_config_t, setup.uniqueids), LST_unique },
193 { ARG_UINT, offsetof(starter_config_t, setup.overridemtu), NULL },
194 { ARG_TIME, offsetof(starter_config_t, setup.crlcheckinterval), NULL },
195 { ARG_ENUM, offsetof(starter_config_t, setup.cachecrls), LST_bool },
196 { ARG_ENUM, offsetof(starter_config_t, setup.strictcrlpolicy), LST_strict },
197 { ARG_ENUM, offsetof(starter_config_t, setup.nocrsend), LST_bool },
198 { ARG_ENUM, offsetof(starter_config_t, setup.nat_traversal), LST_bool },
199 { ARG_TIME, offsetof(starter_config_t, setup.keep_alive), NULL },
200 { ARG_ENUM, offsetof(starter_config_t, setup.force_keepalive), LST_bool },
201 { ARG_STR, offsetof(starter_config_t, setup.virtual_private), NULL },
202 { ARG_STR, offsetof(starter_config_t, setup.pkcs11module), NULL },
203 { ARG_STR, offsetof(starter_config_t, setup.pkcs11initargs), NULL },
204 { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11keepstate), LST_bool },
205 { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11proxy), LST_bool },
206
207 /* KLIPS keywords */
208 { ARG_LST, offsetof(starter_config_t, setup.klipsdebug), LST_klipsdebug },
209 { ARG_ENUM, offsetof(starter_config_t, setup.fragicmp), LST_bool },
210 { ARG_STR, offsetof(starter_config_t, setup.packetdefault), LST_packetdefault },
211 { ARG_ENUM, offsetof(starter_config_t, setup.hidetos), LST_bool },
212
213 /* conn section keywords */
214 { ARG_STR, offsetof(starter_conn_t, name), NULL },
215 { ARG_ENUM, offsetof(starter_conn_t, startup), LST_startup },
216 { ARG_ENUM, offsetof(starter_conn_t, keyexchange), LST_keyexchange },
217 { ARG_MISC, 0, NULL /* KW_TYPE */ },
218 { ARG_MISC, 0, NULL /* KW_PFS */ },
219 { ARG_MISC, 0, NULL /* KW_COMPRESS */ },
220 { ARG_ENUM, offsetof(starter_conn_t, install_policy), LST_bool },
221 { ARG_ENUM, offsetof(starter_conn_t, aggressive), LST_bool },
222 { ARG_MISC, 0, NULL /* KW_AUTH */ },
223 { ARG_STR, offsetof(starter_conn_t, authby), LST_authby },
224 { ARG_STR, offsetof(starter_conn_t, eap_identity), NULL },
225 { ARG_STR, offsetof(starter_conn_t, aaa_identity), NULL },
226 { ARG_MISC, 0, NULL /* KW_MOBIKE */ },
227 { ARG_MISC, 0, NULL /* KW_FORCEENCAPS */ },
228 { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL },
229 { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL },
230 { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL },
231 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_life_bytes), NULL },
232 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_margin_bytes), NULL },
233 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_life_packets), NULL },
234 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_margin_packets), NULL },
235 { ARG_MISC, 0, NULL /* KW_KEYINGTRIES */ },
236 { ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL },
237 { ARG_MISC, 0, NULL /* KW_REKEY */ },
238 { ARG_MISC, 0, NULL /* KW_REAUTH */ },
239 { ARG_STR, offsetof(starter_conn_t, ike), NULL },
240 { ARG_STR, offsetof(starter_conn_t, esp), NULL },
241 { ARG_STR, offsetof(starter_conn_t, pfsgroup), LST_pfsgroup },
242 { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL },
243 { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL },
244 { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action },
245 { ARG_ENUM, offsetof(starter_conn_t, close_action), LST_dpd_action },
246 { ARG_TIME, offsetof(starter_conn_t, inactivity), NULL },
247 { ARG_MISC, 0, NULL /* KW_MODECONFIG */ },
248 { ARG_MISC, 0, NULL /* KW_XAUTH */ },
249 { ARG_STR, offsetof(starter_conn_t, xauth_identity), NULL },
250 { ARG_ENUM, offsetof(starter_conn_t, me_mediation), LST_bool },
251 { ARG_STR, offsetof(starter_conn_t, me_mediated_by), NULL },
252 { ARG_STR, offsetof(starter_conn_t, me_peerid), NULL },
253 { ARG_UINT, offsetof(starter_conn_t, reqid), NULL },
254 { ARG_MISC, 0, NULL /* KW_MARK */ },
255 { ARG_MISC, 0, NULL /* KW_MARK_IN */ },
256 { ARG_MISC, 0, NULL /* KW_MARK_OUT */ },
257 { ARG_MISC, 0, NULL /* KW_TFC */ },
258
259 /* ca section keywords */
260 { ARG_STR, offsetof(starter_ca_t, name), NULL },
261 { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup },
262 { ARG_STR, offsetof(starter_ca_t, cacert), NULL },
263 { ARG_STR, offsetof(starter_ca_t, ldaphost), NULL },
264 { ARG_STR, offsetof(starter_ca_t, ldapbase), NULL },
265 { ARG_STR, offsetof(starter_ca_t, crluri), NULL },
266 { ARG_STR, offsetof(starter_ca_t, crluri2), NULL },
267 { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL },
268 { ARG_STR, offsetof(starter_ca_t, ocspuri2), NULL },
269 { ARG_STR, offsetof(starter_ca_t, certuribase), NULL },
270
271 /* end keywords */
272 { ARG_STR, offsetof(starter_end_t, host), NULL },
273 { ARG_UINT, offsetof(starter_end_t, ikeport), NULL },
274 { ARG_MISC, 0, NULL /* KW_NEXTHOP */ },
275 { ARG_STR, offsetof(starter_end_t, subnet), NULL },
276 { ARG_MISC, 0, NULL /* KW_SUBNETWITHIN */ },
277 { ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
278 { ARG_STR, offsetof(starter_end_t, sourceip), NULL },
279 { ARG_MISC, 0, NULL /* KW_NATIP */ },
280 { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
281 { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
282 { ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool },
283 { ARG_STR, offsetof(starter_end_t, updown), NULL },
284 { ARG_STR, offsetof(starter_end_t, auth), NULL },
285 { ARG_STR, offsetof(starter_end_t, auth2), NULL },
286 { ARG_STR, offsetof(starter_end_t, id), NULL },
287 { ARG_STR, offsetof(starter_end_t, id2), NULL },
288 { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
289 { ARG_STR, offsetof(starter_end_t, cert), NULL },
290 { ARG_STR, offsetof(starter_end_t, cert2), NULL },
291 { ARG_STR, offsetof(starter_end_t, cert_policy), NULL },
292 { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
293 { ARG_STR, offsetof(starter_end_t, ca), NULL },
294 { ARG_STR, offsetof(starter_end_t, ca2), NULL },
295 { ARG_STR, offsetof(starter_end_t, groups), NULL },
296 { ARG_STR, offsetof(starter_end_t, iface), NULL }
297 };
298
299 static void free_list(char **list)
300 {
301 char **s;
302
303 for (s = list; *s; s++)
304 {
305 free(*s);
306 }
307 free(list);
308 }
309
310 char** new_list(char *value)
311 {
312 char *val, *b, *e, *end, **ret;
313 int count;
314
315 val = value ? clone_str(value) : NULL;
316 if (!val)
317 {
318 return NULL;
319 }
320 end = val + strlen(val);
321 for (b = val, count = 0; b < end;)
322 {
323 for (e = b; ((*e != ' ') && (*e != '\0')); e++);
324 *e = '\0';
325 if (e != b)
326 {
327 count++;
328 }
329 b = e + 1;
330 }
331 if (count == 0)
332 {
333 free(val);
334 return NULL;
335 }
336 ret = (char **)malloc((count+1) * sizeof(char *));
337
338 for (b = val, count = 0; b < end; )
339 {
340 for (e = b; (*e != '\0'); e++);
341 if (e != b)
342 {
343 ret[count++] = clone_str(b);
344 }
345 b = e + 1;
346 }
347 ret[count] = NULL;
348 free(val);
349 return ret;
350 }
351
352
353 /*
354 * assigns an argument value to a struct field
355 */
356 bool assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base,
357 bool *assigned)
358 {
359 char *p = base + token_info[token].offset;
360 const char **list = token_info[token].list;
361
362 int index = -1; /* used for enumeration arguments */
363
364 lset_t *seen = (lset_t *)base; /* seen flags are at the top of the struct */
365 lset_t f = LELEM(token - first); /* compute flag position of argument */
366
367 *assigned = FALSE;
368
369 DBG3(DBG_APP, " %s=%s", kw->entry->name, kw->value);
370
371 if (*seen & f)
372 {
373 DBG1(DBG_APP, "# duplicate '%s' option", kw->entry->name);
374 return FALSE;
375 }
376
377 /* set flag that this argument has been seen */
378 *seen |= f;
379
380 /* is there a keyword list? */
381 if (list != NULL && token_info[token].type != ARG_LST)
382 {
383 bool match = FALSE;
384
385 while (*list != NULL && !match)
386 {
387 index++;
388 match = streq(kw->value, *list++);
389 }
390 if (!match)
391 {
392 DBG1(DBG_APP, "# bad value: %s=%s", kw->entry->name, kw->value);
393 return FALSE;
394 }
395 }
396
397 switch (token_info[token].type)
398 {
399 case ARG_NONE:
400 DBG1(DBG_APP, "# option '%s' not supported yet", kw->entry->name);
401 return FALSE;
402 case ARG_ENUM:
403 {
404 if (index < 0)
405 {
406 DBG1(DBG_APP, "# bad enumeration value: %s=%s (%d)",
407 kw->entry->name, kw->value, index);
408 return FALSE;
409 }
410
411 if (token_info[token].list == LST_bool)
412 {
413 bool *b = (bool *)p;
414 *b = (index > 0);
415 }
416 else
417 {
418 int *i = (int *)p;
419 *i = index;
420 }
421 }
422 break;
423
424 case ARG_UINT:
425 {
426 char *endptr;
427 u_int *u = (u_int *)p;
428
429 *u = strtoul(kw->value, &endptr, 10);
430
431 if (*endptr != '\0')
432 {
433 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
434 kw->value);
435 return FALSE;
436 }
437 }
438 break;
439 case ARG_ULNG:
440 case ARG_PCNT:
441 {
442 char *endptr;
443 unsigned long *l = (unsigned long *)p;
444
445 *l = strtoul(kw->value, &endptr, 10);
446
447 if (token_info[token].type == ARG_ULNG)
448 {
449 if (*endptr != '\0')
450 {
451 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
452 kw->value);
453 return FALSE;
454 }
455 }
456 else
457 {
458 if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
459 {
460 DBG1(DBG_APP, "# bad percent value: %s=%s", kw->entry->name,
461 kw->value);
462 return FALSE;
463 }
464 }
465
466 }
467 break;
468 case ARG_ULLI:
469 {
470 char *endptr;
471 unsigned long long *ll = (unsigned long long *)p;
472
473 *ll = strtoull(kw->value, &endptr, 10);
474
475 if (*endptr != '\0')
476 {
477 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
478 kw->value);
479 return FALSE;
480 }
481 }
482 break;
483 case ARG_TIME:
484 {
485 char *endptr;
486 time_t *t = (time_t *)p;
487
488 *t = strtoul(kw->value, &endptr, 10);
489
490 /* time in seconds? */
491 if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
492 {
493 break;
494 }
495 if (endptr[1] == '\0')
496 {
497 if (*endptr == 'm') /* time in minutes? */
498 {
499 *t *= 60;
500 break;
501 }
502 if (*endptr == 'h') /* time in hours? */
503 {
504 *t *= 3600;
505 break;
506 }
507 if (*endptr == 'd') /* time in days? */
508 {
509 *t *= 3600*24;
510 break;
511 }
512 }
513 DBG1(DBG_APP, "# bad duration value: %s=%s", kw->entry->name,
514 kw->value);
515 return FALSE;
516 }
517 case ARG_STR:
518 {
519 char **cp = (char **)p;
520
521 /* free any existing string */
522 free(*cp);
523
524 /* assign the new string */
525 *cp = clone_str(kw->value);
526 }
527 break;
528 case ARG_LST:
529 {
530 char ***listp = (char ***)p;
531
532 /* free any existing list */
533 if (*listp != NULL)
534 {
535 free_list(*listp);
536 }
537 /* create a new list and assign values */
538 *listp = new_list(kw->value);
539
540 /* is there a keyword list? */
541 if (list != NULL)
542 {
543 char ** lst;
544
545 for (lst = *listp; lst && *lst; lst++)
546 {
547 bool match = FALSE;
548
549 list = token_info[token].list;
550
551 while (*list != NULL && !match)
552 {
553 match = streq(*lst, *list++);
554 }
555 if (!match)
556 {
557 DBG1(DBG_APP, "# bad value: %s=%s",
558 kw->entry->name, *lst);
559 return FALSE;
560 }
561 }
562 }
563 }
564 /* fall through */
565 default:
566 return TRUE;
567 }
568
569 *assigned = TRUE;
570 return TRUE;
571 }
572
573 /*
574 * frees all dynamically allocated arguments in a struct
575 */
576 void free_args(kw_token_t first, kw_token_t last, char *base)
577 {
578 kw_token_t token;
579
580 for (token = first; token <= last; token++)
581 {
582 char *p = base + token_info[token].offset;
583
584 switch (token_info[token].type)
585 {
586 case ARG_STR:
587 {
588 char **cp = (char **)p;
589
590 free(*cp);
591 *cp = NULL;
592 }
593 break;
594 case ARG_LST:
595 {
596 char ***listp = (char ***)p;
597
598 if (*listp != NULL)
599 {
600 free_list(*listp);
601 *listp = NULL;
602 }
603 }
604 break;
605 default:
606 break;
607 }
608 }
609 }
610
611 /*
612 * clone all dynamically allocated arguments in a struct
613 */
614 void clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
615 {
616 kw_token_t token;
617
618 for (token = first; token <= last; token++)
619 {
620 if (token_info[token].type == ARG_STR)
621 {
622 char **cp1 = (char **)(base1 + token_info[token].offset);
623 char **cp2 = (char **)(base2 + token_info[token].offset);
624
625 *cp1 = clone_str(*cp2);
626 }
627 }
628 }
629
630 static bool cmp_list(char **list1, char **list2)
631 {
632 if ((list1 == NULL) && (list2 == NULL))
633 {
634 return TRUE;
635 }
636 if ((list1 == NULL) || (list2 == NULL))
637 {
638 return FALSE;
639 }
640
641 for ( ; *list1 && *list2; list1++, list2++)
642 {
643 if (strcmp(*list1,*list2) != 0)
644 {
645 return FALSE;
646 }
647 }
648
649 if ((*list1 != NULL) || (*list2 != NULL))
650 {
651 return FALSE;
652 }
653
654 return TRUE;
655 }
656
657 /*
658 * compare all arguments in a struct
659 */
660 bool cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
661 {
662 kw_token_t token;
663
664 for (token = first; token <= last; token++)
665 {
666 char *p1 = base1 + token_info[token].offset;
667 char *p2 = base2 + token_info[token].offset;
668
669 switch (token_info[token].type)
670 {
671 case ARG_ENUM:
672 if (token_info[token].list == LST_bool)
673 {
674 bool *b1 = (bool *)p1;
675 bool *b2 = (bool *)p2;
676
677 if (*b1 != *b2)
678 {
679 return FALSE;
680 }
681 }
682 else
683 {
684 int *i1 = (int *)p1;
685 int *i2 = (int *)p2;
686
687 if (*i1 != *i2)
688 {
689 return FALSE;
690 }
691 }
692 break;
693 case ARG_UINT:
694 {
695 u_int *u1 = (u_int *)p1;
696 u_int *u2 = (u_int *)p2;
697
698 if (*u1 != *u2)
699 {
700 return FALSE;
701 }
702 }
703 break;
704 case ARG_ULNG:
705 case ARG_PCNT:
706 {
707 unsigned long *l1 = (unsigned long *)p1;
708 unsigned long *l2 = (unsigned long *)p2;
709
710 if (*l1 != *l2)
711 {
712 return FALSE;
713 }
714 }
715 break;
716 case ARG_ULLI:
717 {
718 unsigned long long *ll1 = (unsigned long long *)p1;
719 unsigned long long *ll2 = (unsigned long long *)p2;
720
721 if (*ll1 != *ll2)
722 {
723 return FALSE;
724 }
725 }
726 break;
727 case ARG_TIME:
728 {
729 time_t *t1 = (time_t *)p1;
730 time_t *t2 = (time_t *)p2;
731
732 if (*t1 != *t2)
733 {
734 return FALSE;
735 }
736 }
737 break;
738 case ARG_STR:
739 {
740 char **cp1 = (char **)p1;
741 char **cp2 = (char **)p2;
742
743 if (*cp1 == NULL && *cp2 == NULL)
744 {
745 break;
746 }
747 if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
748 {
749 return FALSE;
750 }
751 }
752 break;
753 case ARG_LST:
754 {
755 char ***listp1 = (char ***)p1;
756 char ***listp2 = (char ***)p2;
757
758 if (!cmp_list(*listp1, *listp2))
759 {
760 return FALSE;
761 }
762 }
763 break;
764 default:
765 break;
766 }
767 }
768 return TRUE;
769 }