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