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