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