starter: Remove left|rightnexthop option.
[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_STR, offsetof(starter_end_t, subnet), NULL },
275 { ARG_MISC, 0, NULL /* KW_SUBNETWITHIN */ },
276 { ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
277 { ARG_STR, offsetof(starter_end_t, sourceip), NULL },
278 { ARG_MISC, 0, NULL /* KW_NATIP */ },
279 { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
280 { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
281 { ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool },
282 { ARG_STR, offsetof(starter_end_t, updown), NULL },
283 { ARG_STR, offsetof(starter_end_t, auth), NULL },
284 { ARG_STR, offsetof(starter_end_t, auth2), NULL },
285 { ARG_STR, offsetof(starter_end_t, id), NULL },
286 { ARG_STR, offsetof(starter_end_t, id2), NULL },
287 { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
288 { ARG_STR, offsetof(starter_end_t, cert), NULL },
289 { ARG_STR, offsetof(starter_end_t, cert2), NULL },
290 { ARG_STR, offsetof(starter_end_t, cert_policy), NULL },
291 { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
292 { ARG_STR, offsetof(starter_end_t, ca), NULL },
293 { ARG_STR, offsetof(starter_end_t, ca2), NULL },
294 { ARG_STR, offsetof(starter_end_t, groups), NULL },
295 { ARG_STR, offsetof(starter_end_t, iface), NULL }
296 };
297
298 static void free_list(char **list)
299 {
300 char **s;
301
302 for (s = list; *s; s++)
303 {
304 free(*s);
305 }
306 free(list);
307 }
308
309 char** new_list(char *value)
310 {
311 char *val, *b, *e, *end, **ret;
312 int count;
313
314 val = strdupnull(value);
315 if (!val)
316 {
317 return NULL;
318 }
319 end = val + strlen(val);
320 for (b = val, count = 0; b < end;)
321 {
322 for (e = b; ((*e != ' ') && (*e != '\0')); e++);
323 *e = '\0';
324 if (e != b)
325 {
326 count++;
327 }
328 b = e + 1;
329 }
330 if (count == 0)
331 {
332 free(val);
333 return NULL;
334 }
335 ret = (char **)malloc((count+1) * sizeof(char *));
336
337 for (b = val, count = 0; b < end; )
338 {
339 for (e = b; (*e != '\0'); e++);
340 if (e != b)
341 {
342 ret[count++] = strdupnull(b);
343 }
344 b = e + 1;
345 }
346 ret[count] = NULL;
347 free(val);
348 return ret;
349 }
350
351
352 /*
353 * assigns an argument value to a struct field
354 */
355 bool assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base,
356 bool *assigned)
357 {
358 char *p = base + token_info[token].offset;
359 const char **list = token_info[token].list;
360
361 int index = -1; /* used for enumeration arguments */
362
363 lset_t *seen = (lset_t *)base; /* seen flags are at the top of the struct */
364 lset_t f = LELEM(token - first); /* compute flag position of argument */
365
366 *assigned = FALSE;
367
368 DBG3(DBG_APP, " %s=%s", kw->entry->name, kw->value);
369
370 if (*seen & f)
371 {
372 DBG1(DBG_APP, "# duplicate '%s' option", kw->entry->name);
373 return FALSE;
374 }
375
376 /* set flag that this argument has been seen */
377 *seen |= f;
378
379 /* is there a keyword list? */
380 if (list != NULL && token_info[token].type != ARG_LST)
381 {
382 bool match = FALSE;
383
384 while (*list != NULL && !match)
385 {
386 index++;
387 match = streq(kw->value, *list++);
388 }
389 if (!match)
390 {
391 DBG1(DBG_APP, "# bad value: %s=%s", kw->entry->name, kw->value);
392 return FALSE;
393 }
394 }
395
396 switch (token_info[token].type)
397 {
398 case ARG_NONE:
399 DBG1(DBG_APP, "# option '%s' not supported yet", kw->entry->name);
400 return FALSE;
401 case ARG_ENUM:
402 {
403 if (index < 0)
404 {
405 DBG1(DBG_APP, "# bad enumeration value: %s=%s (%d)",
406 kw->entry->name, kw->value, index);
407 return FALSE;
408 }
409
410 if (token_info[token].list == LST_bool)
411 {
412 bool *b = (bool *)p;
413 *b = (index > 0);
414 }
415 else
416 {
417 int *i = (int *)p;
418 *i = index;
419 }
420 }
421 break;
422
423 case ARG_UINT:
424 {
425 char *endptr;
426 u_int *u = (u_int *)p;
427
428 *u = strtoul(kw->value, &endptr, 10);
429
430 if (*endptr != '\0')
431 {
432 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
433 kw->value);
434 return FALSE;
435 }
436 }
437 break;
438 case ARG_ULNG:
439 case ARG_PCNT:
440 {
441 char *endptr;
442 unsigned long *l = (unsigned long *)p;
443
444 *l = strtoul(kw->value, &endptr, 10);
445
446 if (token_info[token].type == ARG_ULNG)
447 {
448 if (*endptr != '\0')
449 {
450 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
451 kw->value);
452 return FALSE;
453 }
454 }
455 else
456 {
457 if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
458 {
459 DBG1(DBG_APP, "# bad percent value: %s=%s", kw->entry->name,
460 kw->value);
461 return FALSE;
462 }
463 }
464
465 }
466 break;
467 case ARG_ULLI:
468 {
469 char *endptr;
470 unsigned long long *ll = (unsigned long long *)p;
471
472 *ll = strtoull(kw->value, &endptr, 10);
473
474 if (*endptr != '\0')
475 {
476 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
477 kw->value);
478 return FALSE;
479 }
480 }
481 break;
482 case ARG_TIME:
483 {
484 char *endptr;
485 time_t *t = (time_t *)p;
486
487 *t = strtoul(kw->value, &endptr, 10);
488
489 /* time in seconds? */
490 if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
491 {
492 break;
493 }
494 if (endptr[1] == '\0')
495 {
496 if (*endptr == 'm') /* time in minutes? */
497 {
498 *t *= 60;
499 break;
500 }
501 if (*endptr == 'h') /* time in hours? */
502 {
503 *t *= 3600;
504 break;
505 }
506 if (*endptr == 'd') /* time in days? */
507 {
508 *t *= 3600*24;
509 break;
510 }
511 }
512 DBG1(DBG_APP, "# bad duration value: %s=%s", kw->entry->name,
513 kw->value);
514 return FALSE;
515 }
516 case ARG_STR:
517 {
518 char **cp = (char **)p;
519
520 /* free any existing string */
521 free(*cp);
522
523 /* assign the new string */
524 *cp = strdupnull(kw->value);
525 }
526 break;
527 case ARG_LST:
528 {
529 char ***listp = (char ***)p;
530
531 /* free any existing list */
532 if (*listp != NULL)
533 {
534 free_list(*listp);
535 }
536 /* create a new list and assign values */
537 *listp = new_list(kw->value);
538
539 /* is there a keyword list? */
540 if (list != NULL)
541 {
542 char ** lst;
543
544 for (lst = *listp; lst && *lst; lst++)
545 {
546 bool match = FALSE;
547
548 list = token_info[token].list;
549
550 while (*list != NULL && !match)
551 {
552 match = streq(*lst, *list++);
553 }
554 if (!match)
555 {
556 DBG1(DBG_APP, "# bad value: %s=%s",
557 kw->entry->name, *lst);
558 return FALSE;
559 }
560 }
561 }
562 }
563 /* fall through */
564 default:
565 return TRUE;
566 }
567
568 *assigned = TRUE;
569 return TRUE;
570 }
571
572 /*
573 * frees all dynamically allocated arguments in a struct
574 */
575 void free_args(kw_token_t first, kw_token_t last, char *base)
576 {
577 kw_token_t token;
578
579 for (token = first; token <= last; token++)
580 {
581 char *p = base + token_info[token].offset;
582
583 switch (token_info[token].type)
584 {
585 case ARG_STR:
586 {
587 char **cp = (char **)p;
588
589 free(*cp);
590 *cp = NULL;
591 }
592 break;
593 case ARG_LST:
594 {
595 char ***listp = (char ***)p;
596
597 if (*listp != NULL)
598 {
599 free_list(*listp);
600 *listp = NULL;
601 }
602 }
603 break;
604 default:
605 break;
606 }
607 }
608 }
609
610 /*
611 * clone all dynamically allocated arguments in a struct
612 */
613 void clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
614 {
615 kw_token_t token;
616
617 for (token = first; token <= last; token++)
618 {
619 if (token_info[token].type == ARG_STR)
620 {
621 char **cp1 = (char **)(base1 + token_info[token].offset);
622 char **cp2 = (char **)(base2 + token_info[token].offset);
623
624 *cp1 = strdupnull(*cp2);
625 }
626 }
627 }
628
629 static bool cmp_list(char **list1, char **list2)
630 {
631 if ((list1 == NULL) && (list2 == NULL))
632 {
633 return TRUE;
634 }
635 if ((list1 == NULL) || (list2 == NULL))
636 {
637 return FALSE;
638 }
639
640 for ( ; *list1 && *list2; list1++, list2++)
641 {
642 if (strcmp(*list1,*list2) != 0)
643 {
644 return FALSE;
645 }
646 }
647
648 if ((*list1 != NULL) || (*list2 != NULL))
649 {
650 return FALSE;
651 }
652
653 return TRUE;
654 }
655
656 /*
657 * compare all arguments in a struct
658 */
659 bool cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
660 {
661 kw_token_t token;
662
663 for (token = first; token <= last; token++)
664 {
665 char *p1 = base1 + token_info[token].offset;
666 char *p2 = base2 + token_info[token].offset;
667
668 switch (token_info[token].type)
669 {
670 case ARG_ENUM:
671 if (token_info[token].list == LST_bool)
672 {
673 bool *b1 = (bool *)p1;
674 bool *b2 = (bool *)p2;
675
676 if (*b1 != *b2)
677 {
678 return FALSE;
679 }
680 }
681 else
682 {
683 int *i1 = (int *)p1;
684 int *i2 = (int *)p2;
685
686 if (*i1 != *i2)
687 {
688 return FALSE;
689 }
690 }
691 break;
692 case ARG_UINT:
693 {
694 u_int *u1 = (u_int *)p1;
695 u_int *u2 = (u_int *)p2;
696
697 if (*u1 != *u2)
698 {
699 return FALSE;
700 }
701 }
702 break;
703 case ARG_ULNG:
704 case ARG_PCNT:
705 {
706 unsigned long *l1 = (unsigned long *)p1;
707 unsigned long *l2 = (unsigned long *)p2;
708
709 if (*l1 != *l2)
710 {
711 return FALSE;
712 }
713 }
714 break;
715 case ARG_ULLI:
716 {
717 unsigned long long *ll1 = (unsigned long long *)p1;
718 unsigned long long *ll2 = (unsigned long long *)p2;
719
720 if (*ll1 != *ll2)
721 {
722 return FALSE;
723 }
724 }
725 break;
726 case ARG_TIME:
727 {
728 time_t *t1 = (time_t *)p1;
729 time_t *t2 = (time_t *)p2;
730
731 if (*t1 != *t2)
732 {
733 return FALSE;
734 }
735 }
736 break;
737 case ARG_STR:
738 {
739 char **cp1 = (char **)p1;
740 char **cp2 = (char **)p2;
741
742 if (*cp1 == NULL && *cp2 == NULL)
743 {
744 break;
745 }
746 if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
747 {
748 return FALSE;
749 }
750 }
751 break;
752 case ARG_LST:
753 {
754 char ***listp1 = (char ***)p1;
755 char ***listp2 = (char ***)p2;
756
757 if (!cmp_list(*listp1, *listp2))
758 {
759 return FALSE;
760 }
761 }
762 break;
763 default:
764 break;
765 }
766 }
767 return TRUE;
768 }