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