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