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