configure: Fix gperf length parameter determination
[strongswan.git] / src / starter / confread.c
1 /*
2 * Copyright (C) 2014 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <stddef.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <assert.h>
25 #include <netdb.h>
26
27 #include <library.h>
28 #include <utils/debug.h>
29
30 #include "keywords.h"
31 #include "confread.h"
32 #include "args.h"
33 #include "files.h"
34 #include "parser/conf_parser.h"
35
36 #define IKE_LIFETIME_DEFAULT 10800 /* 3 hours */
37 #define IPSEC_LIFETIME_DEFAULT 3600 /* 1 hour */
38 #define SA_REPLACEMENT_MARGIN_DEFAULT 540 /* 9 minutes */
39 #define SA_REPLACEMENT_FUZZ_DEFAULT 100 /* 100% of margin */
40 #define SA_REPLACEMENT_RETRIES_DEFAULT 3
41 #define SA_REPLAY_WINDOW_DEFAULT -1 /* use charon.replay_window */
42
43 static const char ike_defaults[] = "aes128-sha256-curve25519";
44 static const char esp_defaults[] = "aes128-sha256";
45
46 static const char firewall_defaults[] = IPSEC_SCRIPT " _updown iptables";
47
48 /**
49 * Process deprecated keywords
50 */
51 static bool is_deprecated(kw_token_t token, char *name, char *conn)
52 {
53 switch (token)
54 {
55 case KW_SETUP_DEPRECATED:
56 case KW_PKCS11_DEPRECATED:
57 DBG1(DBG_APP, "# deprecated keyword '%s' in config setup", name);
58 break;
59 case KW_CONN_DEPRECATED:
60 case KW_END_DEPRECATED:
61 case KW_PFS_DEPRECATED:
62 DBG1(DBG_APP, "# deprecated keyword '%s' in conn '%s'", name, conn);
63 break;
64 case KW_CA_DEPRECATED:
65 DBG1(DBG_APP, "# deprecated keyword '%s' in ca '%s'", name, conn);
66 break;
67 default:
68 return FALSE;
69 }
70 /* additional messages for some */
71 switch (token)
72 {
73 case KW_PKCS11_DEPRECATED:
74 DBG1(DBG_APP, " use the 'pkcs11' plugin instead");
75 break;
76 case KW_PFS_DEPRECATED:
77 DBG1(DBG_APP, " PFS is enabled by specifying a DH group in the "
78 "'esp' cipher suite");
79 break;
80 default:
81 break;
82 }
83 return TRUE;
84 }
85
86 /*
87 * parse config setup section
88 */
89 static void load_setup(starter_config_t *cfg, conf_parser_t *parser)
90 {
91 enumerator_t *enumerator;
92 dictionary_t *dict;
93 const kw_entry_t *entry;
94 char *key, *value;
95
96 DBG2(DBG_APP, "Loading config setup");
97 dict = parser->get_section(parser, CONF_PARSER_CONFIG_SETUP, NULL);
98 if (!dict)
99 {
100 return;
101 }
102 enumerator = dict->create_enumerator(dict);
103 while (enumerator->enumerate(enumerator, &key, &value))
104 {
105 bool assigned = FALSE;
106
107 entry = in_word_set(key, strlen(key));
108 if (!entry)
109 {
110 DBG1(DBG_APP, "# unknown keyword '%s'", key);
111 cfg->non_fatal_err++;
112 continue;
113 }
114 if ((int)entry->token < KW_SETUP_FIRST || entry->token > KW_SETUP_LAST)
115 {
116 DBG1(DBG_APP, "# unsupported keyword '%s' in config setup", key);
117 cfg->err++;
118 continue;
119 }
120 if (is_deprecated(entry->token, key, ""))
121 {
122 cfg->non_fatal_err++;
123 continue;
124 }
125 if (!assign_arg(entry->token, KW_SETUP_FIRST, key, value, cfg,
126 &assigned))
127 {
128 DBG1(DBG_APP, " bad argument value in config setup");
129 cfg->err++;
130 }
131 }
132 enumerator->destroy(enumerator);
133 dict->destroy(dict);
134 }
135
136 /*
137 * parse a ca section
138 */
139 static void load_ca(starter_ca_t *ca, starter_config_t *cfg,
140 conf_parser_t *parser)
141 {
142 enumerator_t *enumerator;
143 dictionary_t *dict;
144 const kw_entry_t *entry;
145 kw_token_t token;
146 char *key, *value;
147
148 DBG2(DBG_APP, "Loading ca '%s'", ca->name);
149 dict = parser->get_section(parser, CONF_PARSER_CA, ca->name);
150 if (!dict)
151 {
152 return;
153 }
154 enumerator = dict->create_enumerator(dict);
155 while (enumerator->enumerate(enumerator, &key, &value))
156 {
157 bool assigned = FALSE;
158
159 entry = in_word_set(key, strlen(key));
160 if (!entry)
161 {
162 DBG1(DBG_APP, "# unknown keyword '%s'", key);
163 cfg->non_fatal_err++;
164 continue;
165 }
166 token = entry->token;
167 if (token == KW_AUTO)
168 {
169 token = KW_CA_SETUP;
170 }
171 if (token < KW_CA_FIRST || token > KW_CA_LAST)
172 {
173 DBG1(DBG_APP, "# unsupported keyword '%s' in ca '%s'",
174 key, ca->name);
175 cfg->err++;
176 continue;
177 }
178 if (is_deprecated(token, key, ca->name))
179 {
180 cfg->non_fatal_err++;
181 continue;
182 }
183 if (!assign_arg(token, KW_CA_FIRST, key, value, ca, &assigned))
184 {
185 DBG1(DBG_APP, " bad argument value in ca '%s'", ca->name);
186 cfg->err++;
187 }
188 }
189 enumerator->destroy(enumerator);
190 dict->destroy(dict);
191
192 /* treat 'route' and 'start' as 'add' */
193 if (ca->startup != STARTUP_NO)
194 {
195 ca->startup = STARTUP_ADD;
196 }
197 }
198
199 /*
200 * set some default values
201 */
202 static void conn_defaults(starter_conn_t *conn)
203 {
204 conn->startup = STARTUP_NO;
205 conn->state = STATE_IGNORE;
206 conn->mode = MODE_TUNNEL;
207 conn->options = SA_OPTION_MOBIKE;
208
209 conn->ike = strdupnull(ike_defaults);
210 /* esp defaults are set after parsing the conn section */
211 conn->sa_ike_life_seconds = IKE_LIFETIME_DEFAULT;
212 conn->sa_ipsec_life_seconds = IPSEC_LIFETIME_DEFAULT;
213 conn->sa_rekey_margin = SA_REPLACEMENT_MARGIN_DEFAULT;
214 conn->sa_rekey_fuzz = SA_REPLACEMENT_FUZZ_DEFAULT;
215 conn->sa_keying_tries = SA_REPLACEMENT_RETRIES_DEFAULT;
216 conn->install_policy = TRUE;
217 conn->dpd_delay = 30; /* seconds */
218 conn->dpd_timeout = 150; /* seconds */
219 conn->replay_window = SA_REPLAY_WINDOW_DEFAULT;
220 conn->fragmentation = FRAGMENTATION_YES;
221
222 conn->left.sendcert = CERT_SEND_IF_ASKED;
223 conn->right.sendcert = CERT_SEND_IF_ASKED;
224
225 conn->left.ikeport = 500;
226 conn->right.ikeport = 500;
227
228 conn->left.to_port = 0xffff;
229 conn->right.to_port = 0xffff;
230 }
231
232 /*
233 * parse left|right specific options
234 */
235 static void kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token,
236 char *key, char *value, starter_config_t *cfg)
237 {
238 bool assigned = FALSE;
239
240 if (is_deprecated(token, key, conn->name))
241 {
242 cfg->non_fatal_err++;
243 return;
244 }
245
246 if (!assign_arg(token, KW_END_FIRST, key, value, end, &assigned))
247 {
248 goto err;
249 }
250
251 /* post processing of some keywords that were assigned automatically */
252 switch (token)
253 {
254 case KW_HOST:
255 if (value && strlen(value) > 0 && value[0] == '%')
256 {
257 if (streq(value, "%defaultroute"))
258 {
259 value = "%any";
260 }
261 if (!streq(value, "%any") && !streq(value, "%any4") &&
262 !streq(value, "%any6"))
263 { /* allow_any prefix */
264 end->allow_any = TRUE;
265 value++;
266 }
267 }
268 free(end->host);
269 end->host = strdupnull(value);
270 break;
271 case KW_SOURCEIP:
272 conn->mode = MODE_TUNNEL;
273 conn->proxy_mode = FALSE;
274 break;
275 case KW_SENDCERT:
276 if (end->sendcert == CERT_YES_SEND)
277 {
278 end->sendcert = CERT_ALWAYS_SEND;
279 }
280 else if (end->sendcert == CERT_NO_SEND)
281 {
282 end->sendcert = CERT_NEVER_SEND;
283 }
284 break;
285 default:
286 break;
287 }
288
289 if (assigned)
290 {
291 return;
292 }
293
294 /* individual processing of keywords that were not assigned automatically */
295 switch (token)
296 {
297 case KW_PROTOPORT:
298 {
299 struct protoent *proto;
300 struct servent *svc;
301 char *sep, *port = "", *endptr;
302 long int p;
303
304 sep = strchr(value, '/');
305 if (sep)
306 { /* protocol/port */
307 *sep = '\0';
308 port = sep + 1;
309 }
310
311 if (streq(value, "%any"))
312 {
313 end->protocol = 0;
314 }
315 else
316 {
317 proto = getprotobyname(value);
318 if (proto)
319 {
320 end->protocol = proto->p_proto;
321 }
322 else
323 {
324 p = strtol(value, &endptr, 0);
325 if ((*value && *endptr) || p < 0 || p > 0xff)
326 {
327 DBG1(DBG_APP, "# bad protocol: %s=%s", key, value);
328 goto err;
329 }
330 end->protocol = (uint8_t)p;
331 }
332 }
333 if (streq(port, "%any"))
334 {
335 end->from_port = 0;
336 end->to_port = 0xffff;
337 }
338 else if (streq(port, "%opaque"))
339 {
340 end->from_port = 0xffff;
341 end->to_port = 0;
342 }
343 else if (*port)
344 {
345 svc = getservbyname(port, NULL);
346 if (svc)
347 {
348 end->from_port = end->to_port = ntohs(svc->s_port);
349 }
350 else
351 {
352 p = strtol(port, &endptr, 0);
353 if (p < 0 || p > 0xffff)
354 {
355 DBG1(DBG_APP, "# bad port: %s=%s", key, port);
356 goto err;
357 }
358 end->from_port = p;
359 if (*endptr == '-')
360 {
361 port = endptr + 1;
362 p = strtol(port, &endptr, 0);
363 if (p < 0 || p > 0xffff)
364 {
365 DBG1(DBG_APP, "# bad port: %s=%s", key, port);
366 goto err;
367 }
368 }
369 end->to_port = p;
370 if (*endptr)
371 {
372 DBG1(DBG_APP, "# bad port: %s=%s", key, port);
373 goto err;
374 }
375 }
376 }
377 if (sep)
378 { /* restore the original text in case also= is used */
379 *sep = '/';
380 }
381 break;
382 }
383 default:
384 break;
385 }
386 return;
387
388 err:
389 DBG1(DBG_APP, " bad argument value in conn '%s'", conn->name);
390 cfg->err++;
391 }
392
393 /*
394 * macro to handle simple flags
395 */
396 #define KW_SA_OPTION_FLAG(sy, sn, fl) \
397 if (streq(value, sy)) { conn->options |= fl; } \
398 else if (streq(value, sn)) { conn->options &= ~fl; } \
399 else { DBG1(DBG_APP, "# bad option value: %s=%s", key, value); cfg->err++; }
400
401 /*
402 * parse settings not handled by the simple argument parser
403 */
404 static void handle_keyword(kw_token_t token, starter_conn_t *conn, char *key,
405 char *value, starter_config_t *cfg)
406 {
407 if ((token == KW_ESP && conn->ah) || (token == KW_AH && conn->esp))
408 {
409 DBG1(DBG_APP, "# can't have both 'ah' and 'esp' options");
410 cfg->err++;
411 return;
412 }
413 switch (token)
414 {
415 case KW_TYPE:
416 {
417 conn->mode = MODE_TRANSPORT;
418 conn->proxy_mode = FALSE;
419 if (streq(value, "tunnel"))
420 {
421 conn->mode = MODE_TUNNEL;
422 }
423 else if (streq(value, "beet"))
424 {
425 conn->mode = MODE_BEET;
426 }
427 else if (streq(value, "transport_proxy"))
428 {
429 conn->mode = MODE_TRANSPORT;
430 conn->proxy_mode = TRUE;
431 }
432 else if (streq(value, "passthrough") || streq(value, "pass"))
433 {
434 conn->mode = MODE_PASS;
435 }
436 else if (streq(value, "drop") || streq(value, "reject"))
437 {
438 conn->mode = MODE_DROP;
439 }
440 else if (!streq(value, "transport"))
441 {
442 DBG1(DBG_APP, "# bad policy value: %s=%s", key, value);
443 cfg->err++;
444 }
445 break;
446 }
447 case KW_COMPRESS:
448 KW_SA_OPTION_FLAG("yes", "no", SA_OPTION_COMPRESS)
449 break;
450 case KW_MARK:
451 if (!mark_from_string(value, &conn->mark_in))
452 {
453 cfg->err++;
454 break;
455 }
456 conn->mark_out = conn->mark_in;
457 break;
458 case KW_MARK_IN:
459 if (!mark_from_string(value, &conn->mark_in))
460 {
461 cfg->err++;
462 }
463 break;
464 case KW_MARK_OUT:
465 if (!mark_from_string(value, &conn->mark_out))
466 {
467 cfg->err++;
468 }
469 break;
470 case KW_TFC:
471 if (streq(value, "%mtu"))
472 {
473 conn->tfc = -1;
474 }
475 else
476 {
477 char *endptr;
478
479 conn->tfc = strtoul(value, &endptr, 10);
480 if (*endptr != '\0')
481 {
482 DBG1(DBG_APP, "# bad integer value: %s=%s", key, value);
483 cfg->err++;
484 }
485 }
486 break;
487 case KW_KEYINGTRIES:
488 if (streq(value, "%forever"))
489 {
490 conn->sa_keying_tries = 0;
491 }
492 else
493 {
494 char *endptr;
495
496 conn->sa_keying_tries = strtoul(value, &endptr, 10);
497 if (*endptr != '\0')
498 {
499 DBG1(DBG_APP, "# bad integer value: %s=%s", key, value);
500 cfg->err++;
501 }
502 }
503 break;
504 case KW_REKEY:
505 KW_SA_OPTION_FLAG("no", "yes", SA_OPTION_DONT_REKEY)
506 break;
507 case KW_REAUTH:
508 KW_SA_OPTION_FLAG("no", "yes", SA_OPTION_DONT_REAUTH)
509 break;
510 case KW_MOBIKE:
511 KW_SA_OPTION_FLAG("yes", "no", SA_OPTION_MOBIKE)
512 break;
513 case KW_FORCEENCAPS:
514 KW_SA_OPTION_FLAG("yes", "no", SA_OPTION_FORCE_ENCAP)
515 break;
516 case KW_MODECONFIG:
517 KW_SA_OPTION_FLAG("push", "pull", SA_OPTION_MODECFG_PUSH)
518 break;
519 case KW_XAUTH:
520 KW_SA_OPTION_FLAG("server", "client", SA_OPTION_XAUTH_SERVER)
521 break;
522 default:
523 break;
524 }
525 }
526
527 /*
528 * handles left|rightfirewall and left|rightupdown parameters
529 */
530 static void handle_firewall(const char *label, starter_end_t *end,
531 starter_config_t *cfg)
532 {
533 if (end->firewall)
534 {
535 if (end->updown != NULL)
536 {
537 DBG1(DBG_APP, "# cannot have both %sfirewall and %supdown", label,
538 label);
539 cfg->err++;
540 }
541 else
542 {
543 end->updown = strdupnull(firewall_defaults);
544 end->firewall = FALSE;
545 }
546 }
547 }
548
549 /*
550 * parse a conn section
551 */
552 static void load_conn(starter_conn_t *conn, starter_config_t *cfg,
553 conf_parser_t *parser)
554 {
555 enumerator_t *enumerator;
556 dictionary_t *dict;
557 const kw_entry_t *entry;
558 kw_token_t token;
559 char *key, *value;
560
561 DBG2(DBG_APP, "Loading conn '%s'", conn->name);
562 dict = parser->get_section(parser, CONF_PARSER_CONN, conn->name);
563 if (!dict)
564 {
565 return;
566 }
567 enumerator = dict->create_enumerator(dict);
568 while (enumerator->enumerate(enumerator, &key, &value))
569 {
570 bool assigned = FALSE;
571
572 entry = in_word_set(key, strlen(key));
573 if (!entry)
574 {
575 DBG1(DBG_APP, "# unknown keyword '%s'", key);
576 cfg->non_fatal_err++;
577 continue;
578 }
579 token = entry->token;
580 if (token >= KW_LEFT_FIRST && token <= KW_LEFT_LAST)
581 {
582 kw_end(conn, &conn->left, token - KW_LEFT_FIRST + KW_END_FIRST,
583 key, value, cfg);
584 continue;
585 }
586 else if (token >= KW_RIGHT_FIRST && token <= KW_RIGHT_LAST)
587 {
588 kw_end(conn, &conn->right, token - KW_RIGHT_FIRST + KW_END_FIRST,
589 key, value, cfg);
590 continue;
591 }
592 if (token == KW_AUTO)
593 {
594 token = KW_CONN_SETUP;
595 }
596 if (token < KW_CONN_FIRST || token > KW_CONN_LAST)
597 {
598 DBG1(DBG_APP, "# unsupported keyword '%s' in conn '%s'",
599 key, conn->name);
600 cfg->err++;
601 continue;
602 }
603 if (is_deprecated(token, key, conn->name))
604 {
605 cfg->non_fatal_err++;
606 continue;
607 }
608 if (!assign_arg(token, KW_CONN_FIRST, key, value, conn,
609 &assigned))
610 {
611 DBG1(DBG_APP, " bad argument value in conn '%s'", conn->name);
612 cfg->err++;
613 continue;
614 }
615 if (!assigned)
616 {
617 handle_keyword(token, conn, key, value, cfg);
618 }
619 }
620 enumerator->destroy(enumerator);
621 dict->destroy(dict);
622
623 handle_firewall("left", &conn->left, cfg);
624 handle_firewall("right", &conn->right, cfg);
625
626 if (!conn->esp && !conn->ah)
627 {
628 conn->esp = strdupnull(esp_defaults);
629 }
630 }
631
632 /*
633 * free the memory used by a starter_ca_t object
634 */
635 static void confread_free_ca(starter_ca_t *ca)
636 {
637 free_args(KW_CA_NAME, KW_CA_LAST, (char *)ca);
638 free(ca);
639 }
640
641 /*
642 * free the memory used by a starter_conn_t object
643 */
644 static void confread_free_conn(starter_conn_t *conn)
645 {
646 free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->left);
647 free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->right);
648 free_args(KW_CONN_NAME, KW_CONN_LAST, (char *)conn);
649 free(conn);
650 }
651
652 /*
653 * free the memory used by a starter_config_t object
654 */
655 void confread_free(starter_config_t *cfg)
656 {
657 starter_conn_t *conn = cfg->conn_first;
658 starter_ca_t *ca = cfg->ca_first;
659
660 free_args(KW_SETUP_FIRST, KW_SETUP_LAST, (char *)cfg);
661
662 while (conn != NULL)
663 {
664 starter_conn_t *conn_aux = conn;
665
666 conn = conn->next;
667 confread_free_conn(conn_aux);
668 }
669
670 while (ca != NULL)
671 {
672 starter_ca_t *ca_aux = ca;
673
674 ca = ca->next;
675 confread_free_ca(ca_aux);
676 }
677
678 free(cfg);
679 }
680
681 /*
682 * load and parse an IPsec configuration file
683 */
684 starter_config_t* confread_load(const char *file)
685 {
686 conf_parser_t *parser;
687 starter_config_t *cfg = NULL;
688 enumerator_t *enumerator;
689 u_int total_err;
690 char *name;
691
692 parser = conf_parser_create(file);
693 if (!parser->parse(parser))
694 {
695 parser->destroy(parser);
696 return NULL;
697 }
698
699 INIT(cfg,
700 .setup = {
701 .uniqueids = TRUE,
702 }
703 );
704
705 /* load config setup section */
706 load_setup(cfg, parser);
707
708 /* load ca sections */
709 enumerator = parser->get_sections(parser, CONF_PARSER_CA);
710 while (enumerator->enumerate(enumerator, &name))
711 {
712 u_int previous_err = cfg->err;
713 starter_ca_t *ca;
714
715 INIT(ca,
716 .name = strdup(name),
717 );
718 load_ca(ca, cfg, parser);
719
720 if (cfg->err > previous_err)
721 {
722 total_err = cfg->err - previous_err;
723 DBG1(DBG_APP, "# ignored ca '%s' due to %d parsing error%s", name,
724 total_err, (total_err > 1) ? "s" : "");
725 confread_free_ca(ca);
726 cfg->non_fatal_err += cfg->err - previous_err;
727 cfg->err = previous_err;
728 }
729 else
730 {
731 if (cfg->ca_last)
732 {
733 cfg->ca_last->next = ca;
734 }
735 cfg->ca_last = ca;
736 if (!cfg->ca_first)
737 {
738 cfg->ca_first = ca;
739 }
740 if (ca->startup != STARTUP_NO)
741 {
742 ca->state = STATE_TO_ADD;
743 }
744 }
745 }
746 enumerator->destroy(enumerator);
747
748 /* load conn sections */
749 enumerator = parser->get_sections(parser, CONF_PARSER_CONN);
750 while (enumerator->enumerate(enumerator, &name))
751 {
752 u_int previous_err = cfg->err;
753 starter_conn_t *conn;
754
755 INIT(conn,
756 .name = strdup(name),
757 );
758 conn_defaults(conn);
759 load_conn(conn, cfg, parser);
760
761 if (cfg->err > previous_err)
762 {
763 total_err = cfg->err - previous_err;
764 DBG1(DBG_APP, "# ignored conn '%s' due to %d parsing error%s", name,
765 total_err, (total_err > 1) ? "s" : "");
766 confread_free_conn(conn);
767 cfg->non_fatal_err += cfg->err - previous_err;
768 cfg->err = previous_err;
769 }
770 else
771 {
772 if (cfg->conn_last)
773 {
774 cfg->conn_last->next = conn;
775 }
776 cfg->conn_last = conn;
777 if (!cfg->conn_first)
778 {
779 cfg->conn_first = conn;
780 }
781 if (conn->startup != STARTUP_NO)
782 {
783 conn->state = STATE_TO_ADD;
784 }
785 }
786 }
787 enumerator->destroy(enumerator);
788
789 parser->destroy(parser);
790
791 total_err = cfg->err + cfg->non_fatal_err;
792 if (total_err > 0)
793 {
794 DBG1(DBG_APP, "### %d parsing error%s (%d fatal) ###",
795 total_err, (total_err > 1)?"s":"", cfg->err);
796 }
797 return cfg;
798 }