merged multi-auth branch back into trunk
[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 * RCSID $Id$
16 */
17
18 #include <stddef.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include <freeswan.h>
23
24 #include "../pluto/constants.h"
25 #include "../pluto/defs.h"
26 #include "../pluto/log.h"
27
28 #include "keywords.h"
29 #include "parser.h"
30 #include "confread.h"
31 #include "args.h"
32
33 /* argument types */
34
35 typedef enum {
36 ARG_NONE,
37 ARG_ENUM,
38 ARG_UINT,
39 ARG_TIME,
40 ARG_ULNG,
41 ARG_PCNT,
42 ARG_STR,
43 ARG_LST,
44 ARG_MISC
45 } arg_t;
46
47 /* various keyword lists */
48
49 static const char *LST_bool[] = {
50 "no",
51 "yes",
52 NULL
53 };
54
55 static const char *LST_sendcert[] = {
56 "always",
57 "ifasked",
58 "never",
59 "yes",
60 "no",
61 NULL
62 };
63
64 static const char *LST_unique[] = {
65 "no",
66 "yes",
67 "replace",
68 "keep",
69 NULL
70 };
71
72 static const char *LST_strict[] = {
73 "no",
74 "yes",
75 "ifuri",
76 NULL
77 };
78 static const char *LST_dpd_action[] = {
79 "none",
80 "clear",
81 "hold",
82 "restart",
83 NULL
84 };
85
86 static const char *LST_startup[] = {
87 "ignore",
88 "add",
89 "route",
90 "start",
91 NULL
92 };
93
94 static const char *LST_packetdefault[] = {
95 "drop",
96 "reject",
97 "pass",
98 NULL
99 };
100
101 static const char *LST_keyexchange[] = {
102 "ike",
103 "ikev1",
104 "ikev2",
105 NULL
106 };
107
108 static const char *LST_pfsgroup[] = {
109 "modp1024",
110 "modp1536",
111 "modp2048",
112 "modp3072",
113 "modp4096",
114 "modp6144",
115 "modp8192",
116 NULL
117 };
118
119 static const char *LST_plutodebug[] = {
120 "none",
121 "all",
122 "raw",
123 "crypt",
124 "parsing",
125 "emitting",
126 "control",
127 "lifecycle",
128 "klips",
129 "dns",
130 "natt",
131 "oppo",
132 "controlmore",
133 "private",
134 NULL
135 };
136
137 static const char *LST_klipsdebug[] = {
138 "tunnel",
139 "tunnel-xmit",
140 "pfkey",
141 "xform",
142 "eroute",
143 "spi",
144 "radij",
145 "esp",
146 "ah",
147 "ipcomp",
148 "verbose",
149 "all",
150 "none",
151 NULL
152 };
153
154 typedef struct {
155 arg_t type;
156 size_t offset;
157 const char **list;
158 } token_info_t;
159
160 static const token_info_t token_info[] =
161 {
162 /* config setup keywords */
163 { ARG_LST, offsetof(starter_config_t, setup.interfaces), NULL },
164 { ARG_STR, offsetof(starter_config_t, setup.dumpdir), NULL },
165 { ARG_ENUM, offsetof(starter_config_t, setup.charonstart), LST_bool },
166 { ARG_ENUM, offsetof(starter_config_t, setup.plutostart), LST_bool },
167
168 /* pluto/charon keywords */
169 { ARG_LST, offsetof(starter_config_t, setup.plutodebug), LST_plutodebug },
170 { ARG_STR, offsetof(starter_config_t, setup.charondebug), NULL },
171 { ARG_STR, offsetof(starter_config_t, setup.prepluto), NULL },
172 { ARG_STR, offsetof(starter_config_t, setup.postpluto), NULL },
173 { ARG_STR, offsetof(starter_config_t, setup.plutostderrlog), NULL },
174 { ARG_ENUM, offsetof(starter_config_t, setup.uniqueids), LST_unique },
175 { ARG_UINT, offsetof(starter_config_t, setup.overridemtu), NULL },
176 { ARG_TIME, offsetof(starter_config_t, setup.crlcheckinterval), NULL },
177 { ARG_ENUM, offsetof(starter_config_t, setup.cachecrls), LST_bool },
178 { ARG_ENUM, offsetof(starter_config_t, setup.strictcrlpolicy), LST_strict },
179 { ARG_ENUM, offsetof(starter_config_t, setup.nocrsend), LST_bool },
180 { ARG_ENUM, offsetof(starter_config_t, setup.nat_traversal), LST_bool },
181 { ARG_TIME, offsetof(starter_config_t, setup.keep_alive), NULL },
182 { ARG_ENUM, offsetof(starter_config_t, setup.force_keepalive), LST_bool },
183 { ARG_STR, offsetof(starter_config_t, setup.virtual_private), NULL },
184 { ARG_STR, offsetof(starter_config_t, setup.pkcs11module), NULL },
185 { ARG_STR, offsetof(starter_config_t, setup.pkcs11initargs), NULL },
186 { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11keepstate), LST_bool },
187 { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11proxy), LST_bool },
188
189 /* KLIPS keywords */
190 { ARG_LST, offsetof(starter_config_t, setup.klipsdebug), LST_klipsdebug },
191 { ARG_ENUM, offsetof(starter_config_t, setup.fragicmp), LST_bool },
192 { ARG_STR, offsetof(starter_config_t, setup.packetdefault), LST_packetdefault },
193 { ARG_ENUM, offsetof(starter_config_t, setup.hidetos), LST_bool },
194
195 /* conn section keywords */
196 { ARG_STR, offsetof(starter_conn_t, name), NULL },
197 { ARG_ENUM, offsetof(starter_conn_t, startup), LST_startup },
198 { ARG_ENUM, offsetof(starter_conn_t, keyexchange), LST_keyexchange },
199 { ARG_MISC, 0, NULL /* KW_TYPE */ },
200 { ARG_MISC, 0, NULL /* KW_PFS */ },
201 { ARG_MISC, 0, NULL /* KW_COMPRESS */ },
202 { ARG_ENUM, offsetof(starter_conn_t, install_policy), LST_bool },
203 { ARG_MISC, 0, NULL /* KW_AUTH */ },
204 { ARG_MISC, 0, NULL /* KW_AUTHBY */ },
205 { ARG_MISC, 0, NULL /* KW_EAP */ },
206 { ARG_STR, offsetof(starter_conn_t, eap_identity), NULL },
207 { ARG_MISC, 0, NULL /* KW_MOBIKE */ },
208 { ARG_MISC, 0, NULL /* KW_FORCEENCAPS */ },
209 { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL },
210 { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL },
211 { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL },
212 { ARG_MISC, 0, NULL /* KW_KEYINGTRIES */ },
213 { ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL },
214 { ARG_MISC, 0, NULL /* KW_REKEY */ },
215 { ARG_MISC, 0, NULL /* KW_REAUTH */ },
216 { ARG_STR, offsetof(starter_conn_t, ike), NULL },
217 { ARG_STR, offsetof(starter_conn_t, esp), NULL },
218 { ARG_STR, offsetof(starter_conn_t, pfsgroup), LST_pfsgroup },
219 { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL },
220 { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL },
221 { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action },
222 { ARG_MISC, 0, NULL /* KW_MODECONFIG */ },
223 { ARG_MISC, 0, NULL /* KW_XAUTH */ },
224 { ARG_ENUM, offsetof(starter_conn_t, me_mediation), LST_bool },
225 { ARG_STR, offsetof(starter_conn_t, me_mediated_by), NULL },
226 { ARG_STR, offsetof(starter_conn_t, me_peerid), NULL },
227
228 /* ca section keywords */
229 { ARG_STR, offsetof(starter_ca_t, name), NULL },
230 { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup },
231 { ARG_STR, offsetof(starter_ca_t, cacert), NULL },
232 { ARG_STR, offsetof(starter_ca_t, ldaphost), NULL },
233 { ARG_STR, offsetof(starter_ca_t, ldapbase), NULL },
234 { ARG_STR, offsetof(starter_ca_t, crluri), NULL },
235 { ARG_STR, offsetof(starter_ca_t, crluri2), NULL },
236 { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL },
237 { ARG_STR, offsetof(starter_ca_t, ocspuri2), NULL },
238 { ARG_STR, offsetof(starter_ca_t, certuribase), NULL },
239
240 /* end keywords */
241 { ARG_MISC, 0, NULL /* KW_HOST */ },
242 { ARG_MISC, 0, NULL /* KW_NEXTHOP */ },
243 { ARG_STR, offsetof(starter_end_t, subnet), NULL },
244 { ARG_MISC, 0, NULL /* KW_SUBNETWITHIN */ },
245 { ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
246 { ARG_STR, offsetof(starter_end_t, srcip), NULL },
247 { ARG_MISC, 0, NULL /* KW_NATIP */ },
248 { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
249 { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
250 { ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool },
251 { ARG_STR, offsetof(starter_end_t, updown), NULL },
252 { ARG_STR, offsetof(starter_end_t, auth), NULL },
253 { ARG_STR, offsetof(starter_end_t, auth2), NULL },
254 { ARG_STR, offsetof(starter_end_t, id), NULL },
255 { ARG_STR, offsetof(starter_end_t, id2), NULL },
256 { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
257 { ARG_STR, offsetof(starter_end_t, cert), NULL },
258 { ARG_STR, offsetof(starter_end_t, cert2), NULL },
259 { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
260 { ARG_STR, offsetof(starter_end_t, ca), NULL },
261 { ARG_STR, offsetof(starter_end_t, ca2), NULL },
262 { ARG_STR, offsetof(starter_end_t, groups), NULL },
263 { ARG_STR, offsetof(starter_end_t, iface), NULL }
264 };
265
266 static void
267 free_list(char **list)
268 {
269 char **s;
270
271 for (s = list; *s; s++)
272 pfree(*s);
273 pfree(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, "list 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 pfree(val);
297 return NULL;
298 }
299 ret = (char **)alloc_bytes((count+1) * sizeof(char *), "list");
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, "list value");
306 b = e + 1;
307 }
308 ret[count] = NULL;
309 pfree(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 int *i = (int *)p;
369
370 if (index < 0)
371 {
372 plog("# bad enumeration value: %s=%s (%d)"
373 , kw->entry->name, kw->value, index);
374 return FALSE;
375 }
376 *i = index;
377 }
378 break;
379
380 case ARG_UINT:
381 {
382 char *endptr;
383 u_int *u = (u_int *)p;
384
385 *u = strtoul(kw->value, &endptr, 10);
386
387 if (*endptr != '\0')
388 {
389 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
390 return FALSE;
391 }
392 }
393 break;
394 case ARG_ULNG:
395 case ARG_PCNT:
396 {
397 char *endptr;
398 unsigned long *l = (unsigned long *)p;
399
400 *l = strtoul(kw->value, &endptr, 10);
401
402 if (token_info[token].type == ARG_ULNG)
403 {
404 if (*endptr != '\0')
405 {
406 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
407 return FALSE;
408 }
409 }
410 else
411 {
412 if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
413 {
414 plog("# bad percent value: %s=%s", kw->entry->name, kw->value);
415 return FALSE;
416 }
417 }
418
419 }
420 break;
421 case ARG_TIME:
422 {
423 char *endptr;
424 time_t *t = (time_t *)p;
425
426 *t = strtoul(kw->value, &endptr, 10);
427
428 /* time in seconds? */
429 if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
430 break;
431
432 if (endptr[1] == '\0')
433 {
434 if (*endptr == 'm') /* time in minutes? */
435 {
436 *t *= 60;
437 break;
438 }
439 if (*endptr == 'h') /* time in hours? */
440 {
441 *t *= 3600;
442 break;
443 }
444 if (*endptr == 'd') /* time in days? */
445 {
446 *t *= 3600*24;
447 break;
448 }
449 }
450 plog("# bad duration value: %s=%s", kw->entry->name, kw->value);
451 return FALSE;
452 }
453 case ARG_STR:
454 {
455 char **cp = (char **)p;
456
457 /* free any existing string */
458 pfreeany(*cp);
459
460 /* assign the new string */
461 *cp = clone_str(kw->value, "str_value");
462 }
463 break;
464 case ARG_LST:
465 {
466 char ***listp = (char ***)p;
467
468 /* free any existing list */
469 if (*listp != NULL)
470 free_list(*listp);
471
472 /* create a new list and assign values */
473 *listp = new_list(kw->value);
474
475 /* is there a keyword list? */
476 if (list != NULL)
477 {
478 char ** lst;
479
480 for (lst = *listp; lst && *lst; lst++)
481 {
482 bool match = FALSE;
483
484 list = token_info[token].list;
485
486 while (*list != NULL && !match)
487 {
488 match = streq(*lst, *list++);
489 }
490 if (!match)
491 {
492 plog("# bad value: %s=%s", kw->entry->name, *lst);
493 return FALSE;
494 }
495 }
496 }
497 }
498 default:
499 return TRUE;
500 }
501
502 *assigned = TRUE;
503 return TRUE;
504 }
505
506 /*
507 * frees all dynamically allocated arguments in a struct
508 */
509 void
510 free_args(kw_token_t first, kw_token_t last, char *base)
511 {
512 kw_token_t token;
513
514 for (token = first; token <= last; token++)
515 {
516 char *p = base + token_info[token].offset;
517
518 switch (token_info[token].type)
519 {
520 case ARG_STR:
521 {
522 char **cp = (char **)p;
523
524 pfreeany(*cp);
525 *cp = NULL;
526 }
527 break;
528 case ARG_LST:
529 {
530 char ***listp = (char ***)p;
531
532 if (*listp != NULL)
533 {
534 free_list(*listp);
535 *listp = NULL;
536 }
537 }
538 break;
539 default:
540 break;
541 }
542 }
543 }
544
545 /*
546 * clone all dynamically allocated arguments in a struct
547 */
548 void
549 clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
550 {
551 kw_token_t token;
552
553 for (token = first; token <= last; token++)
554 {
555 if (token_info[token].type == ARG_STR)
556 {
557 char **cp1 = (char **)(base1 + token_info[token].offset);
558 char **cp2 = (char **)(base2 + token_info[token].offset);
559
560 *cp1 = clone_str(*cp2, "cloned str");
561 }
562 }
563 }
564
565 static bool
566 cmp_list(char **list1, char **list2)
567 {
568 if ((list1 == NULL) && (list2 == NULL))
569 return TRUE;
570 if ((list1 == NULL) || (list2 == NULL))
571 return FALSE;
572
573 for ( ; *list1 && *list2; list1++, list2++)
574 {
575 if (strcmp(*list1,*list2) != 0)
576 return FALSE;
577 }
578
579 if ((*list1 != NULL) || (*list2 != NULL))
580 return FALSE;
581
582 return TRUE;
583 }
584
585 /*
586 * compare all arguments in a struct
587 */
588 bool
589 cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
590 {
591 kw_token_t token;
592
593 for (token = first; token <= last; token++)
594 {
595 char *p1 = base1 + token_info[token].offset;
596 char *p2 = base2 + token_info[token].offset;
597
598 switch (token_info[token].type)
599 {
600 case ARG_ENUM:
601 {
602 int *i1 = (int *)p1;
603 int *i2 = (int *)p2;
604
605 if (*i1 != *i2)
606 return FALSE;
607 }
608 break;
609 case ARG_UINT:
610 {
611 u_int *u1 = (u_int *)p1;
612 u_int *u2 = (u_int *)p2;
613
614 if (*u1 != *u2)
615 return FALSE;
616 }
617 break;
618 case ARG_ULNG:
619 case ARG_PCNT:
620 {
621 unsigned long *l1 = (unsigned long *)p1;
622 unsigned long *l2 = (unsigned long *)p2;
623
624 if (*l1 != *l2)
625 return FALSE;
626 }
627 break;
628 case ARG_TIME:
629 {
630 time_t *t1 = (time_t *)p1;
631 time_t *t2 = (time_t *)p2;
632
633 if (*t1 != *t2)
634 return FALSE;
635 }
636 break;
637 case ARG_STR:
638 {
639 char **cp1 = (char **)p1;
640 char **cp2 = (char **)p2;
641
642 if (*cp1 == NULL && *cp2 == NULL)
643 break;
644 if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
645 return FALSE;
646 }
647 break;
648 case ARG_LST:
649 {
650 char ***listp1 = (char ***)p1;
651 char ***listp2 = (char ***)p2;
652
653 if (!cmp_list(*listp1, *listp2))
654 return FALSE;
655 }
656 break;
657 default:
658 break;
659 }
660 }
661 return TRUE;
662 }