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