1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "ap_provider.h" 18#include "httpd.h" 19#include "http_config.h" 20#include "http_core.h" 21#include "http_log.h" 22#include "http_protocol.h" 23#include "http_request.h" 24#include "util_ldap.h" 25 26#include "mod_auth.h" 27 28#include "apr_strings.h" 29#include "apr_xlate.h" 30#define APR_WANT_STRFUNC 31#include "apr_want.h" 32#include "apr_lib.h" 33 34#if APR_HAVE_UNISTD_H 35/* for getpid() */ 36#include <unistd.h> 37#endif 38#include <ctype.h> 39 40#if !APR_HAS_LDAP 41#error mod_authnz_ldap requires APR-util to have LDAP support built in. To fix add --with-ldap to ./configure. 42#endif 43 44typedef struct { 45 apr_pool_t *pool; /* Pool that this config is allocated from */ 46#if APR_HAS_THREADS 47 apr_thread_mutex_t *lock; /* Lock for this config */ 48#endif 49 int auth_authoritative; /* Is this auth method the one and only? */ 50/* int authz_enabled; Is ldap authorization enabled in this directory? */ 51 52 53 /* These parameters are all derived from the AuthLDAPURL directive */ 54 char *url; /* String representation of the URL */ 55 56 char *host; /* Name of the LDAP server (or space separated list) */ 57 int port; /* Port of the LDAP server */ 58 char *basedn; /* Base DN to do all searches from */ 59 char *attribute; /* Attribute to search for */ 60 char **attributes; /* Array of all the attributes to return */ 61 int scope; /* Scope of the search */ 62 char *filter; /* Filter to further limit the search */ 63 deref_options deref; /* how to handle alias dereferening */ 64 char *binddn; /* DN to bind to server (can be NULL) */ 65 char *bindpw; /* Password to bind to server (can be NULL) */ 66 int bind_authoritative; /* If true, will return errors when bind fails */ 67 68 int user_is_dn; /* If true, connection->user is DN instead of userid */ 69 char *remote_user_attribute; /* If set, connection->user is this attribute instead of userid */ 70 int compare_dn_on_server; /* If true, will use server to do DN compare */ 71 72 int have_ldap_url; /* Set if we have found an LDAP url */ 73 74 apr_array_header_t *groupattr; /* List of Group attributes */ 75 int group_attrib_is_dn; /* If true, the group attribute is the DN, otherwise, 76 it's the exact string passed by the HTTP client */ 77 78 int secure; /* True if SSL connections are requested */ 79} authn_ldap_config_t; 80 81typedef struct { 82 char *dn; /* The saved dn from a successful search */ 83 char *user; /* The username provided by the client */ 84} authn_ldap_request_t; 85 86/* maximum group elements supported */ 87#define GROUPATTR_MAX_ELTS 10 88 89struct mod_auth_ldap_groupattr_entry_t { 90 char *name; 91}; 92 93module AP_MODULE_DECLARE_DATA authnz_ldap_module; 94 95static APR_OPTIONAL_FN_TYPE(uldap_connection_close) *util_ldap_connection_close; 96static APR_OPTIONAL_FN_TYPE(uldap_connection_find) *util_ldap_connection_find; 97static APR_OPTIONAL_FN_TYPE(uldap_cache_comparedn) *util_ldap_cache_comparedn; 98static APR_OPTIONAL_FN_TYPE(uldap_cache_compare) *util_ldap_cache_compare; 99static APR_OPTIONAL_FN_TYPE(uldap_cache_checkuserid) *util_ldap_cache_checkuserid; 100static APR_OPTIONAL_FN_TYPE(uldap_cache_getuserdn) *util_ldap_cache_getuserdn; 101static APR_OPTIONAL_FN_TYPE(uldap_ssl_supported) *util_ldap_ssl_supported; 102 103static apr_hash_t *charset_conversions = NULL; 104static char *to_charset = NULL; /* UTF-8 identifier derived from the charset.conv file */ 105 106 107/* Derive a code page ID give a language name or ID */ 108static char* derive_codepage_from_lang (apr_pool_t *p, char *language) 109{ 110 int lang_len; 111 char *charset; 112 113 if (!language) /* our default codepage */ 114 return apr_pstrdup(p, "ISO-8859-1"); 115 else 116 lang_len = strlen(language); 117 118 charset = (char*) apr_hash_get(charset_conversions, language, APR_HASH_KEY_STRING); 119 120 if (!charset) { 121 language[2] = '\0'; 122 charset = (char*) apr_hash_get(charset_conversions, language, APR_HASH_KEY_STRING); 123 } 124 125 if (charset) { 126 charset = apr_pstrdup(p, charset); 127 } 128 129 return charset; 130} 131 132static apr_xlate_t* get_conv_set (request_rec *r) 133{ 134 char *lang_line = (char*)apr_table_get(r->headers_in, "accept-language"); 135 char *lang; 136 apr_xlate_t *convset; 137 138 if (lang_line) { 139 lang_line = apr_pstrdup(r->pool, lang_line); 140 for (lang = lang_line;*lang;lang++) { 141 if ((*lang == ',') || (*lang == ';')) { 142 *lang = '\0'; 143 break; 144 } 145 } 146 lang = derive_codepage_from_lang(r->pool, lang_line); 147 148 if (lang && (apr_xlate_open(&convset, to_charset, lang, r->pool) == APR_SUCCESS)) { 149 return convset; 150 } 151 } 152 153 return NULL; 154} 155 156 157static const char* authn_ldap_xlate_password(request_rec *r, 158 const char* sent_password) 159{ 160 apr_xlate_t *convset = NULL; 161 apr_size_t inbytes; 162 apr_size_t outbytes; 163 char *outbuf; 164 165 if (charset_conversions && (convset = get_conv_set(r)) ) { 166 inbytes = strlen(sent_password); 167 outbytes = (inbytes+1)*3; 168 outbuf = apr_pcalloc(r->pool, outbytes); 169 170 /* Convert the password to UTF-8. */ 171 if (apr_xlate_conv_buffer(convset, sent_password, &inbytes, outbuf, 172 &outbytes) == APR_SUCCESS) 173 return outbuf; 174 } 175 176 return sent_password; 177} 178 179 180/* 181 * Build the search filter, or at least as much of the search filter that 182 * will fit in the buffer. We don't worry about the buffer not being able 183 * to hold the entire filter. If the buffer wasn't big enough to hold the 184 * filter, ldap_search_s will complain, but the only situation where this 185 * is likely to happen is if the client sent a really, really long 186 * username, most likely as part of an attack. 187 * 188 * The search filter consists of the filter provided with the URL, 189 * combined with a filter made up of the attribute provided with the URL, 190 * and the actual username passed by the HTTP client. For example, assume 191 * that the LDAP URL is 192 * 193 * ldap://ldap.airius.com/ou=People, o=Airius?uid??(posixid=*) 194 * 195 * Further, assume that the userid passed by the client was `userj'. The 196 * search filter will be (&(posixid=*)(uid=userj)). 197 */ 198#define FILTER_LENGTH MAX_STRING_LEN 199static void authn_ldap_build_filter(char *filtbuf, 200 request_rec *r, 201 const char* sent_user, 202 const char* sent_filter, 203 authn_ldap_config_t *sec) 204{ 205 char *p, *q, *filtbuf_end; 206 char *user, *filter; 207 apr_xlate_t *convset = NULL; 208 apr_size_t inbytes; 209 apr_size_t outbytes; 210 char *outbuf; 211 212 if (sent_user != NULL) { 213 user = apr_pstrdup (r->pool, sent_user); 214 } 215 else 216 return; 217 218 if (sent_filter != NULL) { 219 filter = apr_pstrdup (r->pool, sent_filter); 220 } 221 else 222 filter = sec->filter; 223 224 if (charset_conversions) { 225 convset = get_conv_set(r); 226 } 227 228 if (convset) { 229 inbytes = strlen(user); 230 outbytes = (inbytes+1)*3; 231 outbuf = apr_pcalloc(r->pool, outbytes); 232 233 /* Convert the user name to UTF-8. This is only valid for LDAP v3 */ 234 if (apr_xlate_conv_buffer(convset, user, &inbytes, outbuf, &outbytes) == APR_SUCCESS) { 235 user = apr_pstrdup(r->pool, outbuf); 236 } 237 } 238 239 /* 240 * Create the first part of the filter, which consists of the 241 * config-supplied portions. 242 */ 243 apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(%s=", filter, sec->attribute); 244 245 /* 246 * Now add the client-supplied username to the filter, ensuring that any 247 * LDAP filter metachars are escaped. 248 */ 249 filtbuf_end = filtbuf + FILTER_LENGTH - 1; 250#if APR_HAS_MICROSOFT_LDAPSDK 251 for (p = user, q=filtbuf + strlen(filtbuf); 252 *p && q < filtbuf_end; ) { 253 if (strchr("*()\\", *p) != NULL) { 254 if ( q + 3 >= filtbuf_end) 255 break; /* Don't write part of escape sequence if we can't write all of it */ 256 *q++ = '\\'; 257 switch ( *p++ ) 258 { 259 case '*': 260 *q++ = '2'; 261 *q++ = 'a'; 262 break; 263 case '(': 264 *q++ = '2'; 265 *q++ = '8'; 266 break; 267 case ')': 268 *q++ = '2'; 269 *q++ = '9'; 270 break; 271 case '\\': 272 *q++ = '5'; 273 *q++ = 'c'; 274 break; 275 } 276 } 277 else 278 *q++ = *p++; 279 } 280#else 281 for (p = user, q=filtbuf + strlen(filtbuf); 282 *p && q < filtbuf_end; *q++ = *p++) { 283 if (strchr("*()\\", *p) != NULL) { 284 *q++ = '\\'; 285 if (q >= filtbuf_end) { 286 break; 287 } 288 } 289 } 290#endif 291 *q = '\0'; 292 293 /* 294 * Append the closing parens of the filter, unless doing so would 295 * overrun the buffer. 296 */ 297 if (q + 2 <= filtbuf_end) 298 strcat(filtbuf, "))"); 299} 300 301static void *create_authnz_ldap_dir_config(apr_pool_t *p, char *d) 302{ 303 authn_ldap_config_t *sec = 304 (authn_ldap_config_t *)apr_pcalloc(p, sizeof(authn_ldap_config_t)); 305 306 sec->pool = p; 307#if APR_HAS_THREADS 308 apr_thread_mutex_create(&sec->lock, APR_THREAD_MUTEX_DEFAULT, p); 309#endif 310/* 311 sec->authz_enabled = 1; 312*/ 313 sec->groupattr = apr_array_make(p, GROUPATTR_MAX_ELTS, 314 sizeof(struct mod_auth_ldap_groupattr_entry_t)); 315 316 sec->have_ldap_url = 0; 317 sec->url = ""; 318 sec->host = NULL; 319 sec->binddn = NULL; 320 sec->bindpw = NULL; 321 sec->bind_authoritative = 1; 322 sec->deref = always; 323 sec->group_attrib_is_dn = 1; 324 sec->auth_authoritative = 1; 325 326/* 327 sec->frontpage_hack = 0; 328*/ 329 330 sec->secure = -1; /*Initialize to unset*/ 331 332 sec->user_is_dn = 0; 333 sec->remote_user_attribute = NULL; 334 sec->compare_dn_on_server = 0; 335 336 return sec; 337} 338 339static apr_status_t authnz_ldap_cleanup_connection_close(void *param) 340{ 341 util_ldap_connection_t *ldc = param; 342 util_ldap_connection_close(ldc); 343 return APR_SUCCESS; 344} 345 346 347/* 348 * Authentication Phase 349 * -------------------- 350 * 351 * This phase authenticates the credentials the user has sent with 352 * the request (ie the username and password are checked). This is done 353 * by making an attempt to bind to the LDAP server using this user's 354 * DN and the supplied password. 355 * 356 */ 357static authn_status authn_ldap_check_password(request_rec *r, const char *user, 358 const char *password) 359{ 360 int failures = 0; 361 const char **vals = NULL; 362 char filtbuf[FILTER_LENGTH]; 363 authn_ldap_config_t *sec = 364 (authn_ldap_config_t *)ap_get_module_config(r->per_dir_config, &authnz_ldap_module); 365 366 util_ldap_connection_t *ldc = NULL; 367 int result = 0; 368 int remote_user_attribute_set = 0; 369 const char *dn = NULL; 370 const char *utfpassword; 371 372 authn_ldap_request_t *req = 373 (authn_ldap_request_t *)apr_pcalloc(r->pool, sizeof(authn_ldap_request_t)); 374 ap_set_module_config(r->request_config, &authnz_ldap_module, req); 375 376/* 377 if (!sec->enabled) { 378 return AUTH_USER_NOT_FOUND; 379 } 380*/ 381 382 /* 383 * Basic sanity checks before any LDAP operations even happen. 384 */ 385 if (!sec->have_ldap_url) { 386 return AUTH_GENERAL_ERROR; 387 } 388 389start_over: 390 391 /* There is a good AuthLDAPURL, right? */ 392 if (sec->host) { 393 ldc = util_ldap_connection_find(r, sec->host, sec->port, 394 sec->binddn, sec->bindpw, sec->deref, 395 sec->secure); 396 } 397 else { 398 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, 399 "[%" APR_PID_T_FMT "] auth_ldap authenticate: no sec->host - weird...?", getpid()); 400 return AUTH_GENERAL_ERROR; 401 } 402 403 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 404 "[%" APR_PID_T_FMT "] auth_ldap authenticate: using URL %s", getpid(), sec->url); 405 406 /* Get the password that the client sent */ 407 if (password == NULL) { 408 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 409 "[%" APR_PID_T_FMT "] auth_ldap authenticate: no password specified", getpid()); 410 util_ldap_connection_close(ldc); 411 return AUTH_GENERAL_ERROR; 412 } 413 414 if (user == NULL) { 415 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 416 "[%" APR_PID_T_FMT "] auth_ldap authenticate: no user specified", getpid()); 417 util_ldap_connection_close(ldc); 418 return AUTH_GENERAL_ERROR; 419 } 420 421 /* build the username filter */ 422 authn_ldap_build_filter(filtbuf, r, user, NULL, sec); 423 424 /* convert password to utf-8 */ 425 utfpassword = authn_ldap_xlate_password(r, password); 426 427 /* do the user search */ 428 result = util_ldap_cache_checkuserid(r, ldc, sec->url, sec->basedn, sec->scope, 429 sec->attributes, filtbuf, utfpassword, 430 &dn, &vals); 431 util_ldap_connection_close(ldc); 432 433 /* sanity check - if server is down, retry it up to 5 times */ 434 if (AP_LDAP_IS_SERVER_DOWN(result)) { 435 if (failures++ <= 5) { 436 goto start_over; 437 } 438 } 439 440 /* handle bind failure */ 441 if (result != LDAP_SUCCESS) { 442 if (!sec->bind_authoritative) { 443 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 444 "[%" APR_PID_T_FMT "] auth_ldap authenticate: " 445 "user %s authentication failed; URI %s [%s][%s] (not authoritative)", 446 getpid(), user, r->uri, ldc->reason, ldap_err2string(result)); 447 return AUTH_USER_NOT_FOUND; 448 } 449 450 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 451 "[%" APR_PID_T_FMT "] auth_ldap authenticate: " 452 "user %s authentication failed; URI %s [%s][%s]", 453 getpid(), user, r->uri, ldc->reason, ldap_err2string(result)); 454 455 return (LDAP_NO_SUCH_OBJECT == result) ? AUTH_USER_NOT_FOUND 456#ifdef LDAP_SECURITY_ERROR 457 : (LDAP_SECURITY_ERROR(result)) ? AUTH_DENIED 458#else 459 : (LDAP_INAPPROPRIATE_AUTH == result) ? AUTH_DENIED 460 : (LDAP_INVALID_CREDENTIALS == result) ? AUTH_DENIED 461#ifdef LDAP_INSUFFICIENT_ACCESS 462 : (LDAP_INSUFFICIENT_ACCESS == result) ? AUTH_DENIED 463#endif 464#ifdef LDAP_INSUFFICIENT_RIGHTS 465 : (LDAP_INSUFFICIENT_RIGHTS == result) ? AUTH_DENIED 466#endif 467#endif 468#ifdef LDAP_CONSTRAINT_VIOLATION 469 /* At least Sun Directory Server sends this if a user is 470 * locked. This is not covered by LDAP_SECURITY_ERROR. 471 */ 472 : (LDAP_CONSTRAINT_VIOLATION == result) ? AUTH_DENIED 473#endif 474 : AUTH_GENERAL_ERROR; 475 } 476 477 /* mark the user and DN */ 478 req->dn = apr_pstrdup(r->pool, dn); 479 req->user = apr_pstrdup(r->pool, user); 480 if (sec->user_is_dn) { 481 r->user = req->dn; 482 } 483 484 /* add environment variables */ 485 if (sec->attributes && vals) { 486 apr_table_t *e = r->subprocess_env; 487 int i = 0; 488 while (sec->attributes[i]) { 489 char *str = apr_pstrcat(r->pool, AUTHN_PREFIX, sec->attributes[i], NULL); 490 int j = sizeof(AUTHN_PREFIX)-1; /* string length of "AUTHENTICATE_", excluding the trailing NIL */ 491 while (str[j]) { 492 str[j] = apr_toupper(str[j]); 493 j++; 494 } 495 apr_table_setn(e, str, vals[i]); 496 497 /* handle remote_user_attribute, if set */ 498 if (sec->remote_user_attribute && 499 !strcmp(sec->remote_user_attribute, sec->attributes[i])) { 500 r->user = (char *)apr_pstrdup(r->pool, vals[i]); 501 remote_user_attribute_set = 1; 502 } 503 i++; 504 } 505 } 506 507 /* sanity check */ 508 if (sec->remote_user_attribute && !remote_user_attribute_set) { 509 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, 510 "[%" APR_PID_T_FMT "] auth_ldap authenticate: " 511 "REMOTE_USER was to be set with attribute '%s', " 512 "but this attribute was not requested for in the " 513 "LDAP query for the user. REMOTE_USER will fall " 514 "back to username or DN as appropriate.", getpid(), 515 sec->remote_user_attribute); 516 } 517 518 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 519 "[%" APR_PID_T_FMT "] auth_ldap authenticate: accepting %s", getpid(), user); 520 521 return AUTH_GRANTED; 522} 523 524/* 525 * Authorisation Phase 526 * ------------------- 527 * 528 * After checking whether the username and password are correct, we need 529 * to check whether that user is authorised to view this resource. The 530 * require directive is used to do this: 531 * 532 * require valid-user Any authenticated is allowed in. 533 * require user <username> This particular user is allowed in. 534 * require group <groupname> The user must be a member of this group 535 * in order to be allowed in. 536 * require dn <dn> The user must have the following DN in the 537 * LDAP tree to be let in. 538 * 539 */ 540static int authz_ldap_check_user_access(request_rec *r) 541{ 542 int result = 0; 543 authn_ldap_request_t *req = 544 (authn_ldap_request_t *)ap_get_module_config(r->request_config, &authnz_ldap_module); 545 authn_ldap_config_t *sec = 546 (authn_ldap_config_t *)ap_get_module_config(r->per_dir_config, &authnz_ldap_module); 547 548 util_ldap_connection_t *ldc = NULL; 549 int m = r->method_number; 550 551 const apr_array_header_t *reqs_arr = ap_requires(r); 552 require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL; 553 554 register int x; 555 const char *t; 556 char *w, *value; 557 int method_restricted = 0; 558 int required_ldap = 0; 559 560 char filtbuf[FILTER_LENGTH]; 561 const char *dn = NULL; 562 const char **vals = NULL; 563 564/* 565 if (!sec->enabled) { 566 return DECLINED; 567 } 568*/ 569 570 if (!sec->have_ldap_url) { 571 return DECLINED; 572 } 573 574 /* pre-scan for ldap-* requirements so we can get out of the way early */ 575 for(x=0; x < reqs_arr->nelts; x++) { 576 if (! (reqs[x].method_mask & (AP_METHOD_BIT << m))) { 577 continue; 578 } 579 580 t = reqs[x].requirement; 581 w = ap_getword_white(r->pool, &t); 582 583 if (strncmp(w, "ldap-",5) == 0) { 584 required_ldap = 1; 585 break; 586 } 587 } 588 589 if (!required_ldap) { 590 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 591 "[%" APR_PID_T_FMT "] auth_ldap authorise: declining to authorise (no ldap requirements)", getpid()); 592 return DECLINED; 593 } 594 595 596 597 if (sec->host) { 598 ldc = util_ldap_connection_find(r, sec->host, sec->port, 599 sec->binddn, sec->bindpw, sec->deref, 600 sec->secure); 601 apr_pool_cleanup_register(r->pool, ldc, 602 authnz_ldap_cleanup_connection_close, 603 apr_pool_cleanup_null); 604 } 605 else { 606 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, 607 "[%" APR_PID_T_FMT "] auth_ldap authorise: no sec->host - weird...?", getpid()); 608 return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED; 609 } 610 611 /* 612 * If there are no elements in the group attribute array, the default should be 613 * member and uniquemember; populate the array now. 614 */ 615 if (sec->groupattr->nelts == 0) { 616 struct mod_auth_ldap_groupattr_entry_t *grp; 617#if APR_HAS_THREADS 618 apr_thread_mutex_lock(sec->lock); 619#endif 620 grp = apr_array_push(sec->groupattr); 621 grp->name = "member"; 622 grp = apr_array_push(sec->groupattr); 623 grp->name = "uniquemember"; 624#if APR_HAS_THREADS 625 apr_thread_mutex_unlock(sec->lock); 626#endif 627 } 628 629 /* 630 * If we have been authenticated by some other module than mod_auth_ldap, 631 * the req structure needed for authorization needs to be created 632 * and populated with the userid and DN of the account in LDAP 633 */ 634 635 /* Check that we have a userid to start with */ 636 if ((!r->user) || (strlen(r->user) == 0)) { 637 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, 638 "ldap authorize: Userid is blank, AuthType=%s", 639 r->ap_auth_type); 640 } 641 642 if(!req) { 643 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 644 "ldap authorize: Creating LDAP req structure"); 645 646 /* Build the username filter */ 647 authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec); 648 649 /* Search for the user DN */ 650 result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn, 651 sec->scope, sec->attributes, filtbuf, &dn, &vals); 652 653 /* Search failed, log error and return failure */ 654 if(result != LDAP_SUCCESS) { 655 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 656 "auth_ldap authorise: User DN not found, %s", ldc->reason); 657 return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED; 658 } 659 660 req = (authn_ldap_request_t *)apr_pcalloc(r->pool, 661 sizeof(authn_ldap_request_t)); 662 ap_set_module_config(r->request_config, &authnz_ldap_module, req); 663 req->dn = apr_pstrdup(r->pool, dn); 664 req->user = r->user; 665 } 666 667 /* Loop through the requirements array until there's no elements 668 * left, or something causes a return from inside the loop */ 669 for(x=0; x < reqs_arr->nelts; x++) { 670 if (! (reqs[x].method_mask & (AP_METHOD_BIT << m))) { 671 continue; 672 } 673 method_restricted = 1; 674 675 t = reqs[x].requirement; 676 w = ap_getword_white(r->pool, &t); 677 678 if (strcmp(w, "ldap-user") == 0) { 679 if (req->dn == NULL || strlen(req->dn) == 0) { 680 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 681 "[%" APR_PID_T_FMT "] auth_ldap authorise: " 682 "require user: user's DN has not been defined; failing authorisation", 683 getpid()); 684 return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED; 685 } 686 /* 687 * First do a whole-line compare, in case it's something like 688 * require user Babs Jensen 689 */ 690 result = util_ldap_cache_compare(r, ldc, sec->url, req->dn, sec->attribute, t); 691 switch(result) { 692 case LDAP_COMPARE_TRUE: { 693 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 694 "[%" APR_PID_T_FMT "] auth_ldap authorise: " 695 "require user: authorisation successful", getpid()); 696 return OK; 697 } 698 default: { 699 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 700 "[%" APR_PID_T_FMT "] auth_ldap authorise: require user: " 701 "authorisation failed [%s][%s]", getpid(), 702 ldc->reason, ldap_err2string(result)); 703 } 704 } 705 /* 706 * Now break apart the line and compare each word on it 707 */ 708 while (t[0]) { 709 w = ap_getword_conf(r->pool, &t); 710 result = util_ldap_cache_compare(r, ldc, sec->url, req->dn, sec->attribute, w); 711 switch(result) { 712 case LDAP_COMPARE_TRUE: { 713 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 714 "[%" APR_PID_T_FMT "] auth_ldap authorise: " 715 "require user: authorisation successful", getpid()); 716 return OK; 717 } 718 default: { 719 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 720 "[%" APR_PID_T_FMT "] auth_ldap authorise: " 721 "require user: authorisation failed [%s][%s]", 722 getpid(), ldc->reason, ldap_err2string(result)); 723 } 724 } 725 } 726 } 727 else if (strcmp(w, "ldap-dn") == 0) { 728 if (req->dn == NULL || strlen(req->dn) == 0) { 729 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 730 "[%" APR_PID_T_FMT "] auth_ldap authorise: " 731 "require dn: user's DN has not been defined; failing authorisation", 732 getpid()); 733 return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED; 734 } 735 736 result = util_ldap_cache_comparedn(r, ldc, sec->url, req->dn, t, sec->compare_dn_on_server); 737 switch(result) { 738 case LDAP_COMPARE_TRUE: { 739 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 740 "[%" APR_PID_T_FMT "] auth_ldap authorise: " 741 "require dn: authorisation successful", getpid()); 742 return OK; 743 } 744 default: { 745 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 746 "[%" APR_PID_T_FMT "] auth_ldap authorise: " 747 "require dn \"%s\": LDAP error [%s][%s]", 748 getpid(), t, ldc->reason, ldap_err2string(result)); 749 } 750 } 751 } 752 else if (strcmp(w, "ldap-group") == 0) { 753 struct mod_auth_ldap_groupattr_entry_t *ent = (struct mod_auth_ldap_groupattr_entry_t *) sec->groupattr->elts; 754 int i; 755 756 if (sec->group_attrib_is_dn) { 757 if (req->dn == NULL || strlen(req->dn) == 0) { 758 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 759 "[%" APR_PID_T_FMT "] auth_ldap authorise: require group: " 760 "user's DN has not been defined; failing authorisation", 761 getpid()); 762 return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED; 763 } 764 } 765 else { 766 if (req->user == NULL || strlen(req->user) == 0) { 767 /* We weren't called in the authentication phase, so we didn't have a 768 * chance to set the user field. Do so now. */ 769 req->user = r->user; 770 } 771 } 772 773 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 774 "[%" APR_PID_T_FMT "] auth_ldap authorise: require group: " 775 "testing for group membership in \"%s\"", 776 getpid(), t); 777 778 for (i = 0; i < sec->groupattr->nelts; i++) { 779 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 780 "[%" APR_PID_T_FMT "] auth_ldap authorise: require group: " 781 "testing for %s: %s (%s)", getpid(), 782 ent[i].name, sec->group_attrib_is_dn ? req->dn : req->user, t); 783 784 result = util_ldap_cache_compare(r, ldc, sec->url, t, ent[i].name, 785 sec->group_attrib_is_dn ? req->dn : req->user); 786 switch(result) { 787 case LDAP_COMPARE_TRUE: { 788 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 789 "[%" APR_PID_T_FMT "] auth_ldap authorise: require group: " 790 "authorisation successful (attribute %s) [%s][%s]", 791 getpid(), ent[i].name, ldc->reason, ldap_err2string(result)); 792 return OK; 793 } 794 default: { 795 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 796 "[%" APR_PID_T_FMT "] auth_ldap authorise: require group \"%s\": " 797 "authorisation failed [%s][%s]", 798 getpid(), t, ldc->reason, ldap_err2string(result)); 799 } 800 } 801 } 802 } 803 else if (strcmp(w, "ldap-attribute") == 0) { 804 if (req->dn == NULL || strlen(req->dn) == 0) { 805 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 806 "[%" APR_PID_T_FMT "] auth_ldap authorise: " 807 "require ldap-attribute: user's DN has not been defined; failing authorisation", 808 getpid()); 809 return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED; 810 } 811 while (t[0]) { 812 w = ap_getword(r->pool, &t, '='); 813 value = ap_getword_conf(r->pool, &t); 814 815 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 816 "[%" APR_PID_T_FMT "] auth_ldap authorise: checking attribute" 817 " %s has value %s", getpid(), w, value); 818 result = util_ldap_cache_compare(r, ldc, sec->url, req->dn, 819 w, value); 820 switch(result) { 821 case LDAP_COMPARE_TRUE: { 822 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 823 0, r, "[%" APR_PID_T_FMT "] auth_ldap authorise: " 824 "require attribute: authorisation " 825 "successful", getpid()); 826 return OK; 827 } 828 default: { 829 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 830 0, r, "[%" APR_PID_T_FMT "] auth_ldap authorise: " 831 "require attribute: authorisation " 832 "failed [%s][%s]", getpid(), 833 ldc->reason, ldap_err2string(result)); 834 } 835 } 836 } 837 } 838 else if (strcmp(w, "ldap-filter") == 0) { 839 if (req->dn == NULL || strlen(req->dn) == 0) { 840 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 841 "[%" APR_PID_T_FMT "] auth_ldap authorise: " 842 "require ldap-filter: user's DN has not been defined; failing authorisation", 843 getpid()); 844 return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED; 845 } 846 if (t[0]) { 847 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 848 "[%" APR_PID_T_FMT "] auth_ldap authorise: checking filter %s", 849 getpid(), t); 850 851 /* Build the username filter */ 852 authn_ldap_build_filter(filtbuf, r, req->user, t, sec); 853 854 /* Search for the user DN */ 855 result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn, 856 sec->scope, sec->attributes, filtbuf, &dn, &vals); 857 858 /* Make sure that the filtered search returned the correct user dn */ 859 if (result == LDAP_SUCCESS) { 860 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 861 "[%" APR_PID_T_FMT "] auth_ldap authorise: checking dn match %s", 862 getpid(), dn); 863 result = util_ldap_cache_comparedn(r, ldc, sec->url, req->dn, dn, 864 sec->compare_dn_on_server); 865 } 866 867 switch(result) { 868 case LDAP_COMPARE_TRUE: { 869 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 870 0, r, "[%" APR_PID_T_FMT "] auth_ldap authorise: " 871 "require ldap-filter: authorisation " 872 "successful", getpid()); 873 return OK; 874 } 875 case LDAP_FILTER_ERROR: { 876 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 877 0, r, "[%" APR_PID_T_FMT "] auth_ldap authorise: " 878 "require ldap-filter: %s authorisation " 879 "failed [%s][%s]", getpid(), 880 filtbuf, ldc->reason, ldap_err2string(result)); 881 break; 882 } 883 default: { 884 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 885 0, r, "[%" APR_PID_T_FMT "] auth_ldap authorise: " 886 "require ldap-filter: authorisation " 887 "failed [%s][%s]", getpid(), 888 ldc->reason, ldap_err2string(result)); 889 } 890 } 891 } 892 } 893 } 894 895 if (!method_restricted) { 896 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 897 "[%" APR_PID_T_FMT "] auth_ldap authorise: agreeing because non-restricted", 898 getpid()); 899 return OK; 900 } 901 902 if (!sec->auth_authoritative) { 903 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 904 "[%" APR_PID_T_FMT "] auth_ldap authorise: declining to authorise (not authoritative)", getpid()); 905 return DECLINED; 906 } 907 908 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 909 "[%" APR_PID_T_FMT "] auth_ldap authorise: authorisation denied", getpid()); 910 ap_note_basic_auth_failure (r); 911 912 return HTTP_UNAUTHORIZED; 913} 914 915 916/* 917 * Use the ldap url parsing routines to break up the ldap url into 918 * host and port. 919 */ 920static const char *mod_auth_ldap_parse_url(cmd_parms *cmd, 921 void *config, 922 const char *url, 923 const char *mode) 924{ 925 int rc; 926 apr_ldap_url_desc_t *urld; 927 apr_ldap_err_t *result; 928 929 authn_ldap_config_t *sec = config; 930 931 rc = apr_ldap_url_parse(cmd->pool, url, &(urld), &(result)); 932 if (rc != APR_SUCCESS) { 933 return result->reason; 934 } 935 sec->url = apr_pstrdup(cmd->pool, url); 936 937 /* Set all the values, or at least some sane defaults */ 938 if (sec->host) { 939 char *p = apr_palloc(cmd->pool, strlen(sec->host) + strlen(urld->lud_host) + 2); 940 strcpy(p, urld->lud_host); 941 strcat(p, " "); 942 strcat(p, sec->host); 943 sec->host = p; 944 } 945 else { 946 sec->host = urld->lud_host? apr_pstrdup(cmd->pool, urld->lud_host) : "localhost"; 947 } 948 sec->basedn = urld->lud_dn? apr_pstrdup(cmd->pool, urld->lud_dn) : ""; 949 if (urld->lud_attrs && urld->lud_attrs[0]) { 950 int i = 1; 951 while (urld->lud_attrs[i]) { 952 i++; 953 } 954 sec->attributes = apr_pcalloc(cmd->pool, sizeof(char *) * (i+1)); 955 i = 0; 956 while (urld->lud_attrs[i]) { 957 sec->attributes[i] = apr_pstrdup(cmd->pool, urld->lud_attrs[i]); 958 i++; 959 } 960 sec->attribute = sec->attributes[0]; 961 } 962 else { 963 sec->attribute = "uid"; 964 } 965 966 sec->scope = urld->lud_scope == LDAP_SCOPE_ONELEVEL ? 967 LDAP_SCOPE_ONELEVEL : LDAP_SCOPE_SUBTREE; 968 969 if (urld->lud_filter) { 970 if (urld->lud_filter[0] == '(') { 971 /* 972 * Get rid of the surrounding parens; later on when generating the 973 * filter, they'll be put back. 974 */ 975 sec->filter = apr_pstrdup(cmd->pool, urld->lud_filter+1); 976 sec->filter[strlen(sec->filter)-1] = '\0'; 977 } 978 else { 979 sec->filter = apr_pstrdup(cmd->pool, urld->lud_filter); 980 } 981 } 982 else { 983 sec->filter = "objectclass=*"; 984 } 985 986 if (mode) { 987 if (0 == strcasecmp("NONE", mode)) { 988 sec->secure = APR_LDAP_NONE; 989 } 990 else if (0 == strcasecmp("SSL", mode)) { 991 sec->secure = APR_LDAP_SSL; 992 } 993 else if (0 == strcasecmp("TLS", mode) || 0 == strcasecmp("STARTTLS", mode)) { 994 sec->secure = APR_LDAP_STARTTLS; 995 } 996 else { 997 return "Invalid LDAP connection mode setting: must be one of NONE, " 998 "SSL, or TLS/STARTTLS"; 999 } 1000 } 1001 1002 /* "ldaps" indicates secure ldap connections desired 1003 */ 1004 if (strncasecmp(url, "ldaps", 5) == 0) 1005 { 1006 sec->secure = APR_LDAP_SSL; 1007 sec->port = urld->lud_port? urld->lud_port : LDAPS_PORT; 1008 } 1009 else 1010 { 1011 sec->port = urld->lud_port? urld->lud_port : LDAP_PORT; 1012 } 1013 1014 sec->have_ldap_url = 1; 1015 1016 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 1017 cmd->server, "[%" APR_PID_T_FMT "] auth_ldap url parse: `%s', Host: %s, Port: %d, DN: %s, attrib: %s, scope: %s, filter: %s, connection mode: %s", 1018 getpid(), 1019 url, 1020 urld->lud_host, 1021 urld->lud_port, 1022 urld->lud_dn, 1023 urld->lud_attrs? urld->lud_attrs[0] : "(null)", 1024 (urld->lud_scope == LDAP_SCOPE_SUBTREE? "subtree" : 1025 urld->lud_scope == LDAP_SCOPE_BASE? "base" : 1026 urld->lud_scope == LDAP_SCOPE_ONELEVEL? "onelevel" : "unknown"), 1027 urld->lud_filter, 1028 sec->secure == APR_LDAP_SSL ? "using SSL": "not using SSL" 1029 ); 1030 1031 return NULL; 1032} 1033 1034static const char *mod_auth_ldap_set_deref(cmd_parms *cmd, void *config, const char *arg) 1035{ 1036 authn_ldap_config_t *sec = config; 1037 1038 if (strcmp(arg, "never") == 0 || strcasecmp(arg, "off") == 0) { 1039 sec->deref = never; 1040 } 1041 else if (strcmp(arg, "searching") == 0) { 1042 sec->deref = searching; 1043 } 1044 else if (strcmp(arg, "finding") == 0) { 1045 sec->deref = finding; 1046 } 1047 else if (strcmp(arg, "always") == 0 || strcasecmp(arg, "on") == 0) { 1048 sec->deref = always; 1049 } 1050 else { 1051 return "Unrecognized value for AuthLDAPAliasDereference directive"; 1052 } 1053 return NULL; 1054} 1055 1056static const char *mod_auth_ldap_add_group_attribute(cmd_parms *cmd, void *config, const char *arg) 1057{ 1058 struct mod_auth_ldap_groupattr_entry_t *new; 1059 1060 authn_ldap_config_t *sec = config; 1061 1062 if (sec->groupattr->nelts > GROUPATTR_MAX_ELTS) 1063 return "Too many AuthLDAPGroupAttribute directives"; 1064 1065 new = apr_array_push(sec->groupattr); 1066 new->name = apr_pstrdup(cmd->pool, arg); 1067 1068 return NULL; 1069} 1070 1071static const char *set_charset_config(cmd_parms *cmd, void *config, const char *arg) 1072{ 1073 ap_set_module_config(cmd->server->module_config, &authnz_ldap_module, 1074 (void *)arg); 1075 return NULL; 1076} 1077 1078static const char *set_bind_password(cmd_parms *cmd, void *_cfg, const char *arg) 1079{ 1080 authn_ldap_config_t *sec = _cfg; 1081 int arglen = strlen(arg); 1082 char **argv; 1083 char *result; 1084 1085 if ((arglen > 5) && strncmp(arg, "exec:", 5) == 0) { 1086 if (apr_tokenize_to_argv(arg+5, &argv, cmd->temp_pool) != APR_SUCCESS) { 1087 return apr_pstrcat(cmd->pool, 1088 "Unable to parse exec arguments from ", 1089 arg+5, NULL); 1090 } 1091 argv[0] = ap_server_root_relative(cmd->temp_pool, argv[0]); 1092 1093 if (!argv[0]) { 1094 return apr_pstrcat(cmd->pool, 1095 "Invalid AuthLDAPBindPassword exec location:", 1096 arg+5, NULL); 1097 } 1098 result = ap_get_exec_line(cmd->pool, 1099 (const char*)argv[0], (const char * const *)argv); 1100 1101 if(!result) { 1102 return apr_pstrcat(cmd->pool, 1103 "Unable to get bind password from exec of ", 1104 arg+5, NULL); 1105 } 1106 sec->bindpw = result; 1107 } 1108 else { 1109 sec->bindpw = (char *)arg; 1110 } 1111 1112 return NULL; 1113} 1114 1115static const command_rec authnz_ldap_cmds[] = 1116{ 1117 AP_INIT_TAKE12("AuthLDAPURL", mod_auth_ldap_parse_url, NULL, OR_AUTHCFG, 1118 "URL to define LDAP connection. This should be an RFC 2255 complaint\n" 1119 "URL of the form ldap://host[:port]/basedn[?attrib[?scope[?filter]]].\n" 1120 "<ul>\n" 1121 "<li>Host is the name of the LDAP server. Use a space separated list of hosts \n" 1122 "to specify redundant servers.\n" 1123 "<li>Port is optional, and specifies the port to connect to.\n" 1124 "<li>basedn specifies the base DN to start searches from\n" 1125 "<li>Attrib specifies what attribute to search for in the directory. If not " 1126 "provided, it defaults to <b>uid</b>.\n" 1127 "<li>Scope is the scope of the search, and can be either <b>sub</b> or " 1128 "<b>one</b>. If not provided, the default is <b>sub</b>.\n" 1129 "<li>Filter is a filter to use in the search. If not provided, " 1130 "defaults to <b>(objectClass=*)</b>.\n" 1131 "</ul>\n" 1132 "Searches are performed using the attribute and the filter combined. " 1133 "For example, assume that the\n" 1134 "LDAP URL is <b>ldap://ldap.airius.com/ou=People, o=Airius?uid?sub?(posixid=*)</b>. " 1135 "Searches will\n" 1136 "be done using the filter <b>(&((posixid=*))(uid=<i>username</i>))</b>, " 1137 "where <i>username</i>\n" 1138 "is the user name passed by the HTTP client. The search will be a subtree " 1139 "search on the branch <b>ou=People, o=Airius</b>."), 1140 1141 AP_INIT_TAKE1("AuthLDAPBindDN", ap_set_string_slot, 1142 (void *)APR_OFFSETOF(authn_ldap_config_t, binddn), OR_AUTHCFG, 1143 "DN to use to bind to LDAP server. If not provided, will do an anonymous bind."), 1144 1145 AP_INIT_TAKE1("AuthLDAPBindPassword", set_bind_password, NULL, OR_AUTHCFG, 1146 "Password to use to bind to LDAP server. If not provided, will do an anonymous bind."), 1147 1148 AP_INIT_FLAG("AuthLDAPBindAuthoritative", ap_set_flag_slot, 1149 (void *)APR_OFFSETOF(authn_ldap_config_t, bind_authoritative), OR_AUTHCFG, 1150 "Set to 'on' to return failures when user-specific bind fails - defaults to on."), 1151 1152 AP_INIT_FLAG("AuthLDAPRemoteUserIsDN", ap_set_flag_slot, 1153 (void *)APR_OFFSETOF(authn_ldap_config_t, user_is_dn), OR_AUTHCFG, 1154 "Set to 'on' to set the REMOTE_USER environment variable to be the full " 1155 "DN of the remote user. By default, this is set to off, meaning that " 1156 "the REMOTE_USER variable will contain whatever value the remote user sent."), 1157 1158 AP_INIT_TAKE1("AuthLDAPRemoteUserAttribute", ap_set_string_slot, 1159 (void *)APR_OFFSETOF(authn_ldap_config_t, 1160 remote_user_attribute), OR_AUTHCFG, 1161 "Override the user supplied username and place the " 1162 "contents of this attribute in the REMOTE_USER " 1163 "environment variable."), 1164 1165 AP_INIT_FLAG("AuthzLDAPAuthoritative", ap_set_flag_slot, 1166 (void *)APR_OFFSETOF(authn_ldap_config_t, auth_authoritative), OR_AUTHCFG, 1167 "Set to 'off' to allow access control to be passed along to lower modules if " 1168 "the UserID and/or group is not known to this module"), 1169 1170 AP_INIT_FLAG("AuthLDAPCompareDNOnServer", ap_set_flag_slot, 1171 (void *)APR_OFFSETOF(authn_ldap_config_t, compare_dn_on_server), OR_AUTHCFG, 1172 "Set to 'on' to force auth_ldap to do DN compares (for the \"require dn\" " 1173 "directive) using the server, and set it 'off' to do the compares locally " 1174 "(at the expense of possible false matches). See the documentation for " 1175 "a complete description of this option."), 1176 1177 AP_INIT_ITERATE("AuthLDAPGroupAttribute", mod_auth_ldap_add_group_attribute, NULL, OR_AUTHCFG, 1178 "A list of attributes used to define group membership - defaults to " 1179 "member and uniquemember"), 1180 1181 AP_INIT_FLAG("AuthLDAPGroupAttributeIsDN", ap_set_flag_slot, 1182 (void *)APR_OFFSETOF(authn_ldap_config_t, group_attrib_is_dn), OR_AUTHCFG, 1183 "If set to 'on', auth_ldap uses the DN that is retrieved from the server for" 1184 "subsequent group comparisons. If set to 'off', auth_ldap uses the string" 1185 "provided by the client directly. Defaults to 'on'."), 1186 1187 AP_INIT_TAKE1("AuthLDAPDereferenceAliases", mod_auth_ldap_set_deref, NULL, OR_AUTHCFG, 1188 "Determines how aliases are handled during a search. Can bo one of the" 1189 "values \"never\", \"searching\", \"finding\", or \"always\". " 1190 "Defaults to always."), 1191 1192/* 1193 AP_INIT_FLAG("AuthLDAPAuthzEnabled", ap_set_flag_slot, 1194 (void *)APR_OFFSETOF(authn_ldap_config_t, authz_enabled), OR_AUTHCFG, 1195 "Set to off to disable the LDAP authorization handler, even if it's been enabled in a higher tree"), 1196*/ 1197 1198 AP_INIT_TAKE1("AuthLDAPCharsetConfig", set_charset_config, NULL, RSRC_CONF, 1199 "Character set conversion configuration file. If omitted, character set" 1200 "conversion is disabled."), 1201 1202 {NULL} 1203}; 1204 1205static int authnz_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) 1206{ 1207 ap_configfile_t *f; 1208 char l[MAX_STRING_LEN]; 1209 const char *charset_confname = ap_get_module_config(s->module_config, 1210 &authnz_ldap_module); 1211 apr_status_t status; 1212 1213 /* 1214 authn_ldap_config_t *sec = (authn_ldap_config_t *) 1215 ap_get_module_config(s->module_config, 1216 &authnz_ldap_module); 1217 1218 if (sec->secure) 1219 { 1220 if (!util_ldap_ssl_supported(s)) 1221 { 1222 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, 1223 "LDAP: SSL connections (ldaps://) not supported by utilLDAP"); 1224 return(!OK); 1225 } 1226 } 1227 */ 1228 1229 /* make sure that mod_ldap (util_ldap) is loaded */ 1230 if (ap_find_linked_module("util_ldap.c") == NULL) { 1231 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, 1232 "Module mod_ldap missing. Mod_ldap (aka. util_ldap) " 1233 "must be loaded in order for mod_auth_ldap to function properly"); 1234 return HTTP_INTERNAL_SERVER_ERROR; 1235 1236 } 1237 1238 if (!charset_confname) { 1239 return OK; 1240 } 1241 1242 charset_confname = ap_server_root_relative(p, charset_confname); 1243 if (!charset_confname) { 1244 ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, 1245 "Invalid charset conversion config path %s", 1246 (const char *)ap_get_module_config(s->module_config, 1247 &authnz_ldap_module)); 1248 return HTTP_INTERNAL_SERVER_ERROR; 1249 } 1250 if ((status = ap_pcfg_openfile(&f, ptemp, charset_confname)) 1251 != APR_SUCCESS) { 1252 ap_log_error(APLOG_MARK, APLOG_ERR, status, s, 1253 "could not open charset conversion config file %s.", 1254 charset_confname); 1255 return HTTP_INTERNAL_SERVER_ERROR; 1256 } 1257 1258 charset_conversions = apr_hash_make(p); 1259 1260 while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) { 1261 const char *ll = l; 1262 char *lang; 1263 1264 if (l[0] == '#') { 1265 continue; 1266 } 1267 lang = ap_getword_conf(p, &ll); 1268 ap_str_tolower(lang); 1269 1270 if (ll[0]) { 1271 char *charset = ap_getword_conf(p, &ll); 1272 apr_hash_set(charset_conversions, lang, APR_HASH_KEY_STRING, charset); 1273 } 1274 } 1275 ap_cfg_closefile(f); 1276 1277 to_charset = derive_codepage_from_lang (p, "utf-8"); 1278 if (to_charset == NULL) { 1279 ap_log_error(APLOG_MARK, APLOG_ERR, status, s, 1280 "could not find the UTF-8 charset in the file %s.", 1281 charset_confname); 1282 return HTTP_INTERNAL_SERVER_ERROR; 1283 } 1284 1285 return OK; 1286} 1287 1288static const authn_provider authn_ldap_provider = 1289{ 1290 &authn_ldap_check_password, 1291}; 1292 1293static void ImportULDAPOptFn(void) 1294{ 1295 util_ldap_connection_close = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_close); 1296 util_ldap_connection_find = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_find); 1297 util_ldap_cache_comparedn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_comparedn); 1298 util_ldap_cache_compare = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_compare); 1299 util_ldap_cache_checkuserid = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_checkuserid); 1300 util_ldap_cache_getuserdn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_getuserdn); 1301 util_ldap_ssl_supported = APR_RETRIEVE_OPTIONAL_FN(uldap_ssl_supported); 1302} 1303 1304static void register_hooks(apr_pool_t *p) 1305{ 1306 static const char * const aszPost[]={ "mod_authz_user.c", NULL }; 1307 1308 ap_register_provider(p, AUTHN_PROVIDER_GROUP, "ldap", "0", 1309 &authn_ldap_provider); 1310 ap_hook_post_config(authnz_ldap_post_config,NULL,NULL,APR_HOOK_MIDDLE); 1311 ap_hook_auth_checker(authz_ldap_check_user_access, NULL, aszPost, APR_HOOK_MIDDLE); 1312 1313 ap_hook_optional_fn_retrieve(ImportULDAPOptFn,NULL,NULL,APR_HOOK_MIDDLE); 1314} 1315 1316module AP_MODULE_DECLARE_DATA authnz_ldap_module = 1317{ 1318 STANDARD20_MODULE_STUFF, 1319 create_authnz_ldap_dir_config, /* dir config creater */ 1320 NULL, /* dir merger --- default is to override */ 1321 NULL, /* server config */ 1322 NULL, /* merge server config */ 1323 authnz_ldap_cmds, /* command apr_table_t */ 1324 register_hooks /* register hooks */ 1325}; 1326