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