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