00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00035 #include "tls_config.h"
00036 #include "tls_domain.h"
00037 #include "tls_mod.h"
00038 #include "tls_util.h"
00039
00040 #include "../../cfg_parser.h"
00041
00042 #include "../../resolve.h"
00043 #include "../../mem/mem.h"
00044 #include "../../dprint.h"
00045 #include "../../trim.h"
00046 #include "../../ut.h"
00047 #include "../../cfg/cfg.h"
00048
00049 static tls_domains_cfg_t* cfg = NULL;
00050 static tls_domain_t* domain = NULL;
00051
00052 #ifdef USE_IPV6
00053 static int parse_ipv6(struct ip_addr* ip, cfg_token_t* token,
00054 cfg_parser_t* st)
00055 {
00056 int ret;
00057 cfg_token_t t;
00058 struct ip_addr* ipv6;
00059 str ip6_str;
00060
00061 ip6_str.s = t.val.s;
00062 while(1) {
00063 ret = cfg_get_token(&t, st, 0);
00064 if (ret != 0) goto err;
00065 if (t.type == ']') break;
00066 if (t.type != CFG_TOKEN_ALPHA && t.type != ':') goto err;
00067 }
00068 ip6_str.len = (int)(long)(t.val.s - ip6_str.s);
00069
00070 ipv6 = str2ip6(&ip6_str);
00071 if (ipv6 == 0) goto err;
00072 *ip = *ipv6;
00073 return 0;
00074
00075 err:
00076 ERR("%s:%d:%d: Invalid IPv6 address\n",
00077 st->file, token->start.line, token->start.col);
00078 return -1;
00079 }
00080 #endif
00081
00082
00083 static int parse_ipv4(struct ip_addr* ip, cfg_token_t* token,
00084 cfg_parser_t* st)
00085 {
00086 int ret, i;
00087 cfg_token_t t;
00088 unsigned int v;
00089
00090 ip->af = AF_INET;
00091 ip->len = 4;
00092
00093 if (str2int(&token->val, &v) < 0) goto err;
00094 if (v < 0 || v > 255) goto err;
00095
00096 ip->u.addr[0] = v;
00097
00098 for(i = 1; i < 4; i++) {
00099 ret = cfg_get_token(&t, st, 0);
00100 if (ret < 0) return -1;
00101 if (ret > 0 || t.type != '.') goto err;
00102
00103 ret = cfg_get_token(&t, st, 0);
00104 if (ret < 0) return -1;
00105 if (ret > 0 || t.type != CFG_TOKEN_ALPHA) goto err;
00106 if (str2int(&t.val, &v) < 0) goto err;
00107 if (v < 0 || v > 255) goto err;
00108 ip->u.addr[i] = v;
00109 }
00110
00111 return 0;
00112 err:
00113 ERR("%s:%d:%d: Invalid IPv4 address\n",
00114 st->file, token->start.line, token->start.col);
00115 return -1;
00116 }
00117
00118
00119 static cfg_option_t methods[] = {
00120 {"SSLv2", .val = TLS_USE_SSLv2},
00121 {"SSLv3", .val = TLS_USE_SSLv3},
00122 {"SSLv23", .val = TLS_USE_SSLv23},
00123 {"TLSv1", .val = TLS_USE_TLSv1},
00124 {0}
00125 };
00126
00127
00128 static cfg_option_t domain_types[] = {
00129 {"server", .val = TLS_DOMAIN_SRV},
00130 {"srv", .val = TLS_DOMAIN_SRV},
00131 {"s", .val = TLS_DOMAIN_SRV},
00132 {"client", .val = TLS_DOMAIN_CLI},
00133 {"cli", .val = TLS_DOMAIN_CLI},
00134 {"c", .val = TLS_DOMAIN_CLI},
00135 {0}
00136 };
00137
00138
00139 static cfg_option_t token_default[] = {
00140 {"default"},
00141 {"def"},
00142 {"*"},
00143 {0}
00144 };
00145
00146
00147 static cfg_option_t options[] = {
00148 {"method", .param = methods, .f = cfg_parse_enum_opt},
00149 {"tls_method", .param = methods, .f = cfg_parse_enum_opt},
00150 {"verify_certificate", .f = cfg_parse_bool_opt},
00151 {"verify_cert", .f = cfg_parse_bool_opt},
00152 {"verify_depth", .f = cfg_parse_int_opt},
00153 {"require_certificate", .f = cfg_parse_bool_opt},
00154 {"require_cert", .f = cfg_parse_bool_opt},
00155 {"private_key", .f = cfg_parse_str_opt, .flags = CFG_STR_SHMMEM},
00156 {"pkey_file", .f = cfg_parse_str_opt, .flags = CFG_STR_SHMMEM},
00157 {"calist_file", .f = cfg_parse_str_opt, .flags = CFG_STR_SHMMEM},
00158 {"certificate", .f = cfg_parse_str_opt, .flags = CFG_STR_SHMMEM},
00159 {"cert_file", .f = cfg_parse_str_opt, .flags = CFG_STR_SHMMEM},
00160 {"cipher_list", .f = cfg_parse_str_opt, .flags = CFG_STR_SHMMEM},
00161 {"ca_list", .f = cfg_parse_str_opt, .flags = CFG_STR_SHMMEM},
00162 {"crl", .f = cfg_parse_str_opt, .flags = CFG_STR_SHMMEM},
00163 {0}
00164 };
00165
00166
00167 static void update_opt_variables(void)
00168 {
00169 int i;
00170 for(i = 0; methods[i].name; i++) {
00171 methods[i].param = &domain->method;
00172 }
00173 options[2].param = &domain->verify_cert;
00174 options[3].param = &domain->verify_cert;
00175 options[4].param = &domain->verify_depth;
00176 options[5].param = &domain->require_cert;
00177 options[6].param = &domain->require_cert;
00178 options[7].param = &domain->pkey_file;
00179 options[8].param = &domain->pkey_file;
00180 options[9].param = &domain->ca_file;
00181 options[10].param = &domain->cert_file;
00182 options[11].param = &domain->cert_file;
00183 options[12].param = &domain->cipher_list;
00184 options[13].param = &domain->ca_file;
00185 options[14].param = &domain->crl_file;
00186 }
00187
00188
00189 static int parse_hostport(int* type, struct ip_addr* ip, unsigned int* port,
00190 cfg_token_t* token, cfg_parser_t* st)
00191 {
00192 int ret;
00193 cfg_token_t t;
00194 cfg_option_t* opt;
00195
00196 ret = cfg_get_token(&t, st, 0);
00197 if (ret < 0) return -1;
00198 if (ret > 0) {
00199 ERR("%s:%d:%d: Missing IP address\n", st->file,
00200 token->start.line, token->start.col);
00201 return -1;
00202 }
00203
00204 if (t.type == '[') {
00205 #ifdef USE_IPV6
00206 if (parse_ipv6(ip, &t, st) < 0) return -1;
00207 #else
00208 ERR("%s:%d:%d: IPv6 address not supported (compiled without IPv6"
00209 " support)\n",
00210 st->file, t.start.line, t.start.col);
00211 return -1;
00212 #endif
00213 } else if (t.type == CFG_TOKEN_ALPHA) {
00214 opt = cfg_lookup_token(token_default, &t.val);
00215 if (opt) {
00216 *type = TLS_DOMAIN_DEF;
00217
00218 return 0;
00219 } else {
00220 if (parse_ipv4(ip, &t, st) < 0) return -1;
00221 }
00222 } else {
00223 ERR("%s:%d:%d: Syntax error, IP address expected\n",
00224 st->file, t.start.line, t.start.col);
00225 return -1;
00226 }
00227 *type = 0;
00228
00229
00230 ret = cfg_get_token(&t, st, 0);
00231 if (ret < 0) return -1;
00232 if (ret > 0) {
00233 ERR("%s:%d:%d: Syntax error, ':' expected\n", st->file, st->line,
00234 st->col);
00235 return -1;
00236 }
00237
00238 if (t.type != ':') {
00239 ERR("%s:%d:%d: Syntax error, ':' expected\n",
00240 st->file, t.start.line, t.start.col);
00241 return -1;
00242 }
00243
00244 ret = cfg_get_token(&t, st, 0);
00245 if (ret < 0) return -1;
00246 if (ret > 0) {
00247 ERR("%s:%d:%d: Premature end of file, port number missing\n",
00248 st->file, t.start.line, t.start.col);
00249 return -1;
00250 }
00251
00252 if (t.type != CFG_TOKEN_ALPHA || (str2int(&t.val, port) < 0)) {
00253 ERR("%s:%d:%d: Invalid port number '%.*s'\n",
00254 st->file, t.start.line, t.start.col, STR_FMT(&t.val));
00255 return -1;
00256 }
00257 return 0;
00258 }
00259
00260
00261 static int parse_domain(void* param, cfg_parser_t* st, unsigned int flags)
00262 {
00263 cfg_token_t t;
00264 int ret;
00265 cfg_option_t* opt;
00266
00267 int type;
00268 struct ip_addr ip;
00269 unsigned int port;
00270
00271 memset(&ip, 0, sizeof(struct ip_addr));
00272
00273 ret = cfg_get_token(&t, st, 0);
00274 if (ret < 0) return -1;
00275 if (ret > 0) {
00276 ERR("%s:%d:%d: TLS domain type missing\n",
00277 st->file, st->line, st->col);
00278 return -1;
00279 }
00280
00281 if (t.type != CFG_TOKEN_ALPHA ||
00282 ((opt = cfg_lookup_token(domain_types, &t.val)) == NULL)) {
00283 ERR("%s:%d:%d: Invalid TLS domain type %d:'%.*s'\n",
00284 st->file, t.start.line, t.start.col, t.type, STR_FMT(&t.val));
00285 return -1;
00286 }
00287
00288 ret = cfg_get_token(&t, st, 0);
00289 if (ret < 0) return -1;
00290 if (ret > 0) {
00291 ERR("%s:%d:%d: TLS domain IP address missing\n",
00292 st->file, st->line, st->col);
00293 return -1;
00294 }
00295 if (t.type != ':') {
00296 ERR("%s:%d:%d: Syntax error, ':' expected\n",
00297 st->file, t.start.line, t.start.col);
00298 return -1;
00299 }
00300
00301 port = 0;
00302 if (parse_hostport(&type, &ip, &port, &t, st) < 0) return -1;
00303
00304 ret = cfg_get_token(&t, st, 0);
00305 if (ret < 0) return -1;
00306 if (ret > 0) {
00307 ERR("%s:%d:%d: Closing ']' missing\n",
00308 st->file, st->line, st->col);
00309 return -1;
00310 }
00311 if (t.type != ']') {
00312 ERR("%s:%d:%d: Syntax error, ']' expected\n",
00313 st->file, t.start.line, t.start.col);
00314 return -1;
00315 }
00316
00317 if (cfg_eat_eol(st, flags)) return -1;
00318
00319 if ((domain = tls_new_domain(opt->val | type, &ip, port)) == NULL) {
00320 ERR("%s:%d: Cannot create TLS domain structure\n", st->file, st->line);
00321 return -1;
00322 }
00323
00324 ret = tls_add_domain(cfg, domain);
00325 if (ret < 0) {
00326 ERR("%s:%d: Error while creating TLS domain structure\n", st->file,
00327 st->line);
00328 tls_free_domain(domain);
00329 return -1;
00330 } else if (ret == 1) {
00331 ERR("%s:%d: Duplicate TLS domain (appears earlier in the config file)\n",
00332 st->file, st->line);
00333 tls_free_domain(domain);
00334 return -1;
00335 }
00336
00337 update_opt_variables();
00338 cfg_set_options(st, options);
00339 return 0;
00340 }
00341
00342
00343
00344
00345
00346 tls_domains_cfg_t* tls_load_config(str* filename)
00347 {
00348 cfg_parser_t* parser;
00349 str empty;
00350
00351 parser = NULL;
00352 if ((cfg = tls_new_cfg()) == NULL) goto error;
00353
00354 empty.s = 0;
00355 empty.len = 0;
00356 if ((parser = cfg_parser_init(&empty, filename)) == NULL) {
00357 ERR("tls: Error while initializing configuration file parser.\n");
00358 goto error;
00359 }
00360
00361 cfg_section_parser(parser, parse_domain, NULL);
00362
00363 if (sr_cfg_parse(parser)) goto error;
00364 cfg_parser_close(parser);
00365 return cfg;
00366
00367 error:
00368 if (parser) cfg_parser_close(parser);
00369 if (cfg) tls_free_cfg(cfg);
00370 return 0;
00371 }
00372
00373
00374
00375
00376
00377 int tls_parse_method(str* method)
00378 {
00379 cfg_option_t* opt;
00380
00381 if (!method) {
00382 BUG("Invalid parameter value\n");
00383 return -1;
00384 }
00385
00386 opt = cfg_lookup_token(methods, method);
00387 if (!opt) return -1;
00388
00389 return opt->val;
00390 }