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