support of plutostderrlog keyword
[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_ENUM, offsetof(starter_config_t, setup.plutostderrlog), LST_bool },
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_MISC, 0, NULL /* KW_AUTH */ },
203 { ARG_MISC, 0, NULL /* KW_AUTHBY */ },
204 { ARG_MISC, 0, NULL /* KW_EAP */ },
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, id), NULL },
251 { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
252 { ARG_STR, offsetof(starter_end_t, cert), NULL },
253 { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
254 { ARG_STR, offsetof(starter_end_t, ca), NULL },
255 { ARG_STR, offsetof(starter_end_t, groups), NULL },
256 { ARG_STR, offsetof(starter_end_t, iface), NULL }
257 };
258
259 static void
260 free_list(char **list)
261 {
262 char **s;
263
264 for (s = list; *s; s++)
265 pfree(*s);
266 pfree(list);
267 }
268
269 char **
270 new_list(char *value)
271 {
272 char *val, *b, *e, *end, **ret;
273 int count;
274
275 val = value ? clone_str(value, "list value") : NULL;
276 if (!val)
277 return NULL;
278 end = val + strlen(val);
279 for (b = val, count = 0; b < end;)
280 {
281 for (e = b; ((*e != ' ') && (*e != '\0')); e++);
282 *e = '\0';
283 if (e != b)
284 count++;
285 b = e + 1;
286 }
287 if (count == 0)
288 {
289 pfree(val);
290 return NULL;
291 }
292 ret = (char **)alloc_bytes((count+1) * sizeof(char *), "list");
293
294 for (b = val, count = 0; b < end; )
295 {
296 for (e = b; (*e != '\0'); e++);
297 if (e != b)
298 ret[count++] = clone_str(b, "list value");
299 b = e + 1;
300 }
301 ret[count] = NULL;
302 pfree(val);
303 return ret;
304 }
305
306
307 /*
308 * assigns an argument value to a struct field
309 */
310 bool
311 assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base
312 , bool *assigned)
313 {
314 char *p = base + token_info[token].offset;
315 const char **list = token_info[token].list;
316
317 int index = -1; /* used for enumeration arguments */
318
319 lset_t *seen = (lset_t *)base; /* seen flags are at the top of the struct */
320 lset_t f = LELEM(token - first); /* compute flag position of argument */
321
322 *assigned = FALSE;
323
324 DBG(DBG_CONTROLMORE,
325 DBG_log(" %s=%s", kw->entry->name, kw->value)
326 )
327
328 if (*seen & f)
329 {
330 plog("# duplicate '%s' option", kw->entry->name);
331 return FALSE;
332 }
333
334 /* set flag that this argument has been seen */
335 *seen |= f;
336
337 /* is there a keyword list? */
338 if (list != NULL && token_info[token].type != ARG_LST)
339 {
340 bool match = FALSE;
341
342 while (*list != NULL && !match)
343 {
344 index++;
345 match = streq(kw->value, *list++);
346 }
347 if (!match)
348 {
349 plog("# bad value: %s=%s", kw->entry->name, kw->value);
350 return FALSE;
351 }
352 }
353
354 switch (token_info[token].type)
355 {
356 case ARG_NONE:
357 plog("# option '%s' not supported yet", kw->entry->name);
358 return FALSE;
359 case ARG_ENUM:
360 {
361 int *i = (int *)p;
362
363 if (index < 0)
364 {
365 plog("# bad enumeration value: %s=%s (%d)"
366 , kw->entry->name, kw->value, index);
367 return FALSE;
368 }
369 *i = index;
370 }
371 break;
372
373 case ARG_UINT:
374 {
375 char *endptr;
376 u_int *u = (u_int *)p;
377
378 *u = strtoul(kw->value, &endptr, 10);
379
380 if (*endptr != '\0')
381 {
382 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
383 return FALSE;
384 }
385 }
386 break;
387 case ARG_ULNG:
388 case ARG_PCNT:
389 {
390 char *endptr;
391 unsigned long *l = (unsigned long *)p;
392
393 *l = strtoul(kw->value, &endptr, 10);
394
395 if (token_info[token].type == ARG_ULNG)
396 {
397 if (*endptr != '\0')
398 {
399 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
400 return FALSE;
401 }
402 }
403 else
404 {
405 if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
406 {
407 plog("# bad percent value: %s=%s", kw->entry->name, kw->value);
408 return FALSE;
409 }
410 }
411
412 }
413 break;
414 case ARG_TIME:
415 {
416 char *endptr;
417 time_t *t = (time_t *)p;
418
419 *t = strtoul(kw->value, &endptr, 10);
420
421 /* time in seconds? */
422 if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
423 break;
424
425 if (endptr[1] == '\0')
426 {
427 if (*endptr == 'm') /* time in minutes? */
428 {
429 *t *= 60;
430 break;
431 }
432 if (*endptr == 'h') /* time in hours? */
433 {
434 *t *= 3600;
435 break;
436 }
437 if (*endptr == 'd') /* time in days? */
438 {
439 *t *= 3600*24;
440 break;
441 }
442 }
443 plog("# bad duration value: %s=%s", kw->entry->name, kw->value);
444 return FALSE;
445 }
446 case ARG_STR:
447 {
448 char **cp = (char **)p;
449
450 /* free any existing string */
451 pfreeany(*cp);
452
453 /* assign the new string */
454 *cp = clone_str(kw->value, "str_value");
455 }
456 break;
457 case ARG_LST:
458 {
459 char ***listp = (char ***)p;
460
461 /* free any existing list */
462 if (*listp != NULL)
463 free_list(*listp);
464
465 /* create a new list and assign values */
466 *listp = new_list(kw->value);
467
468 /* is there a keyword list? */
469 if (list != NULL)
470 {
471 char ** lst;
472
473 for (lst = *listp; lst && *lst; lst++)
474 {
475 bool match = FALSE;
476
477 list = token_info[token].list;
478
479 while (*list != NULL && !match)
480 {
481 match = streq(*lst, *list++);
482 }
483 if (!match)
484 {
485 plog("# bad value: %s=%s", kw->entry->name, *lst);
486 return FALSE;
487 }
488 }
489 }
490 }
491 default:
492 return TRUE;
493 }
494
495 *assigned = TRUE;
496 return TRUE;
497 }
498
499 /*
500 * frees all dynamically allocated arguments in a struct
501 */
502 void
503 free_args(kw_token_t first, kw_token_t last, char *base)
504 {
505 kw_token_t token;
506
507 for (token = first; token <= last; token++)
508 {
509 char *p = base + token_info[token].offset;
510
511 switch (token_info[token].type)
512 {
513 case ARG_STR:
514 {
515 char **cp = (char **)p;
516
517 pfreeany(*cp);
518 *cp = NULL;
519 }
520 break;
521 case ARG_LST:
522 {
523 char ***listp = (char ***)p;
524
525 if (*listp != NULL)
526 {
527 free_list(*listp);
528 *listp = NULL;
529 }
530 }
531 break;
532 default:
533 break;
534 }
535 }
536 }
537
538 /*
539 * clone all dynamically allocated arguments in a struct
540 */
541 void
542 clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
543 {
544 kw_token_t token;
545
546 for (token = first; token <= last; token++)
547 {
548 if (token_info[token].type == ARG_STR)
549 {
550 char **cp1 = (char **)(base1 + token_info[token].offset);
551 char **cp2 = (char **)(base2 + token_info[token].offset);
552
553 *cp1 = clone_str(*cp2, "cloned str");
554 }
555 }
556 }
557
558 static bool
559 cmp_list(char **list1, char **list2)
560 {
561 if ((list1 == NULL) && (list2 == NULL))
562 return TRUE;
563 if ((list1 == NULL) || (list2 == NULL))
564 return FALSE;
565
566 for ( ; *list1 && *list2; list1++, list2++)
567 {
568 if (strcmp(*list1,*list2) != 0)
569 return FALSE;
570 }
571
572 if ((*list1 != NULL) || (*list2 != NULL))
573 return FALSE;
574
575 return TRUE;
576 }
577
578 /*
579 * compare all arguments in a struct
580 */
581 bool
582 cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
583 {
584 kw_token_t token;
585
586 for (token = first; token <= last; token++)
587 {
588 char *p1 = base1 + token_info[token].offset;
589 char *p2 = base2 + token_info[token].offset;
590
591 switch (token_info[token].type)
592 {
593 case ARG_ENUM:
594 {
595 int *i1 = (int *)p1;
596 int *i2 = (int *)p2;
597
598 if (*i1 != *i2)
599 return FALSE;
600 }
601 break;
602 case ARG_UINT:
603 {
604 u_int *u1 = (u_int *)p1;
605 u_int *u2 = (u_int *)p2;
606
607 if (*u1 != *u2)
608 return FALSE;
609 }
610 break;
611 case ARG_ULNG:
612 case ARG_PCNT:
613 {
614 unsigned long *l1 = (unsigned long *)p1;
615 unsigned long *l2 = (unsigned long *)p2;
616
617 if (*l1 != *l2)
618 return FALSE;
619 }
620 break;
621 case ARG_TIME:
622 {
623 time_t *t1 = (time_t *)p1;
624 time_t *t2 = (time_t *)p2;
625
626 if (*t1 != *t2)
627 return FALSE;
628 }
629 break;
630 case ARG_STR:
631 {
632 char **cp1 = (char **)p1;
633 char **cp2 = (char **)p2;
634
635 if (*cp1 == NULL && *cp2 == NULL)
636 break;
637 if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
638 return FALSE;
639 }
640 break;
641 case ARG_LST:
642 {
643 char ***listp1 = (char ***)p1;
644 char ***listp2 = (char ***)p2;
645
646 if (!cmp_list(*listp1, *listp2))
647 return FALSE;
648 }
649 break;
650 default:
651 break;
652 }
653 }
654 return TRUE;
655 }