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