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