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