starter: Remove all ties to pluto/libfreeswan.
[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
16 #include <stddef.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include <library.h>
21 #include <debug.h>
22
23 #include "keywords.h"
24 #include "confread.h"
25 #include "args.h"
26
27 /* argument types */
28
29 typedef enum {
30 ARG_NONE,
31 ARG_ENUM,
32 ARG_UINT,
33 ARG_TIME,
34 ARG_ULNG,
35 ARG_ULLI,
36 ARG_PCNT,
37 ARG_STR,
38 ARG_LST,
39 ARG_MISC
40 } arg_t;
41
42 /* various keyword lists */
43
44 static const char *LST_bool[] = {
45 "no",
46 "yes",
47 NULL
48 };
49
50 static const char *LST_sendcert[] = {
51 "always",
52 "ifasked",
53 "never",
54 "yes",
55 "no",
56 NULL
57 };
58
59 static const char *LST_unique[] = {
60 "no",
61 "yes",
62 "replace",
63 "keep",
64 NULL
65 };
66
67 static const char *LST_strict[] = {
68 "no",
69 "yes",
70 "ifuri",
71 NULL
72 };
73 static const char *LST_dpd_action[] = {
74 "none",
75 "clear",
76 "hold",
77 "restart",
78 NULL
79 };
80
81 static const char *LST_startup[] = {
82 "ignore",
83 "add",
84 "route",
85 "start",
86 NULL
87 };
88
89 static const char *LST_packetdefault[] = {
90 "drop",
91 "reject",
92 "pass",
93 NULL
94 };
95
96 static const char *LST_keyexchange[] = {
97 "ike",
98 "ikev1",
99 "ikev2",
100 NULL
101 };
102
103 static const char *LST_plutodebug[] = {
104 "none",
105 "all",
106 "raw",
107 "crypt",
108 "parsing",
109 "emitting",
110 "control",
111 "lifecycle",
112 "klips",
113 "kernel",
114 "dns",
115 "natt",
116 "oppo",
117 "controlmore",
118 "private",
119 NULL
120 };
121
122 static const char *LST_klipsdebug[] = {
123 "tunnel",
124 "tunnel-xmit",
125 "pfkey",
126 "xform",
127 "eroute",
128 "spi",
129 "radij",
130 "esp",
131 "ah",
132 "ipcomp",
133 "verbose",
134 "all",
135 "none",
136 NULL
137 };
138
139 static const char *LST_authby[] = {
140 "psk",
141 "secret",
142 "pubkey",
143 "rsa",
144 "rsasig",
145 "ecdsa",
146 "ecdsasig",
147 "xauthpsk",
148 "xauthrsasig",
149 "never",
150 NULL
151 };
152
153 typedef struct {
154 arg_t type;
155 size_t offset;
156 const char **list;
157 } token_info_t;
158
159 static const token_info_t token_info[] =
160 {
161 /* config setup keywords */
162 { ARG_LST, offsetof(starter_config_t, setup.interfaces), NULL },
163 { ARG_STR, offsetof(starter_config_t, setup.dumpdir), NULL },
164 { ARG_ENUM, offsetof(starter_config_t, setup.charonstart), LST_bool },
165 { ARG_ENUM, offsetof(starter_config_t, setup.plutostart), LST_bool },
166
167 /* pluto/charon keywords */
168 { ARG_LST, offsetof(starter_config_t, setup.plutodebug), LST_plutodebug },
169 { ARG_STR, offsetof(starter_config_t, setup.charondebug), NULL },
170 { ARG_STR, offsetof(starter_config_t, setup.prepluto), NULL },
171 { ARG_STR, offsetof(starter_config_t, setup.postpluto), NULL },
172 { ARG_STR, offsetof(starter_config_t, setup.plutostderrlog), NULL },
173 { ARG_ENUM, offsetof(starter_config_t, setup.uniqueids), LST_unique },
174 { ARG_UINT, offsetof(starter_config_t, setup.overridemtu), NULL },
175 { ARG_TIME, offsetof(starter_config_t, setup.crlcheckinterval), NULL },
176 { ARG_ENUM, offsetof(starter_config_t, setup.cachecrls), LST_bool },
177 { ARG_ENUM, offsetof(starter_config_t, setup.strictcrlpolicy), LST_strict },
178 { ARG_ENUM, offsetof(starter_config_t, setup.nocrsend), LST_bool },
179 { ARG_ENUM, offsetof(starter_config_t, setup.nat_traversal), LST_bool },
180 { ARG_TIME, offsetof(starter_config_t, setup.keep_alive), NULL },
181 { ARG_ENUM, offsetof(starter_config_t, setup.force_keepalive), LST_bool },
182 { ARG_STR, offsetof(starter_config_t, setup.virtual_private), NULL },
183 { ARG_STR, offsetof(starter_config_t, setup.pkcs11module), NULL },
184 { ARG_STR, offsetof(starter_config_t, setup.pkcs11initargs), NULL },
185 { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11keepstate), LST_bool },
186 { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11proxy), LST_bool },
187
188 /* KLIPS keywords */
189 { ARG_LST, offsetof(starter_config_t, setup.klipsdebug), LST_klipsdebug },
190 { ARG_ENUM, offsetof(starter_config_t, setup.fragicmp), LST_bool },
191 { ARG_STR, offsetof(starter_config_t, setup.packetdefault), LST_packetdefault },
192 { ARG_ENUM, offsetof(starter_config_t, setup.hidetos), LST_bool },
193
194 /* conn section keywords */
195 { ARG_STR, offsetof(starter_conn_t, name), NULL },
196 { ARG_ENUM, offsetof(starter_conn_t, startup), LST_startup },
197 { ARG_ENUM, offsetof(starter_conn_t, keyexchange), LST_keyexchange },
198 { ARG_MISC, 0, NULL /* KW_TYPE */ },
199 { ARG_MISC, 0, NULL /* KW_COMPRESS */ },
200 { ARG_ENUM, offsetof(starter_conn_t, install_policy), LST_bool },
201 { ARG_ENUM, offsetof(starter_conn_t, aggressive), LST_bool },
202 { ARG_MISC, 0, NULL /* KW_AUTH */ },
203 { ARG_STR, offsetof(starter_conn_t, authby), LST_authby },
204 { ARG_STR, offsetof(starter_conn_t, eap_identity), NULL },
205 { ARG_STR, offsetof(starter_conn_t, aaa_identity), NULL },
206 { ARG_MISC, 0, NULL /* KW_MOBIKE */ },
207 { ARG_MISC, 0, NULL /* KW_FORCEENCAPS */ },
208 { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL },
209 { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL },
210 { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL },
211 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_life_bytes), NULL },
212 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_margin_bytes), NULL },
213 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_life_packets), NULL },
214 { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_margin_packets), NULL },
215 { ARG_MISC, 0, NULL /* KW_KEYINGTRIES */ },
216 { ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL },
217 { ARG_MISC, 0, NULL /* KW_REKEY */ },
218 { ARG_MISC, 0, NULL /* KW_REAUTH */ },
219 { ARG_STR, offsetof(starter_conn_t, ike), NULL },
220 { ARG_STR, offsetof(starter_conn_t, esp), NULL },
221 { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL },
222 { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL },
223 { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action },
224 { ARG_ENUM, offsetof(starter_conn_t, close_action), LST_dpd_action },
225 { ARG_TIME, offsetof(starter_conn_t, inactivity), NULL },
226 { ARG_MISC, 0, NULL /* KW_MODECONFIG */ },
227 { ARG_MISC, 0, NULL /* KW_XAUTH */ },
228 { ARG_STR, offsetof(starter_conn_t, xauth_identity), NULL },
229 { ARG_ENUM, offsetof(starter_conn_t, me_mediation), LST_bool },
230 { ARG_STR, offsetof(starter_conn_t, me_mediated_by), NULL },
231 { ARG_STR, offsetof(starter_conn_t, me_peerid), NULL },
232 { ARG_UINT, offsetof(starter_conn_t, reqid), NULL },
233 { ARG_MISC, 0, NULL /* KW_MARK */ },
234 { ARG_MISC, 0, NULL /* KW_MARK_IN */ },
235 { ARG_MISC, 0, NULL /* KW_MARK_OUT */ },
236 { ARG_MISC, 0, NULL /* KW_TFC */ },
237
238 /* ca section keywords */
239 { ARG_STR, offsetof(starter_ca_t, name), NULL },
240 { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup },
241 { ARG_STR, offsetof(starter_ca_t, cacert), NULL },
242 { ARG_STR, offsetof(starter_ca_t, ldaphost), NULL },
243 { ARG_STR, offsetof(starter_ca_t, ldapbase), NULL },
244 { ARG_STR, offsetof(starter_ca_t, crluri), NULL },
245 { ARG_STR, offsetof(starter_ca_t, crluri2), NULL },
246 { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL },
247 { ARG_STR, offsetof(starter_ca_t, ocspuri2), NULL },
248 { ARG_STR, offsetof(starter_ca_t, certuribase), NULL },
249
250 /* end keywords */
251 { ARG_STR, offsetof(starter_end_t, host), NULL },
252 { ARG_UINT, offsetof(starter_end_t, ikeport), NULL },
253 { ARG_STR, offsetof(starter_end_t, subnet), NULL },
254 { ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
255 { ARG_STR, offsetof(starter_end_t, sourceip), NULL },
256 { ARG_MISC, 0, NULL /* KW_NATIP */ },
257 { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
258 { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
259 { ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool },
260 { ARG_STR, offsetof(starter_end_t, updown), NULL },
261 { ARG_STR, offsetof(starter_end_t, auth), NULL },
262 { ARG_STR, offsetof(starter_end_t, auth2), NULL },
263 { ARG_STR, offsetof(starter_end_t, id), NULL },
264 { ARG_STR, offsetof(starter_end_t, id2), NULL },
265 { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
266 { ARG_STR, offsetof(starter_end_t, cert), NULL },
267 { ARG_STR, offsetof(starter_end_t, cert2), NULL },
268 { ARG_STR, offsetof(starter_end_t, cert_policy), NULL },
269 { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
270 { ARG_STR, offsetof(starter_end_t, ca), NULL },
271 { ARG_STR, offsetof(starter_end_t, ca2), NULL },
272 { ARG_STR, offsetof(starter_end_t, groups), NULL },
273 };
274
275 static void free_list(char **list)
276 {
277 char **s;
278
279 for (s = list; *s; s++)
280 {
281 free(*s);
282 }
283 free(list);
284 }
285
286 char** new_list(char *value)
287 {
288 char *val, *b, *e, *end, **ret;
289 int count;
290
291 val = strdupnull(value);
292 if (!val)
293 {
294 return NULL;
295 }
296 end = val + strlen(val);
297 for (b = val, count = 0; b < end;)
298 {
299 for (e = b; ((*e != ' ') && (*e != '\0')); e++);
300 *e = '\0';
301 if (e != b)
302 {
303 count++;
304 }
305 b = e + 1;
306 }
307 if (count == 0)
308 {
309 free(val);
310 return NULL;
311 }
312 ret = (char **)malloc((count+1) * sizeof(char *));
313
314 for (b = val, count = 0; b < end; )
315 {
316 for (e = b; (*e != '\0'); e++);
317 if (e != b)
318 {
319 ret[count++] = strdupnull(b);
320 }
321 b = e + 1;
322 }
323 ret[count] = NULL;
324 free(val);
325 return ret;
326 }
327
328
329 /*
330 * assigns an argument value to a struct field
331 */
332 bool assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base,
333 bool *assigned)
334 {
335 char *p = base + token_info[token].offset;
336 const char **list = token_info[token].list;
337
338 int index = -1; /* used for enumeration arguments */
339
340 seen_t *seen = (seen_t*)base; /* seen flags are at the top of the struct */
341
342 *assigned = FALSE;
343
344 DBG3(DBG_APP, " %s=%s", kw->entry->name, kw->value);
345
346 if (*seen & SEEN_KW(token, first))
347 {
348 DBG1(DBG_APP, "# duplicate '%s' option", kw->entry->name);
349 return FALSE;
350 }
351
352 /* set flag that this argument has been seen */
353 *seen |= SEEN_KW(token, first);
354
355 /* is there a keyword list? */
356 if (list != NULL && token_info[token].type != ARG_LST)
357 {
358 bool match = FALSE;
359
360 while (*list != NULL && !match)
361 {
362 index++;
363 match = streq(kw->value, *list++);
364 }
365 if (!match)
366 {
367 DBG1(DBG_APP, "# bad value: %s=%s", kw->entry->name, kw->value);
368 return FALSE;
369 }
370 }
371
372 switch (token_info[token].type)
373 {
374 case ARG_NONE:
375 DBG1(DBG_APP, "# option '%s' not supported yet", kw->entry->name);
376 return FALSE;
377 case ARG_ENUM:
378 {
379 if (index < 0)
380 {
381 DBG1(DBG_APP, "# bad enumeration value: %s=%s (%d)",
382 kw->entry->name, kw->value, index);
383 return FALSE;
384 }
385
386 if (token_info[token].list == LST_bool)
387 {
388 bool *b = (bool *)p;
389 *b = (index > 0);
390 }
391 else
392 {
393 int *i = (int *)p;
394 *i = index;
395 }
396 }
397 break;
398
399 case ARG_UINT:
400 {
401 char *endptr;
402 u_int *u = (u_int *)p;
403
404 *u = strtoul(kw->value, &endptr, 10);
405
406 if (*endptr != '\0')
407 {
408 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
409 kw->value);
410 return FALSE;
411 }
412 }
413 break;
414 case ARG_ULNG:
415 case ARG_PCNT:
416 {
417 char *endptr;
418 unsigned long *l = (unsigned long *)p;
419
420 *l = strtoul(kw->value, &endptr, 10);
421
422 if (token_info[token].type == ARG_ULNG)
423 {
424 if (*endptr != '\0')
425 {
426 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
427 kw->value);
428 return FALSE;
429 }
430 }
431 else
432 {
433 if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
434 {
435 DBG1(DBG_APP, "# bad percent value: %s=%s", kw->entry->name,
436 kw->value);
437 return FALSE;
438 }
439 }
440
441 }
442 break;
443 case ARG_ULLI:
444 {
445 char *endptr;
446 unsigned long long *ll = (unsigned long long *)p;
447
448 *ll = strtoull(kw->value, &endptr, 10);
449
450 if (*endptr != '\0')
451 {
452 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
453 kw->value);
454 return FALSE;
455 }
456 }
457 break;
458 case ARG_TIME:
459 {
460 char *endptr;
461 time_t *t = (time_t *)p;
462
463 *t = strtoul(kw->value, &endptr, 10);
464
465 /* time in seconds? */
466 if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
467 {
468 break;
469 }
470 if (endptr[1] == '\0')
471 {
472 if (*endptr == 'm') /* time in minutes? */
473 {
474 *t *= 60;
475 break;
476 }
477 if (*endptr == 'h') /* time in hours? */
478 {
479 *t *= 3600;
480 break;
481 }
482 if (*endptr == 'd') /* time in days? */
483 {
484 *t *= 3600*24;
485 break;
486 }
487 }
488 DBG1(DBG_APP, "# bad duration value: %s=%s", kw->entry->name,
489 kw->value);
490 return FALSE;
491 }
492 case ARG_STR:
493 {
494 char **cp = (char **)p;
495
496 /* free any existing string */
497 free(*cp);
498
499 /* assign the new string */
500 *cp = strdupnull(kw->value);
501 }
502 break;
503 case ARG_LST:
504 {
505 char ***listp = (char ***)p;
506
507 /* free any existing list */
508 if (*listp != NULL)
509 {
510 free_list(*listp);
511 }
512 /* create a new list and assign values */
513 *listp = new_list(kw->value);
514
515 /* is there a keyword list? */
516 if (list != NULL)
517 {
518 char ** lst;
519
520 for (lst = *listp; lst && *lst; lst++)
521 {
522 bool match = FALSE;
523
524 list = token_info[token].list;
525
526 while (*list != NULL && !match)
527 {
528 match = streq(*lst, *list++);
529 }
530 if (!match)
531 {
532 DBG1(DBG_APP, "# bad value: %s=%s",
533 kw->entry->name, *lst);
534 return FALSE;
535 }
536 }
537 }
538 }
539 /* fall through */
540 default:
541 return TRUE;
542 }
543
544 *assigned = TRUE;
545 return TRUE;
546 }
547
548 /*
549 * frees all dynamically allocated arguments in a struct
550 */
551 void free_args(kw_token_t first, kw_token_t last, char *base)
552 {
553 kw_token_t token;
554
555 for (token = first; token <= last; token++)
556 {
557 char *p = base + token_info[token].offset;
558
559 switch (token_info[token].type)
560 {
561 case ARG_STR:
562 {
563 char **cp = (char **)p;
564
565 free(*cp);
566 *cp = NULL;
567 }
568 break;
569 case ARG_LST:
570 {
571 char ***listp = (char ***)p;
572
573 if (*listp != NULL)
574 {
575 free_list(*listp);
576 *listp = NULL;
577 }
578 }
579 break;
580 default:
581 break;
582 }
583 }
584 }
585
586 /*
587 * clone all dynamically allocated arguments in a struct
588 */
589 void clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
590 {
591 kw_token_t token;
592
593 for (token = first; token <= last; token++)
594 {
595 if (token_info[token].type == ARG_STR)
596 {
597 char **cp1 = (char **)(base1 + token_info[token].offset);
598 char **cp2 = (char **)(base2 + token_info[token].offset);
599
600 *cp1 = strdupnull(*cp2);
601 }
602 }
603 }
604
605 static bool cmp_list(char **list1, char **list2)
606 {
607 if ((list1 == NULL) && (list2 == NULL))
608 {
609 return TRUE;
610 }
611 if ((list1 == NULL) || (list2 == NULL))
612 {
613 return FALSE;
614 }
615
616 for ( ; *list1 && *list2; list1++, list2++)
617 {
618 if (strcmp(*list1,*list2) != 0)
619 {
620 return FALSE;
621 }
622 }
623
624 if ((*list1 != NULL) || (*list2 != NULL))
625 {
626 return FALSE;
627 }
628
629 return TRUE;
630 }
631
632 /*
633 * compare all arguments in a struct
634 */
635 bool cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
636 {
637 kw_token_t token;
638
639 for (token = first; token <= last; token++)
640 {
641 char *p1 = base1 + token_info[token].offset;
642 char *p2 = base2 + token_info[token].offset;
643
644 switch (token_info[token].type)
645 {
646 case ARG_ENUM:
647 if (token_info[token].list == LST_bool)
648 {
649 bool *b1 = (bool *)p1;
650 bool *b2 = (bool *)p2;
651
652 if (*b1 != *b2)
653 {
654 return FALSE;
655 }
656 }
657 else
658 {
659 int *i1 = (int *)p1;
660 int *i2 = (int *)p2;
661
662 if (*i1 != *i2)
663 {
664 return FALSE;
665 }
666 }
667 break;
668 case ARG_UINT:
669 {
670 u_int *u1 = (u_int *)p1;
671 u_int *u2 = (u_int *)p2;
672
673 if (*u1 != *u2)
674 {
675 return FALSE;
676 }
677 }
678 break;
679 case ARG_ULNG:
680 case ARG_PCNT:
681 {
682 unsigned long *l1 = (unsigned long *)p1;
683 unsigned long *l2 = (unsigned long *)p2;
684
685 if (*l1 != *l2)
686 {
687 return FALSE;
688 }
689 }
690 break;
691 case ARG_ULLI:
692 {
693 unsigned long long *ll1 = (unsigned long long *)p1;
694 unsigned long long *ll2 = (unsigned long long *)p2;
695
696 if (*ll1 != *ll2)
697 {
698 return FALSE;
699 }
700 }
701 break;
702 case ARG_TIME:
703 {
704 time_t *t1 = (time_t *)p1;
705 time_t *t2 = (time_t *)p2;
706
707 if (*t1 != *t2)
708 {
709 return FALSE;
710 }
711 }
712 break;
713 case ARG_STR:
714 {
715 char **cp1 = (char **)p1;
716 char **cp2 = (char **)p2;
717
718 if (*cp1 == NULL && *cp2 == NULL)
719 {
720 break;
721 }
722 if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
723 {
724 return FALSE;
725 }
726 }
727 break;
728 case ARG_LST:
729 {
730 char ***listp1 = (char ***)p1;
731 char ***listp2 = (char ***)p2;
732
733 if (!cmp_list(*listp1, *listp2))
734 {
735 return FALSE;
736 }
737 }
738 break;
739 default:
740 break;
741 }
742 }
743 return TRUE;
744 }