--- src/http_auth.h.orig 2010-01-02 17:58:11.000000000 +0100 +++ src/http_auth.h 2010-01-02 17:59:17.000000000 +0100 @@ -14,7 +14,8 @@ AUTH_BACKEND_PLAIN, AUTH_BACKEND_LDAP, AUTH_BACKEND_HTPASSWD, - AUTH_BACKEND_HTDIGEST + AUTH_BACKEND_HTDIGEST, + AUTH_BACKEND_PROGRAM } auth_backend_t; typedef struct { @@ -38,6 +39,8 @@ unsigned short auth_ldap_starttls; unsigned short auth_ldap_allow_empty_pw; + buffer *auth_program_exec; + unsigned short auth_debug; /* generated */ --- src/http_auth.c.orig 2016-07-31 08:42:39.000000000 -0400 +++ src/http_auth.c 2016-07-31 16:24:22.144575820 -0400 @@ -192,7 +192,8 @@ } fclose(fp); - } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) { + } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP || + p->conf.auth_backend == AUTH_BACKEND_PROGRAM) { return 0; } @@ -711,6 +712,57 @@ return 0; #endif + } else if (p->conf.auth_backend == AUTH_BACKEND_PROGRAM) { + buffer *progbuf = p->conf.auth_program_exec; + const char *prog; + FILE *pipe; + int ret; + + /* + * This is tested when loading configuration, + * but better be paranoid. + */ + if(!progbuf || progbuf->used == 0) { + log_error_write(srv, __FILE__, __LINE__, "s", + "Missing 'auth.backend.program.exec' directive"); + return -1; + } + prog = progbuf->ptr; + /* + * Preliminary check, so we can have better error reporting. + * It was tested during configuration reading, but maybe + * something happened to the program since that time. + * + * If someone mess with the program after this test, it + * would simply fail in the popen()/pclose() which we check anyway. + */ + if(access(prog, F_OK | X_OK) < 0) { + log_error_write(srv, __FILE__, __LINE__, "ssss", + "auth.backend.program: Failed access(", + prog, + "): ", + strerror(errno)); + return -1; + } + if((pipe = popen(prog, "w")) == NULL) { + log_error_write(srv, __FILE__, __LINE__, "ssss", + "Failed popen(", + prog, + "): ", + strerror(errno)); + return -1; + } + fprintf(pipe, "%s:%s\n", username->ptr, pw); + if((ret = pclose(pipe)) != 0) { + log_error_write(srv, __FILE__, __LINE__, "sssds", + "Failed pclose(", prog, "):", ret, strerror(errno)); + return -1; + } + if (p->conf.auth_debug) { + log_error_write(srv, __FILE__, __LINE__, "ss", + "auth.backend.program success for: ", username->ptr); + } + return 0; } return -1; } --- src/mod_auth.c.orig 2010-01-02 17:58:11.000000000 +0100 +++ src/mod_auth.c 2010-01-02 18:08:14.000000000 +0100 @@ -82,6 +82,7 @@ if (s->ldap) ldap_unbind_s(s->ldap); #endif + buffer_free(s->auth_program_exec); free(s); } @@ -119,6 +120,7 @@ PATCH(ldap_filter_pre); PATCH(ldap_filter_post); #endif + PATCH(auth_program_exec); /* skip the first, the global context */ for (i = 1; i < srv->config_context->used; i++) { @@ -169,6 +171,8 @@ PATCH(auth_ldap_bindpw); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.allow-empty-pw"))) { PATCH(auth_ldap_allow_empty_pw); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.program.exec"))) { + PATCH(auth_program_exec); } } } @@ -326,7 +330,8 @@ { "auth.backend.ldap.allow-empty-pw", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 11 */ { "auth.backend.htdigest.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 12 */ { "auth.backend.htpasswd.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 13 */ - { "auth.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 14 */ + { "auth.backend.program.exec", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 14 */ + { "auth.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 15 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; @@ -352,6 +357,7 @@ s->auth_ldap_filter = buffer_init(); s->auth_ldap_cafile = buffer_init(); s->auth_ldap_starttls = 0; + s->auth_program_exec = buffer_init(); s->auth_debug = 0; s->auth_require = array_init(); @@ -376,7 +382,8 @@ cv[11].destination = &(s->auth_ldap_allow_empty_pw); cv[12].destination = s->auth_htdigest_userfile; cv[13].destination = s->auth_htpasswd_userfile; - cv[14].destination = &(s->auth_debug); + cv[14].destination = s->auth_program_exec; + cv[15].destination = &(s->auth_debug); p->config_storage[i] = s; ca = ((data_config *)srv->config_context->data[i])->value; @@ -394,6 +401,8 @@ s->auth_backend = AUTH_BACKEND_PLAIN; } else if (0 == strcmp(s->auth_backend_conf->ptr, "ldap")) { s->auth_backend = AUTH_BACKEND_LDAP; + } else if (0 == strcmp(s->auth_backend_conf->ptr, "program")) { + s->auth_backend = AUTH_BACKEND_PROGRAM; } else { log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf); @@ -534,6 +543,28 @@ return (ret); break; } + case AUTH_BACKEND_PROGRAM: { + const char *prog; + /* + * Let's make some sanity checks so we detect them during + * startup and not only when trying to authenticate. + */ + if(!(s->auth_program_exec) || s->auth_program_exec->used == 0) { + log_error_write(srv, __FILE__, __LINE__, "s", + "Missing or empty auth.backend.program.exec"); + return HANDLER_ERROR; + } + prog = s->auth_program_exec->ptr; + if(access(prog, F_OK | X_OK) < 0) { + log_error_write(srv, __FILE__, __LINE__, "ssss", + "auth.backend.program: Failed access(", + prog, + "): ", + strerror(errno)); + return HANDLER_ERROR; + } + break; + } default: break; } .