"Fossies" - the Fresh Open Source Software Archive

Member "Pound-3.0.2/src/config.c" (28 Nov 2021, 34972 Bytes) of package /linux/www/Pound-3.0.2.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "config.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.0e_vs_3.0.1.

    1 /*
    2  * Pound - the reverse-proxy load-balancer
    3  * Copyright (C) 2002-2020 Apsis GmbH
    4  *
    5  * This file is part of Pound.
    6  *
    7  * Pound is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; either version 3 of the License, or
   10  * (at your option) any later version.
   11  *
   12  * Pound is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program.  If not, see <http://www.gnu.org/licenses/> .
   19  *
   20  * Contact information:
   21  * Apsis GmbH
   22  * P.O.Box
   23  * 8707 Uetikon am See
   24  * Switzerland
   25  * EMail: roseg@apsis.ch
   26  */
   27 
   28 #include    "pound.h"
   29 
   30 static UT_array *ut_backends;
   31 static UT_array *ut_http;
   32 
   33 void
   34 fatal(const char *fmt, ...)
   35 {
   36     char    buf[MAXBUF + 1];
   37     va_list ap;
   38 
   39     buf[MAXBUF] = '\0';
   40     va_start(ap, fmt);
   41     vsnprintf(buf, MAXBUF, fmt, ap);
   42     va_end(ap);
   43 
   44     global.log_level = 1;
   45     logmsg(0, buf);
   46     exit(3);
   47 }
   48 
   49 static char *
   50 file2str(const char *fname)
   51 {
   52     char    *res;
   53     struct  stat st;
   54     FILE    *fin;
   55 
   56     if(stat(fname, &st)
   57     || (fin = fopen(fname, "r")) == NULL
   58     || (res = malloc(st.st_size + 1)) == NULL
   59     || fread(res, 1, st.st_size, fin) != st.st_size)
   60         fatal("YAML can't access file %s", fname);
   61     res[st.st_size] = '\0';
   62     fclose(fin);
   63     return res;
   64 }
   65 
   66 static void
   67 get_global(yaml_document_t *document, yaml_node_t *root)
   68 {
   69     yaml_node_pair_t    *cur_pair;
   70     yaml_node_t         *node;
   71     struct passwd       *pwent;
   72     struct group        *grent;
   73 
   74     logmsg(1, "start get_global %s:%d", __FILE__, __LINE__);
   75     for(cur_pair = root->data.mapping.pairs.start; cur_pair < root->data.mapping.pairs.top; cur_pair++)
   76         if(!strcasecmp("User", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
   77             if((pwent = getpwnam(yaml_document_get_node(document, cur_pair->value)->data.scalar.value)) == NULL)
   78                 fatal("User %s not found", yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
   79             global.user = pwent->pw_uid;
   80             logmsg(4, "user %d %s:%d", global.user, __FILE__, __LINE__);
   81         } else if(!strcasecmp("Group", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
   82             if((grent = getgrnam(yaml_document_get_node(document, cur_pair->value)->data.scalar.value)) == NULL)
   83                 fatal("Group %s not found", yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
   84             global.group = grent->gr_gid;
   85             logmsg(4, "group %d %s:%d", global.group, __FILE__, __LINE__);
   86         } else if(!strcasecmp("RootJail", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
   87             if((global.root_jail = strdup(yaml_document_get_node(document, cur_pair->value)->data.scalar.value)) == NULL)
   88                 fatal("Out of memory at %ld", yaml_document_get_node(document, cur_pair->value)->start_mark.line);
   89             logmsg(4, "RootJail %s %s:%d", global.root_jail, __FILE__, __LINE__);
   90         } else if(!strcasecmp("Err404", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
   91             global.err404 = file2str(yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
   92             logmsg(4, "err404 %s %s:%d", global.err404, __FILE__, __LINE__);
   93         } else if(!strcasecmp("Err405", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
   94             global.err405 = file2str(yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
   95             logmsg(4, "err405 %s %s:%d", global.err405, __FILE__, __LINE__);
   96         } else if(!strcasecmp("Err500", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
   97             global.err500 = file2str(yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
   98             logmsg(4, "err500 %s %s:%d", global.err500, __FILE__, __LINE__);
   99         } else
  100             fatal("Unknown directive %s at line %ld", yaml_document_get_node(document, cur_pair->key)->data.scalar.value,
  101                 yaml_document_get_node(document, cur_pair->key)->start_mark.line);
  102 
  103     if(global.err404 == NULL)
  104         global.err404 = "<html><head><title>Not Found</title></head><body><h1>Page not found</h1></body></html>\r\n";
  105     if(global.err405 == NULL)
  106         global.err405 = "<html><head><title>Not Allowed</title></head><body><h1>Method not allowed</h1></body></html>\r\n";
  107     if(global.err500 == NULL)
  108         global.err500 = "<html><head><title>Error</title></head><body><h1>Internal error</h1></body></html>\r\n";
  109 
  110     return;
  111 }
  112 
  113 static void
  114 get_backends(yaml_document_t *document, yaml_node_t *root)
  115 {
  116     yaml_node_pair_t    *cur_pair;
  117     yaml_node_t         *vals;
  118     yaml_node_item_t    *cur;
  119     BACKEND             res;
  120     char                addr[NI_MAXHOST], port[NI_MAXSERV], redirect[NI_MAXHOST];
  121     struct addrinfo     hints;
  122 
  123     logmsg(1, "start get_backends %s:%d", __FILE__, __LINE__);
  124     memset(&hints, '\0', sizeof(hints));
  125     hints.ai_family = AF_UNSPEC;
  126     hints.ai_socktype = SOCK_STREAM;
  127     for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
  128         memset(&res, '\0', sizeof(res));
  129         res.id = *cur;
  130         vals = yaml_document_get_node(document, *cur);
  131         if(vals->type != YAML_MAPPING_NODE)
  132             fatal("Backend at %ld: not a mapping", vals->start_mark.line);
  133         addr[0] = '\0';
  134         port[0] = '\0';
  135         redirect[0] = '\0';
  136         for(cur_pair = vals->data.mapping.pairs.start; cur_pair < vals->data.mapping.pairs.top; cur_pair++)
  137             if(!strcasecmp("Address", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
  138                 strncpy(addr, yaml_document_get_node(document, cur_pair->value)->data.scalar.value, NI_MAXHOST);
  139                 logmsg(4, "addr %s %s:%d", addr, __FILE__, __LINE__);
  140             } else if(!strcasecmp("Port", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
  141                 strncpy(port, yaml_document_get_node(document, cur_pair->value)->data.scalar.value, NI_MAXSERV);
  142                 logmsg(4, "port %s %s:%d", port, __FILE__, __LINE__);
  143             } else if(!strcasecmp("Timeout", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
  144                 res.timeout = atoi(yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
  145                 logmsg(4, "timeout %d %s:%d", res.timeout, __FILE__, __LINE__);
  146             } else if(!strcasecmp("Threads", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
  147                 res.threads = atoi(yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
  148                 logmsg(4, "threads %d %s:%d", res.threads, __FILE__, __LINE__);
  149             } else if(!strcasecmp("HeadAdd", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
  150                 if((res.add_header = strdup(yaml_document_get_node(document, cur_pair->value)->data.scalar.value)) == NULL)
  151                     fatal("HeadAdd out of memory at line %ld", yaml_document_get_node(document, cur_pair->key)->start_mark.line);
  152                 if(strlen(res.add_header) == 0)
  153                     fatal("HeadAdd at line %ld: header may not be empty", yaml_document_get_node(document, cur_pair->key)->start_mark.line);
  154                 logmsg(4, "HeadAdd %s %s:%d", res.add_header, __FILE__, __LINE__);
  155             } else
  156                 fatal("Unknown directive %s at line %ld", yaml_document_get_node(document, cur_pair->key)->data.scalar.value,
  157                     yaml_document_get_node(document, cur_pair->key)->start_mark.line);
  158             
  159         if(addr[0]) {
  160             if(res.threads <= 0)
  161                 res.threads = 8;
  162             if(res.timeout <= 0)
  163                 res.timeout = 15;
  164             if(getaddrinfo(addr, port, &hints, &res.addr))
  165                 fatal("Backend at %ld: unknown server %s:%s", vals->start_mark.line, addr, port);
  166         } else
  167             fatal("Backend at %ld: missing data", vals->start_mark.line);
  168         logmsg(2, "push %s:%d", __FILE__, __LINE__);
  169         utarray_push_back(ut_backends, &res);
  170     }
  171 }
  172 
  173 static UT_array *
  174 get_svc_backends(yaml_document_t *document, yaml_node_t *root)
  175 {
  176     yaml_node_item_t    *cur;
  177     UT_array            *res;
  178     UT_icd backend_icd = {sizeof(BACKEND *), NULL, NULL, NULL };
  179     int                 i;
  180     BACKEND             *be;
  181 
  182     if(root->type != YAML_SEQUENCE_NODE)
  183         fatal("YAML Services not sequence (%ld)", root->start_mark.line);
  184     utarray_new(res, &backend_icd);
  185     for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
  186         for(i = 0; i < backends_len; i++)
  187             if(backends[i].id == *cur) {
  188                 be = &backends[i];
  189                 utarray_push_back(res, &be);
  190                 break;
  191             }
  192     }
  193     return res;
  194 }
  195 
  196 static UT_array *
  197 get_services(yaml_document_t *document, yaml_node_t *root)
  198 {
  199     yaml_node_pair_t    *map_pair;
  200     yaml_node_item_t    *cur;
  201     yaml_node_t         *vals;
  202     UT_array            *res, *bes;
  203     BACKEND             *be;
  204     UT_icd service_icd = {sizeof(SERVICE), NULL, NULL, NULL };
  205     SERVICE             *svc;
  206     int                 i;
  207     char                pat[MAXBUF];
  208 
  209     logmsg(1, "start get_services %s:%d", __FILE__, __LINE__);
  210     if(root->type != YAML_SEQUENCE_NODE)
  211         fatal("YAML Services not sequence (%ld)", root->start_mark.line);
  212     utarray_new(res, &service_icd);
  213     bes = NULL;
  214 
  215     for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
  216         vals = yaml_document_get_node(document, *cur);
  217         if(vals->type != YAML_MAPPING_NODE)
  218             fatal("Service at %ld: not a mapping", vals->start_mark.line);
  219         if((svc = calloc(1, sizeof(SERVICE))) == NULL)
  220             fatal("Service at %ld: out of memory", vals->start_mark.line);
  221         for(map_pair = vals->data.mapping.pairs.start; map_pair < vals->data.mapping.pairs.top; map_pair++) {
  222             if(!strcasecmp("URL", yaml_document_get_node(document, map_pair->key)->data.scalar.value)) {
  223                 if((svc->url = malloc(sizeof(regex_t))) == NULL)
  224                     fatal("Service at %ld: out of memory", vals->start_mark.line);
  225                 snprintf(pat, MAXBUF, "[^ \t]+[ \t]%s[ \t].*", yaml_document_get_node(document, map_pair->value)->data.scalar.value);
  226                 if(regcomp(svc->url, pat, REG_ICASE))
  227                     fatal("Service at %ld: bad URL pattern %s", vals->start_mark.line, pat);
  228                 logmsg(4, "URL %s %s:%d", yaml_document_get_node(document, map_pair->value)->data.scalar.value, __FILE__, __LINE__);
  229             } else if(!strcasecmp("Session", yaml_document_get_node(document, map_pair->key)->data.scalar.value)) {
  230                 svc->session = atoi(yaml_document_get_node(document, map_pair->value)->data.scalar.value);
  231                 logmsg(4, "session %d %s:%d", svc->session, __FILE__, __LINE__);
  232             } else if(!strcasecmp("HeadRequire", yaml_document_get_node(document, map_pair->key)->data.scalar.value)) {
  233                 if((svc->head_require = malloc(sizeof(regex_t))) == NULL)
  234                     fatal("Service at %ld: out of memory", vals->start_mark.line);
  235                 if(regcomp(svc->head_require, yaml_document_get_node(document, map_pair->value)->data.scalar.value, REG_ICASE))
  236                     fatal("Service at %ld: bad HeadRequire pattern %s", vals->start_mark.line, yaml_document_get_node(document, map_pair->value)->data.scalar.value);
  237                 logmsg(4, "HeadRequire %s %s:%d", yaml_document_get_node(document, map_pair->value)->data.scalar.value, __FILE__, __LINE__);
  238             } else if(!strcasecmp("HeadDeny", yaml_document_get_node(document, map_pair->key)->data.scalar.value)) {
  239                 if((svc->head_deny = malloc(sizeof(regex_t))) == NULL)
  240                     fatal("Service at %ld: out of memory", vals->start_mark.line);
  241                 if(regcomp(svc->head_deny, yaml_document_get_node(document, map_pair->value)->data.scalar.value, REG_ICASE))
  242                     fatal("Service at %ld: bad HeadDeny pattern %s", vals->start_mark.line, yaml_document_get_node(document, map_pair->value)->data.scalar.value);
  243                 logmsg(4, "HeadDeny %s %s:%d", yaml_document_get_node(document, map_pair->value)->data.scalar.value, __FILE__, __LINE__);
  244             } else if(!strcasecmp("Backends", yaml_document_get_node(document, map_pair->key)->data.scalar.value)) {
  245                 bes = get_svc_backends(document, yaml_document_get_node(document, map_pair->value));
  246                 if(utarray_len(bes) <= 0)
  247                     fatal("Service at %ld: no backends defined", vals->start_mark.line);
  248                 svc->backends_len = utarray_len(bes);
  249                 if((svc->backends = calloc(svc->backends_len, sizeof(BACKEND *))) == NULL)
  250                     fatal("Service at %ld: out of memory", vals->start_mark.line);
  251                 for(i = 0; i < svc->backends_len; i++)
  252                     svc->backends[i] = *(BACKEND **)utarray_eltptr(bes, i);
  253                 utarray_free(bes);
  254             } else
  255                 fatal("Unknown directive %s at line %ld", yaml_document_get_node(document, map_pair->key)->data.scalar.value,
  256                     yaml_document_get_node(document, map_pair->key)->start_mark.line);
  257         }
  258         logmsg(2, "push %s:%d", __FILE__, __LINE__);
  259         utarray_push_back(res, &svc);
  260     }
  261 
  262     return res;
  263 }
  264 
  265 static void
  266 get_http(yaml_document_t *document, yaml_node_t *root)
  267 {
  268     yaml_node_pair_t    *map_pairs;
  269     yaml_node_item_t    *cur;
  270     yaml_node_t         *vals;
  271     HTTP_LISTENER       res;
  272     char                addr[NI_MAXHOST], port[NI_MAXSERV];
  273     struct addrinfo     hints;
  274     UT_array            *services;
  275     int                 i;
  276 
  277     logmsg(1, "start get_http %s:%d", __FILE__, __LINE__);
  278     memset(&hints, '\0', sizeof(hints));
  279     hints.ai_family = AF_UNSPEC;
  280     hints.ai_socktype = SOCK_STREAM;
  281     memset(&res, '\0', sizeof(res));
  282     for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
  283         vals = yaml_document_get_node(document, *cur);
  284         if(vals->type != YAML_MAPPING_NODE)
  285             fatal("HTTPListener at %ld: not a mapping", vals->start_mark.line);
  286         addr[0] ='\0';
  287         port[0] = '\0';
  288         for(map_pairs = vals->data.mapping.pairs.start; map_pairs < vals->data.mapping.pairs.top; map_pairs++)
  289             if(!strcasecmp("Address", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
  290                 strncpy(addr, yaml_document_get_node(document, map_pairs->value)->data.scalar.value, NI_MAXHOST);
  291                 logmsg(4, "addr %s %s:%d", addr, __FILE__, __LINE__);
  292             } else if(!strcasecmp("Port", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
  293                 strncpy(port, yaml_document_get_node(document, map_pairs->value)->data.scalar.value, NI_MAXSERV);
  294                 logmsg(4, "port %s %s:%d", port, __FILE__, __LINE__);
  295             } else if(!strcasecmp("Client", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
  296                 res.client = atoi(yaml_document_get_node(document, map_pairs->value)->data.scalar.value);
  297                 logmsg(4, "client %d %s:%d", res.client, __FILE__, __LINE__);
  298             } else if(!strcasecmp("Threads", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
  299                 res.threads = atoi(yaml_document_get_node(document, map_pairs->value)->data.scalar.value);
  300                 logmsg(4, "threads %d %s:%d", res.threads, __FILE__, __LINE__);
  301             } else if(!strcasecmp("Services", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
  302                 services = get_services(document, yaml_document_get_node(document, map_pairs->value));
  303             } else
  304                 fatal("Unknown directive %s at line %ld", yaml_document_get_node(document, map_pairs->key)->data.scalar.value,
  305                     yaml_document_get_node(document, map_pairs->key)->start_mark.line);
  306         if(res.threads <= 0)
  307             res.threads = 8;
  308         if(res.client <= 0)
  309             res.client = 5;
  310         if(getaddrinfo(addr, port, &hints, &res.addr))
  311             fatal("HTTPListener at %ld: unknown server %s:%s", vals->start_mark.line, addr, port);
  312         if(utarray_len(services) == 0)
  313             fatal("HTTPListener at %ld: no services defined", vals->start_mark.line);
  314         res.services_len = utarray_len(services);
  315         if((res.services = calloc(res.services_len, sizeof(SERVICE *))) == NULL)
  316             fatal("HTTPListener at %ld: out of memory", vals->start_mark.line);
  317         for(i = 0; i < res.services_len; i++)
  318             res.services[i] = *(SERVICE **)utarray_eltptr(services, i);
  319         utarray_free(services);
  320         logmsg(2, "push %s:%d", __FILE__, __LINE__);
  321         utarray_push_back(ut_http, &res);
  322     }
  323     return;    
  324 }
  325 
  326 static int *
  327 get_ciphers(yaml_document_t *document, yaml_node_t *root)
  328 {
  329     yaml_node_item_t    *cur;
  330     yaml_node_t         *vals;
  331     UT_array    *list;
  332     int         *res, c;
  333 
  334     logmsg(1, "start get_ciphers %s:%d", __FILE__, __LINE__);
  335     utarray_new(list, &ut_int_icd);
  336     if(root->type == YAML_SCALAR_NODE) {
  337         logmsg(4, "cipher %s %s:%d", root->data.scalar.value, __FILE__, __LINE__);
  338         if((c = mbedtls_ssl_get_ciphersuite_id(root->data.scalar.value)) <= 0)
  339             fatal("Unknown cipher %s", root->data.scalar.value);
  340         utarray_push_back(list, &c);
  341     } else if(root->type == YAML_SEQUENCE_NODE) {
  342         for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
  343             vals = yaml_document_get_node(document, *cur);
  344             if(vals->type != YAML_SCALAR_NODE)
  345                 fatal("Ciphers at %ld: not a sequence", vals->start_mark.line);
  346             logmsg(4, "cipher %s %s:%d", vals->data.scalar.value, __FILE__, __LINE__);
  347             if((c = mbedtls_ssl_get_ciphersuite_id(vals->data.scalar.value)) <= 0)
  348                 fatal("Unknown cipher %s", vals->data.scalar.value);
  349             utarray_push_back(list, &c);
  350         }
  351     } else
  352         fatal("Syntax error at line %ld", root->start_mark.line);
  353     if((res = calloc(utarray_len(list) + 1, sizeof(int))) == NULL)
  354         fatal("Ciphers at %ld: out of memory", root->start_mark.line);
  355     for(c = 0; c < utarray_len(list); c++)
  356         res[c] = *((int *)utarray_eltptr(list, c));
  357     res[utarray_len(list)] = 0;
  358     utarray_free(list);
  359     return res;
  360 }
  361 
  362 static SNI *
  363 get_one(char *filename)
  364 {
  365     SNI         *res;
  366     mbedtls_x509_crt    *cur;
  367     mbedtls_x509_name   *nd;
  368     mbedtls_asn1_buf    data;
  369     mbedtls_x509_sequence   *san;
  370     regex_t     *one_host;
  371     UT_array    *hosts;
  372     UT_icd      regex_icd = {sizeof(regex_t), NULL, NULL, NULL};
  373     char        buf[NI_MAXHOST];
  374     int         i, j;
  375 
  376     logmsg(1, "start get_one(%s) %s:%d", filename, __FILE__, __LINE__);
  377     if((res = malloc(sizeof(SNI))) == NULL)
  378         fatal("SNI: out of memory");
  379     mbedtls_x509_crt_init(&res->certificate);
  380     if(mbedtls_x509_crt_parse_file(&res->certificate, filename))
  381         fatal("SNI: can't read certificate %s", filename);
  382     mbedtls_pk_init(&res->key);
  383     if(mbedtls_pk_parse_keyfile(&res->key, filename, NULL))
  384         fatal("SNI: can't read key %s", filename);
  385     utarray_new(hosts, &regex_icd);
  386     for(cur = &res->certificate; cur != NULL; cur = cur->next) {
  387         if(mbedtls_pk_check_pair(&cur->pk, &res->key))
  388             continue;
  389         for(nd = &cur->subject; nd != NULL; nd = nd->next)
  390             if(MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &nd->oid) == 0) {
  391                 data = nd->val;
  392                 memset(buf, '\0', NI_MAXHOST);
  393                 for(i = j = 0; i < data.len; i++)
  394                     if(data.p[i] == '*') {
  395                         buf[j++] = '[';
  396                         buf[j++] = '^';
  397                         buf[j++] = '.';
  398                         buf[j++] = ']';
  399                         buf[j++] = '+';
  400                     } else if(data.p[i] == '.') {
  401                         buf[j++] = '\\';
  402                         buf[j++] = '.';
  403                     } else
  404                         buf[j++] = data.p[i];
  405                 buf[j] = '\0';
  406                 logmsg(4, "get_one add pattern %s %s:%d", buf, __FILE__, __LINE__);
  407                 if((one_host = (regex_t *)malloc(sizeof(regex_t))) == NULL)
  408                     fatal("Can't alloc regex for %s",buf);
  409                 if(regcomp(one_host, buf, REG_ICASE | REG_EXTENDED))
  410                     fatal("Certificate in %s: bad host name pattern %s",filename, buf);
  411                 utarray_push_back(hosts, one_host);
  412             }
  413 
  414         for(san = &cur->subject_alt_names; san != NULL; san = san->next)
  415             if(san->buf.tag == 130) {
  416                 /* 130 seems to be the OID for DNS entries */
  417                 data = san->buf;
  418                 memset(buf, '\0', NI_MAXHOST);
  419                 for(i = j = 0; i < data.len; i++)
  420                     if(data.p[i] == '*') {
  421                         buf[j++] = '[';
  422                         buf[j++] = '^';
  423                         buf[j++] = '.';
  424                         buf[j++] = ']';
  425                         buf[j++] = '+';
  426                     } else if(data.p[i] == '.') {
  427                         buf[j++] = '\\';
  428                         buf[j++] = '.';
  429                     } else
  430                         buf[j++] = data.p[i];
  431                 buf[j] = '\0';
  432                 logmsg(4, "get_one add pattern %s %s:%d", buf, __FILE__, __LINE__);
  433                 if((one_host = (regex_t *)malloc(sizeof(regex_t))) == NULL)
  434                     fatal("Can't alloc regex for %s",buf);
  435                 if(regcomp(one_host, buf, REG_ICASE | REG_EXTENDED))
  436                     fatal("Certificate in %s: bad host name pattern %s",filename, buf);
  437                 utarray_push_back(hosts, one_host);
  438             }
  439         if((res->host = calloc(utarray_len(hosts), sizeof(regex_t))) == NULL)
  440             fatal("SNI: out of memory");
  441         res->host_len = utarray_len(hosts);
  442         for(i = 0; i < res->host_len; i++)
  443             res->host[i] = *((regex_t *)utarray_eltptr(hosts, i));
  444         utarray_free(hosts);
  445     }
  446     logmsg(4, "get_one: added %d patterns %s:%d", res->host_len, __FILE__, __LINE__);
  447     return res;
  448 }
  449 
  450 static SNI **
  451 get_certificates(yaml_document_t *document, yaml_node_t *root)
  452 {
  453     yaml_node_item_t    *cur;
  454     yaml_node_t         *vals;
  455     UT_array            *list;
  456     UT_icd              ut_sni_icd = {sizeof(SNI *), NULL, NULL, NULL};
  457     SNI                 **res;
  458     int                 i;
  459     SNI                 *sni;
  460     
  461     logmsg(1, "start get_certificates %s:%d", __FILE__, __LINE__);
  462     utarray_new(list, &ut_sni_icd);
  463     if(root->type == YAML_SCALAR_NODE) {
  464         sni = get_one(root->data.scalar.value);
  465         utarray_push_back(list, &sni);
  466     } else if(root->type == YAML_SEQUENCE_NODE) {
  467         for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
  468             vals = yaml_document_get_node(document, *cur);
  469             if(vals->type != YAML_SCALAR_NODE)
  470                 fatal("Certificates at %ld: not a file name", vals->start_mark.line);
  471             sni = get_one(vals->data.scalar.value);
  472             utarray_push_back(list, &sni);
  473         }
  474     } else
  475         fatal("Syntax error at line %ld", root->start_mark.line);
  476     if((res = calloc(utarray_len(list) + 1, sizeof(SNI *))) == NULL)
  477         fatal("SNI at %ld: out of memory", root->start_mark.line);
  478     for(i = 0; i < utarray_len(list); i++)
  479         res[i] = *(SNI **)utarray_eltptr(list, i);
  480     res[utarray_len(list)] = NULL;
  481     utarray_free(list);
  482     return res;
  483 }
  484 
  485 const static char *alpn_protocols[] = { "h2", "http/1.1", NULL};
  486 
  487 static void
  488 get_https(yaml_document_t *document, yaml_node_t *root)
  489 {
  490     yaml_node_pair_t    *map_pairs;
  491     yaml_node_item_t    *cur;
  492     yaml_node_t         *vals;
  493     HTTP_LISTENER       res;
  494     char                addr[NI_MAXHOST], port[NI_MAXSERV];
  495     struct addrinfo     hints;
  496     UT_array            *services;
  497     int                 i, *ciphers;
  498 
  499     logmsg(1, "start get_https %s:%d", __FILE__, __LINE__);
  500     memset(&hints, '\0', sizeof(hints));
  501     hints.ai_family = AF_UNSPEC;
  502     hints.ai_socktype = SOCK_STREAM;
  503     memset(&res, '\0', sizeof(res));
  504     if((res.conf = malloc(sizeof(mbedtls_ssl_config))) == NULL)
  505         fatal("HTTPSListener: out of memory");
  506     mbedtls_ssl_config_init(res.conf);
  507     mbedtls_ssl_conf_rng(res.conf, mbedtls_ctr_drbg_random, &tls_ctr_drbg);
  508     mbedtls_ssl_config_defaults(res.conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
  509     mbedtls_ssl_conf_alpn_protocols(res.conf, alpn_protocols);
  510     mbedtls_ssl_conf_authmode(res.conf, MBEDTLS_SSL_VERIFY_NONE);
  511     for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
  512         vals = yaml_document_get_node(document, *cur);
  513         if(vals->type != YAML_MAPPING_NODE)
  514             fatal("HTTPSListener at %ld: not a mapping", vals->start_mark.line);
  515         addr[0] = '\0';
  516         port[0] = '\0';
  517         for(map_pairs = vals->data.mapping.pairs.start; map_pairs < vals->data.mapping.pairs.top; map_pairs++)
  518             if(!strcasecmp("Address", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
  519                 strncpy(addr, yaml_document_get_node(document, map_pairs->value)->data.scalar.value, NI_MAXHOST);
  520                 logmsg(4, "address %s %s:%d", addr, __FILE__, __LINE__);
  521             } else if(!strcasecmp("Port", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
  522                 strncpy(port, yaml_document_get_node(document, map_pairs->value)->data.scalar.value, NI_MAXSERV);
  523                 logmsg(4, "port %s %s:%d", port, __FILE__, __LINE__);
  524             } else if(!strcasecmp("Client", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
  525                 res.client = atoi(yaml_document_get_node(document, map_pairs->value)->data.scalar.value);
  526                 logmsg(4, "client %d %s:%d", res.client, __FILE__, __LINE__);
  527             } else if(!strcasecmp("Threads", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
  528                 res.threads = atoi(yaml_document_get_node(document, map_pairs->value)->data.scalar.value);
  529                 logmsg(4, "threads %d %s:%d", res.threads, __FILE__, __LINE__);
  530             } else if(!strcasecmp("Services", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
  531                 services = get_services(document, yaml_document_get_node(document, map_pairs->value));
  532             } else if(!strcasecmp("Certificates", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
  533                 res.sni = get_certificates(document, yaml_document_get_node(document, map_pairs->value));
  534             } else if(!strcasecmp("Ciphers", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
  535                 ciphers = get_ciphers(document, yaml_document_get_node(document, map_pairs->value));
  536             } else
  537                 fatal("Unknown directive %s at line %ld", yaml_document_get_node(document, map_pairs->key)->data.scalar.value,
  538                     yaml_document_get_node(document, map_pairs->key)->start_mark.line);
  539         if(res.threads <= 0)
  540             res.threads = 8;
  541         if(res.client <= 0)
  542             res.client = 5;
  543         if(getaddrinfo(addr, port, &hints, &res.addr))
  544             fatal("HTTPSListener at %ld: unknown server %s:%s", vals->start_mark.line, addr, port);
  545         if(utarray_len(services) == 0)
  546             fatal("HTTPSListener at %ld: no services defined", vals->start_mark.line);
  547         res.services_len = utarray_len(services);
  548         if((res.services = calloc(res.services_len, sizeof(SERVICE *))) == NULL)
  549             fatal("HTTPSListener at %ld: out of memory", vals->start_mark.line);
  550         for(i = 0; i < res.services_len; i++)
  551             res.services[i] = *(SERVICE **)utarray_eltptr(services, i);
  552         utarray_free(services);
  553         if(ciphers != NULL)
  554             mbedtls_ssl_conf_ciphersuites(res.conf, ciphers);
  555         if(res.sni == NULL)
  556             fatal("HTTPSListener at %ld: no certificates defined", vals->start_mark.line);
  557         mbedtls_ssl_conf_sni(res.conf, do_sni, res.sni);
  558         mbedtls_ssl_conf_own_cert(res.conf, &res.sni[0]->certificate, &res.sni[0]->key);
  559         if(res.sni[0]->certificate.next != NULL)
  560             mbedtls_ssl_conf_ca_chain(res.conf, res.sni[0]->certificate.next, NULL );
  561         mbedtls_ssl_conf_read_timeout(res.conf, (uint32_t)res.client * 1000);
  562         logmsg(2, "push %s:%d", __FILE__, __LINE__);
  563         utarray_push_back(ut_http, &res);
  564     }
  565     return;    
  566 }
  567 
  568 static void
  569 get_others(yaml_document_t *document, yaml_node_t *root)
  570 {
  571     yaml_node_pair_t    *cur_pair;
  572     yaml_node_t         *node;
  573 
  574     logmsg(1, "start get_others %s:%d", __FILE__, __LINE__);
  575     if(root->type != YAML_MAPPING_NODE)
  576         fatal("YAML root not mapping (%ld)", root->start_mark.line);
  577 
  578     for(cur_pair = root->data.mapping.pairs.start; cur_pair < root->data.mapping.pairs.top; cur_pair++) {
  579         node = yaml_document_get_node(document, cur_pair->key);
  580         if(node->type != YAML_SCALAR_NODE)
  581             fatal("YAML key not scalar (%ld)", node->start_mark.line);
  582         if(strcasecmp("Global", node->data.scalar.value)
  583         && strcasecmp("Backends", node->data.scalar.value)
  584         && strcasecmp("HTTPListeners", node->data.scalar.value)
  585         && strcasecmp("HTTPSListeners", node->data.scalar.value))
  586             fatal("YAML unknown directive %s (%ld)", node->data.scalar.value, node->start_mark.line);
  587     }
  588 
  589     return;
  590 }
  591 
  592 static yaml_node_t *
  593 get_base(yaml_document_t *document, yaml_node_t *root, char *key, int type)
  594 {
  595     yaml_node_pair_t    *cur_pair;
  596     yaml_node_t         *node;
  597 
  598     for(cur_pair = root->data.mapping.pairs.start; cur_pair < root->data.mapping.pairs.top; cur_pair++) {
  599         node = yaml_document_get_node(document, cur_pair->key);
  600         if(!strcasecmp(key, node->data.scalar.value)) {
  601             node = yaml_document_get_node(document, cur_pair->value);
  602             if(node->type != type)
  603                 return NULL;
  604             return node;
  605         }
  606     }
  607     return NULL;
  608 }
  609 void
  610 config(const int argc, char **argv)
  611 {
  612     int                 c_opt, o_check = 0, o_version = 0, is_key, i;
  613     char                *f_conf = F_CONF;
  614     FILE                *f_in;
  615     yaml_parser_t       parser;
  616     yaml_document_t     document;
  617     yaml_node_t         *root, *sub;
  618     UT_icd backend_icd = {sizeof(BACKEND), NULL, NULL, NULL };
  619     BACKEND             *be;
  620     UT_icd http_icd = {sizeof(HTTP_LISTENER), NULL, NULL, NULL };
  621     HTTP_LISTENER       *http;
  622 
  623     memset(&global, '\0', sizeof(global));
  624     opterr = 0;
  625     global.pid = "/var/run/pound.pid";
  626     global.log_level = 0;
  627     while((c_opt = getopt(argc, argv, "f:cvd:p:")) > 0)
  628         switch(c_opt) {
  629         case 'f':
  630             /* configuration file specified on the commend line */
  631             f_conf = optarg;
  632             logmsg(4, "config file option %s %s:%d", f_conf, __FILE__, __LINE__);
  633             break;
  634         case 'p':
  635             /* configuration file specified on the commend line */
  636             global.pid = optarg;
  637             logmsg(4, "pid file option %s %s:%d", global.pid, __FILE__, __LINE__);
  638             break;
  639         case 'd':
  640             /* debug mode: run in foreground, messages to stdout */
  641             global.log_level = atoi(optarg);
  642             logmsg(4, "debug option %d %s:%d", global.log_level, __FILE__, __LINE__);
  643             break;
  644         case 'c':
  645             /* check only: parse configuration and exit */
  646             o_check = 1;
  647             break;
  648         case 'v':
  649             /* print version and exit */
  650             o_version = 1;
  651             break;
  652         default:
  653             global.log_level = 1;
  654             logmsg(0, "Unknown flag %c", c_opt);
  655             exit(1);
  656         }
  657     if(o_version) {
  658         global.log_level = 1;
  659         logmsg(0, "Pound version %s", VERSION);
  660         exit(0);
  661     }
  662 
  663     if((f_in = fopen(f_conf, "r")) == NULL)
  664         fatal("File %s not found", f_conf);
  665     if(!yaml_parser_initialize(&parser))
  666         fatal("Cannot initialise parser");
  667     yaml_parser_set_input_file(&parser, f_in);
  668 
  669     if(!yaml_parser_load(&parser, &document))
  670         fatal("Can't load configuration - YAML error \"%s\" at line %ld", parser.problem, parser.problem_mark.line);
  671     yaml_parser_delete(&parser);
  672     fclose(f_in);
  673 
  674     if((root = yaml_document_get_root_node(&document)) == NULL)
  675         fatal("YAML can't get root");
  676 
  677     utarray_new(ut_backends, &backend_icd);
  678     utarray_new(ut_http, &http_icd);
  679 
  680     get_others(&document, root);
  681     if((sub = get_base(&document, root, "Global", YAML_MAPPING_NODE)) != NULL)
  682         get_global(&document, sub);
  683     if((sub = get_base(&document, root, "Backends", YAML_SEQUENCE_NODE)) == NULL)
  684         fatal("Missing Backends section");
  685     get_backends(&document, sub);
  686 
  687     backends_len = utarray_len(ut_backends);
  688     if(backends_len == 0)
  689         fatal("No backends defined");
  690     if((backends = calloc(backends_len, sizeof(BACKEND))) == NULL)
  691         fatal("Backends: out of memory");
  692     for(i = 0, be = utarray_front(ut_backends); be != NULL; i++, be = utarray_next(ut_backends, be))
  693         memcpy(&backends[i], be, sizeof(BACKEND));
  694     utarray_free(ut_backends);
  695 
  696     if(get_base(&document, root, "HTTPListeners", YAML_SCALAR_NODE) == NULL) {
  697         if((sub = get_base(&document, root, "HTTPListeners", YAML_SEQUENCE_NODE)) == NULL)
  698             fatal("Missing HTTPListeners section");
  699         get_http(&document, sub);
  700     }
  701     if(get_base(&document, root, "HTTPSListeners", YAML_SCALAR_NODE) == NULL) {
  702         if((sub = get_base(&document, root, "HTTPSListeners", YAML_SEQUENCE_NODE)) == NULL)
  703             fatal("Missing HTTPSListeners section");
  704         get_https(&document, sub);
  705     }
  706 
  707     http_len = utarray_len(ut_http);
  708     if(http_len > 0) {
  709         if((http_listeners = calloc(http_len, sizeof(HTTP_LISTENER))) == NULL)
  710             fatal("Listeners: out of memory");
  711         for(i = 0, http = utarray_front(ut_http); http != NULL; i++, http = utarray_next(ut_http, http))
  712             memcpy(&http_listeners[i], http, sizeof(HTTP_LISTENER));
  713     }
  714     utarray_free(ut_http);
  715 
  716     if(http_len == 0)
  717         fatal("No listeners defined");
  718 
  719     yaml_document_delete(&document);
  720     if(o_check)
  721         exit(0);
  722     return;
  723 }