diff --git a/hitch.conf.man.rst b/hitch.conf.man.rst index 8bb9d6f2..d1496183 100644 --- a/hitch.conf.man.rst +++ b/hitch.conf.man.rst @@ -262,6 +262,18 @@ Default is none (match any). pem-dir-glob = "*.pem" +pem-dir-subdir-glob = +------------------------------ + +Match filter for subdirectories of ``pem-dir`` to load files from. + +Default is none (do not match any subdirectories). + +:: + + pem-dir-subdir-glob = "*" + + prefer-server-ciphers = on|off ------------------------------ diff --git a/src/cfg_lex.l b/src/cfg_lex.l index 8e557fca..5be20d3e 100644 --- a/src/cfg_lex.l +++ b/src/cfg_lex.l @@ -87,6 +87,7 @@ char input_line[512]; "ocsp-dir" { return (TOK_OCSP_DIR); } "pem-dir" { return (TOK_PEM_DIR); } "pem-dir-glob" { return (TOK_PEM_DIR_GLOB); } +"pem-dir-subdir-glob" { return (TOK_PEM_DIR_SUBDIR_GLOB); } "session-cache" { return (TOK_SESSION_CACHE); } "shared-cache-listen" { return (TOK_SHARED_CACHE_LISTEN); } "shared-cache-peer" { return (TOK_SHARED_CACHE_PEER); } diff --git a/src/cfg_parser.y b/src/cfg_parser.y index d02a210a..7bebf996 100644 --- a/src/cfg_parser.y +++ b/src/cfg_parser.y @@ -57,7 +57,7 @@ extern char input_line[512]; %token TOK_TLSv1_3 %token TOK_SESSION_CACHE TOK_SHARED_CACHE_LISTEN TOK_SHARED_CACHE_PEER %token TOK_SHARED_CACHE_IF TOK_PRIVATE_KEY TOK_BACKEND_REFRESH -%token TOK_OCSP_REFRESH_INTERVAL TOK_PEM_DIR TOK_PEM_DIR_GLOB +%token TOK_OCSP_REFRESH_INTERVAL TOK_PEM_DIR TOK_PEM_DIR_GLOB TOK_PEM_DIR_SUBDIR_GLOB %token TOK_LOG_LEVEL TOK_PROXY_TLV %parse-param { hitch_config *cfg } @@ -107,6 +107,7 @@ CFG_RECORD | OCSP_DIR | PEM_DIR | PEM_DIR_GLOB + | PEM_DIR_SUBDIR_GLOB | SESSION_CACHE_REC | SHARED_CACHE_LISTEN_REC | SHARED_CACHE_PEER_REC @@ -148,6 +149,9 @@ FB_REC : FB_HOST | FB_PORT | FB_CERT + | FB_PEM_DIR + | FB_PEM_DIR_GLOB + | FB_PEM_DIR_SUBDIR_GLOB | FB_MATCH_GLOBAL | FB_SNI_NOMATCH_ABORT | FB_TLS @@ -227,6 +231,14 @@ PEM_DIR_GLOB: TOK_PEM_DIR_GLOB '=' STRING }; +PEM_DIR_SUBDIR_GLOB: TOK_PEM_DIR_SUBDIR_GLOB '=' STRING +{ + if ($3) + cfg->PEM_DIR_SUBDIR_GLOB = strdup($3); + else + cfg->PEM_DIR_SUBDIR_GLOB = NULL; +}; + OCSP_DIR: TOK_OCSP_DIR '=' STRING { if ($3) @@ -282,6 +294,36 @@ FB_CERT: TOK_PEM_FILE '=' STRING cur_pem = NULL; }; +FB_PEM_DIR: TOK_PEM_DIR '=' STRING +{ + if ($3) { + size_t l; + l = strlen($3); + cur_fa->pem_dir = malloc(l + 2); + strcpy(cur_fa->pem_dir, $3); + if (cur_fa->pem_dir[l-1] != '/') + strcat(cur_fa->pem_dir, "/"); + } + else + cur_fa->pem_dir = NULL; +}; + +FB_PEM_DIR_GLOB: TOK_PEM_DIR_GLOB '=' STRING +{ + if ($3) + cur_fa->pem_dir_glob = strdup($3); + else + cur_fa->pem_dir_glob = NULL; +}; + +FB_PEM_DIR_SUBDIR_GLOB: TOK_PEM_DIR_SUBDIR_GLOB '=' STRING +{ + if ($3) + cur_fa->pem_dir_subdir_glob = strdup($3); + else + cur_fa->pem_dir_subdir_glob = NULL; +}; + FB_MATCH_GLOBAL: TOK_MATCH_GLOBAL '=' BOOL { cur_fa->match_global_certs = $3; }; FB_SNI_NOMATCH_ABORT:TOK_SNI_NOMATCH_ABORT '=' BOOL diff --git a/src/configuration.c b/src/configuration.c index 539386d4..82958268 100644 --- a/src/configuration.c +++ b/src/configuration.c @@ -139,6 +139,9 @@ front_arg_new(void) ALLOC_OBJ(fa, FRONT_ARG_MAGIC); AN(fa); + fa->pem_dir = NULL; + fa->pem_dir_glob = NULL; + fa->pem_dir_subdir_glob = NULL; fa->match_global_certs = -1; fa->sni_nomatch_abort = -1; fa->selected_protos = 0; @@ -156,6 +159,9 @@ front_arg_destroy(struct front_arg *fa) free(fa->ip); free(fa->port); free(fa->pspec); + free(fa->pem_dir); + free(fa->pem_dir_glob); + free(fa->pem_dir_subdir_glob); free(fa->ciphers); HASH_ITER(hh, fa->certs, cf, cftmp) { CHECK_OBJ_NOTNULL(cf, CFG_CERT_FILE_MAGIC); @@ -202,6 +208,8 @@ config_new(void) r->CERT_FILES = NULL; r->LISTEN_ARGS = NULL; r->PEM_DIR = NULL; + r->PEM_DIR_GLOB = NULL; + r->PEM_DIR_SUBDIR_GLOB = NULL; fa = front_arg_new(); fa->port = strdup("8443"); fa->pspec = strdup("default"); @@ -284,6 +292,7 @@ config_destroy(hitch_config *cfg) free(cfg->ALPN_PROTOS_LV); free(cfg->PEM_DIR); free(cfg->PEM_DIR_GLOB); + free(cfg->PEM_DIR_SUBDIR_GLOB); #ifdef USE_SHARED_CACHE int i; free(cfg->SHCUPD_IP); @@ -743,6 +752,8 @@ check_frontend_uniqueness(struct front_arg *cur_fa, hitch_config *cfg) return(1); } +static int front_scan_pem_dir(struct front_arg *fa); + int front_arg_add(hitch_config *cfg, struct front_arg *fa) { @@ -779,6 +790,11 @@ front_arg_add(hitch_config *cfg, struct front_arg *fa) HASH_ADD_KEYPTR(hh, cfg->LISTEN_ARGS, fa->pspec, strlen(fa->pspec), fa); + if (fa->pem_dir != NULL) { + if (front_scan_pem_dir(fa)) + return (0); + } + if (fa->match_global_certs == -1) { if (HASH_CNT(hh, fa->certs) == 0) fa->match_global_certs = 1; @@ -1117,11 +1133,16 @@ config_disp_log_facility (int facility) } } -int -config_scan_pem_dir(char *pemdir, hitch_config *cfg) +static int +scan_pem_dir(const char *pemdir, \ + const char *dir_glob, \ + const char *subdir_glob, \ + struct cfg_cert_file **cert_files, \ + struct cfg_cert_file **cert_default) { int n, i; struct dirent **d; + int retval = 0; n = scandir(pemdir, &d, NULL, alphasort); if (n < 0) { @@ -1133,8 +1154,21 @@ config_scan_pem_dir(char *pemdir, hitch_config *cfg) struct cfg_cert_file *cert; char fpath[PATH_MAX + NAME_MAX]; - if (cfg->PEM_DIR_GLOB != NULL) { - if (fnmatch(cfg->PEM_DIR_GLOB, d[i]->d_name, 0)) + if (d[i]->d_type == DT_DIR) { + if (subdir_glob != NULL && + strcmp(d[i]->d_name, ".") && \ + strcmp(d[i]->d_name, "..") && \ + fnmatch(subdir_glob, d[i]->d_name, 0) == 0) { + snprintf(fpath, PATH_MAX + NAME_MAX, "%s/%s/", pemdir, d[i]->d_name); + retval = scan_pem_dir(fpath, dir_glob, subdir_glob, cert_files, cert_default); + if (retval != 0) + break; + } + continue; + } + + if (dir_glob != NULL) { + if (fnmatch(dir_glob, d[i]->d_name, 0)) continue; } if (d[i]->d_type != DT_REG) @@ -1150,10 +1184,10 @@ config_scan_pem_dir(char *pemdir, hitch_config *cfg) if (r != 0) { /* If no default has been set, use the first * match according to alphasort */ - if (cfg->CERT_DEFAULT == NULL) - cfg->CERT_DEFAULT = cert; + if ((cert_default != NULL) && (*cert_default == NULL)) + *cert_default = cert; else - cfg_cert_add(cert, &cfg->CERT_FILES); + cfg_cert_add(cert, cert_files); } else { cfg_cert_file_free(&cert); } @@ -1161,9 +1195,30 @@ config_scan_pem_dir(char *pemdir, hitch_config *cfg) } free(d); - return (0); + return(retval); +} + +static int +config_scan_pem_dir(hitch_config *cfg) +{ + return scan_pem_dir(cfg->PEM_DIR, \ + cfg->PEM_DIR_GLOB, \ + cfg->PEM_DIR_SUBDIR_GLOB, \ + &cfg->CERT_FILES, \ + &cfg->CERT_DEFAULT); } +static int +front_scan_pem_dir(struct front_arg *fa) +{ + return scan_pem_dir(fa->pem_dir, \ + fa->pem_dir_glob, \ + fa->pem_dir_subdir_glob, \ + &fa->certs, \ + NULL); +} + + void config_print_usage_fd(char *prog, FILE *out) { @@ -1597,7 +1652,7 @@ CFG_ON('s', CFG_SYSLOG); } if (cfg->PEM_DIR != NULL) { - if (config_scan_pem_dir(cfg->PEM_DIR, cfg)) + if (config_scan_pem_dir(cfg)) return (1); } diff --git a/src/configuration.h b/src/configuration.h index 57f8256b..2964f50c 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -86,6 +86,9 @@ struct front_arg { char *port; struct cfg_cert_file *certs; char *pspec; + char *pem_dir; + char *pem_dir_glob; + char *pem_dir_subdir_glob; int match_global_certs; int sni_nomatch_abort; int prefer_server_ciphers; @@ -148,6 +151,7 @@ struct __hitch_config { int TEST; char *PEM_DIR; char *PEM_DIR_GLOB; + char *PEM_DIR_SUBDIR_GLOB; int OCSP_VFY; char *OCSP_DIR; double OCSP_RESP_TMO;