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