1*bcdc6a3bSJan Kneschke #include <sys/types.h> 2*bcdc6a3bSJan Kneschke #include <sys/stat.h> 3*bcdc6a3bSJan Kneschke 4*bcdc6a3bSJan Kneschke #include <stdlib.h> 5*bcdc6a3bSJan Kneschke #include <string.h> 6*bcdc6a3bSJan Kneschke #include <errno.h> 7*bcdc6a3bSJan Kneschke #include <fcntl.h> 8*bcdc6a3bSJan Kneschke #include <unistd.h> 9*bcdc6a3bSJan Kneschke 10*bcdc6a3bSJan Kneschke #include "plugin.h" 11*bcdc6a3bSJan Kneschke #include "http_auth.h" 12*bcdc6a3bSJan Kneschke #include "log.h" 13*bcdc6a3bSJan Kneschke #include "response.h" 14*bcdc6a3bSJan Kneschke 15*bcdc6a3bSJan Kneschke 16*bcdc6a3bSJan Kneschke /** 17*bcdc6a3bSJan Kneschke * the basic and digest auth framework 18*bcdc6a3bSJan Kneschke * 19*bcdc6a3bSJan Kneschke * - config handling 20*bcdc6a3bSJan Kneschke * - protocol handling 21*bcdc6a3bSJan Kneschke * 22*bcdc6a3bSJan Kneschke * http_auth.c 23*bcdc6a3bSJan Kneschke * http_auth_digest.c 24*bcdc6a3bSJan Kneschke * 25*bcdc6a3bSJan Kneschke * do the real work 26*bcdc6a3bSJan Kneschke */ 27*bcdc6a3bSJan Kneschke 28*bcdc6a3bSJan Kneschke INIT_FUNC(mod_auth_init) { 29*bcdc6a3bSJan Kneschke mod_auth_plugin_data *p; 30*bcdc6a3bSJan Kneschke 31*bcdc6a3bSJan Kneschke p = calloc(1, sizeof(*p)); 32*bcdc6a3bSJan Kneschke 33*bcdc6a3bSJan Kneschke p->tmp_buf = buffer_init(); 34*bcdc6a3bSJan Kneschke 35*bcdc6a3bSJan Kneschke p->auth_user = buffer_init(); 36*bcdc6a3bSJan Kneschke #ifdef USE_LDAP 37*bcdc6a3bSJan Kneschke p->ldap_filter = buffer_init(); 38*bcdc6a3bSJan Kneschke #endif 39*bcdc6a3bSJan Kneschke 40*bcdc6a3bSJan Kneschke return p; 41*bcdc6a3bSJan Kneschke } 42*bcdc6a3bSJan Kneschke 43*bcdc6a3bSJan Kneschke FREE_FUNC(mod_auth_free) { 44*bcdc6a3bSJan Kneschke mod_auth_plugin_data *p = p_d; 45*bcdc6a3bSJan Kneschke 46*bcdc6a3bSJan Kneschke UNUSED(srv); 47*bcdc6a3bSJan Kneschke 48*bcdc6a3bSJan Kneschke if (!p) return HANDLER_GO_ON; 49*bcdc6a3bSJan Kneschke 50*bcdc6a3bSJan Kneschke buffer_free(p->tmp_buf); 51*bcdc6a3bSJan Kneschke buffer_free(p->auth_user); 52*bcdc6a3bSJan Kneschke #ifdef USE_LDAP 53*bcdc6a3bSJan Kneschke buffer_free(p->ldap_filter); 54*bcdc6a3bSJan Kneschke #endif 55*bcdc6a3bSJan Kneschke 56*bcdc6a3bSJan Kneschke if (p->config_storage) { 57*bcdc6a3bSJan Kneschke size_t i; 58*bcdc6a3bSJan Kneschke for (i = 0; i < srv->config_context->used; i++) { 59*bcdc6a3bSJan Kneschke mod_auth_plugin_config *s = p->config_storage[i]; 60*bcdc6a3bSJan Kneschke 61*bcdc6a3bSJan Kneschke array_free(s->auth_require); 62*bcdc6a3bSJan Kneschke buffer_free(s->auth_plain_groupfile); 63*bcdc6a3bSJan Kneschke buffer_free(s->auth_plain_userfile); 64*bcdc6a3bSJan Kneschke buffer_free(s->auth_htdigest_userfile); 65*bcdc6a3bSJan Kneschke buffer_free(s->auth_htpasswd_userfile); 66*bcdc6a3bSJan Kneschke buffer_free(s->auth_backend_conf); 67*bcdc6a3bSJan Kneschke 68*bcdc6a3bSJan Kneschke buffer_free(s->auth_ldap_hostname); 69*bcdc6a3bSJan Kneschke buffer_free(s->auth_ldap_basedn); 70*bcdc6a3bSJan Kneschke buffer_free(s->auth_ldap_filter); 71*bcdc6a3bSJan Kneschke 72*bcdc6a3bSJan Kneschke #ifdef USE_LDAP 73*bcdc6a3bSJan Kneschke buffer_free(s->ldap_filter_pre); 74*bcdc6a3bSJan Kneschke buffer_free(s->ldap_filter_post); 75*bcdc6a3bSJan Kneschke 76*bcdc6a3bSJan Kneschke if (s->ldap) ldap_unbind_s(s->ldap); 77*bcdc6a3bSJan Kneschke #endif 78*bcdc6a3bSJan Kneschke 79*bcdc6a3bSJan Kneschke free(s); 80*bcdc6a3bSJan Kneschke } 81*bcdc6a3bSJan Kneschke free(p->config_storage); 82*bcdc6a3bSJan Kneschke } 83*bcdc6a3bSJan Kneschke 84*bcdc6a3bSJan Kneschke free(p); 85*bcdc6a3bSJan Kneschke 86*bcdc6a3bSJan Kneschke return HANDLER_GO_ON; 87*bcdc6a3bSJan Kneschke } 88*bcdc6a3bSJan Kneschke 89*bcdc6a3bSJan Kneschke #define PATCH(x) \ 90*bcdc6a3bSJan Kneschke p->conf.x = s->x; 91*bcdc6a3bSJan Kneschke static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plugin_data *p, const char *stage, size_t stage_len) { 92*bcdc6a3bSJan Kneschke size_t i, j; 93*bcdc6a3bSJan Kneschke 94*bcdc6a3bSJan Kneschke /* skip the first, the global context */ 95*bcdc6a3bSJan Kneschke for (i = 1; i < srv->config_context->used; i++) { 96*bcdc6a3bSJan Kneschke data_config *dc = (data_config *)srv->config_context->data[i]; 97*bcdc6a3bSJan Kneschke mod_auth_plugin_config *s = p->config_storage[i]; 98*bcdc6a3bSJan Kneschke 99*bcdc6a3bSJan Kneschke /* not our stage */ 100*bcdc6a3bSJan Kneschke if (!buffer_is_equal_string(dc->comp_key, stage, stage_len)) continue; 101*bcdc6a3bSJan Kneschke 102*bcdc6a3bSJan Kneschke /* condition didn't match */ 103*bcdc6a3bSJan Kneschke if (!config_check_cond(srv, con, dc)) continue; 104*bcdc6a3bSJan Kneschke 105*bcdc6a3bSJan Kneschke /* merge config */ 106*bcdc6a3bSJan Kneschke for (j = 0; j < dc->value->used; j++) { 107*bcdc6a3bSJan Kneschke data_unset *du = dc->value->data[j]; 108*bcdc6a3bSJan Kneschke 109*bcdc6a3bSJan Kneschke if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) { 110*bcdc6a3bSJan Kneschke PATCH(auth_backend); 111*bcdc6a3bSJan Kneschke } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) { 112*bcdc6a3bSJan Kneschke PATCH(auth_plain_groupfile); 113*bcdc6a3bSJan Kneschke } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) { 114*bcdc6a3bSJan Kneschke PATCH(auth_plain_userfile); 115*bcdc6a3bSJan Kneschke } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) { 116*bcdc6a3bSJan Kneschke PATCH(auth_htdigest_userfile); 117*bcdc6a3bSJan Kneschke } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) { 118*bcdc6a3bSJan Kneschke PATCH(auth_htpasswd_userfile); 119*bcdc6a3bSJan Kneschke } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.require"))) { 120*bcdc6a3bSJan Kneschke PATCH(auth_require); 121*bcdc6a3bSJan Kneschke } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.debug"))) { 122*bcdc6a3bSJan Kneschke PATCH(auth_debug); 123*bcdc6a3bSJan Kneschke } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) { 124*bcdc6a3bSJan Kneschke PATCH(auth_ldap_hostname); 125*bcdc6a3bSJan Kneschke #ifdef USE_LDAP 126*bcdc6a3bSJan Kneschke PATCH(ldap); 127*bcdc6a3bSJan Kneschke PATCH(ldap_filter_pre); 128*bcdc6a3bSJan Kneschke PATCH(ldap_filter_post); 129*bcdc6a3bSJan Kneschke #endif 130*bcdc6a3bSJan Kneschke } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) { 131*bcdc6a3bSJan Kneschke PATCH(auth_ldap_basedn); 132*bcdc6a3bSJan Kneschke } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) { 133*bcdc6a3bSJan Kneschke PATCH(auth_ldap_filter); 134*bcdc6a3bSJan Kneschke } 135*bcdc6a3bSJan Kneschke } 136*bcdc6a3bSJan Kneschke } 137*bcdc6a3bSJan Kneschke 138*bcdc6a3bSJan Kneschke return 0; 139*bcdc6a3bSJan Kneschke } 140*bcdc6a3bSJan Kneschke 141*bcdc6a3bSJan Kneschke static int mod_auth_setup_connection(server *srv, connection *con, mod_auth_plugin_data *p) { 142*bcdc6a3bSJan Kneschke mod_auth_plugin_config *s = p->config_storage[0]; 143*bcdc6a3bSJan Kneschke UNUSED(srv); 144*bcdc6a3bSJan Kneschke UNUSED(con); 145*bcdc6a3bSJan Kneschke 146*bcdc6a3bSJan Kneschke PATCH(auth_backend); 147*bcdc6a3bSJan Kneschke PATCH(auth_plain_groupfile); 148*bcdc6a3bSJan Kneschke PATCH(auth_plain_userfile); 149*bcdc6a3bSJan Kneschke PATCH(auth_htdigest_userfile); 150*bcdc6a3bSJan Kneschke PATCH(auth_htpasswd_userfile); 151*bcdc6a3bSJan Kneschke PATCH(auth_require); 152*bcdc6a3bSJan Kneschke PATCH(auth_debug); 153*bcdc6a3bSJan Kneschke PATCH(auth_ldap_hostname); 154*bcdc6a3bSJan Kneschke PATCH(auth_ldap_basedn); 155*bcdc6a3bSJan Kneschke PATCH(auth_ldap_filter); 156*bcdc6a3bSJan Kneschke #ifdef USE_LDAP 157*bcdc6a3bSJan Kneschke PATCH(ldap); 158*bcdc6a3bSJan Kneschke PATCH(ldap_filter_pre); 159*bcdc6a3bSJan Kneschke PATCH(ldap_filter_post); 160*bcdc6a3bSJan Kneschke #endif 161*bcdc6a3bSJan Kneschke 162*bcdc6a3bSJan Kneschke return 0; 163*bcdc6a3bSJan Kneschke } 164*bcdc6a3bSJan Kneschke #undef PATCH 165*bcdc6a3bSJan Kneschke 166*bcdc6a3bSJan Kneschke static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) { 167*bcdc6a3bSJan Kneschke size_t k; 168*bcdc6a3bSJan Kneschke int auth_required = 0, auth_satisfied = 0; 169*bcdc6a3bSJan Kneschke char *http_authorization = NULL; 170*bcdc6a3bSJan Kneschke data_string *ds; 171*bcdc6a3bSJan Kneschke mod_auth_plugin_data *p = p_d; 172*bcdc6a3bSJan Kneschke array *req; 173*bcdc6a3bSJan Kneschke size_t i; 174*bcdc6a3bSJan Kneschke 175*bcdc6a3bSJan Kneschke /* select the right config */ 176*bcdc6a3bSJan Kneschke mod_auth_setup_connection(srv, con, p); 177*bcdc6a3bSJan Kneschke for (i = 0; i < srv->config_patches->used; i++) { 178*bcdc6a3bSJan Kneschke buffer *patch = srv->config_patches->ptr[i]; 179*bcdc6a3bSJan Kneschke 180*bcdc6a3bSJan Kneschke mod_auth_patch_connection(srv, con, p, CONST_BUF_LEN(patch)); 181*bcdc6a3bSJan Kneschke } 182*bcdc6a3bSJan Kneschke 183*bcdc6a3bSJan Kneschke if (p->conf.auth_require == NULL) return HANDLER_GO_ON; 184*bcdc6a3bSJan Kneschke 185*bcdc6a3bSJan Kneschke /* 186*bcdc6a3bSJan Kneschke * AUTH 187*bcdc6a3bSJan Kneschke * 188*bcdc6a3bSJan Kneschke */ 189*bcdc6a3bSJan Kneschke 190*bcdc6a3bSJan Kneschke /* do we have to ask for auth ? */ 191*bcdc6a3bSJan Kneschke 192*bcdc6a3bSJan Kneschke auth_required = 0; 193*bcdc6a3bSJan Kneschke auth_satisfied = 0; 194*bcdc6a3bSJan Kneschke 195*bcdc6a3bSJan Kneschke /* search auth-directives for path */ 196*bcdc6a3bSJan Kneschke for (k = 0; k < p->conf.auth_require->used; k++) { 197*bcdc6a3bSJan Kneschke if (p->conf.auth_require->data[k]->key->used == 0) continue; 198*bcdc6a3bSJan Kneschke 199*bcdc6a3bSJan Kneschke if (0 == strncmp(con->uri.path->ptr, p->conf.auth_require->data[k]->key->ptr, p->conf.auth_require->data[k]->key->used - 1)) { 200*bcdc6a3bSJan Kneschke auth_required = 1; 201*bcdc6a3bSJan Kneschke break; 202*bcdc6a3bSJan Kneschke } 203*bcdc6a3bSJan Kneschke } 204*bcdc6a3bSJan Kneschke 205*bcdc6a3bSJan Kneschke /* nothing to do for us */ 206*bcdc6a3bSJan Kneschke if (auth_required == 0) return HANDLER_GO_ON; 207*bcdc6a3bSJan Kneschke 208*bcdc6a3bSJan Kneschke req = ((data_array *)(p->conf.auth_require->data[k]))->value; 209*bcdc6a3bSJan Kneschke 210*bcdc6a3bSJan Kneschke /* try to get Authorization-header */ 211*bcdc6a3bSJan Kneschke 212*bcdc6a3bSJan Kneschke if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) { 213*bcdc6a3bSJan Kneschke http_authorization = ds->value->ptr; 214*bcdc6a3bSJan Kneschke } 215*bcdc6a3bSJan Kneschke 216*bcdc6a3bSJan Kneschke if (ds && ds->value && ds->value->used) { 217*bcdc6a3bSJan Kneschke char *auth_realm; 218*bcdc6a3bSJan Kneschke data_string *method; 219*bcdc6a3bSJan Kneschke 220*bcdc6a3bSJan Kneschke method = (data_string *)array_get_element(req, "method"); 221*bcdc6a3bSJan Kneschke 222*bcdc6a3bSJan Kneschke /* parse auth-header */ 223*bcdc6a3bSJan Kneschke if (NULL != (auth_realm = strchr(http_authorization, ' '))) { 224*bcdc6a3bSJan Kneschke int auth_type_len = auth_realm - http_authorization; 225*bcdc6a3bSJan Kneschke 226*bcdc6a3bSJan Kneschke if ((auth_type_len == 5) && 227*bcdc6a3bSJan Kneschke (0 == strncmp(http_authorization, "Basic", auth_type_len))) { 228*bcdc6a3bSJan Kneschke 229*bcdc6a3bSJan Kneschke if (0 == strcmp(method->value->ptr, "basic")) { 230*bcdc6a3bSJan Kneschke auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1); 231*bcdc6a3bSJan Kneschke } 232*bcdc6a3bSJan Kneschke } else if ((auth_type_len == 6) && 233*bcdc6a3bSJan Kneschke (0 == strncmp(http_authorization, "Digest", auth_type_len))) { 234*bcdc6a3bSJan Kneschke if (0 == strcmp(method->value->ptr, "digest")) { 235*bcdc6a3bSJan Kneschke if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) { 236*bcdc6a3bSJan Kneschke con->http_status = 400; 237*bcdc6a3bSJan Kneschke 238*bcdc6a3bSJan Kneschke /* a field was missing */ 239*bcdc6a3bSJan Kneschke 240*bcdc6a3bSJan Kneschke return HANDLER_FINISHED; 241*bcdc6a3bSJan Kneschke } 242*bcdc6a3bSJan Kneschke } 243*bcdc6a3bSJan Kneschke } else { 244*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "ss", 245*bcdc6a3bSJan Kneschke "unknown authentification type:", 246*bcdc6a3bSJan Kneschke http_authorization); 247*bcdc6a3bSJan Kneschke } 248*bcdc6a3bSJan Kneschke } 249*bcdc6a3bSJan Kneschke } 250*bcdc6a3bSJan Kneschke 251*bcdc6a3bSJan Kneschke if (!auth_satisfied) { 252*bcdc6a3bSJan Kneschke data_string *method, *realm; 253*bcdc6a3bSJan Kneschke method = (data_string *)array_get_element(req, "method"); 254*bcdc6a3bSJan Kneschke realm = (data_string *)array_get_element(req, "realm"); 255*bcdc6a3bSJan Kneschke 256*bcdc6a3bSJan Kneschke con->http_status = 401; 257*bcdc6a3bSJan Kneschke 258*bcdc6a3bSJan Kneschke if (0 == strcmp(method->value->ptr, "basic")) { 259*bcdc6a3bSJan Kneschke buffer_copy_string(p->tmp_buf, "Basic realm=\""); 260*bcdc6a3bSJan Kneschke buffer_append_string_buffer(p->tmp_buf, realm->value); 261*bcdc6a3bSJan Kneschke buffer_append_string(p->tmp_buf, "\""); 262*bcdc6a3bSJan Kneschke 263*bcdc6a3bSJan Kneschke response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf)); 264*bcdc6a3bSJan Kneschke } else if (0 == strcmp(method->value->ptr, "digest")) { 265*bcdc6a3bSJan Kneschke char hh[33]; 266*bcdc6a3bSJan Kneschke http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh); 267*bcdc6a3bSJan Kneschke 268*bcdc6a3bSJan Kneschke buffer_copy_string(p->tmp_buf, "Digest realm=\""); 269*bcdc6a3bSJan Kneschke buffer_append_string_buffer(p->tmp_buf, realm->value); 270*bcdc6a3bSJan Kneschke buffer_append_string(p->tmp_buf, "\", nonce=\""); 271*bcdc6a3bSJan Kneschke buffer_append_string(p->tmp_buf, hh); 272*bcdc6a3bSJan Kneschke buffer_append_string(p->tmp_buf, "\", qop=\"auth\""); 273*bcdc6a3bSJan Kneschke 274*bcdc6a3bSJan Kneschke response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf)); 275*bcdc6a3bSJan Kneschke } else { 276*bcdc6a3bSJan Kneschke /* evil */ 277*bcdc6a3bSJan Kneschke } 278*bcdc6a3bSJan Kneschke return HANDLER_FINISHED; 279*bcdc6a3bSJan Kneschke } else { 280*bcdc6a3bSJan Kneschke /* the REMOTE_USER header */ 281*bcdc6a3bSJan Kneschke 282*bcdc6a3bSJan Kneschke buffer_copy_string_buffer(con->authed_user, p->auth_user); 283*bcdc6a3bSJan Kneschke } 284*bcdc6a3bSJan Kneschke 285*bcdc6a3bSJan Kneschke return HANDLER_GO_ON; 286*bcdc6a3bSJan Kneschke } 287*bcdc6a3bSJan Kneschke 288*bcdc6a3bSJan Kneschke SETDEFAULTS_FUNC(mod_auth_set_defaults) { 289*bcdc6a3bSJan Kneschke mod_auth_plugin_data *p = p_d; 290*bcdc6a3bSJan Kneschke size_t i; 291*bcdc6a3bSJan Kneschke 292*bcdc6a3bSJan Kneschke config_values_t cv[] = { 293*bcdc6a3bSJan Kneschke { "auth.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ 294*bcdc6a3bSJan Kneschke { "auth.backend.plain.groupfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, 295*bcdc6a3bSJan Kneschke { "auth.backend.plain.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, 296*bcdc6a3bSJan Kneschke { "auth.require", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, 297*bcdc6a3bSJan Kneschke { "auth.backend.ldap.hostname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, 298*bcdc6a3bSJan Kneschke { "auth.backend.ldap.base-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, 299*bcdc6a3bSJan Kneschke { "auth.backend.ldap.filter", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, 300*bcdc6a3bSJan Kneschke { "auth.backend.htdigest.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, 301*bcdc6a3bSJan Kneschke { "auth.backend.htpasswd.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, 302*bcdc6a3bSJan Kneschke { "auth.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */ 303*bcdc6a3bSJan Kneschke { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } 304*bcdc6a3bSJan Kneschke }; 305*bcdc6a3bSJan Kneschke 306*bcdc6a3bSJan Kneschke p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *)); 307*bcdc6a3bSJan Kneschke 308*bcdc6a3bSJan Kneschke for (i = 0; i < srv->config_context->used; i++) { 309*bcdc6a3bSJan Kneschke mod_auth_plugin_config *s; 310*bcdc6a3bSJan Kneschke size_t n; 311*bcdc6a3bSJan Kneschke data_array *da; 312*bcdc6a3bSJan Kneschke array *ca; 313*bcdc6a3bSJan Kneschke 314*bcdc6a3bSJan Kneschke s = malloc(sizeof(mod_auth_plugin_config)); 315*bcdc6a3bSJan Kneschke s->auth_plain_groupfile = buffer_init(); 316*bcdc6a3bSJan Kneschke s->auth_plain_userfile = buffer_init(); 317*bcdc6a3bSJan Kneschke s->auth_htdigest_userfile = buffer_init(); 318*bcdc6a3bSJan Kneschke s->auth_htpasswd_userfile = buffer_init(); 319*bcdc6a3bSJan Kneschke s->auth_backend_conf = buffer_init(); 320*bcdc6a3bSJan Kneschke 321*bcdc6a3bSJan Kneschke s->auth_ldap_hostname = buffer_init(); 322*bcdc6a3bSJan Kneschke s->auth_ldap_basedn = buffer_init(); 323*bcdc6a3bSJan Kneschke s->auth_ldap_filter = buffer_init(); 324*bcdc6a3bSJan Kneschke s->auth_debug = 0; 325*bcdc6a3bSJan Kneschke 326*bcdc6a3bSJan Kneschke s->auth_require = array_init(); 327*bcdc6a3bSJan Kneschke 328*bcdc6a3bSJan Kneschke #ifdef USE_LDAP 329*bcdc6a3bSJan Kneschke s->ldap_filter_pre = buffer_init(); 330*bcdc6a3bSJan Kneschke s->ldap_filter_post = buffer_init(); 331*bcdc6a3bSJan Kneschke s->ldap = NULL; 332*bcdc6a3bSJan Kneschke #endif 333*bcdc6a3bSJan Kneschke 334*bcdc6a3bSJan Kneschke cv[0].destination = s->auth_backend_conf; 335*bcdc6a3bSJan Kneschke cv[1].destination = s->auth_plain_groupfile; 336*bcdc6a3bSJan Kneschke cv[2].destination = s->auth_plain_userfile; 337*bcdc6a3bSJan Kneschke cv[3].destination = s->auth_require; 338*bcdc6a3bSJan Kneschke cv[4].destination = s->auth_ldap_hostname; 339*bcdc6a3bSJan Kneschke cv[5].destination = s->auth_ldap_basedn; 340*bcdc6a3bSJan Kneschke cv[6].destination = s->auth_ldap_filter; 341*bcdc6a3bSJan Kneschke cv[7].destination = s->auth_htdigest_userfile; 342*bcdc6a3bSJan Kneschke cv[8].destination = s->auth_htpasswd_userfile; 343*bcdc6a3bSJan Kneschke cv[9].destination = &(s->auth_debug); 344*bcdc6a3bSJan Kneschke 345*bcdc6a3bSJan Kneschke p->config_storage[i] = s; 346*bcdc6a3bSJan Kneschke ca = ((data_config *)srv->config_context->data[i])->value; 347*bcdc6a3bSJan Kneschke 348*bcdc6a3bSJan Kneschke if (0 != config_insert_values_global(srv, ca, cv)) { 349*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 350*bcdc6a3bSJan Kneschke } 351*bcdc6a3bSJan Kneschke 352*bcdc6a3bSJan Kneschke if (s->auth_backend_conf->used) { 353*bcdc6a3bSJan Kneschke if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) { 354*bcdc6a3bSJan Kneschke s->auth_backend = AUTH_BACKEND_HTPASSWD; 355*bcdc6a3bSJan Kneschke } else if (0 == strcmp(s->auth_backend_conf->ptr, "htdigest")) { 356*bcdc6a3bSJan Kneschke s->auth_backend = AUTH_BACKEND_HTDIGEST; 357*bcdc6a3bSJan Kneschke } else if (0 == strcmp(s->auth_backend_conf->ptr, "plain")) { 358*bcdc6a3bSJan Kneschke s->auth_backend = AUTH_BACKEND_PLAIN; 359*bcdc6a3bSJan Kneschke } else if (0 == strcmp(s->auth_backend_conf->ptr, "ldap")) { 360*bcdc6a3bSJan Kneschke s->auth_backend = AUTH_BACKEND_LDAP; 361*bcdc6a3bSJan Kneschke } else { 362*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf); 363*bcdc6a3bSJan Kneschke 364*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 365*bcdc6a3bSJan Kneschke } 366*bcdc6a3bSJan Kneschke } 367*bcdc6a3bSJan Kneschke 368*bcdc6a3bSJan Kneschke /* no auth.require for this section */ 369*bcdc6a3bSJan Kneschke if (NULL == (da = (data_array *)array_get_element(ca, "auth.require"))) continue; 370*bcdc6a3bSJan Kneschke 371*bcdc6a3bSJan Kneschke if (da->type != TYPE_ARRAY) continue; 372*bcdc6a3bSJan Kneschke 373*bcdc6a3bSJan Kneschke for (n = 0; n < da->value->used; n++) { 374*bcdc6a3bSJan Kneschke size_t m; 375*bcdc6a3bSJan Kneschke data_array *da_file = (data_array *)da->value->data[n]; 376*bcdc6a3bSJan Kneschke const char *method, *realm, *require; 377*bcdc6a3bSJan Kneschke 378*bcdc6a3bSJan Kneschke if (da->value->data[n]->type != TYPE_ARRAY) { 379*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "sssbs", 380*bcdc6a3bSJan Kneschke "unexpected type for key: ", "auth.require", "[", da->value->data[n]->key, "](string)"); 381*bcdc6a3bSJan Kneschke 382*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 383*bcdc6a3bSJan Kneschke } 384*bcdc6a3bSJan Kneschke 385*bcdc6a3bSJan Kneschke method = realm = require = NULL; 386*bcdc6a3bSJan Kneschke 387*bcdc6a3bSJan Kneschke for (m = 0; m < da_file->value->used; m++) { 388*bcdc6a3bSJan Kneschke if (da_file->value->data[m]->type == TYPE_STRING) { 389*bcdc6a3bSJan Kneschke if (0 == strcmp(da_file->value->data[m]->key->ptr, "method")) { 390*bcdc6a3bSJan Kneschke method = ((data_string *)(da_file->value->data[m]))->value->ptr; 391*bcdc6a3bSJan Kneschke } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "realm")) { 392*bcdc6a3bSJan Kneschke realm = ((data_string *)(da_file->value->data[m]))->value->ptr; 393*bcdc6a3bSJan Kneschke } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) { 394*bcdc6a3bSJan Kneschke require = ((data_string *)(da_file->value->data[m]))->value->ptr; 395*bcdc6a3bSJan Kneschke } else { 396*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "sssbs", "unexpected type for key: ", "auth.require", "[", da_file->value->data[m]->key, "](string)"); 397*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 398*bcdc6a3bSJan Kneschke } 399*bcdc6a3bSJan Kneschke } else { 400*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "sssbs", "unexpected type for key: ", "auth.require", "[", da_file->value->data[m]->key, "](string)"); 401*bcdc6a3bSJan Kneschke 402*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 403*bcdc6a3bSJan Kneschke } 404*bcdc6a3bSJan Kneschke } 405*bcdc6a3bSJan Kneschke 406*bcdc6a3bSJan Kneschke if (method == NULL) { 407*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "sssss", "missing entry for key: ", "auth.require", "[", "method", "](string)"); 408*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 409*bcdc6a3bSJan Kneschke } 410*bcdc6a3bSJan Kneschke 411*bcdc6a3bSJan Kneschke if (realm == NULL) { 412*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "sssss", "missing entry for key: ", "auth.require", "[", "realm", "](string)"); 413*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 414*bcdc6a3bSJan Kneschke } 415*bcdc6a3bSJan Kneschke 416*bcdc6a3bSJan Kneschke if (require == NULL) { 417*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "sssss", "missing entry for key: ", "auth.require", "[", "require", "](string)"); 418*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 419*bcdc6a3bSJan Kneschke } 420*bcdc6a3bSJan Kneschke 421*bcdc6a3bSJan Kneschke if (method && realm && require) { 422*bcdc6a3bSJan Kneschke data_string *ds; 423*bcdc6a3bSJan Kneschke data_array *a; 424*bcdc6a3bSJan Kneschke 425*bcdc6a3bSJan Kneschke a = data_array_init(); 426*bcdc6a3bSJan Kneschke buffer_copy_string_buffer(a->key, da_file->key); 427*bcdc6a3bSJan Kneschke 428*bcdc6a3bSJan Kneschke ds = data_string_init(); 429*bcdc6a3bSJan Kneschke 430*bcdc6a3bSJan Kneschke buffer_copy_string(ds->key, "method"); 431*bcdc6a3bSJan Kneschke buffer_copy_string(ds->value, method); 432*bcdc6a3bSJan Kneschke 433*bcdc6a3bSJan Kneschke array_insert_unique(a->value, (data_unset *)ds); 434*bcdc6a3bSJan Kneschke 435*bcdc6a3bSJan Kneschke ds = data_string_init(); 436*bcdc6a3bSJan Kneschke 437*bcdc6a3bSJan Kneschke buffer_copy_string(ds->key, "realm"); 438*bcdc6a3bSJan Kneschke buffer_copy_string(ds->value, realm); 439*bcdc6a3bSJan Kneschke 440*bcdc6a3bSJan Kneschke array_insert_unique(a->value, (data_unset *)ds); 441*bcdc6a3bSJan Kneschke 442*bcdc6a3bSJan Kneschke ds = data_string_init(); 443*bcdc6a3bSJan Kneschke 444*bcdc6a3bSJan Kneschke buffer_copy_string(ds->key, "require"); 445*bcdc6a3bSJan Kneschke buffer_copy_string(ds->value, require); 446*bcdc6a3bSJan Kneschke 447*bcdc6a3bSJan Kneschke array_insert_unique(a->value, (data_unset *)ds); 448*bcdc6a3bSJan Kneschke 449*bcdc6a3bSJan Kneschke array_insert_unique(s->auth_require, (data_unset *)a); 450*bcdc6a3bSJan Kneschke } 451*bcdc6a3bSJan Kneschke } 452*bcdc6a3bSJan Kneschke 453*bcdc6a3bSJan Kneschke switch(s->auth_backend) { 454*bcdc6a3bSJan Kneschke case AUTH_BACKEND_PLAIN: 455*bcdc6a3bSJan Kneschke if (s->auth_plain_userfile->used) { 456*bcdc6a3bSJan Kneschke int fd; 457*bcdc6a3bSJan Kneschke /* try to read */ 458*bcdc6a3bSJan Kneschke if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) { 459*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "sbss", 460*bcdc6a3bSJan Kneschke "opening auth.backend.plain.userfile:", s->auth_plain_userfile, 461*bcdc6a3bSJan Kneschke "failed:", strerror(errno)); 462*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 463*bcdc6a3bSJan Kneschke } 464*bcdc6a3bSJan Kneschke close(fd); 465*bcdc6a3bSJan Kneschke } 466*bcdc6a3bSJan Kneschke break; 467*bcdc6a3bSJan Kneschke case AUTH_BACKEND_HTPASSWD: 468*bcdc6a3bSJan Kneschke if (s->auth_htpasswd_userfile->used) { 469*bcdc6a3bSJan Kneschke int fd; 470*bcdc6a3bSJan Kneschke /* try to read */ 471*bcdc6a3bSJan Kneschke if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) { 472*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "sbss", 473*bcdc6a3bSJan Kneschke "opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile, 474*bcdc6a3bSJan Kneschke "failed:", strerror(errno)); 475*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 476*bcdc6a3bSJan Kneschke } 477*bcdc6a3bSJan Kneschke close(fd); 478*bcdc6a3bSJan Kneschke } 479*bcdc6a3bSJan Kneschke break; 480*bcdc6a3bSJan Kneschke case AUTH_BACKEND_HTDIGEST: 481*bcdc6a3bSJan Kneschke if (s->auth_htdigest_userfile->used) { 482*bcdc6a3bSJan Kneschke int fd; 483*bcdc6a3bSJan Kneschke /* try to read */ 484*bcdc6a3bSJan Kneschke if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) { 485*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "sbss", 486*bcdc6a3bSJan Kneschke "opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile, 487*bcdc6a3bSJan Kneschke "failed:", strerror(errno)); 488*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 489*bcdc6a3bSJan Kneschke } 490*bcdc6a3bSJan Kneschke close(fd); 491*bcdc6a3bSJan Kneschke } 492*bcdc6a3bSJan Kneschke break; 493*bcdc6a3bSJan Kneschke case AUTH_BACKEND_LDAP: 494*bcdc6a3bSJan Kneschke #ifdef USE_LDAP 495*bcdc6a3bSJan Kneschke #if 0 496*bcdc6a3bSJan Kneschke if (s->auth_ldap_basedn->used == 0) { 497*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set"); 498*bcdc6a3bSJan Kneschke 499*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 500*bcdc6a3bSJan Kneschke } 501*bcdc6a3bSJan Kneschke #endif 502*bcdc6a3bSJan Kneschke 503*bcdc6a3bSJan Kneschke if (s->auth_ldap_filter->used) { 504*bcdc6a3bSJan Kneschke char *dollar; 505*bcdc6a3bSJan Kneschke 506*bcdc6a3bSJan Kneschke /* parse filter */ 507*bcdc6a3bSJan Kneschke 508*bcdc6a3bSJan Kneschke if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) { 509*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'"); 510*bcdc6a3bSJan Kneschke 511*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 512*bcdc6a3bSJan Kneschke } 513*bcdc6a3bSJan Kneschke 514*bcdc6a3bSJan Kneschke buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr); 515*bcdc6a3bSJan Kneschke buffer_copy_string(s->ldap_filter_post, dollar+1); 516*bcdc6a3bSJan Kneschke } 517*bcdc6a3bSJan Kneschke 518*bcdc6a3bSJan Kneschke if (s->auth_ldap_hostname->used) { 519*bcdc6a3bSJan Kneschke int ret; 520*bcdc6a3bSJan Kneschke if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) { 521*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno)); 522*bcdc6a3bSJan Kneschke 523*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 524*bcdc6a3bSJan Kneschke } 525*bcdc6a3bSJan Kneschke 526*bcdc6a3bSJan Kneschke ret = LDAP_VERSION3; 527*bcdc6a3bSJan Kneschke if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) { 528*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret)); 529*bcdc6a3bSJan Kneschke 530*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 531*bcdc6a3bSJan Kneschke } 532*bcdc6a3bSJan Kneschke 533*bcdc6a3bSJan Kneschke 534*bcdc6a3bSJan Kneschke /* 1. */ 535*bcdc6a3bSJan Kneschke if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) { 536*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret)); 537*bcdc6a3bSJan Kneschke 538*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 539*bcdc6a3bSJan Kneschke } 540*bcdc6a3bSJan Kneschke } 541*bcdc6a3bSJan Kneschke #else 542*bcdc6a3bSJan Kneschke log_error_write(srv, __FILE__, __LINE__, "s", "no ldap support available"); 543*bcdc6a3bSJan Kneschke return HANDLER_ERROR; 544*bcdc6a3bSJan Kneschke #endif 545*bcdc6a3bSJan Kneschke break; 546*bcdc6a3bSJan Kneschke default: 547*bcdc6a3bSJan Kneschke break; 548*bcdc6a3bSJan Kneschke } 549*bcdc6a3bSJan Kneschke } 550*bcdc6a3bSJan Kneschke 551*bcdc6a3bSJan Kneschke return HANDLER_GO_ON; 552*bcdc6a3bSJan Kneschke } 553*bcdc6a3bSJan Kneschke 554*bcdc6a3bSJan Kneschke int mod_auth_plugin_init(plugin *p) { 555*bcdc6a3bSJan Kneschke p->version = LIGHTTPD_VERSION_ID; 556*bcdc6a3bSJan Kneschke p->name = buffer_init_string("auth"); 557*bcdc6a3bSJan Kneschke p->init = mod_auth_init; 558*bcdc6a3bSJan Kneschke p->set_defaults = mod_auth_set_defaults; 559*bcdc6a3bSJan Kneschke p->handle_uri_clean = mod_auth_uri_handler; 560*bcdc6a3bSJan Kneschke p->cleanup = mod_auth_free; 561*bcdc6a3bSJan Kneschke 562*bcdc6a3bSJan Kneschke p->data = NULL; 563*bcdc6a3bSJan Kneschke 564*bcdc6a3bSJan Kneschke return 0; 565*bcdc6a3bSJan Kneschke } 566