kernel-netlink: Check return value of both halfs when installing default route in...
[strongswan.git] / src / starter / args.c
1 /*
2 * Copyright (C) 2014 Tobias Brunner
3 * Copyright (C) 2006 Andreas Steffen
4 * HSR Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <stddef.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include <library.h>
22 #include <utils/debug.h>
23
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_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 "accept",
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_ENUM, offsetof(starter_conn_t, sha256_96), LST_bool },
169 { ARG_TIME, offsetof(starter_conn_t, inactivity), NULL },
170 { ARG_MISC, 0, NULL /* KW_MODECONFIG */ },
171 { ARG_MISC, 0, NULL /* KW_XAUTH */ },
172 { ARG_STR, offsetof(starter_conn_t, xauth_identity), NULL },
173 { ARG_ENUM, offsetof(starter_conn_t, me_mediation), LST_bool },
174 { ARG_STR, offsetof(starter_conn_t, me_mediated_by), NULL },
175 { ARG_STR, offsetof(starter_conn_t, me_peerid), NULL },
176 { ARG_UINT, offsetof(starter_conn_t, reqid), NULL },
177 { ARG_UINT, offsetof(starter_conn_t, replay_window), NULL },
178 { ARG_MISC, 0, NULL /* KW_MARK */ },
179 { ARG_MISC, 0, NULL /* KW_MARK_IN */ },
180 { ARG_MISC, 0, NULL /* KW_MARK_OUT */ },
181 { ARG_MISC, 0, NULL /* KW_TFC */ },
182 { ARG_MISC, 0, NULL /* KW_PFS_DEPRECATED */ },
183 { ARG_MISC, 0, NULL /* KW_CONN_DEPRECATED */ },
184
185 /* ca section keywords */
186 { ARG_STR, offsetof(starter_ca_t, name), NULL },
187 { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup },
188 { ARG_STR, offsetof(starter_ca_t, cacert), NULL },
189 { ARG_STR, offsetof(starter_ca_t, crluri), NULL },
190 { ARG_STR, offsetof(starter_ca_t, crluri2), NULL },
191 { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL },
192 { ARG_STR, offsetof(starter_ca_t, ocspuri2), NULL },
193 { ARG_STR, offsetof(starter_ca_t, certuribase), NULL },
194 { ARG_MISC, 0, NULL /* KW_CA_DEPRECATED */ },
195
196 /* end keywords */
197 { ARG_STR, offsetof(starter_end_t, host), NULL },
198 { ARG_UINT, offsetof(starter_end_t, ikeport), NULL },
199 { ARG_STR, offsetof(starter_end_t, subnet), NULL },
200 { ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
201 { ARG_STR, offsetof(starter_end_t, sourceip), NULL },
202 { ARG_STR, offsetof(starter_end_t, dns), NULL },
203 { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
204 { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
205 { ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool },
206 { ARG_STR, offsetof(starter_end_t, updown), NULL },
207 { ARG_STR, offsetof(starter_end_t, auth), NULL },
208 { ARG_STR, offsetof(starter_end_t, auth2), NULL },
209 { ARG_STR, offsetof(starter_end_t, id), NULL },
210 { ARG_STR, offsetof(starter_end_t, id2), NULL },
211 { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
212 { ARG_STR, offsetof(starter_end_t, cert), NULL },
213 { ARG_STR, offsetof(starter_end_t, cert2), NULL },
214 { ARG_STR, offsetof(starter_end_t, cert_policy), NULL },
215 { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
216 { ARG_STR, offsetof(starter_end_t, ca), NULL },
217 { ARG_STR, offsetof(starter_end_t, ca2), NULL },
218 { ARG_STR, offsetof(starter_end_t, groups), NULL },
219 { ARG_STR, offsetof(starter_end_t, groups2), NULL },
220 { ARG_MISC, 0, NULL /* KW_END_DEPRECATED */ },
221 };
222
223 /*
224 * assigns an argument value to a struct field
225 */
226 bool assign_arg(kw_token_t token, kw_token_t first, char *key, char *value,
227 void *base, bool *assigned)
228 {
229 char *p = (char*)base + token_info[token].offset;
230 const char **list = token_info[token].list;
231 int index = -1; /* used for enumeration arguments */
232
233 *assigned = FALSE;
234
235 DBG3(DBG_APP, " %s=%s", key, value);
236
237 /* is there a keyword list? */
238 if (list != NULL)
239 {
240 bool match = FALSE;
241
242 while (*list != NULL && !match)
243 {
244 index++;
245 match = streq(value, *list++);
246 }
247 if (!match)
248 {
249 DBG1(DBG_APP, "# bad value: %s=%s", key, value);
250 return FALSE;
251 }
252 }
253
254 switch (token_info[token].type)
255 {
256 case ARG_NONE:
257 DBG1(DBG_APP, "# option '%s' not supported yet", key);
258 return FALSE;
259 case ARG_ENUM:
260 {
261 if (index < 0)
262 {
263 DBG1(DBG_APP, "# bad enumeration value: %s=%s (%d)",
264 key, value, index);
265 return FALSE;
266 }
267
268 if (token_info[token].list == LST_bool)
269 {
270 bool *b = (bool *)p;
271 *b = (index > 0);
272 }
273 else
274 { /* FIXME: this is not entirely correct as the args are enums */
275 int *i = (int *)p;
276 *i = index;
277 }
278 break;
279 }
280 case ARG_UINT:
281 {
282 char *endptr;
283 u_int *u = (u_int *)p;
284
285 *u = strtoul(value, &endptr, 10);
286
287 if (*endptr != '\0')
288 {
289 DBG1(DBG_APP, "# bad integer value: %s=%s", key, value);
290 return FALSE;
291 }
292 break;
293 }
294 case ARG_ULNG:
295 case ARG_PCNT:
296 {
297 char *endptr;
298 unsigned long *l = (unsigned long *)p;
299
300 *l = strtoul(value, &endptr, 10);
301
302 if (token_info[token].type == ARG_ULNG)
303 {
304 if (*endptr != '\0')
305 {
306 DBG1(DBG_APP, "# bad integer value: %s=%s", key, value);
307 return FALSE;
308 }
309 }
310 else
311 {
312 if ((*endptr != '%') || (endptr[1] != '\0') || endptr == value)
313 {
314 DBG1(DBG_APP, "# bad percent value: %s=%s", key, value);
315 return FALSE;
316 }
317 }
318 break;
319 }
320 case ARG_ULLI:
321 {
322 char *endptr;
323 unsigned long long *ll = (unsigned long long *)p;
324
325 *ll = strtoull(value, &endptr, 10);
326
327 if (*endptr != '\0')
328 {
329 DBG1(DBG_APP, "# bad integer value: %s=%s", key, value);
330 return FALSE;
331 }
332 break;
333 }
334 case ARG_UBIN:
335 {
336 char *endptr;
337 u_int *u = (u_int *)p;
338
339 *u = strtoul(value, &endptr, 2);
340
341 if (*endptr != '\0')
342 {
343 DBG1(DBG_APP, "# bad binary value: %s=%s", key, value);
344 return FALSE;
345 }
346 break;
347 }
348 case ARG_TIME:
349 {
350 char *endptr;
351 time_t *t = (time_t *)p;
352
353 *t = strtoul(value, &endptr, 10);
354
355 /* time in seconds? */
356 if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
357 {
358 break;
359 }
360 if (endptr[1] == '\0')
361 {
362 if (*endptr == 'm') /* time in minutes? */
363 {
364 *t *= 60;
365 break;
366 }
367 if (*endptr == 'h') /* time in hours? */
368 {
369 *t *= 3600;
370 break;
371 }
372 if (*endptr == 'd') /* time in days? */
373 {
374 *t *= 3600*24;
375 break;
376 }
377 }
378 DBG1(DBG_APP, "# bad duration value: %s=%s", key, value);
379 return FALSE;
380 }
381 case ARG_STR:
382 {
383 char **cp = (char **)p;
384
385 /* free any existing string */
386 free(*cp);
387 /* assign the new string */
388 *cp = strdupnull(value);
389 break;
390 }
391 default:
392 return TRUE;
393 }
394
395 *assigned = TRUE;
396 return TRUE;
397 }
398
399 /*
400 * frees all dynamically allocated arguments in a struct
401 */
402 void free_args(kw_token_t first, kw_token_t last, void *base)
403 {
404 kw_token_t token;
405
406 for (token = first; token <= last; token++)
407 {
408 char *p = (char*)base + token_info[token].offset;
409
410 switch (token_info[token].type)
411 {
412 case ARG_STR:
413 {
414 char **cp = (char **)p;
415
416 free(*cp);
417 *cp = NULL;
418 break;
419 }
420 default:
421 break;
422 }
423 }
424 }
425
426 /*
427 * compare all arguments in a struct
428 */
429 bool cmp_args(kw_token_t first, kw_token_t last, void *base1, void *base2)
430 {
431 kw_token_t token;
432
433 for (token = first; token <= last; token++)
434 {
435 char *p1 = (char*)base1 + token_info[token].offset;
436 char *p2 = (char*)base2 + token_info[token].offset;
437
438 switch (token_info[token].type)
439 {
440 case ARG_ENUM:
441 {
442 if (token_info[token].list == LST_bool)
443 {
444 bool *b1 = (bool *)p1;
445 bool *b2 = (bool *)p2;
446
447 if (*b1 != *b2)
448 {
449 return FALSE;
450 }
451 }
452 else
453 {
454 int *i1 = (int *)p1;
455 int *i2 = (int *)p2;
456
457 if (*i1 != *i2)
458 {
459 return FALSE;
460 }
461 }
462 break;
463 }
464 case ARG_UINT:
465 {
466 u_int *u1 = (u_int *)p1;
467 u_int *u2 = (u_int *)p2;
468
469 if (*u1 != *u2)
470 {
471 return FALSE;
472 }
473 break;
474 }
475 case ARG_ULNG:
476 case ARG_PCNT:
477 {
478 unsigned long *l1 = (unsigned long *)p1;
479 unsigned long *l2 = (unsigned long *)p2;
480
481 if (*l1 != *l2)
482 {
483 return FALSE;
484 }
485 break;
486 }
487 case ARG_ULLI:
488 {
489 unsigned long long *ll1 = (unsigned long long *)p1;
490 unsigned long long *ll2 = (unsigned long long *)p2;
491
492 if (*ll1 != *ll2)
493 {
494 return FALSE;
495 }
496 break;
497 }
498 case ARG_TIME:
499 {
500 time_t *t1 = (time_t *)p1;
501 time_t *t2 = (time_t *)p2;
502
503 if (*t1 != *t2)
504 {
505 return FALSE;
506 }
507 break;
508 }
509 case ARG_STR:
510 {
511 char **cp1 = (char **)p1;
512 char **cp2 = (char **)p2;
513
514 if (*cp1 == NULL && *cp2 == NULL)
515 {
516 break;
517 }
518 if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
519 {
520 return FALSE;
521 }
522 break;
523 }
524 default:
525 break;
526 }
527 }
528 return TRUE;
529 }