allow ECP DH groups in pfsgroup definition
[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_MISC, 0, NULL /* KW_MODECONFIG */ },
231 { ARG_MISC, 0, NULL /* KW_XAUTH */ },
232 { ARG_ENUM, offsetof(starter_conn_t, me_mediation), LST_bool },
233 { ARG_STR, offsetof(starter_conn_t, me_mediated_by), NULL },
234 { ARG_STR, offsetof(starter_conn_t, me_peerid), NULL },
235
236 /* ca section keywords */
237 { ARG_STR, offsetof(starter_ca_t, name), NULL },
238 { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup },
239 { ARG_STR, offsetof(starter_ca_t, cacert), NULL },
240 { ARG_STR, offsetof(starter_ca_t, ldaphost), NULL },
241 { ARG_STR, offsetof(starter_ca_t, ldapbase), NULL },
242 { ARG_STR, offsetof(starter_ca_t, crluri), NULL },
243 { ARG_STR, offsetof(starter_ca_t, crluri2), NULL },
244 { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL },
245 { ARG_STR, offsetof(starter_ca_t, ocspuri2), NULL },
246 { ARG_STR, offsetof(starter_ca_t, certuribase), NULL },
247
248 /* end keywords */
249 { ARG_MISC, 0, NULL /* KW_HOST */ },
250 { ARG_MISC, 0, NULL /* KW_NEXTHOP */ },
251 { ARG_STR, offsetof(starter_end_t, subnet), NULL },
252 { ARG_MISC, 0, NULL /* KW_SUBNETWITHIN */ },
253 { ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
254 { ARG_MISC, 0, NULL /* KW_SOURCEIP */ },
255 { ARG_MISC, 0, NULL /* KW_NATIP */ },
256 { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
257 { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
258 { ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool },
259 { ARG_STR, offsetof(starter_end_t, updown), NULL },
260 { ARG_STR, offsetof(starter_end_t, auth), NULL },
261 { ARG_STR, offsetof(starter_end_t, auth2), NULL },
262 { ARG_STR, offsetof(starter_end_t, id), NULL },
263 { ARG_STR, offsetof(starter_end_t, id2), NULL },
264 { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
265 { ARG_STR, offsetof(starter_end_t, cert), NULL },
266 { ARG_STR, offsetof(starter_end_t, cert2), NULL },
267 { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
268 { ARG_STR, offsetof(starter_end_t, ca), NULL },
269 { ARG_STR, offsetof(starter_end_t, ca2), NULL },
270 { ARG_STR, offsetof(starter_end_t, groups), NULL },
271 { ARG_STR, offsetof(starter_end_t, iface), NULL }
272 };
273
274 static void free_list(char **list)
275 {
276 char **s;
277
278 for (s = list; *s; s++)
279 {
280 free(*s);
281 }
282 free(list);
283 }
284
285 char** new_list(char *value)
286 {
287 char *val, *b, *e, *end, **ret;
288 int count;
289
290 val = value ? clone_str(value) : NULL;
291 if (!val)
292 {
293 return NULL;
294 }
295 end = val + strlen(val);
296 for (b = val, count = 0; b < end;)
297 {
298 for (e = b; ((*e != ' ') && (*e != '\0')); e++);
299 *e = '\0';
300 if (e != b)
301 {
302 count++;
303 }
304 b = e + 1;
305 }
306 if (count == 0)
307 {
308 free(val);
309 return NULL;
310 }
311 ret = (char **)malloc((count+1) * sizeof(char *));
312
313 for (b = val, count = 0; b < end; )
314 {
315 for (e = b; (*e != '\0'); e++);
316 if (e != b)
317 {
318 ret[count++] = clone_str(b);
319 }
320 b = e + 1;
321 }
322 ret[count] = NULL;
323 free(val);
324 return ret;
325 }
326
327
328 /*
329 * assigns an argument value to a struct field
330 */
331 bool assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base,
332 bool *assigned)
333 {
334 char *p = base + token_info[token].offset;
335 const char **list = token_info[token].list;
336
337 int index = -1; /* used for enumeration arguments */
338
339 lset_t *seen = (lset_t *)base; /* seen flags are at the top of the struct */
340 lset_t f = LELEM(token - first); /* compute flag position of argument */
341
342 *assigned = FALSE;
343
344 DBG(DBG_CONTROLMORE,
345 DBG_log(" %s=%s", kw->entry->name, kw->value)
346 )
347
348 if (*seen & f)
349 {
350 plog("# duplicate '%s' option", kw->entry->name);
351 return FALSE;
352 }
353
354 /* set flag that this argument has been seen */
355 *seen |= f;
356
357 /* is there a keyword list? */
358 if (list != NULL && token_info[token].type != ARG_LST)
359 {
360 bool match = FALSE;
361
362 while (*list != NULL && !match)
363 {
364 index++;
365 match = streq(kw->value, *list++);
366 }
367 if (!match)
368 {
369 plog("# bad value: %s=%s", kw->entry->name, kw->value);
370 return FALSE;
371 }
372 }
373
374 switch (token_info[token].type)
375 {
376 case ARG_NONE:
377 plog("# option '%s' not supported yet", kw->entry->name);
378 return FALSE;
379 case ARG_ENUM:
380 {
381 if (index < 0)
382 {
383 plog("# bad enumeration value: %s=%s (%d)"
384 , kw->entry->name, kw->value, index);
385 return FALSE;
386 }
387
388 if (token_info[token].list == LST_bool)
389 {
390 bool *b = (bool *)p;
391 *b = (index > 0);
392 }
393 else
394 {
395 int *i = (int *)p;
396 *i = index;
397 }
398 }
399 break;
400
401 case ARG_UINT:
402 {
403 char *endptr;
404 u_int *u = (u_int *)p;
405
406 *u = strtoul(kw->value, &endptr, 10);
407
408 if (*endptr != '\0')
409 {
410 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
411 return FALSE;
412 }
413 }
414 break;
415 case ARG_ULNG:
416 case ARG_PCNT:
417 {
418 char *endptr;
419 unsigned long *l = (unsigned long *)p;
420
421 *l = strtoul(kw->value, &endptr, 10);
422
423 if (token_info[token].type == ARG_ULNG)
424 {
425 if (*endptr != '\0')
426 {
427 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
428 return FALSE;
429 }
430 }
431 else
432 {
433 if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
434 {
435 plog("# bad percent value: %s=%s", kw->entry->name, kw->value);
436 return FALSE;
437 }
438 }
439
440 }
441 break;
442 case ARG_ULLI:
443 {
444 char *endptr;
445 unsigned long long *ll = (unsigned long long *)p;
446
447 *ll = strtoull(kw->value, &endptr, 10);
448
449 if (*endptr != '\0')
450 {
451 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
452 return FALSE;
453 }
454 }
455 break;
456 case ARG_TIME:
457 {
458 char *endptr;
459 time_t *t = (time_t *)p;
460
461 *t = strtoul(kw->value, &endptr, 10);
462
463 /* time in seconds? */
464 if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
465 {
466 break;
467 }
468 if (endptr[1] == '\0')
469 {
470 if (*endptr == 'm') /* time in minutes? */
471 {
472 *t *= 60;
473 break;
474 }
475 if (*endptr == 'h') /* time in hours? */
476 {
477 *t *= 3600;
478 break;
479 }
480 if (*endptr == 'd') /* time in days? */
481 {
482 *t *= 3600*24;
483 break;
484 }
485 }
486 plog("# bad duration value: %s=%s", kw->entry->name, kw->value);
487 return FALSE;
488 }
489 case ARG_STR:
490 {
491 char **cp = (char **)p;
492
493 /* free any existing string */
494 free(*cp);
495
496 /* assign the new string */
497 *cp = clone_str(kw->value);
498 }
499 break;
500 case ARG_LST:
501 {
502 char ***listp = (char ***)p;
503
504 /* free any existing list */
505 if (*listp != NULL)
506 {
507 free_list(*listp);
508 }
509 /* create a new list and assign values */
510 *listp = new_list(kw->value);
511
512 /* is there a keyword list? */
513 if (list != NULL)
514 {
515 char ** lst;
516
517 for (lst = *listp; lst && *lst; lst++)
518 {
519 bool match = FALSE;
520
521 list = token_info[token].list;
522
523 while (*list != NULL && !match)
524 {
525 match = streq(*lst, *list++);
526 }
527 if (!match)
528 {
529 plog("# bad value: %s=%s", kw->entry->name, *lst);
530 return FALSE;
531 }
532 }
533 }
534 }
535 default:
536 return TRUE;
537 }
538
539 *assigned = TRUE;
540 return TRUE;
541 }
542
543 /*
544 * frees all dynamically allocated arguments in a struct
545 */
546 void free_args(kw_token_t first, kw_token_t last, char *base)
547 {
548 kw_token_t token;
549
550 for (token = first; token <= last; token++)
551 {
552 char *p = base + token_info[token].offset;
553
554 switch (token_info[token].type)
555 {
556 case ARG_STR:
557 {
558 char **cp = (char **)p;
559
560 free(*cp);
561 *cp = NULL;
562 }
563 break;
564 case ARG_LST:
565 {
566 char ***listp = (char ***)p;
567
568 if (*listp != NULL)
569 {
570 free_list(*listp);
571 *listp = NULL;
572 }
573 }
574 break;
575 default:
576 break;
577 }
578 }
579 }
580
581 /*
582 * clone all dynamically allocated arguments in a struct
583 */
584 void clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
585 {
586 kw_token_t token;
587
588 for (token = first; token <= last; token++)
589 {
590 if (token_info[token].type == ARG_STR)
591 {
592 char **cp1 = (char **)(base1 + token_info[token].offset);
593 char **cp2 = (char **)(base2 + token_info[token].offset);
594
595 *cp1 = clone_str(*cp2);
596 }
597 }
598 }
599
600 static bool cmp_list(char **list1, char **list2)
601 {
602 if ((list1 == NULL) && (list2 == NULL))
603 {
604 return TRUE;
605 }
606 if ((list1 == NULL) || (list2 == NULL))
607 {
608 return FALSE;
609 }
610
611 for ( ; *list1 && *list2; list1++, list2++)
612 {
613 if (strcmp(*list1,*list2) != 0)
614 {
615 return FALSE;
616 }
617 }
618
619 if ((*list1 != NULL) || (*list2 != NULL))
620 {
621 return FALSE;
622 }
623
624 return TRUE;
625 }
626
627 /*
628 * compare all arguments in a struct
629 */
630 bool cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
631 {
632 kw_token_t token;
633
634 for (token = first; token <= last; token++)
635 {
636 char *p1 = base1 + token_info[token].offset;
637 char *p2 = base2 + token_info[token].offset;
638
639 switch (token_info[token].type)
640 {
641 case ARG_ENUM:
642 if (token_info[token].list == LST_bool)
643 {
644 bool *b1 = (bool *)p1;
645 bool *b2 = (bool *)p2;
646
647 if (*b1 != *b2)
648 {
649 return FALSE;
650 }
651 }
652 else
653 {
654 int *i1 = (int *)p1;
655 int *i2 = (int *)p2;
656
657 if (*i1 != *i2)
658 {
659 return FALSE;
660 }
661 }
662 break;
663 case ARG_UINT:
664 {
665 u_int *u1 = (u_int *)p1;
666 u_int *u2 = (u_int *)p2;
667
668 if (*u1 != *u2)
669 {
670 return FALSE;
671 }
672 }
673 break;
674 case ARG_ULNG:
675 case ARG_PCNT:
676 {
677 unsigned long *l1 = (unsigned long *)p1;
678 unsigned long *l2 = (unsigned long *)p2;
679
680 if (*l1 != *l2)
681 {
682 return FALSE;
683 }
684 }
685 break;
686 case ARG_ULLI:
687 {
688 unsigned long long *ll1 = (unsigned long long *)p1;
689 unsigned long long *ll2 = (unsigned long long *)p2;
690
691 if (*ll1 != *ll2)
692 {
693 return FALSE;
694 }
695 }
696 break;
697 case ARG_TIME:
698 {
699 time_t *t1 = (time_t *)p1;
700 time_t *t2 = (time_t *)p2;
701
702 if (*t1 != *t2)
703 {
704 return FALSE;
705 }
706 }
707 break;
708 case ARG_STR:
709 {
710 char **cp1 = (char **)p1;
711 char **cp2 = (char **)p2;
712
713 if (*cp1 == NULL && *cp2 == NULL)
714 {
715 break;
716 }
717 if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
718 {
719 return FALSE;
720 }
721 }
722 break;
723 case ARG_LST:
724 {
725 char ***listp1 = (char ***)p1;
726 char ***listp2 = (char ***)p2;
727
728 if (!cmp_list(*listp1, *listp2))
729 {
730 return FALSE;
731 }
732 }
733 break;
734 default:
735 break;
736 }
737 }
738 return TRUE;
739 }