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