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