starter: Use automake LEX/YACC automatisms.
[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 <freeswan.h>
21
22 #include "../pluto/constants.h"
23 #include "../pluto/defs.h"
24 #include "../pluto/log.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 typedef struct {
159 arg_t type;
160 size_t offset;
161 const char **list;
162 } token_info_t;
163
164 static const token_info_t token_info[] =
165 {
166 /* config setup keywords */
167 { ARG_LST, offsetof(starter_config_t, setup.interfaces), NULL },
168 { ARG_STR, offsetof(starter_config_t, setup.dumpdir), NULL },
169 { ARG_ENUM, offsetof(starter_config_t, setup.charonstart), LST_bool },
170 { ARG_ENUM, offsetof(starter_config_t, setup.plutostart), LST_bool },
171
172 /* pluto/charon keywords */
173 { ARG_LST, offsetof(starter_config_t, setup.plutodebug), LST_plutodebug },
174 { ARG_STR, offsetof(starter_config_t, setup.charondebug), NULL },
175 { ARG_STR, offsetof(starter_config_t, setup.prepluto), NULL },
176 { ARG_STR, offsetof(starter_config_t, setup.postpluto), NULL },
177 { ARG_STR, offsetof(starter_config_t, setup.plutostderrlog), NULL },
178 { ARG_ENUM, offsetof(starter_config_t, setup.uniqueids), LST_unique },
179 { ARG_UINT, offsetof(starter_config_t, setup.overridemtu), NULL },
180 { ARG_TIME, offsetof(starter_config_t, setup.crlcheckinterval), NULL },
181 { ARG_ENUM, offsetof(starter_config_t, setup.cachecrls), LST_bool },
182 { ARG_ENUM, offsetof(starter_config_t, setup.strictcrlpolicy), LST_strict },
183 { ARG_ENUM, offsetof(starter_config_t, setup.nocrsend), LST_bool },
184 { ARG_ENUM, offsetof(starter_config_t, setup.nat_traversal), LST_bool },
185 { ARG_TIME, offsetof(starter_config_t, setup.keep_alive), NULL },
186 { ARG_ENUM, offsetof(starter_config_t, setup.force_keepalive), LST_bool },
187 { ARG_STR, offsetof(starter_config_t, setup.virtual_private), NULL },
188 { ARG_STR, offsetof(starter_config_t, setup.pkcs11module), NULL },
189 { ARG_STR, offsetof(starter_config_t, setup.pkcs11initargs), NULL },
190 { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11keepstate), LST_bool },
191 { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11proxy), LST_bool },
192
193 /* KLIPS keywords */
194 { ARG_LST, offsetof(starter_config_t, setup.klipsdebug), LST_klipsdebug },
195 { ARG_ENUM, offsetof(starter_config_t, setup.fragicmp), LST_bool },
196 { ARG_STR, offsetof(starter_config_t, setup.packetdefault), LST_packetdefault },
197 { ARG_ENUM, offsetof(starter_config_t, setup.hidetos), LST_bool },
198
199 /* conn section keywords */
200 { ARG_STR, offsetof(starter_conn_t, name), NULL },
201 { ARG_ENUM, offsetof(starter_conn_t, startup), LST_startup },
202 { ARG_ENUM, offsetof(starter_conn_t, keyexchange), LST_keyexchange },
203 { ARG_MISC, 0, NULL /* KW_TYPE */ },
204 { ARG_MISC, 0, NULL /* KW_PFS */ },
205 { ARG_MISC, 0, NULL /* KW_COMPRESS */ },
206 { ARG_ENUM, offsetof(starter_conn_t, install_policy), LST_bool },
207 { ARG_MISC, 0, NULL /* KW_AUTH */ },
208 { ARG_MISC, 0, NULL /* KW_AUTHBY */ },
209 { ARG_MISC, 0, NULL /* KW_EAP */ },
210 { ARG_STR, offsetof(starter_conn_t, eap_identity), NULL },
211 { ARG_STR, offsetof(starter_conn_t, aaa_identity), NULL },
212 { ARG_MISC, 0, NULL /* KW_MOBIKE */ },
213 { ARG_MISC, 0, NULL /* KW_FORCEENCAPS */ },
214 { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL },
215 { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL },
216 { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL },
217 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_life_bytes), NULL },
218 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_margin_bytes), NULL },
219 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_life_packets), NULL },
220 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_margin_packets), NULL },
221 { ARG_MISC, 0, NULL /* KW_KEYINGTRIES */ },
222 { ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL },
223 { ARG_MISC, 0, NULL /* KW_REKEY */ },
224 { ARG_MISC, 0, NULL /* KW_REAUTH */ },
225 { ARG_STR, offsetof(starter_conn_t, ike), NULL },
226 { ARG_STR, offsetof(starter_conn_t, esp), NULL },
227 { ARG_STR, offsetof(starter_conn_t, pfsgroup), LST_pfsgroup },
228 { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL },
229 { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL },
230 { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action },
231 { ARG_ENUM, offsetof(starter_conn_t, close_action), LST_dpd_action },
232 { ARG_TIME, offsetof(starter_conn_t, inactivity), NULL },
233 { ARG_MISC, 0, NULL /* KW_MODECONFIG */ },
234 { ARG_MISC, 0, NULL /* KW_XAUTH */ },
235 { ARG_STR, offsetof(starter_conn_t, xauth_identity), NULL },
236 { ARG_ENUM, offsetof(starter_conn_t, me_mediation), LST_bool },
237 { ARG_STR, offsetof(starter_conn_t, me_mediated_by), NULL },
238 { ARG_STR, offsetof(starter_conn_t, me_peerid), NULL },
239 { ARG_UINT, offsetof(starter_conn_t, reqid), NULL },
240 { ARG_MISC, 0, NULL /* KW_MARK */ },
241 { ARG_MISC, 0, NULL /* KW_MARK_IN */ },
242 { ARG_MISC, 0, NULL /* KW_MARK_OUT */ },
243 { ARG_MISC, 0, NULL /* KW_TFC */ },
244
245 /* ca section keywords */
246 { ARG_STR, offsetof(starter_ca_t, name), NULL },
247 { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup },
248 { ARG_STR, offsetof(starter_ca_t, cacert), NULL },
249 { ARG_STR, offsetof(starter_ca_t, ldaphost), NULL },
250 { ARG_STR, offsetof(starter_ca_t, ldapbase), NULL },
251 { ARG_STR, offsetof(starter_ca_t, crluri), NULL },
252 { ARG_STR, offsetof(starter_ca_t, crluri2), NULL },
253 { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL },
254 { ARG_STR, offsetof(starter_ca_t, ocspuri2), NULL },
255 { ARG_STR, offsetof(starter_ca_t, certuribase), NULL },
256
257 /* end keywords */
258 { ARG_STR, offsetof(starter_end_t, host), NULL },
259 { ARG_UINT, offsetof(starter_end_t, ikeport), NULL },
260 { ARG_MISC, 0, NULL /* KW_NEXTHOP */ },
261 { ARG_STR, offsetof(starter_end_t, subnet), NULL },
262 { ARG_MISC, 0, NULL /* KW_SUBNETWITHIN */ },
263 { ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
264 { ARG_STR, offsetof(starter_end_t, sourceip), NULL },
265 { ARG_MISC, 0, NULL /* KW_NATIP */ },
266 { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
267 { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
268 { ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool },
269 { ARG_STR, offsetof(starter_end_t, updown), NULL },
270 { ARG_STR, offsetof(starter_end_t, auth), NULL },
271 { ARG_STR, offsetof(starter_end_t, auth2), NULL },
272 { ARG_STR, offsetof(starter_end_t, id), NULL },
273 { ARG_STR, offsetof(starter_end_t, id2), NULL },
274 { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
275 { ARG_STR, offsetof(starter_end_t, cert), NULL },
276 { ARG_STR, offsetof(starter_end_t, cert2), NULL },
277 { ARG_STR, offsetof(starter_end_t, cert_policy), NULL },
278 { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
279 { ARG_STR, offsetof(starter_end_t, ca), NULL },
280 { ARG_STR, offsetof(starter_end_t, ca2), NULL },
281 { ARG_STR, offsetof(starter_end_t, groups), NULL },
282 { ARG_STR, offsetof(starter_end_t, iface), NULL }
283 };
284
285 static void free_list(char **list)
286 {
287 char **s;
288
289 for (s = list; *s; s++)
290 {
291 free(*s);
292 }
293 free(list);
294 }
295
296 char** new_list(char *value)
297 {
298 char *val, *b, *e, *end, **ret;
299 int count;
300
301 val = value ? clone_str(value) : NULL;
302 if (!val)
303 {
304 return NULL;
305 }
306 end = val + strlen(val);
307 for (b = val, count = 0; b < end;)
308 {
309 for (e = b; ((*e != ' ') && (*e != '\0')); e++);
310 *e = '\0';
311 if (e != b)
312 {
313 count++;
314 }
315 b = e + 1;
316 }
317 if (count == 0)
318 {
319 free(val);
320 return NULL;
321 }
322 ret = (char **)malloc((count+1) * sizeof(char *));
323
324 for (b = val, count = 0; b < end; )
325 {
326 for (e = b; (*e != '\0'); e++);
327 if (e != b)
328 {
329 ret[count++] = clone_str(b);
330 }
331 b = e + 1;
332 }
333 ret[count] = NULL;
334 free(val);
335 return ret;
336 }
337
338
339 /*
340 * assigns an argument value to a struct field
341 */
342 bool assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base,
343 bool *assigned)
344 {
345 char *p = base + token_info[token].offset;
346 const char **list = token_info[token].list;
347
348 int index = -1; /* used for enumeration arguments */
349
350 lset_t *seen = (lset_t *)base; /* seen flags are at the top of the struct */
351 lset_t f = LELEM(token - first); /* compute flag position of argument */
352
353 *assigned = FALSE;
354
355 DBG(DBG_CONTROLMORE,
356 DBG_log(" %s=%s", kw->entry->name, kw->value)
357 )
358
359 if (*seen & f)
360 {
361 plog("# duplicate '%s' option", kw->entry->name);
362 return FALSE;
363 }
364
365 /* set flag that this argument has been seen */
366 *seen |= f;
367
368 /* is there a keyword list? */
369 if (list != NULL && token_info[token].type != ARG_LST)
370 {
371 bool match = FALSE;
372
373 while (*list != NULL && !match)
374 {
375 index++;
376 match = streq(kw->value, *list++);
377 }
378 if (!match)
379 {
380 plog("# bad value: %s=%s", kw->entry->name, kw->value);
381 return FALSE;
382 }
383 }
384
385 switch (token_info[token].type)
386 {
387 case ARG_NONE:
388 plog("# option '%s' not supported yet", kw->entry->name);
389 return FALSE;
390 case ARG_ENUM:
391 {
392 if (index < 0)
393 {
394 plog("# bad enumeration value: %s=%s (%d)"
395 , kw->entry->name, kw->value, index);
396 return FALSE;
397 }
398
399 if (token_info[token].list == LST_bool)
400 {
401 bool *b = (bool *)p;
402 *b = (index > 0);
403 }
404 else
405 {
406 int *i = (int *)p;
407 *i = index;
408 }
409 }
410 break;
411
412 case ARG_UINT:
413 {
414 char *endptr;
415 u_int *u = (u_int *)p;
416
417 *u = strtoul(kw->value, &endptr, 10);
418
419 if (*endptr != '\0')
420 {
421 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
422 return FALSE;
423 }
424 }
425 break;
426 case ARG_ULNG:
427 case ARG_PCNT:
428 {
429 char *endptr;
430 unsigned long *l = (unsigned long *)p;
431
432 *l = strtoul(kw->value, &endptr, 10);
433
434 if (token_info[token].type == ARG_ULNG)
435 {
436 if (*endptr != '\0')
437 {
438 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
439 return FALSE;
440 }
441 }
442 else
443 {
444 if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
445 {
446 plog("# bad percent value: %s=%s", kw->entry->name, kw->value);
447 return FALSE;
448 }
449 }
450
451 }
452 break;
453 case ARG_ULLI:
454 {
455 char *endptr;
456 unsigned long long *ll = (unsigned long long *)p;
457
458 *ll = strtoull(kw->value, &endptr, 10);
459
460 if (*endptr != '\0')
461 {
462 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
463 return FALSE;
464 }
465 }
466 break;
467 case ARG_TIME:
468 {
469 char *endptr;
470 time_t *t = (time_t *)p;
471
472 *t = strtoul(kw->value, &endptr, 10);
473
474 /* time in seconds? */
475 if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
476 {
477 break;
478 }
479 if (endptr[1] == '\0')
480 {
481 if (*endptr == 'm') /* time in minutes? */
482 {
483 *t *= 60;
484 break;
485 }
486 if (*endptr == 'h') /* time in hours? */
487 {
488 *t *= 3600;
489 break;
490 }
491 if (*endptr == 'd') /* time in days? */
492 {
493 *t *= 3600*24;
494 break;
495 }
496 }
497 plog("# bad duration value: %s=%s", kw->entry->name, kw->value);
498 return FALSE;
499 }
500 case ARG_STR:
501 {
502 char **cp = (char **)p;
503
504 /* free any existing string */
505 free(*cp);
506
507 /* assign the new string */
508 *cp = clone_str(kw->value);
509 }
510 break;
511 case ARG_LST:
512 {
513 char ***listp = (char ***)p;
514
515 /* free any existing list */
516 if (*listp != NULL)
517 {
518 free_list(*listp);
519 }
520 /* create a new list and assign values */
521 *listp = new_list(kw->value);
522
523 /* is there a keyword list? */
524 if (list != NULL)
525 {
526 char ** lst;
527
528 for (lst = *listp; lst && *lst; lst++)
529 {
530 bool match = FALSE;
531
532 list = token_info[token].list;
533
534 while (*list != NULL && !match)
535 {
536 match = streq(*lst, *list++);
537 }
538 if (!match)
539 {
540 plog("# bad value: %s=%s", kw->entry->name, *lst);
541 return FALSE;
542 }
543 }
544 }
545 }
546 /* fall through */
547 default:
548 return TRUE;
549 }
550
551 *assigned = TRUE;
552 return TRUE;
553 }
554
555 /*
556 * frees all dynamically allocated arguments in a struct
557 */
558 void free_args(kw_token_t first, kw_token_t last, char *base)
559 {
560 kw_token_t token;
561
562 for (token = first; token <= last; token++)
563 {
564 char *p = base + token_info[token].offset;
565
566 switch (token_info[token].type)
567 {
568 case ARG_STR:
569 {
570 char **cp = (char **)p;
571
572 free(*cp);
573 *cp = NULL;
574 }
575 break;
576 case ARG_LST:
577 {
578 char ***listp = (char ***)p;
579
580 if (*listp != NULL)
581 {
582 free_list(*listp);
583 *listp = NULL;
584 }
585 }
586 break;
587 default:
588 break;
589 }
590 }
591 }
592
593 /*
594 * clone all dynamically allocated arguments in a struct
595 */
596 void clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
597 {
598 kw_token_t token;
599
600 for (token = first; token <= last; token++)
601 {
602 if (token_info[token].type == ARG_STR)
603 {
604 char **cp1 = (char **)(base1 + token_info[token].offset);
605 char **cp2 = (char **)(base2 + token_info[token].offset);
606
607 *cp1 = clone_str(*cp2);
608 }
609 }
610 }
611
612 static bool cmp_list(char **list1, char **list2)
613 {
614 if ((list1 == NULL) && (list2 == NULL))
615 {
616 return TRUE;
617 }
618 if ((list1 == NULL) || (list2 == NULL))
619 {
620 return FALSE;
621 }
622
623 for ( ; *list1 && *list2; list1++, list2++)
624 {
625 if (strcmp(*list1,*list2) != 0)
626 {
627 return FALSE;
628 }
629 }
630
631 if ((*list1 != NULL) || (*list2 != NULL))
632 {
633 return FALSE;
634 }
635
636 return TRUE;
637 }
638
639 /*
640 * compare all arguments in a struct
641 */
642 bool cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
643 {
644 kw_token_t token;
645
646 for (token = first; token <= last; token++)
647 {
648 char *p1 = base1 + token_info[token].offset;
649 char *p2 = base2 + token_info[token].offset;
650
651 switch (token_info[token].type)
652 {
653 case ARG_ENUM:
654 if (token_info[token].list == LST_bool)
655 {
656 bool *b1 = (bool *)p1;
657 bool *b2 = (bool *)p2;
658
659 if (*b1 != *b2)
660 {
661 return FALSE;
662 }
663 }
664 else
665 {
666 int *i1 = (int *)p1;
667 int *i2 = (int *)p2;
668
669 if (*i1 != *i2)
670 {
671 return FALSE;
672 }
673 }
674 break;
675 case ARG_UINT:
676 {
677 u_int *u1 = (u_int *)p1;
678 u_int *u2 = (u_int *)p2;
679
680 if (*u1 != *u2)
681 {
682 return FALSE;
683 }
684 }
685 break;
686 case ARG_ULNG:
687 case ARG_PCNT:
688 {
689 unsigned long *l1 = (unsigned long *)p1;
690 unsigned long *l2 = (unsigned long *)p2;
691
692 if (*l1 != *l2)
693 {
694 return FALSE;
695 }
696 }
697 break;
698 case ARG_ULLI:
699 {
700 unsigned long long *ll1 = (unsigned long long *)p1;
701 unsigned long long *ll2 = (unsigned long long *)p2;
702
703 if (*ll1 != *ll2)
704 {
705 return FALSE;
706 }
707 }
708 break;
709 case ARG_TIME:
710 {
711 time_t *t1 = (time_t *)p1;
712 time_t *t2 = (time_t *)p2;
713
714 if (*t1 != *t2)
715 {
716 return FALSE;
717 }
718 }
719 break;
720 case ARG_STR:
721 {
722 char **cp1 = (char **)p1;
723 char **cp2 = (char **)p2;
724
725 if (*cp1 == NULL && *cp2 == NULL)
726 {
727 break;
728 }
729 if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
730 {
731 return FALSE;
732 }
733 }
734 break;
735 case ARG_LST:
736 {
737 char ***listp1 = (char ***)p1;
738 char ***listp2 = (char ***)p2;
739
740 if (!cmp_list(*listp1, *listp2))
741 {
742 return FALSE;
743 }
744 }
745 break;
746 default:
747 break;
748 }
749 }
750 return TRUE;
751 }