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