00d66eaed2a8aaefafebed6fca3461f16de6ba81
[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 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_ENUM, offsetof(starter_conn_t, aggressive), LST_bool },
208 { ARG_MISC, 0, NULL /* KW_AUTH */ },
209 { ARG_MISC, 0, NULL /* KW_AUTHBY */ },
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 DBG3(DBG_APP, " %s=%s", kw->entry->name, kw->value);
356
357 if (*seen & f)
358 {
359 DBG1(DBG_APP, "# duplicate '%s' option", kw->entry->name);
360 return FALSE;
361 }
362
363 /* set flag that this argument has been seen */
364 *seen |= f;
365
366 /* is there a keyword list? */
367 if (list != NULL && token_info[token].type != ARG_LST)
368 {
369 bool match = FALSE;
370
371 while (*list != NULL && !match)
372 {
373 index++;
374 match = streq(kw->value, *list++);
375 }
376 if (!match)
377 {
378 DBG1(DBG_APP, "# bad value: %s=%s", kw->entry->name, kw->value);
379 return FALSE;
380 }
381 }
382
383 switch (token_info[token].type)
384 {
385 case ARG_NONE:
386 DBG1(DBG_APP, "# option '%s' not supported yet", kw->entry->name);
387 return FALSE;
388 case ARG_ENUM:
389 {
390 if (index < 0)
391 {
392 DBG1(DBG_APP, "# bad enumeration value: %s=%s (%d)",
393 kw->entry->name, kw->value, index);
394 return FALSE;
395 }
396
397 if (token_info[token].list == LST_bool)
398 {
399 bool *b = (bool *)p;
400 *b = (index > 0);
401 }
402 else
403 {
404 int *i = (int *)p;
405 *i = index;
406 }
407 }
408 break;
409
410 case ARG_UINT:
411 {
412 char *endptr;
413 u_int *u = (u_int *)p;
414
415 *u = strtoul(kw->value, &endptr, 10);
416
417 if (*endptr != '\0')
418 {
419 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
420 kw->value);
421 return FALSE;
422 }
423 }
424 break;
425 case ARG_ULNG:
426 case ARG_PCNT:
427 {
428 char *endptr;
429 unsigned long *l = (unsigned long *)p;
430
431 *l = strtoul(kw->value, &endptr, 10);
432
433 if (token_info[token].type == ARG_ULNG)
434 {
435 if (*endptr != '\0')
436 {
437 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
438 kw->value);
439 return FALSE;
440 }
441 }
442 else
443 {
444 if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
445 {
446 DBG1(DBG_APP, "# bad percent value: %s=%s", kw->entry->name,
447 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 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
464 kw->value);
465 return FALSE;
466 }
467 }
468 break;
469 case ARG_TIME:
470 {
471 char *endptr;
472 time_t *t = (time_t *)p;
473
474 *t = strtoul(kw->value, &endptr, 10);
475
476 /* time in seconds? */
477 if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
478 {
479 break;
480 }
481 if (endptr[1] == '\0')
482 {
483 if (*endptr == 'm') /* time in minutes? */
484 {
485 *t *= 60;
486 break;
487 }
488 if (*endptr == 'h') /* time in hours? */
489 {
490 *t *= 3600;
491 break;
492 }
493 if (*endptr == 'd') /* time in days? */
494 {
495 *t *= 3600*24;
496 break;
497 }
498 }
499 DBG1(DBG_APP, "# bad duration value: %s=%s", kw->entry->name,
500 kw->value);
501 return FALSE;
502 }
503 case ARG_STR:
504 {
505 char **cp = (char **)p;
506
507 /* free any existing string */
508 free(*cp);
509
510 /* assign the new string */
511 *cp = clone_str(kw->value);
512 }
513 break;
514 case ARG_LST:
515 {
516 char ***listp = (char ***)p;
517
518 /* free any existing list */
519 if (*listp != NULL)
520 {
521 free_list(*listp);
522 }
523 /* create a new list and assign values */
524 *listp = new_list(kw->value);
525
526 /* is there a keyword list? */
527 if (list != NULL)
528 {
529 char ** lst;
530
531 for (lst = *listp; lst && *lst; lst++)
532 {
533 bool match = FALSE;
534
535 list = token_info[token].list;
536
537 while (*list != NULL && !match)
538 {
539 match = streq(*lst, *list++);
540 }
541 if (!match)
542 {
543 DBG1(DBG_APP, "# bad value: %s=%s",
544 kw->entry->name, *lst);
545 return FALSE;
546 }
547 }
548 }
549 }
550 /* fall through */
551 default:
552 return TRUE;
553 }
554
555 *assigned = TRUE;
556 return TRUE;
557 }
558
559 /*
560 * frees all dynamically allocated arguments in a struct
561 */
562 void free_args(kw_token_t first, kw_token_t last, char *base)
563 {
564 kw_token_t token;
565
566 for (token = first; token <= last; token++)
567 {
568 char *p = base + token_info[token].offset;
569
570 switch (token_info[token].type)
571 {
572 case ARG_STR:
573 {
574 char **cp = (char **)p;
575
576 free(*cp);
577 *cp = NULL;
578 }
579 break;
580 case ARG_LST:
581 {
582 char ***listp = (char ***)p;
583
584 if (*listp != NULL)
585 {
586 free_list(*listp);
587 *listp = NULL;
588 }
589 }
590 break;
591 default:
592 break;
593 }
594 }
595 }
596
597 /*
598 * clone all dynamically allocated arguments in a struct
599 */
600 void clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
601 {
602 kw_token_t token;
603
604 for (token = first; token <= last; token++)
605 {
606 if (token_info[token].type == ARG_STR)
607 {
608 char **cp1 = (char **)(base1 + token_info[token].offset);
609 char **cp2 = (char **)(base2 + token_info[token].offset);
610
611 *cp1 = clone_str(*cp2);
612 }
613 }
614 }
615
616 static bool cmp_list(char **list1, char **list2)
617 {
618 if ((list1 == NULL) && (list2 == NULL))
619 {
620 return TRUE;
621 }
622 if ((list1 == NULL) || (list2 == NULL))
623 {
624 return FALSE;
625 }
626
627 for ( ; *list1 && *list2; list1++, list2++)
628 {
629 if (strcmp(*list1,*list2) != 0)
630 {
631 return FALSE;
632 }
633 }
634
635 if ((*list1 != NULL) || (*list2 != NULL))
636 {
637 return FALSE;
638 }
639
640 return TRUE;
641 }
642
643 /*
644 * compare all arguments in a struct
645 */
646 bool cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
647 {
648 kw_token_t token;
649
650 for (token = first; token <= last; token++)
651 {
652 char *p1 = base1 + token_info[token].offset;
653 char *p2 = base2 + token_info[token].offset;
654
655 switch (token_info[token].type)
656 {
657 case ARG_ENUM:
658 if (token_info[token].list == LST_bool)
659 {
660 bool *b1 = (bool *)p1;
661 bool *b2 = (bool *)p2;
662
663 if (*b1 != *b2)
664 {
665 return FALSE;
666 }
667 }
668 else
669 {
670 int *i1 = (int *)p1;
671 int *i2 = (int *)p2;
672
673 if (*i1 != *i2)
674 {
675 return FALSE;
676 }
677 }
678 break;
679 case ARG_UINT:
680 {
681 u_int *u1 = (u_int *)p1;
682 u_int *u2 = (u_int *)p2;
683
684 if (*u1 != *u2)
685 {
686 return FALSE;
687 }
688 }
689 break;
690 case ARG_ULNG:
691 case ARG_PCNT:
692 {
693 unsigned long *l1 = (unsigned long *)p1;
694 unsigned long *l2 = (unsigned long *)p2;
695
696 if (*l1 != *l2)
697 {
698 return FALSE;
699 }
700 }
701 break;
702 case ARG_ULLI:
703 {
704 unsigned long long *ll1 = (unsigned long long *)p1;
705 unsigned long long *ll2 = (unsigned long long *)p2;
706
707 if (*ll1 != *ll2)
708 {
709 return FALSE;
710 }
711 }
712 break;
713 case ARG_TIME:
714 {
715 time_t *t1 = (time_t *)p1;
716 time_t *t2 = (time_t *)p2;
717
718 if (*t1 != *t2)
719 {
720 return FALSE;
721 }
722 }
723 break;
724 case ARG_STR:
725 {
726 char **cp1 = (char **)p1;
727 char **cp2 = (char **)p2;
728
729 if (*cp1 == NULL && *cp2 == NULL)
730 {
731 break;
732 }
733 if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
734 {
735 return FALSE;
736 }
737 }
738 break;
739 case ARG_LST:
740 {
741 char ***listp1 = (char ***)p1;
742 char ***listp2 = (char ***)p2;
743
744 if (!cmp_list(*listp1, *listp2))
745 {
746 return FALSE;
747 }
748 }
749 break;
750 default:
751 break;
752 }
753 }
754 return TRUE;
755 }