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