support of force_keepalive parameter
[strongswan.git] / src / starter / args.c
1 /* automatic handling of confread struct arguments
2 * Copyright (C) 2007 Tobias Brunner
3 * Copyright (C) 2006 Andreas Steffen
4 * Hochschule fuer Technik Rapperswil, Switzerland
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * RCSID $Id$
17 */
18
19 #include <stddef.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <freeswan.h>
24
25 #include "../pluto/constants.h"
26 #include "../pluto/defs.h"
27 #include "../pluto/log.h"
28
29 #include "keywords.h"
30 #include "parser.h"
31 #include "confread.h"
32 #include "args.h"
33
34 /* argument types */
35
36 typedef enum {
37 ARG_NONE,
38 ARG_ENUM,
39 ARG_UINT,
40 ARG_TIME,
41 ARG_ULNG,
42 ARG_PCNT,
43 ARG_STR,
44 ARG_LST,
45 ARG_MISC
46 } arg_t;
47
48 /* various keyword lists */
49
50 static const char *LST_bool[] = {
51 "no",
52 "yes",
53 NULL
54 };
55
56 static const char *LST_sendcert[] = {
57 "always",
58 "ifasked",
59 "never",
60 "yes",
61 "no",
62 NULL
63 };
64
65 static const char *LST_strict[] = {
66 "no",
67 "yes",
68 "ifuri",
69 NULL
70 };
71 static const char *LST_dpd_action[] = {
72 "none",
73 "clear",
74 "hold",
75 "restart",
76 NULL
77 };
78
79 static const char *LST_startup[] = {
80 "ignore",
81 "add",
82 "route",
83 "start",
84 NULL
85 };
86
87 static const char *LST_packetdefault[] = {
88 "drop",
89 "reject",
90 "pass",
91 NULL
92 };
93
94 static const char *LST_keyexchange[] = {
95 "ike",
96 "ikev1",
97 "ikev2",
98 NULL
99 };
100
101 static const char *LST_pfsgroup[] = {
102 "modp1024",
103 "modp1536",
104 "modp2048",
105 "modp3072",
106 "modp4096",
107 "modp6144",
108 "modp8192",
109 NULL
110 };
111
112 static const char *LST_plutodebug[] = {
113 "none",
114 "all",
115 "raw",
116 "crypt",
117 "parsing",
118 "emitting",
119 "control",
120 "lifecycle",
121 "klips",
122 "dns",
123 "natt",
124 "oppo",
125 "controlmore",
126 "private",
127 NULL
128 };
129
130 static const char *LST_klipsdebug[] = {
131 "tunnel",
132 "tunnel-xmit",
133 "pfkey",
134 "xform",
135 "eroute",
136 "spi",
137 "radij",
138 "esp",
139 "ah",
140 "ipcomp",
141 "verbose",
142 "all",
143 "none",
144 NULL
145 };
146
147 typedef struct {
148 arg_t type;
149 size_t offset;
150 const char **list;
151 } token_info_t;
152
153 static const token_info_t token_info[] =
154 {
155 /* config setup keywords */
156 { ARG_LST, offsetof(starter_config_t, setup.interfaces), NULL },
157 { ARG_STR, offsetof(starter_config_t, setup.dumpdir), NULL },
158 { ARG_ENUM, offsetof(starter_config_t, setup.charonstart), LST_bool },
159 { ARG_ENUM, offsetof(starter_config_t, setup.plutostart), LST_bool },
160
161 /* pluto/charon keywords */
162 { ARG_LST, offsetof(starter_config_t, setup.plutodebug), LST_plutodebug },
163 { ARG_STR, offsetof(starter_config_t, setup.charondebug), NULL },
164 { ARG_STR, offsetof(starter_config_t, setup.prepluto), NULL },
165 { ARG_STR, offsetof(starter_config_t, setup.postpluto), NULL },
166 { ARG_ENUM, offsetof(starter_config_t, setup.uniqueids), LST_bool },
167 { ARG_UINT, offsetof(starter_config_t, setup.overridemtu), NULL },
168 { ARG_TIME, offsetof(starter_config_t, setup.crlcheckinterval), NULL },
169 { ARG_ENUM, offsetof(starter_config_t, setup.cachecrls), LST_bool },
170 { ARG_ENUM, offsetof(starter_config_t, setup.strictcrlpolicy), LST_strict },
171 { ARG_ENUM, offsetof(starter_config_t, setup.nocrsend), LST_bool },
172 { ARG_ENUM, offsetof(starter_config_t, setup.nat_traversal), LST_bool },
173 { ARG_TIME, offsetof(starter_config_t, setup.keep_alive), NULL },
174 { ARG_ENUM, offsetof(starter_config_t, setup.force_keepalive), LST_bool },
175 { ARG_STR, offsetof(starter_config_t, setup.virtual_private), NULL },
176 { ARG_STR, offsetof(starter_config_t, setup.pkcs11module), NULL },
177 { ARG_STR, offsetof(starter_config_t, setup.pkcs11initargs), NULL },
178 { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11keepstate), LST_bool },
179 { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11proxy), LST_bool },
180
181 /* KLIPS keywords */
182 { ARG_LST, offsetof(starter_config_t, setup.klipsdebug), LST_klipsdebug },
183 { ARG_ENUM, offsetof(starter_config_t, setup.fragicmp), LST_bool },
184 { ARG_STR, offsetof(starter_config_t, setup.packetdefault), LST_packetdefault },
185 { ARG_ENUM, offsetof(starter_config_t, setup.hidetos), LST_bool },
186
187 /* conn section keywords */
188 { ARG_STR, offsetof(starter_conn_t, name), NULL },
189 { ARG_ENUM, offsetof(starter_conn_t, startup), LST_startup },
190 { ARG_ENUM, offsetof(starter_conn_t, keyexchange), LST_keyexchange },
191 { ARG_MISC, 0, NULL /* KW_TYPE */ },
192 { ARG_MISC, 0, NULL /* KW_PFS */ },
193 { ARG_MISC, 0, NULL /* KW_COMPRESS */ },
194 { ARG_MISC, 0, NULL /* KW_AUTH */ },
195 { ARG_MISC, 0, NULL /* KW_AUTHBY */ },
196 { ARG_MISC, 0, NULL /* KW_EAP */ },
197 { ARG_MISC, 0, NULL /* KW_MOBIKE */ },
198 { ARG_MISC, 0, NULL /* KW_FORCEENCAPS */ },
199 { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL },
200 { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL },
201 { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL },
202 { ARG_MISC, 0, NULL /* KW_KEYINGTRIES */ },
203 { ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL },
204 { ARG_MISC, 0, NULL /* KW_REKEY */ },
205 { ARG_MISC, 0, NULL /* KW_REAUTH */ },
206 { ARG_STR, offsetof(starter_conn_t, ike), NULL },
207 { ARG_STR, offsetof(starter_conn_t, esp), NULL },
208 { ARG_STR, offsetof(starter_conn_t, pfsgroup), LST_pfsgroup },
209 { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL },
210 { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL },
211 { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action },
212 { ARG_MISC, 0, NULL /* KW_MODECONFIG */ },
213 { ARG_MISC, 0, NULL /* KW_XAUTH */ },
214 { ARG_ENUM, offsetof(starter_conn_t, me_mediation), LST_bool },
215 { ARG_STR, offsetof(starter_conn_t, me_mediated_by), NULL },
216 { ARG_STR, offsetof(starter_conn_t, me_peerid), NULL },
217
218 /* ca section keywords */
219 { ARG_STR, offsetof(starter_ca_t, name), NULL },
220 { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup },
221 { ARG_STR, offsetof(starter_ca_t, cacert), NULL },
222 { ARG_STR, offsetof(starter_ca_t, ldaphost), NULL },
223 { ARG_STR, offsetof(starter_ca_t, ldapbase), NULL },
224 { ARG_STR, offsetof(starter_ca_t, crluri), NULL },
225 { ARG_STR, offsetof(starter_ca_t, crluri2), NULL },
226 { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL },
227 { ARG_STR, offsetof(starter_ca_t, ocspuri2), NULL },
228
229 /* end keywords */
230 { ARG_MISC, 0, NULL /* KW_HOST */ },
231 { ARG_MISC, 0, NULL /* KW_NEXTHOP */ },
232 { ARG_MISC, 0, NULL /* KW_SUBNET */ },
233 { ARG_MISC, 0, NULL /* KW_SUBNETWITHIN */ },
234 { ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
235 { ARG_MISC, 0, NULL /* KW_SOURCEIP */ },
236 { ARG_MISC, 0, NULL /* KW_NATIP */ },
237 { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
238 { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
239 { ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool },
240 { ARG_STR, offsetof(starter_end_t, updown), NULL },
241 { ARG_STR, offsetof(starter_end_t, id), NULL },
242 { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
243 { ARG_STR, offsetof(starter_end_t, cert), NULL },
244 { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
245 { ARG_STR, offsetof(starter_end_t, ca), NULL },
246 { ARG_STR, offsetof(starter_end_t, groups), NULL },
247 { ARG_STR, offsetof(starter_end_t, iface), NULL }
248 };
249
250 static void
251 free_list(char **list)
252 {
253 char **s;
254
255 for (s = list; *s; s++)
256 pfree(*s);
257 pfree(list);
258 }
259
260 char **
261 new_list(char *value)
262 {
263 char *val, *b, *e, *end, **ret;
264 int count;
265
266 val = value ? clone_str(value, "list value") : NULL;
267 if (!val)
268 return NULL;
269 end = val + strlen(val);
270 for (b = val, count = 0; b < end;)
271 {
272 for (e = b; ((*e != ' ') && (*e != '\0')); e++);
273 *e = '\0';
274 if (e != b)
275 count++;
276 b = e + 1;
277 }
278 if (count == 0)
279 {
280 pfree(val);
281 return NULL;
282 }
283 ret = (char **)alloc_bytes((count+1) * sizeof(char *), "list");
284
285 for (b = val, count = 0; b < end; )
286 {
287 for (e = b; (*e != '\0'); e++);
288 if (e != b)
289 ret[count++] = clone_str(b, "list value");
290 b = e + 1;
291 }
292 ret[count] = NULL;
293 pfree(val);
294 return ret;
295 }
296
297
298 /*
299 * assigns an argument value to a struct field
300 */
301 bool
302 assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base
303 , bool *assigned)
304 {
305 char *p = base + token_info[token].offset;
306 const char **list = token_info[token].list;
307
308 int index = -1; /* used for enumeration arguments */
309
310 lset_t *seen = (lset_t *)base; /* seen flags are at the top of the struct */
311 lset_t f = LELEM(token - first); /* compute flag position of argument */
312
313 *assigned = FALSE;
314
315 DBG(DBG_CONTROLMORE,
316 DBG_log(" %s=%s", kw->entry->name, kw->value)
317 )
318
319 if (*seen & f)
320 {
321 plog("# duplicate '%s' option", kw->entry->name);
322 return FALSE;
323 }
324
325 /* set flag that this argument has been seen */
326 *seen |= f;
327
328 /* is there a keyword list? */
329 if (list != NULL && token_info[token].type != ARG_LST)
330 {
331 bool match = FALSE;
332
333 while (*list != NULL && !match)
334 {
335 index++;
336 match = streq(kw->value, *list++);
337 }
338 if (!match)
339 {
340 plog("# bad value: %s=%s", kw->entry->name, kw->value);
341 return FALSE;
342 }
343 }
344
345 switch (token_info[token].type)
346 {
347 case ARG_NONE:
348 plog("# option '%s' not supported yet", kw->entry->name);
349 return FALSE;
350 case ARG_ENUM:
351 {
352 int *i = (int *)p;
353
354 if (index < 0)
355 {
356 plog("# bad enumeration value: %s=%s (%d)"
357 , kw->entry->name, kw->value, index);
358 return FALSE;
359 }
360 *i = index;
361 }
362 break;
363
364 case ARG_UINT:
365 {
366 char *endptr;
367 u_int *u = (u_int *)p;
368
369 *u = strtoul(kw->value, &endptr, 10);
370
371 if (*endptr != '\0')
372 {
373 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
374 return FALSE;
375 }
376 }
377 break;
378 case ARG_ULNG:
379 case ARG_PCNT:
380 {
381 char *endptr;
382 unsigned long *l = (unsigned long *)p;
383
384 *l = strtoul(kw->value, &endptr, 10);
385
386 if (token_info[token].type == ARG_ULNG)
387 {
388 if (*endptr != '\0')
389 {
390 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
391 return FALSE;
392 }
393 }
394 else
395 {
396 if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
397 {
398 plog("# bad percent value: %s=%s", kw->entry->name, kw->value);
399 return FALSE;
400 }
401 }
402
403 }
404 break;
405 case ARG_TIME:
406 {
407 char *endptr;
408 time_t *t = (time_t *)p;
409
410 *t = strtoul(kw->value, &endptr, 10);
411
412 /* time in seconds? */
413 if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
414 break;
415
416 if (endptr[1] == '\0')
417 {
418 if (*endptr == 'm') /* time in minutes? */
419 {
420 *t *= 60;
421 break;
422 }
423 if (*endptr == 'h') /* time in hours? */
424 {
425 *t *= 3600;
426 break;
427 }
428 if (*endptr == 'd') /* time in days? */
429 {
430 *t *= 3600*24;
431 break;
432 }
433 }
434 plog("# bad duration value: %s=%s", kw->entry->name, kw->value);
435 return FALSE;
436 }
437 case ARG_STR:
438 {
439 char **cp = (char **)p;
440
441 /* free any existing string */
442 pfreeany(*cp);
443
444 /* assign the new string */
445 *cp = clone_str(kw->value, "str_value");
446 }
447 break;
448 case ARG_LST:
449 {
450 char ***listp = (char ***)p;
451
452 /* free any existing list */
453 if (*listp != NULL)
454 free_list(*listp);
455
456 /* create a new list and assign values */
457 *listp = new_list(kw->value);
458
459 /* is there a keyword list? */
460 if (list != NULL)
461 {
462 char ** lst;
463
464 for (lst = *listp; lst && *lst; lst++)
465 {
466 bool match = FALSE;
467
468 list = token_info[token].list;
469
470 while (*list != NULL && !match)
471 {
472 match = streq(*lst, *list++);
473 }
474 if (!match)
475 {
476 plog("# bad value: %s=%s", kw->entry->name, *lst);
477 return FALSE;
478 }
479 }
480 }
481 }
482 default:
483 return TRUE;
484 }
485
486 *assigned = TRUE;
487 return TRUE;
488 }
489
490 /*
491 * frees all dynamically allocated arguments in a struct
492 */
493 void
494 free_args(kw_token_t first, kw_token_t last, char *base)
495 {
496 kw_token_t token;
497
498 for (token = first; token <= last; token++)
499 {
500 char *p = base + token_info[token].offset;
501
502 switch (token_info[token].type)
503 {
504 case ARG_STR:
505 {
506 char **cp = (char **)p;
507
508 pfreeany(*cp);
509 *cp = NULL;
510 }
511 break;
512 case ARG_LST:
513 {
514 char ***listp = (char ***)p;
515
516 if (*listp != NULL)
517 {
518 free_list(*listp);
519 *listp = NULL;
520 }
521 }
522 break;
523 default:
524 break;
525 }
526 }
527 }
528
529 /*
530 * clone all dynamically allocated arguments in a struct
531 */
532 void
533 clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
534 {
535 kw_token_t token;
536
537 for (token = first; token <= last; token++)
538 {
539 if (token_info[token].type == ARG_STR)
540 {
541 char **cp1 = (char **)(base1 + token_info[token].offset);
542 char **cp2 = (char **)(base2 + token_info[token].offset);
543
544 *cp1 = clone_str(*cp2, "cloned str");
545 }
546 }
547 }
548
549 static bool
550 cmp_list(char **list1, char **list2)
551 {
552 if ((list1 == NULL) && (list2 == NULL))
553 return TRUE;
554 if ((list1 == NULL) || (list2 == NULL))
555 return FALSE;
556
557 for ( ; *list1 && *list2; list1++, list2++)
558 {
559 if (strcmp(*list1,*list2) != 0)
560 return FALSE;
561 }
562
563 if ((*list1 != NULL) || (*list2 != NULL))
564 return FALSE;
565
566 return TRUE;
567 }
568
569 /*
570 * compare all arguments in a struct
571 */
572 bool
573 cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
574 {
575 kw_token_t token;
576
577 for (token = first; token <= last; token++)
578 {
579 char *p1 = base1 + token_info[token].offset;
580 char *p2 = base2 + token_info[token].offset;
581
582 switch (token_info[token].type)
583 {
584 case ARG_ENUM:
585 {
586 int *i1 = (int *)p1;
587 int *i2 = (int *)p2;
588
589 if (*i1 != *i2)
590 return FALSE;
591 }
592 break;
593 case ARG_UINT:
594 {
595 u_int *u1 = (u_int *)p1;
596 u_int *u2 = (u_int *)p2;
597
598 if (*u1 != *u2)
599 return FALSE;
600 }
601 break;
602 case ARG_ULNG:
603 case ARG_PCNT:
604 {
605 unsigned long *l1 = (unsigned long *)p1;
606 unsigned long *l2 = (unsigned long *)p2;
607
608 if (*l1 != *l2)
609 return FALSE;
610 }
611 break;
612 case ARG_TIME:
613 {
614 time_t *t1 = (time_t *)p1;
615 time_t *t2 = (time_t *)p2;
616
617 if (*t1 != *t2)
618 return FALSE;
619 }
620 break;
621 case ARG_STR:
622 {
623 char **cp1 = (char **)p1;
624 char **cp2 = (char **)p2;
625
626 if (*cp1 == NULL && *cp2 == NULL)
627 break;
628 if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
629 return FALSE;
630 }
631 break;
632 case ARG_LST:
633 {
634 char ***listp1 = (char ***)p1;
635 char ***listp2 = (char ***)p2;
636
637 if (!cmp_list(*listp1, *listp2))
638 return FALSE;
639 }
640 break;
641 default:
642 break;
643 }
644 }
645 return TRUE;
646 }