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