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