📄 confread.c
字号:
/* Openswan config file parser (confread.c) * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security * Copyright (C) 2004 Xelerance Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * RCSID $Id: confread.c,v 1.11 2004/04/11 15:17:30 ken Exp $ */#include <stdlib.h>#include <string.h>#include <limits.h>#include <assert.h>#include <sys/queue.h>#include "parser.h"#include "confread.h"#include "interfaces.h"#include "starterlog.h"static char _tmp_err[512];/** * A policy only conn means that we load it, and do the appropriate firewalling to make * sure that no packets get out that this conn would apply to, but we refuse to negotiate * it in any way, either incoming or outgoing. */#define POLICY_ONLY_CONN(conn) if(conn->options[KBF_AUTO] > STARTUP_ROUTE) { conn->options[KBF_AUTO]=STARTUP_POLICY; }void free_list(char **list);char **new_list(char *value);/** * Set up hardcoded defaults, from data in programs/pluto/constants.h * * @param cfg starter_config struct * @return void */static void default_values (struct starter_config *cfg){ if (!cfg) return; memset(cfg, 0, sizeof(struct starter_config)); TAILQ_INIT(&cfg->conns); cfg->setup.options[KBF_FRAGICMP] = TRUE; cfg->setup.options[KBF_HIDETOS] = TRUE; cfg->setup.options[KBF_UNIQUEIDS]= FALSE; cfg->setup.options[KBF_TYPE] = KS_TUNNEL; cfg->conn_default.policy = POLICY_ENCRYPT | POLICY_TUNNEL | POLICY_RSASIG; cfg->conn_default.options[KBF_IKELIFETIME] = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT; cfg->conn_default.options[KBF_SALIFETIME] = SA_LIFE_DURATION_DEFAULT; cfg->conn_default.options[KBF_REKEYMARGIN] = SA_REPLACEMENT_MARGIN_DEFAULT; cfg->conn_default.options[KBF_REKEYFUZZ] = SA_REPLACEMENT_FUZZ_DEFAULT; cfg->conn_default.options[KBF_KEYINGTRIES] = SA_REPLACEMENT_RETRIES_DEFAULT; cfg->conn_default.left.addr_family = AF_INET; anyaddr(AF_INET, &cfg->conn_default.left.addr); anyaddr(AF_INET, &cfg->conn_default.left.nexthop); cfg->conn_default.right.addr_family = AF_INET; anyaddr(AF_INET, &cfg->conn_default.right.addr); anyaddr(AF_INET, &cfg->conn_default.right.nexthop); cfg->conn_default.options[KBF_AUTO] = STARTUP_NO; cfg->conn_default.state = STATE_LOADED;}#define ERR_FOUND(args...) \ { if (perr && (*perr==NULL)) { \ snprintf(_tmp_err, sizeof(_tmp_err)-1, ## args); \ *perr = xstrdup(_tmp_err); } \ err++; }#define KW_POLICY_FLAG(val,fl) if(conn->options_set[val]) \ { if(conn->options[val]) \ { \ conn->policy |= fl; \ } else { \ conn->policy &= ~fl;\ }}/** * Free the pointer list * * @param list list of pointers * @return void */void free_list(char **list){ char **s; for (s=list; *s; s++) free(*s); free(list);}/** * Create a new list of pointers * * @param value * @return new_list (pointer to list of pointers) */char **new_list(char *value){ char *val, *b, *e, *end, **ret; int count; val = value ? xstrdup(value) : NULL; if (!val) return NULL; end = val + strlen(val); for (b=val, count=0; b<end; ) { for (e=b; ((*e!=' ') && (*e!='\0')); e++); *e = '\0'; if (e!=b) { count++; } b=e+1; } if (count==0) { free(val); return NULL; } ret = (char **)malloc((count+1) * sizeof(char *)); if (!ret) { free(val); return NULL; } for (b=val, count=0; b<end; ) { for (e=b; (*e!='\0'); e++); if (e!=b) { ret[count++] = xstrdup(b); } b=e+1; } ret[count] = NULL; free(val); return ret;}/** * Load a parsed config * * @param cfg starter_config structure * @param cfgp config_parsed (ie: valid) struct * @param perr pointer to store errors in * @return int 0 if successfull */static int load_setup (struct starter_config *cfg , struct config_parsed *cfgp , char **perr){ unsigned int err = 0; struct kw_list *kw; for (kw=cfgp->config_setup; kw; kw=kw->next) { /** * the parser already made sure that only config keywords were used, * but we double check! */ assert(kw->keyword.keydef->validity & kv_config); switch(kw->keyword.keydef->type) { case kt_string: case kt_filename: case kt_dirname: case kt_loose_enum: /* all treated as strings for now */ assert(kw->keyword.keydef->field < sizeof(cfg->setup.strings)); if(cfg->setup.strings[kw->keyword.keydef->field]) free(cfg->setup.strings[kw->keyword.keydef->field]); cfg->setup.strings[kw->keyword.keydef->field] = xstrdup(kw->string); break; case kt_appendstring: assert(kw->keyword.keydef->field < KEY_STRINGS_MAX); if(!cfg->setup.strings[kw->keyword.keydef->field]) { cfg->setup.strings[kw->keyword.keydef->field] = xstrdup(kw->string); } else { int len; char *s; len = strlen(cfg->setup.strings[kw->keyword.keydef->field])+1; len += strlen(kw->string)+1; /* allocate the string */ s = cfg->setup.strings[kw->keyword.keydef->field]; s = xrealloc(s, len); strncat(s, " ", len); strncat(s, kw->string, len); cfg->setup.strings[kw->keyword.keydef->field] = s; } break; case kt_list: case kt_bool: case kt_invertbool: case kt_enum: case kt_number: case kt_time: case kt_percent: /* all treated as a number for now */ assert(kw->keyword.keydef->field < sizeof(cfg->setup.options)); cfg->setup.options[kw->keyword.keydef->field] = kw->number; break; case kt_bitstring: case kt_rsakey: case kt_ipaddr: case kt_subnet: case kt_idtype: err++; break; } } /* now process some things with specific values */ /* interfaces has to be chopped up */ if (cfg->setup.interfaces) free_list(cfg->setup.interfaces); cfg->setup.interfaces = new_list(cfg->setup.strings[KSF_INTERFACES]); return err;}/** * Validate that yes in fact we are one side of the tunnel * * The function checks that IP addresses are valid, nexthops are * present (if needed) as well as policies * * @param conn_st a connection definition * @param end a connection end * @param left boolean (are we 'left'? 1 = yes, 0 = no) * @param perr pointer to char containing error value * @return int 0 if successfull */static int validate_end(struct starter_conn *conn_st , struct starter_end *end , bool left, char **perr){ err_t er = NULL; int err=0; end->addrtype=end->options[KNCF_IP]; /* validate the KSCF_IP/KNCF_IP */ switch(end->addrtype) { case KH_ANY: anyaddr(AF_INET, &(end->addr)); break; case KH_IFACE: assert(end->strings[KSCF_IP] != NULL); if (end->iface) free(end->iface); end->iface = xstrdup(end->strings[KNCF_IP]); if (starter_iface_find(end->iface, AF_INET, &(end->addr), &(end->nexthop)) == -1) { conn_st->state = STATE_INVALID; } break; case KH_IPADDR: assert(end->strings[KSCF_IP] != NULL); er = ttoaddr(end->strings[KNCF_IP], 0, AF_INET, &(end->addr)); if (er) ERR_FOUND("bad addr %s=%s [%s]", (left ? "left" : "right"), end->strings[KNCF_IP], er); break; case KH_OPPO: conn_st->policy |= POLICY_OPPO; break; case KH_OPPOGROUP: conn_st->policy |= POLICY_GROUP|POLICY_GROUP; break; case KH_GROUP: conn_st->policy |= POLICY_GROUP; break; case KH_DEFAULTROUTE: break; case KH_NOTSET: break; } /* validate the KSCF_SUBNET */ if(end->strings[KSCF_SUBNET] != NULL) { char *value = end->strings[KSCF_SUBNET];#ifdef VIRTUAL_IP if ( ((strlen(value)>=6) && (strncmp(value,"vhost:",6)==0)) || ((strlen(value)>=5) && (strncmp(value,"vnet:",5)==0)) ) { er = NULL; end->virt = xstrdup(value); if (!end->virt) ERR_FOUND("can't alloc memory"); } else { end->has_client = TRUE; er = ttosubnet(value, 0, AF_INET, &(end->subnet)); }#else end->has_client = TRUE; end->has_client_wildcard = FALSE; er = ttosubnet(value, 0, AF_INET, &(end->subnet));#endif if (er) ERR_FOUND("bad subnet %s=%s [%s]", (left ? "leftsubnet" : "rightsubnet"), value, er); } /* validate the KSCF_NEXTHOP */ if(end->strings[KSCF_NEXTHOP] != NULL) { char *value = end->strings[KSCF_NEXTHOP]; er = ttoaddr(value, 0, AF_INET, &(end->nexthop)); if (er) ERR_FOUND("bad addr %s=%s [%s]", (left ? "lextnexthop" : "rightnexthop"), value, er); } else { anyaddr(AF_INET, &end->nexthop); } /* validate the KSCF_ID */ if(end->strings[KSCF_ID] != NULL) { char *value = end->strings[KSCF_ID]; if (end->id) free(end->id); end->id = xstrdup(value); } /* validate the KSCF_RSAKEY1/RSAKEY2 */ if(end->strings[KSCF_RSAKEY1] != NULL) { char *value = end->strings[KSCF_RSAKEY1]; if (end->rsakey1) free(end->rsakey1); end->rsakey1 = xstrdup(value); } if(end->strings[KSCF_RSAKEY2] != NULL) { char *value = end->strings[KSCF_RSAKEY2]; if (end->rsakey2) free(end->rsakey2); end->rsakey2 = xstrdup(value); } return err;}/** * Take keywords from ipsec.conf syntax and load into a conn struct * * * @param conn a connection definition * @param sl a section_list * @param permitreplace boolean (can we replace this conn?) * @return bool 0 if successfull */static bool translate_conn (struct starter_conn *conn , struct section_list *sl , bool permitreplace){ unsigned int err, field; ksf *the_strings; knf *the_options; str_set *set_strings; int_set *set_options; volatile int i; /* just to keep it around for debugging */ struct kw_list *kw = sl->kw; err = 0; i = 0; for ( ; kw; kw=kw->next) { i++; the_strings = &conn->strings; set_strings = &conn->strings_set; the_options = &conn->options; set_options = &conn->options_set; if((kw->keyword.keydef->validity & kv_conn) == 0) { /* this isn't valid in a conn! */ starter_log(LOG_LEVEL_INFO, "keyword '%s' is not valid in a conn (%s) (#%d)\n", kw->keyword.keydef->keyname, sl->name, i); continue; } if(kw->keyword.keydef->validity & kv_leftright) { if(kw->keyword.keyleft) { the_strings = &conn->left.strings; the_options = &conn->left.options; set_strings = &conn->left.strings_set; set_options = &conn->left.options_set; } else { the_strings = &conn->right.strings; the_options = &conn->right.options; set_strings = &conn->right.strings_set; set_options = &conn->right.options_set; } } field = kw->keyword.keydef->field; assert(kw->keyword.keydef != NULL); switch(kw->keyword.keydef->type) { case kt_string: case kt_filename: case kt_dirname: case kt_bitstring: case kt_ipaddr: case kt_subnet: case kt_idtype: /* all treated as strings for now */ assert(kw->keyword.keydef->field < KEY_STRINGS_MAX); if((*set_strings)[field]) { if(!permitreplace) { starter_log(LOG_LEVEL_INFO , "duplicate key '%s' in conn %s while processing def %s" , kw->keyword.keydef->keyname , conn->name , sl->name); if(kw->keyword.string == NULL || (*the_strings)[field] == NULL || strcmp(kw->keyword.string, (*the_strings)[field])!=0) { err++; break; } } } if((*the_strings)[field]) { free((*the_strings)[field]); } (*the_strings)[field] = xstrdup(kw->string); (*set_strings)[field] = TRUE; break; case kt_appendstring: /* implicitely, this field can have multiple values */ assert(kw->keyword.keydef->field < KEY_STRINGS_MAX); if(!(*the_strings)[field]) { (*the_strings)[field] = xstrdup(kw->string); } else { int len; char *s; len = strlen((*the_strings)[field])+1; len += strlen(kw->string)+1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -