starter: Allow %any also for protocol in left|rightprotoport
[strongswan.git] / src / starter / confread.c
1 /* strongSwan IPsec config file parser
2 * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 */
14
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <unistd.h>
18 #include <stddef.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <assert.h>
22 #include <netdb.h>
23
24 #include <library.h>
25 #include <debug.h>
26
27 #include "keywords.h"
28 #include "confread.h"
29 #include "args.h"
30 #include "files.h"
31
32 #define IKE_LIFETIME_DEFAULT 10800 /* 3 hours */
33 #define IPSEC_LIFETIME_DEFAULT 3600 /* 1 hour */
34 #define SA_REPLACEMENT_MARGIN_DEFAULT 540 /* 9 minutes */
35 #define SA_REPLACEMENT_FUZZ_DEFAULT 100 /* 100% of margin */
36 #define SA_REPLACEMENT_RETRIES_DEFAULT 3
37
38 static const char ike_defaults[] = "aes128-sha1-modp2048,3des-sha1-modp1536";
39 static const char esp_defaults[] = "aes128-sha1-modp2048,3des-sha1-modp1536";
40
41 static const char firewall_defaults[] = "ipsec _updown iptables";
42
43 static bool daemon_exists(char *daemon, char *path)
44 {
45 struct stat st;
46 if (stat(path, &st) != 0)
47 {
48 DBG1(DBG_APP, "Disabling %sstart option, '%s' not found", daemon, path);
49 return FALSE;
50 }
51 return TRUE;
52 }
53
54 /**
55 * Process deprecated keywords
56 */
57 static bool is_deprecated(kw_token_t token, kw_list_t *kw, char *name)
58 {
59 switch (token)
60 {
61 case KW_SETUP_DEPRECATED:
62 case KW_PKCS11_DEPRECATED:
63 DBG1(DBG_APP, "# deprecated keyword '%s' in config setup",
64 kw->entry->name);
65 break;
66 case KW_CONN_DEPRECATED:
67 case KW_END_DEPRECATED:
68 case KW_PFS_DEPRECATED:
69 DBG1(DBG_APP, "# deprecated keyword '%s' in conn '%s'",
70 kw->entry->name, name);
71 break;
72 case KW_CA_DEPRECATED:
73 DBG1(DBG_APP, "# deprecated keyword '%s' in ca '%s'",
74 kw->entry->name, name);
75 break;
76 default:
77 return FALSE;
78 }
79 /* additional messages for some */
80 switch (token)
81 {
82 case KW_PKCS11_DEPRECATED:
83 DBG1(DBG_APP, " use the 'pkcs11' plugin instead", kw->entry->name);
84 break;
85 case KW_PFS_DEPRECATED:
86 DBG1(DBG_APP, " PFS is enabled by specifying a DH group in the "
87 "'esp' cipher suite", kw->entry->name);
88 break;
89 default:
90 break;
91 }
92 return TRUE;
93 }
94
95 static void default_values(starter_config_t *cfg)
96 {
97 if (cfg == NULL)
98 return;
99
100 memset(cfg, 0, sizeof(struct starter_config));
101
102 /* is there enough space for all seen flags? */
103 assert(KW_SETUP_LAST - KW_SETUP_FIRST <
104 sizeof(cfg->setup.seen) * BITS_PER_BYTE);
105 assert(KW_CONN_LAST - KW_CONN_FIRST <
106 sizeof(cfg->conn_default.seen) * BITS_PER_BYTE);
107 assert(KW_END_LAST - KW_END_FIRST <
108 sizeof(cfg->conn_default.right.seen) * BITS_PER_BYTE);
109 assert(KW_CA_LAST - KW_CA_FIRST <
110 sizeof(cfg->ca_default.seen) * BITS_PER_BYTE);
111
112 cfg->setup.seen = SEEN_NONE;
113 cfg->setup.uniqueids = TRUE;
114
115 #ifdef START_CHARON
116 cfg->setup.charonstart = TRUE;
117 #endif
118
119 cfg->conn_default.seen = SEEN_NONE;
120 cfg->conn_default.startup = STARTUP_NO;
121 cfg->conn_default.state = STATE_IGNORE;
122 cfg->conn_default.mode = MODE_TUNNEL;
123 cfg->conn_default.options = SA_OPTION_MOBIKE;
124
125 cfg->conn_default.ike = strdupnull(ike_defaults);
126 cfg->conn_default.esp = strdupnull(esp_defaults);
127 cfg->conn_default.sa_ike_life_seconds = IKE_LIFETIME_DEFAULT;
128 cfg->conn_default.sa_ipsec_life_seconds = IPSEC_LIFETIME_DEFAULT;
129 cfg->conn_default.sa_rekey_margin = SA_REPLACEMENT_MARGIN_DEFAULT;
130 cfg->conn_default.sa_rekey_fuzz = SA_REPLACEMENT_FUZZ_DEFAULT;
131 cfg->conn_default.sa_keying_tries = SA_REPLACEMENT_RETRIES_DEFAULT;
132 cfg->conn_default.install_policy = TRUE;
133 cfg->conn_default.dpd_delay = 30; /* seconds */
134 cfg->conn_default.dpd_timeout = 150; /* seconds */
135
136 cfg->conn_default.left.seen = SEEN_NONE;
137 cfg->conn_default.right.seen = SEEN_NONE;
138
139 cfg->conn_default.left.sendcert = CERT_SEND_IF_ASKED;
140 cfg->conn_default.right.sendcert = CERT_SEND_IF_ASKED;
141
142 cfg->conn_default.left.ikeport = 500;
143 cfg->conn_default.right.ikeport = 500;
144
145 cfg->ca_default.seen = SEEN_NONE;
146 }
147
148 #define KW_SA_OPTION_FLAG(sy, sn, fl) \
149 if (streq(kw->value, sy)) { conn->options |= fl; } \
150 else if (streq(kw->value, sn)) { conn->options &= ~fl; } \
151 else { DBG1(DBG_APP, "# bad option value: %s=%s", kw->entry->name, kw->value); cfg->err++; }
152
153 static void load_setup(starter_config_t *cfg, config_parsed_t *cfgp)
154 {
155 kw_list_t *kw;
156
157 DBG2(DBG_APP, "Loading config setup");
158
159 for (kw = cfgp->config_setup; kw; kw = kw->next)
160 {
161 bool assigned = FALSE;
162
163 kw_token_t token = kw->entry->token;
164
165 if ((int)token < KW_SETUP_FIRST || token > KW_SETUP_LAST)
166 {
167 DBG1(DBG_APP, "# unsupported keyword '%s' in config setup",
168 kw->entry->name);
169 cfg->err++;
170 continue;
171 }
172
173 if (is_deprecated(token, kw, ""))
174 {
175 cfg->non_fatal_err++;
176 continue;
177 }
178
179 if (!assign_arg(token, KW_SETUP_FIRST, kw, (char *)cfg, &assigned))
180 {
181 DBG1(DBG_APP, " bad argument value in config setup");
182 cfg->err++;
183 continue;
184 }
185 }
186
187 /* verify the executables are actually available */
188 #ifdef START_CHARON
189 cfg->setup.charonstart = cfg->setup.charonstart &&
190 daemon_exists("charon", CHARON_CMD);
191 #else
192 cfg->setup.charonstart = FALSE;
193 #endif
194 }
195
196 static void kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token,
197 kw_list_t *kw, char *conn_name, starter_config_t *cfg)
198 {
199 bool assigned = FALSE;
200
201 char *name = kw->entry->name;
202 char *value = kw->value;
203
204 if (is_deprecated(token, kw, conn_name))
205 {
206 cfg->non_fatal_err++;
207 return;
208 }
209
210 if (!assign_arg(token, KW_END_FIRST, kw, (char *)end, &assigned))
211 goto err;
212
213 /* post processing of some keywords that were assigned automatically */
214 switch (token)
215 {
216 case KW_HOST:
217 if (value && strlen(value) > 0 && value[0] == '%')
218 {
219 if (streq(value, "%defaultroute"))
220 {
221 value = "%any";
222 }
223 if (!streq(value, "%any") && !streq(value, "%any4") &&
224 !streq(value, "%any6"))
225 { /* allow_any prefix */
226 end->allow_any = TRUE;
227 value++;
228 }
229 }
230 free(end->host);
231 end->host = strdupnull(value);
232 break;
233 case KW_SOURCEIP:
234 conn->mode = MODE_TUNNEL;
235 conn->proxy_mode = FALSE;
236 break;
237 case KW_SENDCERT:
238 if (end->sendcert == CERT_YES_SEND)
239 {
240 end->sendcert = CERT_ALWAYS_SEND;
241 }
242 else if (end->sendcert == CERT_NO_SEND)
243 {
244 end->sendcert = CERT_NEVER_SEND;
245 }
246 break;
247 default:
248 break;
249 }
250
251 if (assigned)
252 return;
253
254 /* individual processing of keywords that were not assigned automatically */
255 switch (token)
256 {
257 case KW_PROTOPORT:
258 {
259 struct protoent *proto;
260 struct servent *svc;
261 char *sep, *port = "", *endptr;
262 long int p;
263
264 sep = strchr(value, '/');
265 if (sep)
266 { /* protocol/port */
267 *sep = '\0';
268 port = sep + 1;
269 }
270
271 if (streq(value, "%any"))
272 {
273 end->protocol = 0;
274 }
275 else
276 {
277 proto = getprotobyname(value);
278 if (proto)
279 {
280 end->protocol = proto->p_proto;
281 }
282 else
283 {
284 p = strtol(value, &endptr, 0);
285 if ((*value && *endptr) || p < 0 || p > 0xff)
286 {
287 DBG1(DBG_APP, "# bad protocol: %s=%s", name, value);
288 goto err;
289 }
290 end->protocol = (u_int8_t)p;
291 }
292 }
293 if (streq(port, "%any"))
294 {
295 end->port = 0;
296 }
297 else
298 {
299 svc = getservbyname(port, NULL);
300 if (svc)
301 {
302 end->port = ntohs(svc->s_port);
303 }
304 else
305 {
306 p = strtol(port, &endptr, 0);
307 if ((*port && *endptr) || p < 0 || p > 0xffff)
308 {
309 DBG1(DBG_APP, "# bad port: %s=%s", name, value);
310 goto err;
311 }
312 end->port = (u_int16_t)p;
313 }
314 }
315 if (sep)
316 { /* restore the original text in case also= is used */
317 *sep = '/';
318 }
319 break;
320 }
321 default:
322 break;
323 }
324 return;
325
326 err:
327 DBG1(DBG_APP, " bad argument value in conn '%s'", conn_name);
328 cfg->err++;
329 }
330
331 /*
332 * handles left|rightfirewall and left|rightupdown parameters
333 */
334 static void handle_firewall(const char *label, starter_end_t *end,
335 starter_config_t *cfg)
336 {
337 if (end->firewall && (end->seen & SEEN_KW(KW_FIREWALL, KW_END_FIRST)))
338 {
339 if (end->updown != NULL)
340 {
341 DBG1(DBG_APP, "# cannot have both %sfirewall and %supdown", label,
342 label);
343 cfg->err++;
344 }
345 else
346 {
347 end->updown = strdupnull(firewall_defaults);
348 end->firewall = FALSE;
349 }
350 }
351 }
352
353 static bool handle_mark(char *value, mark_t *mark)
354 {
355 char *sep, *endptr;
356
357 sep = strchr(value, '/');
358 if (sep)
359 {
360 *sep = '\0';
361 mark->mask = strtoul(sep+1, &endptr, 0);
362 if (*endptr != '\0')
363 {
364 DBG1(DBG_APP, "# invalid mark mask: %s", sep+1);
365 return FALSE;
366 }
367 }
368 else
369 {
370 mark->mask = 0xffffffff;
371 }
372 if (value == '\0')
373 {
374 mark->value = 0;
375 }
376 else
377 {
378 mark->value = strtoul(value, &endptr, 0);
379 if (*endptr != '\0')
380 {
381 DBG1(DBG_APP, "# invalid mark value: %s", value);
382 return FALSE;
383 }
384 }
385 if (sep)
386 { /* restore the original text in case also= is used */
387 *sep = '/';
388 }
389 /* apply the mask to ensure the value is in range */
390 mark->value &= mark->mask;
391 return TRUE;
392 }
393
394 /*
395 * parse a conn section
396 */
397 static void load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg)
398 {
399 char *conn_name = (conn->name == NULL)? "%default":conn->name;
400
401 for ( ; kw; kw = kw->next)
402 {
403 bool assigned = FALSE;
404
405 kw_token_t token = kw->entry->token;
406
407 if (token >= KW_LEFT_FIRST && token <= KW_LEFT_LAST)
408 {
409 kw_end(conn, &conn->left, token - KW_LEFT_FIRST + KW_END_FIRST
410 , kw, conn_name, cfg);
411 continue;
412 }
413 else if (token >= KW_RIGHT_FIRST && token <= KW_RIGHT_LAST)
414 {
415 kw_end(conn, &conn->right, token - KW_RIGHT_FIRST + KW_END_FIRST
416 , kw, conn_name, cfg);
417 continue;
418 }
419
420 if (token == KW_AUTO)
421 {
422 token = KW_CONN_SETUP;
423 }
424 else if (token == KW_ALSO)
425 {
426 if (cfg->parse_also)
427 {
428 also_t *also = malloc_thing(also_t);
429
430 also->name = strdupnull(kw->value);
431 also->next = conn->also;
432 conn->also = also;
433
434 DBG2(DBG_APP, " also=%s", kw->value);
435 }
436 continue;
437 }
438
439 if (token < KW_CONN_FIRST || token > KW_CONN_LAST)
440 {
441 DBG1(DBG_APP, "# unsupported keyword '%s' in conn '%s'",
442 kw->entry->name, conn_name);
443 cfg->err++;
444 continue;
445 }
446
447 if (is_deprecated(token, kw, conn_name))
448 {
449 cfg->non_fatal_err++;
450 continue;
451 }
452
453 if (!assign_arg(token, KW_CONN_FIRST, kw, (char *)conn, &assigned))
454 {
455 DBG1(DBG_APP, " bad argument value in conn '%s'", conn_name);
456 cfg->err++;
457 continue;
458 }
459
460 if (assigned)
461 continue;
462
463 switch (token)
464 {
465 case KW_TYPE:
466 conn->mode = MODE_TRANSPORT;
467 conn->proxy_mode = FALSE;
468 if (streq(kw->value, "tunnel"))
469 {
470 conn->mode = MODE_TUNNEL;
471 }
472 else if (streq(kw->value, "beet"))
473 {
474 conn->mode = MODE_BEET;
475 }
476 else if (streq(kw->value, "transport_proxy"))
477 {
478 conn->mode = MODE_TRANSPORT;
479 conn->proxy_mode = TRUE;
480 }
481 else if (streq(kw->value, "passthrough") || streq(kw->value, "pass"))
482 {
483 conn->mode = MODE_PASS;
484 }
485 else if (streq(kw->value, "drop") || streq(kw->value, "reject"))
486 {
487 conn->mode = MODE_DROP;
488 }
489 else if (!streq(kw->value, "transport"))
490 {
491 DBG1(DBG_APP, "# bad policy value: %s=%s", kw->entry->name,
492 kw->value);
493 cfg->err++;
494 }
495 break;
496 case KW_COMPRESS:
497 KW_SA_OPTION_FLAG("yes", "no", SA_OPTION_COMPRESS)
498 break;
499 case KW_AUTH:
500 KW_SA_OPTION_FLAG("ah", "esp", SA_OPTION_AUTHENTICATE)
501 break;
502 case KW_MARK:
503 if (!handle_mark(kw->value, &conn->mark_in))
504 {
505 cfg->err++;
506 break;
507 }
508 conn->mark_out = conn->mark_in;
509 break;
510 case KW_MARK_IN:
511 if (!handle_mark(kw->value, &conn->mark_in))
512 {
513 cfg->err++;
514 }
515 break;
516 case KW_MARK_OUT:
517 if (!handle_mark(kw->value, &conn->mark_out))
518 {
519 cfg->err++;
520 }
521 break;
522 case KW_TFC:
523 if (streq(kw->value, "%mtu"))
524 {
525 conn->tfc = -1;
526 }
527 else
528 {
529 char *endptr;
530
531 conn->tfc = strtoul(kw->value, &endptr, 10);
532 if (*endptr != '\0')
533 {
534 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
535 kw->value);
536 cfg->err++;
537 }
538 }
539 break;
540 case KW_KEYINGTRIES:
541 if (streq(kw->value, "%forever"))
542 {
543 conn->sa_keying_tries = 0;
544 }
545 else
546 {
547 char *endptr;
548
549 conn->sa_keying_tries = strtoul(kw->value, &endptr, 10);
550 if (*endptr != '\0')
551 {
552 DBG1(DBG_APP, "# bad integer value: %s=%s", kw->entry->name,
553 kw->value);
554 cfg->err++;
555 }
556 }
557 break;
558 case KW_REKEY:
559 KW_SA_OPTION_FLAG("no", "yes", SA_OPTION_DONT_REKEY)
560 break;
561 case KW_REAUTH:
562 KW_SA_OPTION_FLAG("no", "yes", SA_OPTION_DONT_REAUTH)
563 break;
564 case KW_MOBIKE:
565 KW_SA_OPTION_FLAG("yes", "no", SA_OPTION_MOBIKE)
566 break;
567 case KW_FORCEENCAPS:
568 KW_SA_OPTION_FLAG("yes", "no", SA_OPTION_FORCE_ENCAP)
569 break;
570 case KW_MODECONFIG:
571 KW_SA_OPTION_FLAG("push", "pull", SA_OPTION_MODECFG_PUSH)
572 break;
573 case KW_XAUTH:
574 KW_SA_OPTION_FLAG("server", "client", SA_OPTION_XAUTH_SERVER)
575 break;
576 default:
577 break;
578 }
579 }
580
581 handle_firewall("left", &conn->left, cfg);
582 handle_firewall("right", &conn->right, cfg);
583 }
584
585 /*
586 * initialize a conn object with the default conn
587 */
588 static void conn_default(char *name, starter_conn_t *conn, starter_conn_t *def)
589 {
590 memcpy(conn, def, sizeof(starter_conn_t));
591 conn->name = strdupnull(name);
592
593 clone_args(KW_CONN_FIRST, KW_CONN_LAST, (char *)conn, (char *)def);
594 clone_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->left, (char *)&def->left);
595 clone_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->right, (char *)&def->right);
596 }
597
598 /*
599 * parse a ca section
600 */
601 static void load_ca(starter_ca_t *ca, kw_list_t *kw, starter_config_t *cfg)
602 {
603 char *ca_name = (ca->name == NULL)? "%default":ca->name;
604
605 for ( ; kw; kw = kw->next)
606 {
607 bool assigned = FALSE;
608
609 kw_token_t token = kw->entry->token;
610
611 if (token == KW_AUTO)
612 {
613 token = KW_CA_SETUP;
614 }
615 else if (token == KW_ALSO)
616 {
617 if (cfg->parse_also)
618 {
619 also_t *also = malloc_thing(also_t);
620
621 also->name = strdupnull(kw->value);
622 also->next = ca->also;
623 ca->also = also;
624
625 DBG2(DBG_APP, " also=%s", kw->value);
626 }
627 continue;
628 }
629
630 if (token < KW_CA_FIRST || token > KW_CA_LAST)
631 {
632 DBG1(DBG_APP, "# unsupported keyword '%s' in ca '%s'",
633 kw->entry->name, ca_name);
634 cfg->err++;
635 continue;
636 }
637
638 if (is_deprecated(token, kw, ca_name))
639 {
640 cfg->non_fatal_err++;
641 continue;
642 }
643
644 if (!assign_arg(token, KW_CA_FIRST, kw, (char *)ca, &assigned))
645 {
646 DBG1(DBG_APP, " bad argument value in ca '%s'", ca_name);
647 cfg->err++;
648 }
649 }
650
651 /* treat 'route' and 'start' as 'add' */
652 if (ca->startup != STARTUP_NO)
653 ca->startup = STARTUP_ADD;
654 }
655
656 /*
657 * initialize a ca object with the default ca
658 */
659 static void ca_default(char *name, starter_ca_t *ca, starter_ca_t *def)
660 {
661 memcpy(ca, def, sizeof(starter_ca_t));
662 ca->name = strdupnull(name);
663
664 clone_args(KW_CA_FIRST, KW_CA_LAST, (char *)ca, (char *)def);
665 }
666
667 static kw_list_t* find_also_conn(const char* name, starter_conn_t *conn,
668 starter_config_t *cfg);
669
670 static void load_also_conns(starter_conn_t *conn, also_t *also,
671 starter_config_t *cfg)
672 {
673 while (also != NULL)
674 {
675 kw_list_t *kw = find_also_conn(also->name, conn, cfg);
676
677 if (kw == NULL)
678 {
679 DBG1(DBG_APP, " conn '%s' cannot include '%s'", conn->name,
680 also->name);
681 }
682 else
683 {
684 DBG2(DBG_APP, "conn '%s' includes '%s'", conn->name, also->name);
685 /* only load if no error occurred in the first round */
686 if (cfg->err == 0)
687 load_conn(conn, kw, cfg);
688 }
689 also = also->next;
690 }
691 }
692
693 /*
694 * find a conn included by also
695 */
696 static kw_list_t* find_also_conn(const char* name, starter_conn_t *conn,
697 starter_config_t *cfg)
698 {
699 starter_conn_t *c = cfg->conn_first;
700
701 while (c != NULL)
702 {
703 if (streq(name, c->name))
704 {
705 if (conn->visit == c->visit)
706 {
707 DBG1(DBG_APP, "# detected also loop");
708 cfg->err++;
709 return NULL;
710 }
711 c->visit = conn->visit;
712 load_also_conns(conn, c->also, cfg);
713 return c->kw;
714 }
715 c = c->next;
716 }
717
718 DBG1(DBG_APP, "# also '%s' not found", name);
719 cfg->err++;
720 return NULL;
721 }
722
723 static kw_list_t* find_also_ca(const char* name, starter_ca_t *ca,
724 starter_config_t *cfg);
725
726 static void load_also_cas(starter_ca_t *ca, also_t *also, starter_config_t *cfg)
727 {
728 while (also != NULL)
729 {
730 kw_list_t *kw = find_also_ca(also->name, ca, cfg);
731
732 if (kw == NULL)
733 {
734 DBG1(DBG_APP, " ca '%s' cannot include '%s'", ca->name,
735 also->name);
736 }
737 else
738 {
739 DBG2(DBG_APP, "ca '%s' includes '%s'", ca->name, also->name);
740 /* only load if no error occurred in the first round */
741 if (cfg->err == 0)
742 load_ca(ca, kw, cfg);
743 }
744 also = also->next;
745 }
746 }
747
748 /*
749 * find a ca included by also
750 */
751 static kw_list_t* find_also_ca(const char* name, starter_ca_t *ca,
752 starter_config_t *cfg)
753 {
754 starter_ca_t *c = cfg->ca_first;
755
756 while (c != NULL)
757 {
758 if (streq(name, c->name))
759 {
760 if (ca->visit == c->visit)
761 {
762 DBG1(DBG_APP, "# detected also loop");
763 cfg->err++;
764 return NULL;
765 }
766 c->visit = ca->visit;
767 load_also_cas(ca, c->also, cfg);
768 return c->kw;
769 }
770 c = c->next;
771 }
772
773 DBG1(DBG_APP, "# also '%s' not found", name);
774 cfg->err++;
775 return NULL;
776 }
777
778 /*
779 * free the memory used by also_t objects
780 */
781 static void free_also(also_t *head)
782 {
783 while (head != NULL)
784 {
785 also_t *also = head;
786
787 head = also->next;
788 free(also->name);
789 free(also);
790 }
791 }
792
793 /*
794 * free the memory used by a starter_conn_t object
795 */
796 static void confread_free_conn(starter_conn_t *conn)
797 {
798 free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->left);
799 free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->right);
800 free_args(KW_CONN_NAME, KW_CONN_LAST, (char *)conn);
801 free_also(conn->also);
802 }
803
804 /*
805 * free the memory used by a starter_ca_t object
806 */
807 static void
808 confread_free_ca(starter_ca_t *ca)
809 {
810 free_args(KW_CA_NAME, KW_CA_LAST, (char *)ca);
811 free_also(ca->also);
812 }
813
814 /*
815 * free the memory used by a starter_config_t object
816 */
817 void confread_free(starter_config_t *cfg)
818 {
819 starter_conn_t *conn = cfg->conn_first;
820 starter_ca_t *ca = cfg->ca_first;
821
822 free_args(KW_SETUP_FIRST, KW_SETUP_LAST, (char *)cfg);
823
824 confread_free_conn(&cfg->conn_default);
825
826 while (conn != NULL)
827 {
828 starter_conn_t *conn_aux = conn;
829
830 conn = conn->next;
831 confread_free_conn(conn_aux);
832 free(conn_aux);
833 }
834
835 confread_free_ca(&cfg->ca_default);
836
837 while (ca != NULL)
838 {
839 starter_ca_t *ca_aux = ca;
840
841 ca = ca->next;
842 confread_free_ca(ca_aux);
843 free(ca_aux);
844 }
845
846 free(cfg);
847 }
848
849 /*
850 * load and parse an IPsec configuration file
851 */
852 starter_config_t* confread_load(const char *file)
853 {
854 starter_config_t *cfg = NULL;
855 config_parsed_t *cfgp;
856 section_list_t *sconn, *sca;
857 starter_conn_t *conn;
858 starter_ca_t *ca;
859
860 u_int total_err;
861 u_int visit = 0;
862
863 /* load IPSec configuration file */
864 cfgp = parser_load_conf(file);
865 if (!cfgp)
866 {
867 return NULL;
868 }
869 cfg = malloc_thing(starter_config_t);
870
871 /* set default values */
872 default_values(cfg);
873
874 /* load config setup section */
875 load_setup(cfg, cfgp);
876
877 /* in the first round parse also statements */
878 cfg->parse_also = TRUE;
879
880 /* find %default ca section */
881 for (sca = cfgp->ca_first; sca; sca = sca->next)
882 {
883 if (streq(sca->name, "%default"))
884 {
885 DBG2(DBG_APP, "Loading ca %%default");
886 load_ca(&cfg->ca_default, sca->kw, cfg);
887 }
888 }
889
890 /* parameters defined in ca %default sections can be overloads */
891 cfg->ca_default.seen = SEEN_NONE;
892
893 /* load other ca sections */
894 for (sca = cfgp->ca_first; sca; sca = sca->next)
895 {
896 u_int previous_err;
897
898 /* skip %default ca section */
899 if (streq(sca->name, "%default"))
900 continue;
901
902 DBG2(DBG_APP, "Loading ca '%s'", sca->name);
903 ca = malloc_thing(starter_ca_t);
904
905 ca_default(sca->name, ca, &cfg->ca_default);
906 ca->kw = sca->kw;
907 ca->next = NULL;
908
909 previous_err = cfg->err;
910 load_ca(ca, ca->kw, cfg);
911 if (cfg->err > previous_err)
912 {
913 /* errors occurred - free the ca */
914 confread_free_ca(ca);
915 cfg->non_fatal_err += cfg->err - previous_err;
916 cfg->err = previous_err;
917 }
918 else
919 {
920 /* success - insert the ca into the chained list */
921 if (cfg->ca_last)
922 cfg->ca_last->next = ca;
923 cfg->ca_last = ca;
924 if (!cfg->ca_first)
925 cfg->ca_first = ca;
926 }
927 }
928
929 for (ca = cfg->ca_first; ca; ca = ca->next)
930 {
931 also_t *also = ca->also;
932
933 while (also != NULL)
934 {
935 kw_list_t *kw = find_also_ca(also->name, cfg->ca_first, cfg);
936
937 load_ca(ca, kw, cfg);
938 also = also->next;
939 }
940
941 if (ca->startup != STARTUP_NO)
942 ca->state = STATE_TO_ADD;
943 }
944
945 /* find %default conn sections */
946 for (sconn = cfgp->conn_first; sconn; sconn = sconn->next)
947 {
948 if (streq(sconn->name, "%default"))
949 {
950 DBG2(DBG_APP, "Loading conn %%default");
951 load_conn(&cfg->conn_default, sconn->kw, cfg);
952 }
953 }
954
955 /* parameters defined in conn %default sections can be overloaded */
956 cfg->conn_default.seen = SEEN_NONE;
957 cfg->conn_default.right.seen = SEEN_NONE;
958 cfg->conn_default.left.seen = SEEN_NONE;
959
960 /* load other conn sections */
961 for (sconn = cfgp->conn_first; sconn; sconn = sconn->next)
962 {
963 u_int previous_err;
964
965 /* skip %default conn section */
966 if (streq(sconn->name, "%default"))
967 continue;
968
969 DBG2(DBG_APP, "Loading conn '%s'", sconn->name);
970 conn = malloc_thing(starter_conn_t);
971
972 conn_default(sconn->name, conn, &cfg->conn_default);
973 conn->kw = sconn->kw;
974 conn->next = NULL;
975
976 previous_err = cfg->err;
977 load_conn(conn, conn->kw, cfg);
978 if (cfg->err > previous_err)
979 {
980 /* error occurred - free the conn */
981 confread_free_conn(conn);
982 cfg->non_fatal_err += cfg->err - previous_err;
983 cfg->err = previous_err;
984 }
985 else
986 {
987 /* success - insert the conn into the chained list */
988 if (cfg->conn_last)
989 cfg->conn_last->next = conn;
990 cfg->conn_last = conn;
991 if (!cfg->conn_first)
992 cfg->conn_first = conn;
993 }
994 }
995
996 /* in the second round do not parse also statements */
997 cfg->parse_also = FALSE;
998
999 for (ca = cfg->ca_first; ca; ca = ca->next)
1000 {
1001 ca->visit = ++visit;
1002 load_also_cas(ca, ca->also, cfg);
1003
1004 if (ca->startup != STARTUP_NO)
1005 ca->state = STATE_TO_ADD;
1006 }
1007
1008 for (conn = cfg->conn_first; conn; conn = conn->next)
1009 {
1010 conn->visit = ++visit;
1011 load_also_conns(conn, conn->also, cfg);
1012
1013 if (conn->startup != STARTUP_NO)
1014 conn->state = STATE_TO_ADD;
1015 }
1016
1017 parser_free_conf(cfgp);
1018
1019 total_err = cfg->err + cfg->non_fatal_err;
1020 if (total_err > 0)
1021 {
1022 DBG1(DBG_APP, "### %d parsing error%s (%d fatal) ###",
1023 total_err, (total_err > 1)?"s":"", cfg->err);
1024 }
1025
1026 return cfg;
1027 }