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