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