tls_config.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * TLS module - Configuration file parser
00005  *
00006  * Copyright (C) 2001-2003 FhG FOKUS
00007  * Copyright (C) 2004,2005 Free Software Foundation, Inc.
00008  * Copyright (C) 2005,2006 iptelorg GmbH
00009  *
00010  * This file is part of SIP-router, a free SIP server.
00011  *
00012  * SIP-router is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 2 of the License, or
00015  * (at your option) any later version
00016  *
00017  * SIP-router is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  * GNU General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with this program; if not, write to the Free Software
00024  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 /* USE_IPV6 */
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 /* USE_IPV6 */
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                              /* Default domain */
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              /* Parse port */
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  * Create configuration structures from configuration file
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  * Convert TLS method string to integer
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 }