implemented IKE_SA uniqueness using ipsec.conf uniqueids paramater
[strongswan.git] / src / starter / args.c
1 /* automatic handling of confread struct arguments
2 * Copyright (C) 2007 Tobias Brunner
3 * Copyright (C) 2006 Andreas Steffen
4 * Hochschule fuer Technik Rapperswil, Switzerland
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * RCSID $Id$
17 */
18
19 #include <stddef.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <freeswan.h>
24
25 #include "../pluto/constants.h"
26 #include "../pluto/defs.h"
27 #include "../pluto/log.h"
28
29 #include "keywords.h"
30 #include "parser.h"
31 #include "confread.h"
32 #include "args.h"
33
34 /* argument types */
35
36 typedef enum {
37 ARG_NONE,
38 ARG_ENUM,
39 ARG_UINT,
40 ARG_TIME,
41 ARG_ULNG,
42 ARG_PCNT,
43 ARG_STR,
44 ARG_LST,
45 ARG_MISC
46 } arg_t;
47
48 /* various keyword lists */
49
50 static const char *LST_bool[] = {
51 "no",
52 "yes",
53 NULL
54 };
55
56 static const char *LST_sendcert[] = {
57 "always",
58 "ifasked",
59 "never",
60 "yes",
61 "no",
62 NULL
63 };
64
65 static const char *LST_unique[] = {
66 "no",
67 "yes",
68 "replace",
69 "keep",
70 NULL
71 };
72
73 static const char *LST_strict[] = {
74 "no",
75 "yes",
76 "ifuri",
77 NULL
78 };
79 static const char *LST_dpd_action[] = {
80 "none",
81 "clear",
82 "hold",
83 "restart",
84 NULL
85 };
86
87 static const char *LST_startup[] = {
88 "ignore",
89 "add",
90 "route",
91 "start",
92 NULL
93 };
94
95 static const char *LST_packetdefault[] = {
96 "drop",
97 "reject",
98 "pass",
99 NULL
100 };
101
102 static const char *LST_keyexchange[] = {
103 "ike",
104 "ikev1",
105 "ikev2",
106 NULL
107 };
108
109 static const char *LST_pfsgroup[] = {
110 "modp1024",
111 "modp1536",
112 "modp2048",
113 "modp3072",
114 "modp4096",
115 "modp6144",
116 "modp8192",
117 NULL
118 };
119
120 static const char *LST_plutodebug[] = {
121 "none",
122 "all",
123 "raw",
124 "crypt",
125 "parsing",
126 "emitting",
127 "control",
128 "lifecycle",
129 "klips",
130 "dns",
131 "natt",
132 "oppo",
133 "controlmore",
134 "private",
135 NULL
136 };
137
138 static const char *LST_klipsdebug[] = {
139 "tunnel",
140 "tunnel-xmit",
141 "pfkey",
142 "xform",
143 "eroute",
144 "spi",
145 "radij",
146 "esp",
147 "ah",
148 "ipcomp",
149 "verbose",
150 "all",
151 "none",
152 NULL
153 };
154
155 typedef struct {
156 arg_t type;
157 size_t offset;
158 const char **list;
159 } token_info_t;
160
161 static const token_info_t token_info[] =
162 {
163 /* config setup keywords */
164 { ARG_LST, offsetof(starter_config_t, setup.interfaces), NULL },
165 { ARG_STR, offsetof(starter_config_t, setup.dumpdir), NULL },
166 { ARG_ENUM, offsetof(starter_config_t, setup.charonstart), LST_bool },
167 { ARG_ENUM, offsetof(starter_config_t, setup.plutostart), LST_bool },
168
169 /* pluto/charon keywords */
170 { ARG_LST, offsetof(starter_config_t, setup.plutodebug), LST_plutodebug },
171 { ARG_STR, offsetof(starter_config_t, setup.charondebug), NULL },
172 { ARG_STR, offsetof(starter_config_t, setup.prepluto), NULL },
173 { ARG_STR, offsetof(starter_config_t, setup.postpluto), NULL },
174 { ARG_ENUM, offsetof(starter_config_t, setup.uniqueids), LST_unique },
175 { ARG_UINT, offsetof(starter_config_t, setup.overridemtu), NULL },
176 { ARG_TIME, offsetof(starter_config_t, setup.crlcheckinterval), NULL },
177 { ARG_ENUM, offsetof(starter_config_t, setup.cachecrls), LST_bool },
178 { ARG_ENUM, offsetof(starter_config_t, setup.strictcrlpolicy), LST_strict },
179 { ARG_ENUM, offsetof(starter_config_t, setup.nocrsend), LST_bool },
180 { ARG_ENUM, offsetof(starter_config_t, setup.nat_traversal), LST_bool },
181 { ARG_TIME, offsetof(starter_config_t, setup.keep_alive), NULL },
182 { ARG_ENUM, offsetof(starter_config_t, setup.force_keepalive), LST_bool },
183 { ARG_STR, offsetof(starter_config_t, setup.virtual_private), NULL },
184 { ARG_STR, offsetof(starter_config_t, setup.pkcs11module), NULL },
185 { ARG_STR, offsetof(starter_config_t, setup.pkcs11initargs), NULL },
186 { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11keepstate), LST_bool },
187 { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11proxy), LST_bool },
188
189 /* KLIPS keywords */
190 { ARG_LST, offsetof(starter_config_t, setup.klipsdebug), LST_klipsdebug },
191 { ARG_ENUM, offsetof(starter_config_t, setup.fragicmp), LST_bool },
192 { ARG_STR, offsetof(starter_config_t, setup.packetdefault), LST_packetdefault },
193 { ARG_ENUM, offsetof(starter_config_t, setup.hidetos), LST_bool },
194
195 /* conn section keywords */
196 { ARG_STR, offsetof(starter_conn_t, name), NULL },
197 { ARG_ENUM, offsetof(starter_conn_t, startup), LST_startup },
198 { ARG_ENUM, offsetof(starter_conn_t, keyexchange), LST_keyexchange },
199 { ARG_MISC, 0, NULL /* KW_TYPE */ },
200 { ARG_MISC, 0, NULL /* KW_PFS */ },
201 { ARG_MISC, 0, NULL /* KW_COMPRESS */ },
202 { ARG_MISC, 0, NULL /* KW_AUTH */ },
203 { ARG_MISC, 0, NULL /* KW_AUTHBY */ },
204 { ARG_MISC, 0, NULL /* KW_EAP */ },
205 { ARG_MISC, 0, NULL /* KW_MOBIKE */ },
206 { ARG_MISC, 0, NULL /* KW_FORCEENCAPS */ },
207 { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL },
208 { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL },
209 { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL },
210 { ARG_MISC, 0, NULL /* KW_KEYINGTRIES */ },
211 { ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL },
212 { ARG_MISC, 0, NULL /* KW_REKEY */ },
213 { ARG_MISC, 0, NULL /* KW_REAUTH */ },
214 { ARG_STR, offsetof(starter_conn_t, ike), NULL },
215 { ARG_STR, offsetof(starter_conn_t, esp), NULL },
216 { ARG_STR, offsetof(starter_conn_t, pfsgroup), LST_pfsgroup },
217 { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL },
218 { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL },
219 { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action },
220 { ARG_MISC, 0, NULL /* KW_MODECONFIG */ },
221 { ARG_MISC, 0, NULL /* KW_XAUTH */ },
222 { ARG_ENUM, offsetof(starter_conn_t, me_mediation), LST_bool },
223 { ARG_STR, offsetof(starter_conn_t, me_mediated_by), NULL },
224 { ARG_STR, offsetof(starter_conn_t, me_peerid), NULL },
225
226 /* ca section keywords */
227 { ARG_STR, offsetof(starter_ca_t, name), NULL },
228 { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup },
229 { ARG_STR, offsetof(starter_ca_t, cacert), NULL },
230 { ARG_STR, offsetof(starter_ca_t, ldaphost), NULL },
231 { ARG_STR, offsetof(starter_ca_t, ldapbase), NULL },
232 { ARG_STR, offsetof(starter_ca_t, crluri), NULL },
233 { ARG_STR, offsetof(starter_ca_t, crluri2), NULL },
234 { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL },
235 { ARG_STR, offsetof(starter_ca_t, ocspuri2), NULL },
236
237 /* end keywords */
238 { ARG_MISC, 0, NULL /* KW_HOST */ },
239 { ARG_MISC, 0, NULL /* KW_NEXTHOP */ },
240 { ARG_MISC, 0, NULL /* KW_SUBNET */ },
241 { ARG_MISC, 0, NULL /* KW_SUBNETWITHIN */ },
242 { ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
243 { ARG_MISC, 0, NULL /* KW_SOURCEIP */ },
244 { ARG_MISC, 0, NULL /* KW_NATIP */ },
245 { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
246 { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
247 { ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool },
248 { ARG_STR, offsetof(starter_end_t, updown), NULL },
249 { ARG_STR, offsetof(starter_end_t, id), NULL },
250 { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
251 { ARG_STR, offsetof(starter_end_t, cert), NULL },
252 { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
253 { ARG_STR, offsetof(starter_end_t, ca), NULL },
254 { ARG_STR, offsetof(starter_end_t, groups), NULL },
255 { ARG_STR, offsetof(starter_end_t, iface), NULL }
256 };
257
258 static void
259 free_list(char **list)
260 {
261 char **s;
262
263 for (s = list; *s; s++)
264 pfree(*s);
265 pfree(list);
266 }
267
268 char **
269 new_list(char *value)
270 {
271 char *val, *b, *e, *end, **ret;
272 int count;
273
274 val = value ? clone_str(value, "list value") : NULL;
275 if (!val)
276 return NULL;
277 end = val + strlen(val);
278 for (b = val, count = 0; b < end;)
279 {
280 for (e = b; ((*e != ' ') && (*e != '\0')); e++);
281 *e = '\0';
282 if (e != b)
283 count++;
284 b = e + 1;
285 }
286 if (count == 0)
287 {
288 pfree(val);
289 return NULL;
290 }
291 ret = (char **)alloc_bytes((count+1) * sizeof(char *), "list");
292
293 for (b = val, count = 0; b < end; )
294 {
295 for (e = b; (*e != '\0'); e++);
296 if (e != b)
297 ret[count++] = clone_str(b, "list value");
298 b = e + 1;
299 }
300 ret[count] = NULL;
301 pfree(val);
302 return ret;
303 }
304
305
306 /*
307 * assigns an argument value to a struct field
308 */
309 bool
310 assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base
311 , bool *assigned)
312 {
313 char *p = base + token_info[token].offset;
314 const char **list = token_info[token].list;
315
316 int index = -1; /* used for enumeration arguments */
317
318 lset_t *seen = (lset_t *)base; /* seen flags are at the top of the struct */
319 lset_t f = LELEM(token - first); /* compute flag position of argument */
320
321 *assigned = FALSE;
322
323 DBG(DBG_CONTROLMORE,
324 DBG_log(" %s=%s", kw->entry->name, kw->value)
325 )
326
327 if (*seen & f)
328 {
329 plog("# duplicate '%s' option", kw->entry->name);
330 return FALSE;
331 }
332
333 /* set flag that this argument has been seen */
334 *seen |= f;
335
336 /* is there a keyword list? */
337 if (list != NULL && token_info[token].type != ARG_LST)
338 {
339 bool match = FALSE;
340
341 while (*list != NULL && !match)
342 {
343 index++;
344 match = streq(kw->value, *list++);
345 }
346 if (!match)
347 {
348 plog("# bad value: %s=%s", kw->entry->name, kw->value);
349 return FALSE;
350 }
351 }
352
353 switch (token_info[token].type)
354 {
355 case ARG_NONE:
356 plog("# option '%s' not supported yet", kw->entry->name);
357 return FALSE;
358 case ARG_ENUM:
359 {
360 int *i = (int *)p;
361
362 if (index < 0)
363 {
364 plog("# bad enumeration value: %s=%s (%d)"
365 , kw->entry->name, kw->value, index);
366 return FALSE;
367 }
368 *i = index;
369 }
370 break;
371
372 case ARG_UINT:
373 {
374 char *endptr;
375 u_int *u = (u_int *)p;
376
377 *u = strtoul(kw->value, &endptr, 10);
378
379 if (*endptr != '\0')
380 {
381 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
382 return FALSE;
383 }
384 }
385 break;
386 case ARG_ULNG:
387 case ARG_PCNT:
388 {
389 char *endptr;
390 unsigned long *l = (unsigned long *)p;
391
392 *l = strtoul(kw->value, &endptr, 10);
393
394 if (token_info[token].type == ARG_ULNG)
395 {
396 if (*endptr != '\0')
397 {
398 plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
399 return FALSE;
400 }
401 }
402 else
403 {
404 if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
405 {
406 plog("# bad percent value: %s=%s", kw->entry->name, kw->value);
407 return FALSE;
408 }
409 }
410
411 }
412 break;
413 case ARG_TIME:
414 {
415 char *endptr;
416 time_t *t = (time_t *)p;
417
418 *t = strtoul(kw->value, &endptr, 10);
419
420 /* time in seconds? */
421 if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
422 break;
423
424 if (endptr[1] == '\0')
425 {
426 if (*endptr == 'm') /* time in minutes? */
427 {
428 *t *= 60;
429 break;
430 }
431 if (*endptr == 'h') /* time in hours? */
432 {
433 *t *= 3600;
434 break;
435 }
436 if (*endptr == 'd') /* time in days? */
437 {
438 *t *= 3600*24;
439 break;
440 }
441 }
442 plog("# bad duration value: %s=%s", kw->entry->name, kw->value);
443 return FALSE;
444 }
445 case ARG_STR:
446 {
447 char **cp = (char **)p;
448
449 /* free any existing string */
450 pfreeany(*cp);
451
452 /* assign the new string */
453 *cp = clone_str(kw->value, "str_value");
454 }
455 break;
456 case ARG_LST:
457 {
458 char ***listp = (char ***)p;
459
460 /* free any existing list */
461 if (*listp != NULL)
462 free_list(*listp);
463
464 /* create a new list and assign values */
465 *listp = new_list(kw->value);
466
467 /* is there a keyword list? */
468 if (list != NULL)
469 {
470 char ** lst;
471
472 for (lst = *listp; lst && *lst; lst++)
473 {
474 bool match = FALSE;
475
476 list = token_info[token].list;
477
478 while (*list != NULL && !match)
479 {
480 match = streq(*lst, *list++);
481 }
482 if (!match)
483 {
484 plog("# bad value: %s=%s", kw->entry->name, *lst);
485 return FALSE;
486 }
487 }
488 }
489 }
490 default:
491 return TRUE;
492 }
493
494 *assigned = TRUE;
495 return TRUE;
496 }
497
498 /*
499 * frees all dynamically allocated arguments in a struct
500 */
501 void
502 free_args(kw_token_t first, kw_token_t last, char *base)
503 {
504 kw_token_t token;
505
506 for (token = first; token <= last; token++)
507 {
508 char *p = base + token_info[token].offset;
509
510 switch (token_info[token].type)
511 {
512 case ARG_STR:
513 {
514 char **cp = (char **)p;
515
516 pfreeany(*cp);
517 *cp = NULL;
518 }
519 break;
520 case ARG_LST:
521 {
522 char ***listp = (char ***)p;
523
524 if (*listp != NULL)
525 {
526 free_list(*listp);
527 *listp = NULL;
528 }
529 }
530 break;
531 default:
532 break;
533 }
534 }
535 }
536
537 /*
538 * clone all dynamically allocated arguments in a struct
539 */
540 void
541 clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
542 {
543 kw_token_t token;
544
545 for (token = first; token <= last; token++)
546 {
547 if (token_info[token].type == ARG_STR)
548 {
549 char **cp1 = (char **)(base1 + token_info[token].offset);
550 char **cp2 = (char **)(base2 + token_info[token].offset);
551
552 *cp1 = clone_str(*cp2, "cloned str");
553 }
554 }
555 }
556
557 static bool
558 cmp_list(char **list1, char **list2)
559 {
560 if ((list1 == NULL) && (list2 == NULL))
561 return TRUE;
562 if ((list1 == NULL) || (list2 == NULL))
563 return FALSE;
564
565 for ( ; *list1 && *list2; list1++, list2++)
566 {
567 if (strcmp(*list1,*list2) != 0)
568 return FALSE;
569 }
570
571 if ((*list1 != NULL) || (*list2 != NULL))
572 return FALSE;
573
574 return TRUE;
575 }
576
577 /*
578 * compare all arguments in a struct
579 */
580 bool
581 cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
582 {
583 kw_token_t token;
584
585 for (token = first; token <= last; token++)
586 {
587 char *p1 = base1 + token_info[token].offset;
588 char *p2 = base2 + token_info[token].offset;
589
590 switch (token_info[token].type)
591 {
592 case ARG_ENUM:
593 {
594 int *i1 = (int *)p1;
595 int *i2 = (int *)p2;
596
597 if (*i1 != *i2)
598 return FALSE;
599 }
600 break;
601 case ARG_UINT:
602 {
603 u_int *u1 = (u_int *)p1;
604 u_int *u2 = (u_int *)p2;
605
606 if (*u1 != *u2)
607 return FALSE;
608 }
609 break;
610 case ARG_ULNG:
611 case ARG_PCNT:
612 {
613 unsigned long *l1 = (unsigned long *)p1;
614 unsigned long *l2 = (unsigned long *)p2;
615
616 if (*l1 != *l2)
617 return FALSE;
618 }
619 break;
620 case ARG_TIME:
621 {
622 time_t *t1 = (time_t *)p1;
623 time_t *t2 = (time_t *)p2;
624
625 if (*t1 != *t2)
626 return FALSE;
627 }
628 break;
629 case ARG_STR:
630 {
631 char **cp1 = (char **)p1;
632 char **cp2 = (char **)p2;
633
634 if (*cp1 == NULL && *cp2 == NULL)
635 break;
636 if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
637 return FALSE;
638 }
639 break;
640 case ARG_LST:
641 {
642 char ***listp1 = (char ***)p1;
643 char ***listp2 = (char ***)p2;
644
645 if (!cmp_list(*listp1, *listp2))
646 return FALSE;
647 }
648 break;
649 default:
650 break;
651 }
652 }
653 return TRUE;
654 }