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