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