ebbd42cc87243579b47d409518c688abee20badc
[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 "parser.h"
28 #include "confread.h"
29 #include "args.h"
30
31 /* argument types */
32
33 typedef enum {
34 ARG_NONE,
35 ARG_ENUM,
36 ARG_UINT,
37 ARG_TIME,
38 ARG_ULNG,
39 ARG_ULLI,
40 ARG_PCNT,
41 ARG_STR,
42 ARG_LST,
43 ARG_MISC
44 } arg_t;
45
46 /* various keyword lists */
47
48 static const char *LST_bool[] = {
49 "no",
50 "yes",
51 NULL
52 };
53
54 static const char *LST_sendcert[] = {
55 "always",
56 "ifasked",
57 "never",
58 "yes",
59 "no",
60 NULL
61 };
62
63 static const char *LST_unique[] = {
64 "no",
65 "yes",
66 "replace",
67 "keep",
68 NULL
69 };
70
71 static const char *LST_strict[] = {
72 "no",
73 "yes",
74 "ifuri",
75 NULL
76 };
77 static const char *LST_dpd_action[] = {
78 "none",
79 "clear",
80 "hold",
81 "restart",
82 NULL
83 };
84
85 static const char *LST_startup[] = {
86 "ignore",
87 "add",
88 "route",
89 "start",
90 NULL
91 };
92
93 static const char *LST_packetdefault[] = {
94 "drop",
95 "reject",
96 "pass",
97 NULL
98 };
99
100 static const char *LST_keyexchange[] = {
101 "ike",
102 "ikev1",
103 "ikev2",
104 NULL
105 };
106
107 static const char *LST_pfsgroup[] = {
108 "modp1024",
109 "modp1536",
110 "modp2048",
111 "modp3072",
112 "modp4096",
113 "modp6144",
114 "modp8192",
115 "ecp192",
116 "ecp224",
117 "ecp256",
118 "ecp384",
119 "ecp521",
120 NULL
121 };
122
123 static const char *LST_plutodebug[] = {
124 "none",
125 "all",
126 "raw",
127 "crypt",
128 "parsing",
129 "emitting",
130 "control",
131 "lifecycle",
132 "klips",
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_MISC, 0, NULL /* KW_MOBIKE */ },
212 { ARG_MISC, 0, NULL /* KW_FORCEENCAPS */ },
213 { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL },
214 { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL },
215 { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL },
216 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_life_bytes), NULL },
217 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_margin_bytes), NULL },
218 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_life_packets), NULL },
219 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_margin_packets), NULL },
220 { ARG_MISC, 0, NULL /* KW_KEYINGTRIES */ },
221 { ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL },
222 { ARG_MISC, 0, NULL /* KW_REKEY */ },
223 { ARG_MISC, 0, NULL /* KW_REAUTH */ },
224 { ARG_STR, offsetof(starter_conn_t, ike), NULL },
225 { ARG_STR, offsetof(starter_conn_t, esp), NULL },
226 { ARG_STR, offsetof(starter_conn_t, pfsgroup), LST_pfsgroup },
227 { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL },
228 { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL },
229 { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action },
230 { ARG_TIME, offsetof(starter_conn_t, inactivity), NULL },
231 { ARG_MISC, 0, NULL /* KW_MODECONFIG */ },
232 { ARG_MISC, 0, NULL /* KW_XAUTH */ },
233 { ARG_ENUM, offsetof(starter_conn_t, me_mediation), LST_bool },
234 { ARG_STR, offsetof(starter_conn_t, me_mediated_by), NULL },
235 { ARG_STR, offsetof(starter_conn_t, me_peerid), NULL },
236
237 /* ca section keywords */
238 { ARG_STR, offsetof(starter_ca_t, name), NULL },
239 { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup },
240 { ARG_STR, offsetof(starter_ca_t, cacert), NULL },
241 { ARG_STR, offsetof(starter_ca_t, ldaphost), NULL },
242 { ARG_STR, offsetof(starter_ca_t, ldapbase), NULL },
243 { ARG_STR, offsetof(starter_ca_t, crluri), NULL },
244 { ARG_STR, offsetof(starter_ca_t, crluri2), NULL },
245 { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL },
246 { ARG_STR, offsetof(starter_ca_t, ocspuri2), NULL },
247 { ARG_STR, offsetof(starter_ca_t, certuribase), NULL },
248
249 /* end keywords */
250 { ARG_MISC, 0, NULL /* KW_HOST */ },
251 { ARG_MISC, 0, NULL /* KW_NEXTHOP */ },
252 { ARG_STR, offsetof(starter_end_t, subnet), NULL },
253 { ARG_MISC, 0, NULL /* KW_SUBNETWITHIN */ },
254 { ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
255 { ARG_MISC, 0, NULL /* KW_SOURCEIP */ },
256 { ARG_MISC, 0, NULL /* KW_NATIP */ },
257 { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
258 { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
259 { ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool },
260 { ARG_STR, offsetof(starter_end_t, updown), NULL },
261 { ARG_STR, offsetof(starter_end_t, auth), NULL },
262 { ARG_STR, offsetof(starter_end_t, auth2), NULL },
263 { ARG_STR, offsetof(starter_end_t, id), NULL },
264 { ARG_STR, offsetof(starter_end_t, id2), NULL },
265 { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
266 { ARG_STR, offsetof(starter_end_t, cert), NULL },
267 { ARG_STR, offsetof(starter_end_t, cert2), NULL },
268 { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
269 { ARG_STR, offsetof(starter_end_t, ca), NULL },
270 { ARG_STR, offsetof(starter_end_t, ca2), NULL },
271 { ARG_STR, offsetof(starter_end_t, groups), NULL },
272 { ARG_STR, offsetof(starter_end_t, iface), NULL }
273 };
274
275 static void free_list(char **list)
276 {
277 char **s;
278
279 for (s = list; *s; s++)
280 {
281 free(*s);
282 }
283 free(list);
284 }
285
286 char** new_list(char *value)
287 {
288 char *val, *b, *e, *end, **ret;
289 int count;
290
291 val = value ? clone_str(value) : NULL;
292 if (!val)
293 {
294 return NULL;
295 }
296 end = val + strlen(val);
297 for (b = val, count = 0; b < end;)
298 {
299 for (e = b; ((*e != ' ') && (*e != '\0')); e++);
300 *e = '\0';
301 if (e != b)
302 {
303 count++;
304 }
305 b = e + 1;
306 }
307 if (count == 0)
308 {
309 free(val);
310 return NULL;
311 }
312 ret = (char **)malloc((count+1) * sizeof(char *));
313
314 for (b = val, count = 0; b < end; )
315 {
316 for (e = b; (*e != '\0'); e++);
317 if (e != b)
318 {
319 ret[count++] = clone_str(b);
320 }
321 b = e + 1;
322 }
323 ret[count] = NULL;
324 free(val);
325 return ret;
326 }
327
328
329 /*
330 * assigns an argument value to a struct field
331 */
332 bool assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base,
333 bool *assigned)
334 {
335 char *p = base + token_info[token].offset;
336 const char **list = token_info[token].list;
337
338 int index = -1; /* used for enumeration arguments */
339
340 lset_t *seen = (lset_t *)base; /* seen flags are at the top of the struct */
341 lset_t f = LELEM(token - first); /* compute flag position of argument */
342
343 *assigned = FALSE;
344
345 DBG(DBG_CONTROLMORE,
346 DBG_log(" %s=%s", kw->entry->name, kw->value)
347 )
348
349 if (*seen & f)
350 {
351 plog("# duplicate '%s' option", kw->entry->name);
352 return FALSE;
353 }
354
355 /* set flag that this argument has been seen */
356 *seen |= f;
357
358 /* is there a keyword list? */
359 if (list != NULL && token_info[token].type != ARG_LST)
360 {
361 bool match = FALSE;
362
363 while (*list != NULL && !match)
364 {
365 index++;
366 match = streq(kw->value, *list++);
367 }
368 if (!match)
369 {
370 plog("# bad value: %s=%s", kw->entry->name, kw->value);
371 return FALSE;
372 }
373 }
374
375 switch (token_info[token].type)
376 {
377 case ARG_NONE:
378 plog("# option '%s' not supported yet", kw->entry->name);
379 return FALSE;
380 case ARG_ENUM:
381 {
382 if (index < 0)
383 {
384 plog("# bad enumeration value: %s=%s (%d)"
385 , kw->entry->name, kw->value, index);
386 return FALSE;
387 }
388
389 if (token_info[token].list == LST_bool)
390 {
391 bool *b = (bool *)p;
392 *b = (index > 0);
393 }
394 else
395 {
396 int *i = (int *)p;
397 *i = index;
398 }
399 }
400 break;
401
402 case ARG_UINT:
403 {
404 char *endptr;
405 u_int *u = (u_int *)p;
406
407 *u = strtoul(kw->value, &endptr, 10);
408
409 if (*endptr != '\0')
410 {
411 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
412 return FALSE;
413 }
414 }
415 break;
416 case ARG_ULNG:
417 case ARG_PCNT:
418 {
419 char *endptr;
420 unsigned long *l = (unsigned long *)p;
421
422 *l = strtoul(kw->value, &endptr, 10);
423
424 if (token_info[token].type == ARG_ULNG)
425 {
426 if (*endptr != '\0')
427 {
428 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
429 return FALSE;
430 }
431 }
432 else
433 {
434 if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
435 {
436 plog("# bad percent value: %s=%s", kw->entry->name, kw->value);
437 return FALSE;
438 }
439 }
440
441 }
442 break;
443 case ARG_ULLI:
444 {
445 char *endptr;
446 unsigned long long *ll = (unsigned long long *)p;
447
448 *ll = strtoull(kw->value, &endptr, 10);
449
450 if (*endptr != '\0')
451 {
452 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
453 return FALSE;
454 }
455 }
456 break;
457 case ARG_TIME:
458 {
459 char *endptr;
460 time_t *t = (time_t *)p;
461
462 *t = strtoul(kw->value, &endptr, 10);
463
464 /* time in seconds? */
465 if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
466 {
467 break;
468 }
469 if (endptr[1] == '\0')
470 {
471 if (*endptr == 'm') /* time in minutes? */
472 {
473 *t *= 60;
474 break;
475 }
476 if (*endptr == 'h') /* time in hours? */
477 {
478 *t *= 3600;
479 break;
480 }
481 if (*endptr == 'd') /* time in days? */
482 {
483 *t *= 3600*24;
484 break;
485 }
486 }
487 plog("# bad duration value: %s=%s", kw->entry->name, kw->value);
488 return FALSE;
489 }
490 case ARG_STR:
491 {
492 char **cp = (char **)p;
493
494 /* free any existing string */
495 free(*cp);
496
497 /* assign the new string */
498 *cp = clone_str(kw->value);
499 }
500 break;
501 case ARG_LST:
502 {
503 char ***listp = (char ***)p;
504
505 /* free any existing list */
506 if (*listp != NULL)
507 {
508 free_list(*listp);
509 }
510 /* create a new list and assign values */
511 *listp = new_list(kw->value);
512
513 /* is there a keyword list? */
514 if (list != NULL)
515 {
516 char ** lst;
517
518 for (lst = *listp; lst && *lst; lst++)
519 {
520 bool match = FALSE;
521
522 list = token_info[token].list;
523
524 while (*list != NULL && !match)
525 {
526 match = streq(*lst, *list++);
527 }
528 if (!match)
529 {
530 plog("# bad value: %s=%s", kw->entry->name, *lst);
531 return FALSE;
532 }
533 }
534 }
535 }
536 default:
537 return TRUE;
538 }
539
540 *assigned = TRUE;
541 return TRUE;
542 }
543
544 /*
545 * frees all dynamically allocated arguments in a struct
546 */
547 void free_args(kw_token_t first, kw_token_t last, char *base)
548 {
549 kw_token_t token;
550
551 for (token = first; token <= last; token++)
552 {
553 char *p = base + token_info[token].offset;
554
555 switch (token_info[token].type)
556 {
557 case ARG_STR:
558 {
559 char **cp = (char **)p;
560
561 free(*cp);
562 *cp = NULL;
563 }
564 break;
565 case ARG_LST:
566 {
567 char ***listp = (char ***)p;
568
569 if (*listp != NULL)
570 {
571 free_list(*listp);
572 *listp = NULL;
573 }
574 }
575 break;
576 default:
577 break;
578 }
579 }
580 }
581
582 /*
583 * clone all dynamically allocated arguments in a struct
584 */
585 void clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
586 {
587 kw_token_t token;
588
589 for (token = first; token <= last; token++)
590 {
591 if (token_info[token].type == ARG_STR)
592 {
593 char **cp1 = (char **)(base1 + token_info[token].offset);
594 char **cp2 = (char **)(base2 + token_info[token].offset);
595
596 *cp1 = clone_str(*cp2);
597 }
598 }
599 }
600
601 static bool cmp_list(char **list1, char **list2)
602 {
603 if ((list1 == NULL) && (list2 == NULL))
604 {
605 return TRUE;
606 }
607 if ((list1 == NULL) || (list2 == NULL))
608 {
609 return FALSE;
610 }
611
612 for ( ; *list1 && *list2; list1++, list2++)
613 {
614 if (strcmp(*list1,*list2) != 0)
615 {
616 return FALSE;
617 }
618 }
619
620 if ((*list1 != NULL) || (*list2 != NULL))
621 {
622 return FALSE;
623 }
624
625 return TRUE;
626 }
627
628 /*
629 * compare all arguments in a struct
630 */
631 bool cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
632 {
633 kw_token_t token;
634
635 for (token = first; token <= last; token++)
636 {
637 char *p1 = base1 + token_info[token].offset;
638 char *p2 = base2 + token_info[token].offset;
639
640 switch (token_info[token].type)
641 {
642 case ARG_ENUM:
643 if (token_info[token].list == LST_bool)
644 {
645 bool *b1 = (bool *)p1;
646 bool *b2 = (bool *)p2;
647
648 if (*b1 != *b2)
649 {
650 return FALSE;
651 }
652 }
653 else
654 {
655 int *i1 = (int *)p1;
656 int *i2 = (int *)p2;
657
658 if (*i1 != *i2)
659 {
660 return FALSE;
661 }
662 }
663 break;
664 case ARG_UINT:
665 {
666 u_int *u1 = (u_int *)p1;
667 u_int *u2 = (u_int *)p2;
668
669 if (*u1 != *u2)
670 {
671 return FALSE;
672 }
673 }
674 break;
675 case ARG_ULNG:
676 case ARG_PCNT:
677 {
678 unsigned long *l1 = (unsigned long *)p1;
679 unsigned long *l2 = (unsigned long *)p2;
680
681 if (*l1 != *l2)
682 {
683 return FALSE;
684 }
685 }
686 break;
687 case ARG_ULLI:
688 {
689 unsigned long long *ll1 = (unsigned long long *)p1;
690 unsigned long long *ll2 = (unsigned long long *)p2;
691
692 if (*ll1 != *ll2)
693 {
694 return FALSE;
695 }
696 }
697 break;
698 case ARG_TIME:
699 {
700 time_t *t1 = (time_t *)p1;
701 time_t *t2 = (time_t *)p2;
702
703 if (*t1 != *t2)
704 {
705 return FALSE;
706 }
707 }
708 break;
709 case ARG_STR:
710 {
711 char **cp1 = (char **)p1;
712 char **cp2 = (char **)p2;
713
714 if (*cp1 == NULL && *cp2 == NULL)
715 {
716 break;
717 }
718 if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
719 {
720 return FALSE;
721 }
722 }
723 break;
724 case ARG_LST:
725 {
726 char ***listp1 = (char ***)p1;
727 char ***listp2 = (char ***)p2;
728
729 if (!cmp_list(*listp1, *listp2))
730 {
731 return FALSE;
732 }
733 }
734 break;
735 default:
736 break;
737 }
738 }
739 return TRUE;
740 }