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