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