Apache HTTPD
mod_authnz_ldap.c
Go to the documentation of this file.
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 "ap_provider.h"
21#include "http_core.h"
22#include "http_log.h"
23#include "http_protocol.h"
24#include "http_request.h"
25#include "util_ldap.h"
26
27#include "mod_auth.h"
28
29#include "apr_strings.h"
30#include "apr_xlate.h"
31#define APR_WANT_STRFUNC
32#include "apr_want.h"
33#include "apr_lib.h"
34
35#include <ctype.h>
36
37#if !APR_HAS_LDAP
38#error mod_authnz_ldap requires APR-util to have LDAP support built in. To fix add --with-ldap to ./configure.
39#endif
40
41static char *default_attributes[3] = { "member", "uniqueMember", NULL };
42
43typedef struct {
44 apr_pool_t *pool; /* Pool that this config is allocated from */
45#if APR_HAS_THREADS
46 apr_thread_mutex_t *lock; /* Lock for this config */
47#endif
48
49 /* These parameters are all derived from the AuthLDAPURL directive */
50 char *url; /* String representation of the URL */
51
52 char *host; /* Name of the LDAP server (or space separated list) */
53 int port; /* Port of the LDAP server */
54 char *basedn; /* Base DN to do all searches from */
55 char *attribute; /* Attribute to search for */
56 char **attributes; /* Array of all the attributes to return */
57 int scope; /* Scope of the search */
58 char *filter; /* Filter to further limit the search */
59 deref_options deref; /* how to handle alias dereferening */
60 char *binddn; /* DN to bind to server (can be NULL) */
61 char *bindpw; /* Password to bind to server (can be NULL) */
62 int bind_authoritative; /* If true, will return errors when bind fails */
63
64 int user_is_dn; /* If true, r->user is replaced by DN during authn */
65 char *remote_user_attribute; /* If set, r->user is replaced by this attribute during authn */
66 int compare_dn_on_server; /* If true, will use server to do DN compare */
67
68 int have_ldap_url; /* Set if we have found an LDAP url */
69
70 apr_array_header_t *groupattr; /* List of Group attributes identifying user members. Default:"member uniqueMember" */
71 int group_attrib_is_dn; /* If true, the group attribute is the DN, otherwise,
72 it's the exact string passed by the HTTP client */
73 char **sgAttributes; /* Array of strings constructed (post-config) from subgroupattrs. Last entry is NULL. */
74 apr_array_header_t *subgroupclasses; /* List of object classes of sub-groups. Default:"groupOfNames groupOfUniqueNames" */
75 int maxNestingDepth; /* Maximum recursive nesting depth permitted during subgroup processing. Default: 10 */
76
77 int secure; /* True if SSL connections are requested */
78 char *authz_prefix; /* Prefix for environment variables added during authz */
79 int initial_bind_as_user; /* true if we should try to bind (to lookup DN) directly with the basic auth username */
80 ap_regex_t *bind_regex; /* basic auth -> bind'able username regex */
81 const char *bind_subst; /* basic auth -> bind'able username substitution */
82 int search_as_user; /* true if authz searches should be done with the users credentials (when we did authn) */
83 int compare_as_user; /* true if authz compares should be done with the users credentials (when we did authn) */
85
86typedef struct {
87 char *dn; /* The saved dn from a successful search */
88 char *user; /* The username provided by the client */
89 const char **vals; /* The additional values pulled during the DN search*/
90 char *password; /* if this module successfully authenticates, the basic auth password, else null */
92
96
100
101/* maximum group elements supported */
102#define GROUPATTR_MAX_ELTS 10
103
104module AP_MODULE_DECLARE_DATA authnz_ldap_module;
105
114
116static char *to_charset = NULL; /* UTF-8 identifier derived from the charset.conv file */
117
118
119/* Derive a code page ID give a language name or ID */
121{
122 char *charset;
123
124 if (!language) /* our default codepage */
125 return apr_pstrdup(p, "ISO-8859-1");
126
128
129 /*
130 * Test if language values like 'en-US' return a match from the charset
131 * conversion map when shortened to 'en'.
132 */
133 if (!charset && strlen(language) > 3 && language[2] == '-') {
136 }
137
138 if (charset) {
139 charset = apr_pstrdup(p, charset);
140 }
141
142 return charset;
143}
144
146{
147 char *lang_line = (char*)apr_table_get(r->headers_in, "accept-language");
148 char *lang;
149 apr_xlate_t *convset;
150
151 if (lang_line) {
153 for (lang = lang_line;*lang;lang++) {
154 if ((*lang == ',') || (*lang == ';')) {
155 *lang = '\0';
156 break;
157 }
158 }
160
161 if (lang && (apr_xlate_open(&convset, to_charset, lang, r->pool) == APR_SUCCESS)) {
162 return convset;
163 }
164 }
165
166 return NULL;
167}
168
169
171 const char* sent_password)
172{
173 apr_xlate_t *convset = NULL;
176 char *outbuf;
177
178 if (charset_conversions && (convset = get_conv_set(r)) ) {
179 inbytes = strlen(sent_password);
180 outbytes = (inbytes+1)*3;
182
183 /* Convert the password to UTF-8. */
186 return outbuf;
187 }
188
189 return sent_password;
190}
191
192
193/*
194 * Build the search filter, or at least as much of the search filter that
195 * will fit in the buffer. We don't worry about the buffer not being able
196 * to hold the entire filter. If the buffer wasn't big enough to hold the
197 * filter, ldap_search_s will complain, but the only situation where this
198 * is likely to happen is if the client sent a really, really long
199 * username, most likely as part of an attack.
200 *
201 * The search filter consists of the filter provided with the URL,
202 * combined with a filter made up of the attribute provided with the URL,
203 * and the actual username passed by the HTTP client. For example, assume
204 * that the LDAP URL is
205 *
206 * ldap://ldap.airius.com/ou=People, o=Airius?uid??(posixid=*)
207 *
208 * Further, assume that the userid passed by the client was `userj'. The
209 * search filter will be (&(posixid=*)(uid=userj)).
210 */
211#define FILTER_LENGTH MAX_STRING_LEN
213 request_rec *r,
214 const char* sent_user,
215 const char* sent_filter,
217{
218 char *p, *q, *filtbuf_end;
219 char *user, *filter;
220 apr_xlate_t *convset = NULL;
223 char *outbuf;
224 int nofilter = 0;
225
226 if (sent_user != NULL) {
227 user = apr_pstrdup (r->pool, sent_user);
228 }
229 else
230 return;
231
232 if (sent_filter != NULL) {
233 filter = apr_pstrdup (r->pool, sent_filter);
234 }
235 else
236 filter = sec->filter;
237
239 convset = get_conv_set(r);
240 }
241
242 if (convset) {
243 inbytes = strlen(user);
244 outbytes = (inbytes+1)*3;
246
247 /* Convert the user name to UTF-8. This is only valid for LDAP v3 */
248 if (apr_xlate_conv_buffer(convset, user, &inbytes, outbuf, &outbytes) == APR_SUCCESS) {
249 user = apr_pstrdup(r->pool, outbuf);
250 }
251 }
252
253 /*
254 * Create the first part of the filter, which consists of the
255 * config-supplied portions.
256 */
257
258 if ((nofilter = (filter && !strcasecmp(filter, "none")))) {
259 apr_snprintf(filtbuf, FILTER_LENGTH, "(%s=", sec->attribute);
260 }
261 else {
262 apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(%s=", filter, sec->attribute);
263 }
264
265 /*
266 * Now add the client-supplied username to the filter, ensuring that any
267 * LDAP filter metachars are escaped.
268 */
270#if APR_HAS_MICROSOFT_LDAPSDK
271 for (p = user, q=filtbuf + strlen(filtbuf);
272 *p && q < filtbuf_end; ) {
273 if (strchr("*()\\", *p) != NULL) {
274 if ( q + 3 >= filtbuf_end)
275 break; /* Don't write part of escape sequence if we can't write all of it */
276 *q++ = '\\';
277 switch ( *p++ )
278 {
279 case '*':
280 *q++ = '2';
281 *q++ = 'a';
282 break;
283 case '(':
284 *q++ = '2';
285 *q++ = '8';
286 break;
287 case ')':
288 *q++ = '2';
289 *q++ = '9';
290 break;
291 case '\\':
292 *q++ = '5';
293 *q++ = 'c';
294 break;
295 }
296 }
297 else
298 *q++ = *p++;
299 }
300#else
301 for (p = user, q=filtbuf + strlen(filtbuf);
302 *p && q < filtbuf_end; *q++ = *p++) {
303 if (strchr("*()\\", *p) != NULL) {
304 *q++ = '\\';
305 if (q >= filtbuf_end) {
306 break;
307 }
308 }
309 }
310#endif
311 *q = '\0';
312
313 /*
314 * Append the closing parens of the filter, unless doing so would
315 * overrun the buffer.
316 */
317
318 if (nofilter) {
319 if (q + 1 <= filtbuf_end)
320 strcat(filtbuf, ")");
321 }
322 else {
323 if (q + 2 <= filtbuf_end)
324 strcat(filtbuf, "))");
325 }
326
327}
328
330{
333
334 sec->pool = p;
335#if APR_HAS_THREADS
337#endif
338/*
339 sec->authz_enabled = 1;
340*/
342 sizeof(struct mod_auth_ldap_groupattr_entry_t));
343 sec->subgroupclasses = apr_array_make(p, GROUPATTR_MAX_ELTS,
344 sizeof(struct mod_auth_ldap_groupattr_entry_t));
345
346 sec->have_ldap_url = 0;
347 sec->url = "";
348 sec->host = NULL;
349 sec->binddn = NULL;
350 sec->bindpw = NULL;
351 sec->bind_authoritative = 1;
352 sec->deref = always;
353 sec->group_attrib_is_dn = 1;
354 sec->secure = -1; /*Initialize to unset*/
355 sec->maxNestingDepth = 10;
356 sec->sgAttributes = apr_pcalloc(p, sizeof (char *) * GROUPATTR_MAX_ELTS + 1);
357
358 sec->user_is_dn = 0;
359 sec->remote_user_attribute = NULL;
360 sec->compare_dn_on_server = 0;
361
362 sec->authz_prefix = AUTHZ_PREFIX;
363
364 return sec;
365}
366
373
375 char *prefix = NULL;
376 int prefix_len;
382 const char **vals = req->vals;
383
384 prefix = (phase == LDAP_AUTHN) ? AUTHN_PREFIX : sec->authz_prefix;
385 prefix_len = strlen(prefix);
386
387 if (sec->attributes && vals) {
389 int i = 0;
390 while (sec->attributes[i]) {
391 char *str = apr_pstrcat(r->pool, prefix, sec->attributes[i], NULL);
392 int j = prefix_len;
393 while (str[j]) {
394 str[j] = apr_toupper(str[j]);
395 j++;
396 }
397 apr_table_setn(e, str, vals[i] ? vals[i] : "");
398
399 /* handle remote_user_attribute, if set */
400 if ((phase == LDAP_AUTHN) &&
401 sec->remote_user_attribute &&
402 !strcmp(sec->remote_user_attribute, sec->attributes[i])) {
403 r->user = (char *)apr_pstrdup(r->pool, vals[i]);
405 }
406 i++;
407 }
408 }
410}
411
412static const char *ldap_determine_binddn(request_rec *r, const char *user) {
415 const char *result = user;
417
418 if (NULL == user || NULL == sec || !sec->bind_regex || !sec->bind_subst) {
419 return result;
420 }
421
422 if (!ap_regexec(sec->bind_regex, user, AP_MAX_REG_MATCH, regm, 0)) {
423 char *substituted = ap_pregsub(r->pool, sec->bind_subst, user, AP_MAX_REG_MATCH, regm);
424 if (NULL != substituted) {
426 }
427 }
428
429 apr_table_set(r->subprocess_env, "LDAP_BINDASUSER", result);
430
431 return result;
432}
433
434
435/* Some LDAP servers restrict who can search or compare, and the hard-coded ID
436 * might be good for the DN lookup but not for later operations.
437 */
443
444 char *binddn = sec->binddn;
445 char *bindpw = sec->bindpw;
446
447 /* If the per-request config isn't set, we didn't authenticate this user, and leave the default credentials */
448 if (req && req->password &&
449 ((type == LDAP_SEARCH && sec->search_as_user) ||
450 (type == LDAP_COMPARE && sec->compare_as_user) ||
451 (type == LDAP_COMPARE_AND_SEARCH && sec->compare_as_user && sec->search_as_user))){
452 binddn = req->dn;
453 bindpw = req->password;
454 }
455
456 return util_ldap_connection_find(r, sec->host, sec->port,
457 binddn, bindpw,
458 sec->deref, sec->secure);
459}
460/*
461 * Authentication Phase
462 * --------------------
463 *
464 * This phase authenticates the credentials the user has sent with
465 * the request (ie the username and password are checked). This is done
466 * by making an attempt to bind to the LDAP server using this user's
467 * DN and the supplied password.
468 *
469 */
471 const char *password)
472{
476
478 int result = 0;
480 const char *dn = NULL;
481 const char *utfpassword;
482
485 ap_set_module_config(r->request_config, &authnz_ldap_module, req);
486
487/*
488 if (!sec->enabled) {
489 return AUTH_USER_NOT_FOUND;
490 }
491*/
492
493 /*
494 * Basic sanity checks before any LDAP operations even happen.
495 */
496 if (!sec->have_ldap_url) {
498 "no AuthLDAPURL");
499
500 return AUTH_GENERAL_ERROR;
501 }
502
503 /* Get the password that the client sent */
504 if (password == NULL) {
506 "auth_ldap authenticate: no password specified");
507 return AUTH_GENERAL_ERROR;
508 }
509
510 if (user == NULL) {
512 "auth_ldap authenticate: no user specified");
513 return AUTH_GENERAL_ERROR;
514 }
515
516 /*
517 * A bind to the server with an empty password always succeeds, so
518 * we check to ensure that the password is not empty. This implies
519 * that users who actually do have empty passwords will never be
520 * able to authenticate with this module. I don't see this as a big
521 * problem.
522 */
523 if (!(*password)) {
525 "auth_ldap authenticate: empty password specified");
526 return AUTH_DENIED;
527 }
528
529 /* There is a good AuthLDAPURL, right? */
530 if (sec->host) {
531 const char *binddn = sec->binddn;
532 const char *bindpw = sec->bindpw;
533 if (sec->initial_bind_as_user) {
534 bindpw = password;
535 binddn = ldap_determine_binddn(r, user);
536 }
537
538 ldc = util_ldap_connection_find(r, sec->host, sec->port,
539 binddn, bindpw,
540 sec->deref, sec->secure);
541 }
542 else {
544 "auth_ldap authenticate: no sec->host - weird...?");
545 return AUTH_GENERAL_ERROR;
546 }
547
549 "auth_ldap authenticate: using URL %s", sec->url);
550
551 /* build the username filter */
553
555 "auth_ldap authenticate: final authn filter is %s", filtbuf);
556
557 /* convert password to utf-8 */
559
560 /* do the user search */
561 result = util_ldap_cache_checkuserid(r, ldc, sec->url, sec->basedn, sec->scope,
562 sec->attributes, filtbuf, utfpassword,
563 &dn, &(req->vals));
565
566 /* handle bind failure */
567 if (result != LDAP_SUCCESS) {
568 if (!sec->bind_authoritative) {
570 "auth_ldap authenticate: user %s authentication failed; "
571 "URI %s [%s][%s] (not authoritative)",
572 user, r->uri, ldc->reason, ldap_err2string(result));
573 return AUTH_USER_NOT_FOUND;
574 }
575
577 "auth_ldap authenticate: "
578 "user %s authentication failed; URI %s [%s][%s]",
579 user, r->uri, ldc->reason, ldap_err2string(result));
580
581 /* talking to a primitive LDAP server (like RACF-over-LDAP) that doesn't return specific errors */
582 if (!strcasecmp(sec->filter, "none") && LDAP_OTHER == result) {
583 return AUTH_USER_NOT_FOUND;
584 }
585
587#ifdef LDAP_SECURITY_ERROR
589#else
594#endif
597#endif
598#endif
600 /* At least Sun Directory Server sends this if a user is
601 * locked. This is not covered by LDAP_SECURITY_ERROR.
602 */
604#endif
606 }
607
608 /* mark the user and DN */
609 req->dn = apr_pstrdup(r->pool, dn);
610 req->user = apr_pstrdup(r->pool, user);
612 if (sec->user_is_dn) {
613 r->user = req->dn;
614 }
615
616 /* add environment variables */
618
619 /* sanity check */
620 if (sec->remote_user_attribute && !remote_user_attribute_set) {
622 "auth_ldap authenticate: "
623 "REMOTE_USER was to be set with attribute '%s', "
624 "but this attribute was not requested for in the "
625 "LDAP query for the user. REMOTE_USER will fall "
626 "back to username or DN as appropriate.",
627 sec->remote_user_attribute);
628 }
629
631 "auth_ldap authenticate: accepting %s", user);
632
633 return AUTH_GRANTED;
634}
635
637 const char *require_args,
638 const void *parsed_require_args)
639{
640 int result = 0;
645
647
648 const char *err = NULL;
650 const char *require;
651
652 const char *t;
653 char *w;
654
656 const char *dn = NULL;
657
658 if (!r->user) {
660 }
661
662 if (!sec->have_ldap_url) {
663 return AUTHZ_DENIED;
664 }
665
666 if (sec->host) {
671 }
672 else {
674 "auth_ldap authorize: no sec->host - weird...?");
675 return AUTHZ_DENIED;
676 }
677
678 /*
679 * If we have been authenticated by some other module than mod_authnz_ldap,
680 * the req structure needed for authorization needs to be created
681 * and populated with the userid and DN of the account in LDAP
682 */
683
684
685 if (!strlen(r->user)) {
687 "ldap authorize: Userid is blank, AuthType=%s",
688 r->ap_auth_type);
689 }
690
691 if(!req) {
693 "ldap authorize: Creating LDAP req structure");
694
696 sizeof(authn_ldap_request_t));
697
698 /* Build the username filter */
700
701 /* Search for the user DN */
702 result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn,
703 sec->scope, sec->attributes, filtbuf, &dn, &(req->vals));
704
705 /* Search failed, log error and return failure */
706 if(result != LDAP_SUCCESS) {
708 "auth_ldap authorise: User DN not found, %s", ldc->reason);
709 return AUTHZ_DENIED;
710 }
711
712 ap_set_module_config(r->request_config, &authnz_ldap_module, req);
713 req->dn = apr_pstrdup(r->pool, dn);
714 req->user = r->user;
715
716 }
717
718 if (req->dn == NULL || strlen(req->dn) == 0) {
720 "auth_ldap authorize: require user: user's DN has not "
721 "been defined; failing authorization");
722 return AUTHZ_DENIED;
723 }
724
725 require = ap_expr_str_exec(r, expr, &err);
726 if (err) {
728 "auth_ldap authorize: require user: Can't evaluate expression: %s",
729 err);
730 return AUTHZ_DENIED;
731 }
732
733 /*
734 * First do a whole-line compare, in case it's something like
735 * require user Babs Jensen
736 */
737 result = util_ldap_cache_compare(r, ldc, sec->url, req->dn, sec->attribute, require);
738 switch(result) {
739 case LDAP_COMPARE_TRUE: {
741 "auth_ldap authorize: require user: authorization "
742 "successful");
744 return AUTHZ_GRANTED;
745 }
746 default: {
748 "auth_ldap authorize: require user: "
749 "authorization failed [%s][%s]",
750 ldc->reason, ldap_err2string(result));
751 }
752 }
753
754 /*
755 * Now break apart the line and compare each word on it
756 */
757 t = require;
758 while ((w = ap_getword_conf(r->pool, &t)) && w[0]) {
759 result = util_ldap_cache_compare(r, ldc, sec->url, req->dn, sec->attribute, w);
760 switch(result) {
761 case LDAP_COMPARE_TRUE: {
763 "auth_ldap authorize: "
764 "require user: authorization successful");
766 return AUTHZ_GRANTED;
767 }
768 default: {
770 "auth_ldap authorize: "
771 "require user: authorization failed [%s][%s]",
772 ldc->reason, ldap_err2string(result));
773 }
774 }
775 }
776
778 "auth_ldap authorize user: authorization denied for "
779 "user %s to %s",
780 r->user, r->uri);
781
782 return AUTHZ_DENIED;
783}
784
786 const char *require_args,
787 const void *parsed_require_args)
788{
789 int result = 0;
794
796
797 const char *err = NULL;
799 const char *require;
800
801 const char *t;
802
804 const char *dn = NULL;
806 int i;
807
808 if (!r->user) {
810 }
811
812 if (!sec->have_ldap_url) {
813 return AUTHZ_DENIED;
814 }
815
816 if (sec->host) {
817 ldc = get_connection_for_authz(r, LDAP_COMPARE); /* for the top-level group only */
821 }
822 else {
824 "auth_ldap authorize: no sec->host - weird...?");
825 return AUTHZ_DENIED;
826 }
827
828 /*
829 * If there are no elements in the group attribute array, the default should be
830 * member and uniquemember; populate the array now.
831 */
832 if (sec->groupattr->nelts == 0) {
834#if APR_HAS_THREADS
836#endif
837 grp = apr_array_push(sec->groupattr);
838 grp->name = "member";
839 grp = apr_array_push(sec->groupattr);
840 grp->name = "uniqueMember";
841#if APR_HAS_THREADS
843#endif
844 }
845
846 /*
847 * If there are no elements in the sub group classes array, the default
848 * should be groupOfNames and groupOfUniqueNames; populate the array now.
849 */
850 if (sec->subgroupclasses->nelts == 0) {
852#if APR_HAS_THREADS
854#endif
855 grp = apr_array_push(sec->subgroupclasses);
856 grp->name = "groupOfNames";
857 grp = apr_array_push(sec->subgroupclasses);
858 grp->name = "groupOfUniqueNames";
859#if APR_HAS_THREADS
861#endif
862 }
863
864 /*
865 * If we have been authenticated by some other module than mod_auth_ldap,
866 * the req structure needed for authorization needs to be created
867 * and populated with the userid and DN of the account in LDAP
868 */
869
870 if (!strlen(r->user)) {
872 "ldap authorize: Userid is blank, AuthType=%s",
873 r->ap_auth_type);
874 }
875
876 if(!req) {
878 "ldap authorize: Creating LDAP req structure");
879
881 sizeof(authn_ldap_request_t));
882 /* Build the username filter */
884
885 /* Search for the user DN */
886 result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn,
887 sec->scope, sec->attributes, filtbuf, &dn, &(req->vals));
888
889 /* Search failed, log error and return failure */
890 if(result != LDAP_SUCCESS) {
892 "auth_ldap authorise: User DN not found, %s", ldc->reason);
893 return AUTHZ_DENIED;
894 }
895
896 ap_set_module_config(r->request_config, &authnz_ldap_module, req);
897 req->dn = apr_pstrdup(r->pool, dn);
898 req->user = r->user;
899 }
900
901 ent = (struct mod_auth_ldap_groupattr_entry_t *) sec->groupattr->elts;
902
903 if (sec->group_attrib_is_dn) {
904 if (req->dn == NULL || strlen(req->dn) == 0) {
906 "auth_ldap authorize: require group: user's DN has "
907 "not been defined; failing authorization for user %s",
908 r->user);
909 return AUTHZ_DENIED;
910 }
911 }
912 else {
913 if (req->user == NULL || strlen(req->user) == 0) {
914 /* We weren't called in the authentication phase, so we didn't have a
915 * chance to set the user field. Do so now. */
916 req->user = r->user;
917 }
918 }
919
920 require = ap_expr_str_exec(r, expr, &err);
921 if (err) {
923 "auth_ldap authorize: require group: Can't evaluate expression: %s",
924 err);
925 return AUTHZ_DENIED;
926 }
927
928 t = require;
929
931 "auth_ldap authorize: require group: testing for group "
932 "membership in \"%s\"",
933 t);
934
935 /* PR52464 exhaust attrs in base group before checking subgroups */
936 for (i = 0; i < sec->groupattr->nelts; i++) {
938 "auth_ldap authorize: require group: testing for %s: "
939 "%s (%s)",
940 ent[i].name,
941 sec->group_attrib_is_dn ? req->dn : req->user, t);
942
944 sec->group_attrib_is_dn ? req->dn : req->user);
945 if (result == LDAP_COMPARE_TRUE) {
947 "auth_ldap authorize: require group: "
948 "authorization successful (attribute %s) "
949 "[%s][%d - %s]",
950 ent[i].name, ldc->reason, result,
953 return AUTHZ_GRANTED;
954 }
955 else {
957 "auth_ldap authorize: require group \"%s\": "
958 "didn't match with attr %s [%s][%d - %s]",
959 t, ent[i].name, ldc->reason, result,
961 }
962 }
963
964 for (i = 0; i < sec->groupattr->nelts; i++) {
965 /* nested groups need searches and compares, so grab a new handle */
968
973
975 "auth_ldap authorise: require group \"%s\": "
976 "failed [%s][%d - %s], checking sub-groups",
977 t, ldc->reason, result, ldap_err2string(result));
978
980 sec->group_attrib_is_dn ? req->dn : req->user,
981 sec->sgAttributes[0] ? sec->sgAttributes : default_attributes,
982 sec->subgroupclasses,
983 0, sec->maxNestingDepth);
984 if (result == LDAP_COMPARE_TRUE) {
986 "auth_ldap authorise: require group "
987 "(sub-group): authorisation successful "
988 "(attribute %s) [%s][%d - %s]",
989 ent[i].name, ldc->reason, result,
992 return AUTHZ_GRANTED;
993 }
994 else {
996 "auth_ldap authorise: require group "
997 "(sub-group) \"%s\": didn't match with attr %s "
998 "[%s][%d - %s]",
999 t, ldc->reason, ent[i].name, result,
1001 }
1002 }
1003
1005 "auth_ldap authorize group: authorization denied for "
1006 "user %s to %s",
1007 r->user, r->uri);
1008
1009 return AUTHZ_DENIED;
1010}
1011
1013 const char *require_args,
1014 const void *parsed_require_args)
1015{
1016 int result = 0;
1020 (authn_ldap_config_t *)ap_get_module_config(r->per_dir_config, &authnz_ldap_module);
1021
1023
1024 const char *err = NULL;
1025 const ap_expr_info_t *expr = parsed_require_args;
1026 const char *require;
1027
1028 const char *t;
1029
1030 char filtbuf[FILTER_LENGTH];
1031 const char *dn = NULL;
1032
1033 if (!r->user) {
1034 return AUTHZ_DENIED_NO_USER;
1035 }
1036
1037 if (!sec->have_ldap_url) {
1038 return AUTHZ_DENIED;
1039 }
1040
1041 if (sec->host) {
1042 ldc = get_connection_for_authz(r, LDAP_SEARCH); /* _comparedn is a searche */
1046 }
1047 else {
1049 "auth_ldap authorize: no sec->host - weird...?");
1050 return AUTHZ_DENIED;
1051 }
1052
1053 /*
1054 * If we have been authenticated by some other module than mod_auth_ldap,
1055 * the req structure needed for authorization needs to be created
1056 * and populated with the userid and DN of the account in LDAP
1057 */
1058
1059 if (!strlen(r->user)) {
1061 "ldap authorize: Userid is blank, AuthType=%s",
1062 r->ap_auth_type);
1063 }
1064
1065 if(!req) {
1067 "ldap authorize: Creating LDAP req structure");
1068
1070 sizeof(authn_ldap_request_t));
1071 /* Build the username filter */
1073
1074 /* Search for the user DN */
1075 result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn,
1076 sec->scope, sec->attributes, filtbuf, &dn, &(req->vals));
1077
1078 /* Search failed, log error and return failure */
1079 if(result != LDAP_SUCCESS) {
1081 "auth_ldap authorise: User DN not found with filter %s: %s", filtbuf, ldc->reason);
1082 return AUTHZ_DENIED;
1083 }
1084
1085 ap_set_module_config(r->request_config, &authnz_ldap_module, req);
1086 req->dn = apr_pstrdup(r->pool, dn);
1087 req->user = r->user;
1088 }
1089
1090 require = ap_expr_str_exec(r, expr, &err);
1091 if (err) {
1093 "auth_ldap authorize: require dn: Can't evaluate expression: %s",
1094 err);
1095 return AUTHZ_DENIED;
1096 }
1097
1098 t = require;
1099
1100 if (req->dn == NULL || strlen(req->dn) == 0) {
1102 "auth_ldap authorize: require dn: user's DN has not "
1103 "been defined; failing authorization");
1104 return AUTHZ_DENIED;
1105 }
1106
1107 result = util_ldap_cache_comparedn(r, ldc, sec->url, req->dn, t, sec->compare_dn_on_server);
1108 switch(result) {
1109 case LDAP_COMPARE_TRUE: {
1111 "auth_ldap authorize: "
1112 "require dn: authorization successful");
1114 return AUTHZ_GRANTED;
1115 }
1116 default: {
1118 "auth_ldap authorize: "
1119 "require dn \"%s\": LDAP error [%s][%s]",
1120 t, ldc->reason, ldap_err2string(result));
1121 }
1122 }
1123
1124
1126 "auth_ldap authorize dn: authorization denied for "
1127 "user %s to %s",
1128 r->user, r->uri);
1129
1130 return AUTHZ_DENIED;
1131}
1132
1134 const char *require_args,
1135 const void *parsed_require_args)
1136{
1137 int result = 0;
1141 (authn_ldap_config_t *)ap_get_module_config(r->per_dir_config, &authnz_ldap_module);
1142
1144
1145 const char *err = NULL;
1146 const ap_expr_info_t *expr = parsed_require_args;
1147 const char *require;
1148
1149 const char *t;
1150 char *w, *value;
1151
1152 char filtbuf[FILTER_LENGTH];
1153 const char *dn = NULL;
1154
1155 if (!r->user) {
1156 return AUTHZ_DENIED_NO_USER;
1157 }
1158
1159 if (!sec->have_ldap_url) {
1160 return AUTHZ_DENIED;
1161 }
1162
1163 if (sec->host) {
1168 }
1169 else {
1171 "auth_ldap authorize: no sec->host - weird...?");
1172 return AUTHZ_DENIED;
1173 }
1174
1175 /*
1176 * If we have been authenticated by some other module than mod_auth_ldap,
1177 * the req structure needed for authorization needs to be created
1178 * and populated with the userid and DN of the account in LDAP
1179 */
1180
1181 if (!strlen(r->user)) {
1183 "ldap authorize: Userid is blank, AuthType=%s",
1184 r->ap_auth_type);
1185 }
1186
1187 if(!req) {
1189 "ldap authorize: Creating LDAP req structure");
1190
1192 sizeof(authn_ldap_request_t));
1193 /* Build the username filter */
1195
1196 /* Search for the user DN */
1197 result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn,
1198 sec->scope, sec->attributes, filtbuf, &dn, &(req->vals));
1199
1200 /* Search failed, log error and return failure */
1201 if(result != LDAP_SUCCESS) {
1203 "auth_ldap authorise: User DN not found with filter %s: %s", filtbuf, ldc->reason);
1204 return AUTHZ_DENIED;
1205 }
1206
1207 ap_set_module_config(r->request_config, &authnz_ldap_module, req);
1208 req->dn = apr_pstrdup(r->pool, dn);
1209 req->user = r->user;
1210 }
1211
1212 if (req->dn == NULL || strlen(req->dn) == 0) {
1214 "auth_ldap authorize: require ldap-attribute: user's DN "
1215 "has not been defined; failing authorization");
1216 return AUTHZ_DENIED;
1217 }
1218
1219 require = ap_expr_str_exec(r, expr, &err);
1220 if (err) {
1222 "auth_ldap authorize: require ldap-attribute: Can't "
1223 "evaluate expression: %s", err);
1224 return AUTHZ_DENIED;
1225 }
1226
1227 t = require;
1228
1229 while (t[0]) {
1230 w = ap_getword(r->pool, &t, '=');
1232
1234 "auth_ldap authorize: checking attribute %s has value %s",
1235 w, value);
1236 result = util_ldap_cache_compare(r, ldc, sec->url, req->dn, w, value);
1237 switch(result) {
1238 case LDAP_COMPARE_TRUE: {
1240 "auth_ldap authorize: "
1241 "require attribute: authorization successful");
1243 return AUTHZ_GRANTED;
1244 }
1245 default: {
1247 "auth_ldap authorize: require attribute: "
1248 "authorization failed [%s][%s]",
1249 ldc->reason, ldap_err2string(result));
1250 }
1251 }
1252 }
1253
1255 "auth_ldap authorize attribute: authorization denied for "
1256 "user %s to %s",
1257 r->user, r->uri);
1258
1259 return AUTHZ_DENIED;
1260}
1261
1263 const char *require_args,
1264 const void *parsed_require_args)
1265{
1266 int result = 0;
1270 (authn_ldap_config_t *)ap_get_module_config(r->per_dir_config, &authnz_ldap_module);
1271
1273
1274 const char *err = NULL;
1275 const ap_expr_info_t *expr = parsed_require_args;
1276 const char *require;
1277
1278 const char *t;
1279
1280 char filtbuf[FILTER_LENGTH];
1281 const char *dn = NULL;
1282
1283 if (!r->user) {
1284 return AUTHZ_DENIED_NO_USER;
1285 }
1286
1287 if (!sec->have_ldap_url) {
1288 return AUTHZ_DENIED;
1289 }
1290
1291 if (sec->host) {
1296 }
1297 else {
1299 "auth_ldap authorize: no sec->host - weird...?");
1300 return AUTHZ_DENIED;
1301 }
1302
1303 /*
1304 * If we have been authenticated by some other module than mod_auth_ldap,
1305 * the req structure needed for authorization needs to be created
1306 * and populated with the userid and DN of the account in LDAP
1307 */
1308
1309 if (!strlen(r->user)) {
1311 "ldap authorize: Userid is blank, AuthType=%s",
1312 r->ap_auth_type);
1313 }
1314
1315 if(!req) {
1317 "ldap authorize: Creating LDAP req structure");
1318
1320 sizeof(authn_ldap_request_t));
1321 /* Build the username filter */
1323
1324 /* Search for the user DN */
1325 result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn,
1326 sec->scope, sec->attributes, filtbuf, &dn, &(req->vals));
1327
1328 /* Search failed, log error and return failure */
1329 if(result != LDAP_SUCCESS) {
1331 "auth_ldap authorise: User DN not found with filter %s: %s", filtbuf, ldc->reason);
1332 return AUTHZ_DENIED;
1333 }
1334
1335 ap_set_module_config(r->request_config, &authnz_ldap_module, req);
1336 req->dn = apr_pstrdup(r->pool, dn);
1337 req->user = r->user;
1338 }
1339
1340 if (req->dn == NULL || strlen(req->dn) == 0) {
1342 "auth_ldap authorize: require ldap-filter: user's DN "
1343 "has not been defined; failing authorization");
1344 return AUTHZ_DENIED;
1345 }
1346
1347 require = ap_expr_str_exec(r, expr, &err);
1348 if (err) {
1350 "auth_ldap authorize: require ldap-filter: Can't "
1351 "evaluate require expression: %s", err);
1352 return AUTHZ_DENIED;
1353 }
1354
1355 t = require;
1356
1357 if (t[0]) {
1359 "auth_ldap authorize: checking filter %s", t);
1360
1361 /* Build the username filter */
1363
1364 /* Search for the user DN */
1365 result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn,
1366 sec->scope, sec->attributes, filtbuf, &dn, &(req->vals));
1367
1368 /* Make sure that the filtered search returned the correct user dn */
1369 if (result == LDAP_SUCCESS) {
1371 "auth_ldap authorize: checking dn match %s", dn);
1372 if (sec->compare_as_user) {
1373 /* ldap-filter is the only authz that requires a search and a compare */
1377 }
1378 result = util_ldap_cache_comparedn(r, ldc, sec->url, req->dn, dn,
1379 sec->compare_dn_on_server);
1380 }
1381
1382 switch(result) {
1383 case LDAP_COMPARE_TRUE: {
1385 "auth_ldap authorize: require ldap-filter: "
1386 "authorization successful");
1388 return AUTHZ_GRANTED;
1389 }
1390 case LDAP_FILTER_ERROR: {
1392 "auth_ldap authorize: require ldap-filter: "
1393 "%s authorization failed [%s][%s]",
1394 filtbuf, ldc->reason, ldap_err2string(result));
1395 break;
1396 }
1397 default: {
1399 "auth_ldap authorize: require ldap-filter: "
1400 "authorization failed [%s][%s]",
1401 ldc->reason, ldap_err2string(result));
1402 }
1403 }
1404 }
1405
1407 "auth_ldap authorize filter: authorization denied for "
1408 "user %s to %s",
1409 r->user, r->uri);
1410
1411 return AUTHZ_DENIED;
1412}
1413
1414static const char *ldap_parse_config(cmd_parms *cmd, const char *require_line,
1415 const void **parsed_require_line)
1416{
1417 const char *expr_err = NULL;
1418 ap_expr_info_t *expr;
1419
1421 &expr_err, NULL);
1422
1423 if (expr_err)
1424 return apr_pstrcat(cmd->temp_pool,
1425 "Cannot parse expression in require line: ",
1426 expr_err, NULL);
1427
1428 *parsed_require_line = expr;
1429
1430 return NULL;
1431}
1432
1433
1434/*
1435 * Use the ldap url parsing routines to break up the ldap url into
1436 * host and port.
1437 */
1439 void *config,
1440 const char *url,
1441 const char *mode)
1442{
1443 int rc;
1446
1447 authn_ldap_config_t *sec = config;
1448
1449 rc = apr_ldap_url_parse(cmd->pool, url, &(urld), &(result));
1450 if (rc != APR_SUCCESS) {
1451 return result->reason;
1452 }
1453 sec->url = apr_pstrdup(cmd->pool, url);
1454
1455 /* Set all the values, or at least some sane defaults */
1456 if (sec->host) {
1457 sec->host = apr_pstrcat(cmd->pool, urld->lud_host, " ", sec->host, NULL);
1458 }
1459 else {
1460 sec->host = urld->lud_host? apr_pstrdup(cmd->pool, urld->lud_host) : "localhost";
1461 }
1462 sec->basedn = urld->lud_dn? apr_pstrdup(cmd->pool, urld->lud_dn) : "";
1463 if (urld->lud_attrs && urld->lud_attrs[0]) {
1464 int i = 1;
1465 while (urld->lud_attrs[i]) {
1466 i++;
1467 }
1468 sec->attributes = apr_pcalloc(cmd->pool, sizeof(char *) * (i+1));
1469 i = 0;
1470 while (urld->lud_attrs[i]) {
1471 sec->attributes[i] = apr_pstrdup(cmd->pool, urld->lud_attrs[i]);
1472 i++;
1473 }
1474 sec->attribute = sec->attributes[0];
1475 }
1476 else {
1477 sec->attribute = "uid";
1478 }
1479
1480 sec->scope = urld->lud_scope == LDAP_SCOPE_ONELEVEL ?
1482
1483 if (urld->lud_filter) {
1484 if (urld->lud_filter[0] == '(') {
1485 /*
1486 * Get rid of the surrounding parens; later on when generating the
1487 * filter, they'll be put back.
1488 */
1489 sec->filter = apr_pstrmemdup(cmd->pool, urld->lud_filter+1,
1490 strlen(urld->lud_filter)-2);
1491 }
1492 else {
1493 sec->filter = apr_pstrdup(cmd->pool, urld->lud_filter);
1494 }
1495 }
1496 else {
1497 sec->filter = "objectclass=*";
1498 }
1499
1500 if (mode) {
1501 if (0 == strcasecmp("NONE", mode)) {
1502 sec->secure = APR_LDAP_NONE;
1503 }
1504 else if (0 == strcasecmp("SSL", mode)) {
1505 sec->secure = APR_LDAP_SSL;
1506 }
1507 else if (0 == strcasecmp("TLS", mode) || 0 == strcasecmp("STARTTLS", mode)) {
1508 sec->secure = APR_LDAP_STARTTLS;
1509 }
1510 else {
1511 return "Invalid LDAP connection mode setting: must be one of NONE, "
1512 "SSL, or TLS/STARTTLS";
1513 }
1514 }
1515
1516 /* "ldaps" indicates secure ldap connections desired
1517 */
1518 if (strncasecmp(url, "ldaps", 5) == 0)
1519 {
1520 sec->secure = APR_LDAP_SSL;
1521 sec->port = urld->lud_port? urld->lud_port : LDAPS_PORT;
1522 }
1523 else
1524 {
1525 sec->port = urld->lud_port? urld->lud_port : LDAP_PORT;
1526 }
1527
1528 sec->have_ldap_url = 1;
1529
1531 "auth_ldap url parse: `%s', Host: %s, Port: %d, DN: %s, "
1532 "attrib: %s, scope: %s, filter: %s, connection mode: %s",
1533 url,
1534 urld->lud_host,
1535 urld->lud_port,
1536 urld->lud_dn,
1537 urld->lud_attrs? urld->lud_attrs[0] : "(null)",
1538 (urld->lud_scope == LDAP_SCOPE_SUBTREE? "subtree" :
1539 urld->lud_scope == LDAP_SCOPE_BASE? "base" :
1540 urld->lud_scope == LDAP_SCOPE_ONELEVEL? "onelevel" : "unknown"),
1541 urld->lud_filter,
1542 sec->secure == APR_LDAP_SSL ? "using SSL": "not using SSL"
1543 );
1544
1545 return NULL;
1546}
1547
1548static const char *mod_auth_ldap_set_deref(cmd_parms *cmd, void *config, const char *arg)
1549{
1550 authn_ldap_config_t *sec = config;
1551
1552 if (strcmp(arg, "never") == 0 || strcasecmp(arg, "off") == 0) {
1553 sec->deref = never;
1554 }
1555 else if (strcmp(arg, "searching") == 0) {
1556 sec->deref = searching;
1557 }
1558 else if (strcmp(arg, "finding") == 0) {
1559 sec->deref = finding;
1560 }
1561 else if (strcmp(arg, "always") == 0 || strcasecmp(arg, "on") == 0) {
1562 sec->deref = always;
1563 }
1564 else {
1565 return "Unrecognized value for AuthLDAPDereferenceAliases directive";
1566 }
1567 return NULL;
1568}
1569
1570static const char *mod_auth_ldap_add_subgroup_attribute(cmd_parms *cmd, void *config, const char *arg)
1571{
1572 int i = 0;
1573
1574 authn_ldap_config_t *sec = config;
1575
1576 for (i = 0; sec->sgAttributes[i]; i++) {
1577 ;
1578 }
1579 if (i == GROUPATTR_MAX_ELTS)
1580 return "Too many AuthLDAPSubGroupAttribute values";
1581
1582 sec->sgAttributes[i] = apr_pstrdup(cmd->pool, arg);
1583
1584 return NULL;
1585}
1586
1587static const char *mod_auth_ldap_add_subgroup_class(cmd_parms *cmd, void *config, const char *arg)
1588{
1590
1591 authn_ldap_config_t *sec = config;
1592
1593 if (sec->subgroupclasses->nelts > GROUPATTR_MAX_ELTS)
1594 return "Too many AuthLDAPSubGroupClass values";
1595
1596 new = apr_array_push(sec->subgroupclasses);
1597 new->name = apr_pstrdup(cmd->pool, arg);
1598
1599 return NULL;
1600}
1601
1603 void *config,
1604 const char *max_depth)
1605{
1606 authn_ldap_config_t *sec = config;
1607
1609
1610 return NULL;
1611}
1612
1613static const char *mod_auth_ldap_add_group_attribute(cmd_parms *cmd, void *config, const char *arg)
1614{
1616
1617 authn_ldap_config_t *sec = config;
1618
1619 if (sec->groupattr->nelts > GROUPATTR_MAX_ELTS)
1620 return "Too many AuthLDAPGroupAttribute directives";
1621
1622 new = apr_array_push(sec->groupattr);
1623 new->name = apr_pstrdup(cmd->pool, arg);
1624
1625 return NULL;
1626}
1627
1628static const char *set_charset_config(cmd_parms *cmd, void *config, const char *arg)
1629{
1630 ap_set_module_config(cmd->server->module_config, &authnz_ldap_module,
1631 (void *)arg);
1632 return NULL;
1633}
1634
1635static const char *set_bind_pattern(cmd_parms *cmd, void *_cfg, const char *exp, const char *subst)
1636{
1638 ap_regex_t *regexp;
1639
1640 regexp = ap_pregcomp(cmd->pool, exp, AP_REG_EXTENDED);
1641
1642 if (!regexp) {
1643 return apr_pstrcat(cmd->pool, "AuthLDAPInitialBindPattern: cannot compile regular "
1644 "expression '", exp, "'", NULL);
1645 }
1646
1647 sec->bind_regex = regexp;
1648 sec->bind_subst = subst;
1649
1650 return NULL;
1651}
1652
1653static const char *set_bind_password(cmd_parms *cmd, void *_cfg, const char *arg)
1654{
1656 int arglen = strlen(arg);
1657 char **argv;
1658 char *result;
1659
1660 if ((arglen > 5) && strncmp(arg, "exec:", 5) == 0) {
1661 if (apr_tokenize_to_argv(arg+5, &argv, cmd->temp_pool) != APR_SUCCESS) {
1662 return apr_pstrcat(cmd->pool,
1663 "Unable to parse exec arguments from ",
1664 arg+5, NULL);
1665 }
1666 argv[0] = ap_server_root_relative(cmd->temp_pool, argv[0]);
1667
1668 if (!argv[0]) {
1669 return apr_pstrcat(cmd->pool,
1670 "Invalid AuthLDAPBindPassword exec location:",
1671 arg+5, NULL);
1672 }
1673 result = ap_get_exec_line(cmd->pool,
1674 (const char*)argv[0], (const char * const *)argv);
1675
1676 if (!result) {
1677 return apr_pstrcat(cmd->pool,
1678 "Unable to get bind password from exec of ",
1679 arg+5, NULL);
1680 }
1681 sec->bindpw = result;
1682 }
1683 else {
1684 sec->bindpw = (char *)arg;
1685 }
1686
1687 if (!(*sec->bindpw)) {
1688 return "Empty passwords are invalid for AuthLDAPBindPassword";
1689 }
1690
1691 return NULL;
1692}
1693
1695{
1697 "URL to define LDAP connection. This should be an RFC 2255 compliant\n"
1698 "URL of the form ldap://host[:port]/basedn[?attrib[?scope[?filter]]].\n"
1699 "<ul>\n"
1700 "<li>Host is the name of the LDAP server. Use a space separated list of hosts \n"
1701 "to specify redundant servers.\n"
1702 "<li>Port is optional, and specifies the port to connect to.\n"
1703 "<li>basedn specifies the base DN to start searches from\n"
1704 "<li>Attrib specifies what attribute to search for in the directory. If not "
1705 "provided, it defaults to <b>uid</b>.\n"
1706 "<li>Scope is the scope of the search, and can be either <b>sub</b> or "
1707 "<b>one</b>. If not provided, the default is <b>sub</b>.\n"
1708 "<li>Filter is a filter to use in the search. If not provided, "
1709 "defaults to <b>(objectClass=*)</b>.\n"
1710 "</ul>\n"
1711 "Searches are performed using the attribute and the filter combined. "
1712 "For example, assume that the\n"
1713 "LDAP URL is <b>ldap://ldap.airius.com/ou=People, o=Airius?uid?sub?(posixid=*)</b>. "
1714 "Searches will\n"
1715 "be done using the filter <b>(&((posixid=*))(uid=<i>username</i>))</b>, "
1716 "where <i>username</i>\n"
1717 "is the user name passed by the HTTP client. The search will be a subtree "
1718 "search on the branch <b>ou=People, o=Airius</b>."),
1719
1720 AP_INIT_TAKE1("AuthLDAPBindDN", ap_set_string_slot,
1722 "DN to use to bind to LDAP server. If not provided, will do an anonymous bind."),
1723
1724 AP_INIT_TAKE1("AuthLDAPBindPassword", set_bind_password, NULL, OR_AUTHCFG,
1725 "Password to use to bind to LDAP server. If not provided, will do an anonymous bind."),
1726
1727 AP_INIT_FLAG("AuthLDAPBindAuthoritative", ap_set_flag_slot,
1728 (void *)APR_OFFSETOF(authn_ldap_config_t, bind_authoritative), OR_AUTHCFG,
1729 "Set to 'on' to return failures when user-specific bind fails - defaults to on."),
1730
1731 AP_INIT_FLAG("AuthLDAPRemoteUserIsDN", ap_set_flag_slot,
1732 (void *)APR_OFFSETOF(authn_ldap_config_t, user_is_dn), OR_AUTHCFG,
1733 "Set to 'on' to set the REMOTE_USER environment variable to be the full "
1734 "DN of the remote user. By default, this is set to off, meaning that "
1735 "the REMOTE_USER variable will contain whatever value the remote user sent."),
1736
1737 AP_INIT_TAKE1("AuthLDAPRemoteUserAttribute", ap_set_string_slot,
1738 (void *)APR_OFFSETOF(authn_ldap_config_t, remote_user_attribute), OR_AUTHCFG,
1739 "Override the user supplied username and place the "
1740 "contents of this attribute in the REMOTE_USER "
1741 "environment variable."),
1742
1743 AP_INIT_FLAG("AuthLDAPCompareDNOnServer", ap_set_flag_slot,
1744 (void *)APR_OFFSETOF(authn_ldap_config_t, compare_dn_on_server), OR_AUTHCFG,
1745 "Set to 'on' to force auth_ldap to do DN compares (for the \"require dn\" "
1746 "directive) using the server, and set it 'off' to do the compares locally "
1747 "(at the expense of possible false matches). See the documentation for "
1748 "a complete description of this option."),
1749
1751 "Attribute labels used to define sub-group (or nested group) membership in groups - "
1752 "defaults to member and uniqueMember"),
1753
1755 "LDAP objectClass values used to identify sub-group instances - "
1756 "defaults to groupOfNames and groupOfUniqueNames"),
1757
1759 "Maximum subgroup nesting depth to be evaluated - defaults to 10 (top-level group = 0)"),
1760
1762 "A list of attribute labels used to identify the user members of groups - defaults to "
1763 "member and uniquemember"),
1764
1765 AP_INIT_FLAG("AuthLDAPGroupAttributeIsDN", ap_set_flag_slot,
1766 (void *)APR_OFFSETOF(authn_ldap_config_t, group_attrib_is_dn), OR_AUTHCFG,
1767 "If set to 'on', auth_ldap uses the DN that is retrieved from the server for "
1768 "subsequent group comparisons. If set to 'off', auth_ldap uses the string "
1769 "provided by the client directly. Defaults to 'on'."),
1770
1771 AP_INIT_TAKE1("AuthLDAPDereferenceAliases", mod_auth_ldap_set_deref, NULL, OR_AUTHCFG,
1772 "Determines how aliases are handled during a search. Can be one of the "
1773 "values \"never\", \"searching\", \"finding\", or \"always\". "
1774 "Defaults to always."),
1775
1776 AP_INIT_TAKE1("AuthLDAPCharsetConfig", set_charset_config, NULL, RSRC_CONF,
1777 "Character set conversion configuration file. If omitted, character set "
1778 "conversion is disabled."),
1779
1780 AP_INIT_TAKE1("AuthLDAPAuthorizePrefix", ap_set_string_slot,
1781 (void *)APR_OFFSETOF(authn_ldap_config_t, authz_prefix), OR_AUTHCFG,
1782 "The prefix to add to environment variables set during "
1783 "successful authorization, default '" AUTHZ_PREFIX "'"),
1784
1785 AP_INIT_FLAG("AuthLDAPInitialBindAsUser", ap_set_flag_slot,
1786 (void *)APR_OFFSETOF(authn_ldap_config_t, initial_bind_as_user), OR_AUTHCFG,
1787 "Set to 'on' to perform the initial DN lookup with the basic auth credentials "
1788 "instead of anonymous or hard-coded credentials"),
1789
1790 AP_INIT_TAKE2("AuthLDAPInitialBindPattern", set_bind_pattern, NULL, OR_AUTHCFG,
1791 "The regex and substitution to determine a username that can bind based on an HTTP basic auth username"),
1792
1793 AP_INIT_FLAG("AuthLDAPSearchAsUser", ap_set_flag_slot,
1794 (void *)APR_OFFSETOF(authn_ldap_config_t, search_as_user), OR_AUTHCFG,
1795 "Set to 'on' to perform authorization-based searches with the users credentials, when this module "
1796 "has also performed authentication. Does not affect nested groups lookup."),
1797 AP_INIT_FLAG("AuthLDAPCompareAsUser", ap_set_flag_slot,
1798 (void *)APR_OFFSETOF(authn_ldap_config_t, compare_as_user), OR_AUTHCFG,
1799 "Set to 'on' to perform authorization-based compares with the users credentials, when this module "
1800 "has also performed authentication. Does not affect nested groups lookups."),
1801 {NULL}
1802};
1803
1805{
1807 char l[MAX_STRING_LEN];
1808 const char *charset_confname = ap_get_module_config(s->module_config,
1809 &authnz_ldap_module);
1811
1812 /*
1813 authn_ldap_config_t *sec = (authn_ldap_config_t *)
1814 ap_get_module_config(s->module_config,
1815 &authnz_ldap_module);
1816
1817 if (sec->secure)
1818 {
1819 if (!util_ldap_ssl_supported(s))
1820 {
1821 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, APLOGNO(03159)
1822 "LDAP: SSL connections (ldaps://) not supported by utilLDAP");
1823 return(!OK);
1824 }
1825 }
1826 */
1827
1828 /* make sure that mod_ldap (util_ldap) is loaded */
1829 if (ap_find_linked_module("util_ldap.c") == NULL) {
1831 "Module mod_ldap missing. Mod_ldap (aka. util_ldap) "
1832 "must be loaded in order for mod_authnz_ldap to function properly");
1834
1835 }
1836
1837 if (!charset_confname) {
1838 return OK;
1839 }
1840
1842 if (!charset_confname) {
1844 "Invalid charset conversion config path %s",
1845 (const char *)ap_get_module_config(s->module_config,
1846 &authnz_ldap_module));
1848 }
1849 if ((status = ap_pcfg_openfile(&f, ptemp, charset_confname))
1850 != APR_SUCCESS) {
1852 "could not open charset conversion config file %s.",
1855 }
1856
1858
1859 while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {
1860 const char *ll = l;
1861 char *lang;
1862
1863 if (l[0] == '#') {
1864 continue;
1865 }
1866 lang = ap_getword_conf(p, &ll);
1867 ap_str_tolower(lang);
1868
1869 if (ll[0]) {
1870 char *charset = ap_getword_conf(p, &ll);
1872 }
1873 }
1875
1877 if (to_charset == NULL) {
1879 "could not find the UTF-8 charset in the file %s.",
1882 }
1883
1884 return OK;
1885}
1886
1888{
1890 NULL,
1891};
1892
1903
1909
1915
1921
1933
1967
1969{
1971 create_authnz_ldap_dir_config, /* dir config creater */
1972 NULL, /* dir merger --- default is to override */
1973 NULL, /* server config */
1974 NULL, /* merge server config */
1975 authnz_ldap_cmds, /* command apr_table_t */
1976 register_hooks /* register hooks */
1977};
Apache Provider API.
#define AP_REG_EXTENDED
Definition ap_regex.h:78
apr_size_t char apr_size_t * outbytes
apr_size_t * inbytes
APR general purpose library routines.
apr_size_t const unsigned char unsigned int unsigned int d
Definition apr_siphash.h:72
APR Strings library.
APR Standard Headers Support.
APR I18N translation library.
static sem_id lock
Definition threadpriv.c:21
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
#define ap_get_module_config(v, m)
int ap_cfg_closefile(ap_configfile_t *cfp)
Definition util.c:931
void ap_hook_post_config(ap_HOOK_post_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:105
apr_status_t ap_pcfg_openfile(ap_configfile_t **ret_cfg, apr_pool_t *p, const char *name)
Definition util.c:957
#define AP_DECLARE_MODULE(foo)
#define AP_INIT_FLAG(directive, func, mconfig, where, help)
#define AP_INIT_ITERATE(directive, func, mconfig, where, help)
char * ap_server_root_relative(apr_pool_t *p, const char *fname)
Definition config.c:1594
const char * ap_set_string_slot(cmd_parms *cmd, void *struct_ptr, const char *arg)
Definition config.c:1469
#define ap_set_module_config(v, m, val)
#define AP_INIT_TAKE12(directive, func, mconfig, where, help)
const char * ap_set_flag_slot(cmd_parms *cmd, void *struct_ptr, int arg)
Definition config.c:1512
request_rec * r
void ap_hook_optional_fn_retrieve(ap_HOOK_optional_fn_retrieve_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:195
apr_status_t ap_cfg_getline(char *buf, apr_size_t bufsize, ap_configfile_t *cfp)
Definition util.c:1198
#define AP_INIT_TAKE2(directive, func, mconfig, where, help)
#define MAX_STRING_LEN
Definition httpd.h:300
#define AP_MAX_REG_MATCH
Definition httpd.h:309
#define OK
Definition httpd.h:456
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_INFO
Definition http_log.h:70
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_WARNING
Definition http_log.h:68
#define APLOG_TRACE1
Definition http_log.h:72
#define APLOG_DEBUG
Definition http_log.h:71
apr_status_t ap_register_auth_provider(apr_pool_t *pool, const char *provider_group, const char *provider_name, const char *provider_version, const void *provider, int type)
Definition request.c:2179
#define AP_AUTH_INTERNAL_PER_CONF
void const char * arg
Definition http_vhost.h:63
#define APR_EBADPATH
Definition apr_errno.h:332
apr_file_t * f
apr_bucket * e
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
const char * url
Definition apr_escape.h:120
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define APR_RETRIEVE_OPTIONAL_FN(name)
#define APR_OPTIONAL_FN_TYPE(name)
apr_redis_t * rc
Definition apr_redis.h:173
struct apr_xlate_t apr_xlate_t
Definition apr_xlate.h:39
const char apr_size_t char * outbuf
Definition apr_xlate.h:120
#define AP_EXPR_FLAG_STRING_RESULT
Definition ap_expr.h:68
#define ap_expr_parse_cmd(cmd, expr, flags, err, lookup_fn)
Definition ap_expr.h:340
const char * ap_expr_str_exec(request_rec *r, const ap_expr_info_t *expr, const char **err)
#define RSRC_CONF
#define OR_AUTHCFG
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
#define STANDARD20_MODULE_STUFF
char * ap_get_exec_line(apr_pool_t *p, const char *cmd, const char *const *argv)
Definition util.c:3386
char * ap_getword(apr_pool_t *p, const char **line, char stop)
Definition util.c:723
char * ap_pregsub(apr_pool_t *p, const char *input, const char *source, apr_size_t nmatch, ap_regmatch_t pmatch[])
Definition util.c:457
void ap_str_tolower(char *s)
Definition util.c:2410
ap_regex_t * ap_pregcomp(apr_pool_t *p, const char *pattern, int cflags)
Definition util.c:262
char * ap_getword_conf(apr_pool_t *p, const char **line)
Definition util.c:833
apr_size_t size
#define apr_toupper(c)
Definition apr_lib.h:233
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
int type
apr_array_header_t ** result
int strcasecmp(const char *a, const char *b)
int strncasecmp(const char *a, const char *b, size_t n)
#define APR_HASH_KEY_STRING
Definition apr_hash.h:47
apr_interval_time_t t
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * s
Definition apr_strings.h:95
const char const char * password
apr_int32_t apr_int32_t apr_int32_t err
apr_cmdtype_e cmd
int int status
Apache Configuration.
CORE HTTP Daemon.
Apache Logging library.
HTTP protocol handling.
Apache Request library.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
Authentication and Authorization Extension for Apache.
#define AUTHN_PROVIDER_VERSION
Definition mod_auth.h:41
#define AUTHN_PROVIDER_GROUP
Definition mod_auth.h:39
authz_status
Definition mod_auth.h:72
@ AUTHZ_DENIED
Definition mod_auth.h:73
@ AUTHZ_DENIED_NO_USER
Definition mod_auth.h:77
@ AUTHZ_GRANTED
Definition mod_auth.h:74
authn_status
Definition mod_auth.h:64
@ AUTH_GRANTED
Definition mod_auth.h:66
@ AUTH_DENIED
Definition mod_auth.h:65
@ AUTH_GENERAL_ERROR
Definition mod_auth.h:69
@ AUTH_USER_NOT_FOUND
Definition mod_auth.h:68
#define AUTHZ_PROVIDER_VERSION
Definition mod_auth.h:42
#define AUTHN_PREFIX
Definition mod_auth.h:48
#define AUTHZ_PROVIDER_GROUP
Definition mod_auth.h:40
#define AUTHZ_PREFIX
Definition mod_auth.h:49
static apr_status_t authnz_ldap_cleanup_connection_close(void *param)
static apr_xlate_t * get_conv_set(request_rec *r)
static authz_status ldapgroup_check_authorization(request_rec *r, const char *require_args, const void *parsed_require_args)
static apr_OFN_uldap_connection_close_t * util_ldap_connection_close
static char * default_attributes[3]
static const authz_provider authz_ldapdn_provider
static void ImportULDAPOptFn(void)
static const authz_provider authz_ldapattribute_provider
static const char * ldap_determine_binddn(request_rec *r, const char *user)
static util_ldap_connection_t * get_connection_for_authz(request_rec *r, enum auth_ldap_optype type)
static apr_hash_t * charset_conversions
static const char * mod_auth_ldap_set_subgroup_maxdepth(cmd_parms *cmd, void *config, const char *max_depth)
static const char * mod_auth_ldap_parse_url(cmd_parms *cmd, void *config, const char *url, const char *mode)
static int set_request_vars(request_rec *r, enum auth_ldap_phase phase)
static char * derive_codepage_from_lang(apr_pool_t *p, char *language)
static int authnz_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
static const char * mod_auth_ldap_add_group_attribute(cmd_parms *cmd, void *config, const char *arg)
static authz_status ldapattribute_check_authorization(request_rec *r, const char *require_args, const void *parsed_require_args)
auth_ldap_optype
@ LDAP_COMPARE
@ LDAP_COMPARE_AND_SEARCH
@ LDAP_SEARCH
static const authz_provider authz_ldapuser_provider
static authn_status authn_ldap_check_password(request_rec *r, const char *user, const char *password)
static const char * authn_ldap_xlate_password(request_rec *r, const char *sent_password)
static apr_OFN_uldap_ssl_supported_t * util_ldap_ssl_supported
static void authn_ldap_build_filter(char *filtbuf, request_rec *r, const char *sent_user, const char *sent_filter, authn_ldap_config_t *sec)
static const authz_provider authz_ldapfilter_provider
auth_ldap_phase
@ LDAP_AUTHZ
@ LDAP_AUTHN
static const char * set_bind_pattern(cmd_parms *cmd, void *_cfg, const char *exp, const char *subst)
static const char * mod_auth_ldap_set_deref(cmd_parms *cmd, void *config, const char *arg)
static const char * set_bind_password(cmd_parms *cmd, void *_cfg, const char *arg)
static void register_hooks(apr_pool_t *p)
static authz_status ldapfilter_check_authorization(request_rec *r, const char *require_args, const void *parsed_require_args)
static const char * set_charset_config(cmd_parms *cmd, void *config, const char *arg)
static const char * ldap_parse_config(cmd_parms *cmd, const char *require_line, const void **parsed_require_line)
#define GROUPATTR_MAX_ELTS
static apr_OFN_uldap_cache_getuserdn_t * util_ldap_cache_getuserdn
static apr_OFN_uldap_cache_comparedn_t * util_ldap_cache_comparedn
static const command_rec authnz_ldap_cmds[]
static const char * mod_auth_ldap_add_subgroup_class(cmd_parms *cmd, void *config, const char *arg)
static apr_OFN_uldap_connection_find_t * util_ldap_connection_find
static const char * mod_auth_ldap_add_subgroup_attribute(cmd_parms *cmd, void *config, const char *arg)
static char * to_charset
static const authz_provider authz_ldapgroup_provider
static authz_status ldapdn_check_authorization(request_rec *r, const char *require_args, const void *parsed_require_args)
static apr_OFN_uldap_cache_checkuserid_t * util_ldap_cache_checkuserid
static void * create_authnz_ldap_dir_config(apr_pool_t *p, char *d)
static authz_status ldapuser_check_authorization(request_rec *r, const char *require_args, const void *parsed_require_args)
static apr_OFN_uldap_cache_compare_t * util_ldap_cache_compare
static apr_OFN_uldap_cache_check_subgroups_t * util_ldap_cache_check_subgroups
#define FILTER_LENGTH
static const authn_provider authn_ldap_provider
struct param_s param
const char * argv[3]
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
char * name
apr_array_header_t * groupattr
const char * bind_subst
apr_array_header_t * subgroupclasses
ap_regex_t * bind_regex
char * name
A structure that represents the current request.
Definition httpd.h:845
char * user
Definition httpd.h:1005
char * uri
Definition httpd.h:1016
apr_pool_t * pool
Definition httpd.h:847
struct ap_conf_vector_t * request_config
Definition httpd.h:1049
apr_table_t * headers_in
Definition httpd.h:976
apr_table_t * subprocess_env
Definition httpd.h:983
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
char * ap_auth_type
Definition httpd.h:1007
A structure to keep track of authorization requirements.
Definition http_core.h:316
A structure to store information for each virtual server.
Definition httpd.h:1322
#define str
static int uldap_cache_check_subgroups(request_rec *r, util_ldap_connection_t *ldc, const char *url, const char *dn, const char *attrib, const char *value, char **subgroupAttrs, apr_array_header_t *subgroupclasses, int cur_subgroup_depth, int max_subgroup_depth)
Definition util_ldap.c:1453
static int uldap_cache_comparedn(request_rec *r, util_ldap_connection_t *ldc, const char *url, const char *dn, const char *reqdn, int compare_dn_on_server)
Definition util_ldap.c:946
static int uldap_cache_compare(request_rec *r, util_ldap_connection_t *ldc, const char *url, const char *dn, const char *attrib, const char *value)
Definition util_ldap.c:1093
static void uldap_connection_close(util_ldap_connection_t *ldc)
Definition util_ldap.c:197
static int uldap_ssl_supported(request_rec *r)
Definition util_ldap.c:2180
static util_ldap_connection_t * uldap_connection_find(request_rec *r, const char *host, int port, const char *binddn, const char *bindpw, deref_options deref, int secure)
Definition util_ldap.c:742
static int uldap_cache_checkuserid(request_rec *r, util_ldap_connection_t *ldc, const char *url, const char *basedn, int scope, char **attrs, const char *filter, const char *bindpw, const char **binddn, const char ***retvals)
Definition util_ldap.c:1697
static int uldap_cache_getuserdn(request_rec *r, util_ldap_connection_t *ldc, const char *url, const char *basedn, int scope, char **attrs, const char *filter, const char **binddn, const char ***retvals)
Definition util_ldap.c:1974
Apache LDAP library.