"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * mod_auth_ldap
3 *
4 * User Authentication against LDAP database
5 *
6 * Alexander Mayrhofer axelm+ldap@nona.net
7 *
8 * http://nona.net/software/ldap/
9 *
10 */
11
12 /*
13 * MODULE-DEFINITION-START
14 * Name: ldap_auth_module
15 * ConfigStart
16 LDAP_LIBS="-lldap -llber"
17 LIBS="$LIBS $LDAP_LIBS"
18 echo " + using LDAP libraries for auth_ldap module"
19 * ConfigEnd
20 * MODULE-DEFINITION-END
21 */
22
23 #include "httpd.h"
24 #include "http_config.h"
25 #include "http_core.h"
26 #include "http_log.h"
27 #include "http_protocol.h"
28 #include <lber.h>
29 #include <ldap.h>
30 #include <unistd.h>
31
32 #define SHA1_DIGEST_LENGTH 29 /* sha1 digest length including null character */
33
34 typedef struct {
35
36 char *auth_ldaphosts;
37 char *auth_ldapbinddn;
38 char *auth_ldapbindpassword;
39 char *auth_ldapbasedn;
40 char *auth_ldapuserkey;
41 char *auth_ldappasskey;
42 char *auth_ldapgroupkey;
43 char *auth_ldapsearchscope;
44 int auth_ldapauthoritative;
45 int auth_ldapbasesearch;
46 int auth_ldapcryptpasswords;
47 int auth_ldapbindasuser;
48 int auth_ldapschemeprefix;
49
50 } ldap_auth_config_rec;
51
52 void *create_ldap_auth_dir_config (pool *p, char *d)
53 {
54 ldap_auth_config_rec *sec
55 = (ldap_auth_config_rec *)ap_pcalloc (p, sizeof(ldap_auth_config_rec));
56
57 sec->auth_ldaphosts = NULL;
58 sec->auth_ldapbinddn = NULL;
59 sec->auth_ldapbindpassword = NULL;
60 sec->auth_ldapbasedn = NULL;
61 sec->auth_ldapsearchscope = NULL;
62 sec->auth_ldapauthoritative = 1; /* fortress is secure by default */
63 sec->auth_ldapbasesearch = 0;
64 sec->auth_ldapcryptpasswords = 0;
65 sec->auth_ldapbindasuser = 0; /* by default, we bind as configured user to ldap */
66 sec->auth_ldapschemeprefix = 0; /* no scheme prefix in password strings */
67
68 return sec;
69 }
70
71 command_rec ldap_auth_cmds[] = {
72 { "AuthLDAPHosts", ap_set_string_slot,
73 (void*)XtOffsetOf(ldap_auth_config_rec, auth_ldaphosts),
74 OR_AUTHCFG, TAKE1,
75 "List of LDAP hosts which should be queried" },
76 { "AuthLDAPBindDN", ap_set_string_slot,
77 (void*)XtOffsetOf(ldap_auth_config_rec, auth_ldapbinddn),
78 OR_AUTHCFG, TAKE1,
79 "As which DN to bind to the LDAP directory" },
80 { "AuthLDAPBindPassword", ap_set_string_slot,
81 (void*)XtOffsetOf(ldap_auth_config_rec, auth_ldapbindpassword),
82 OR_AUTHCFG, TAKE1,
83 "The password corresponding to AuthLDAPBindDN" },
84 { "AuthLDAPBaseDN", ap_set_string_slot,
85 (void*)XtOffsetOf(ldap_auth_config_rec, auth_ldapbasedn),
86 OR_AUTHCFG, TAKE1,
87 "The DN in the LDAP directory which contains the per-user subnodes" },
88 { "AuthLDAPUserKey", ap_set_string_slot,
89 (void*)XtOffsetOf(ldap_auth_config_rec, auth_ldapuserkey),
90 OR_AUTHCFG, TAKE1,
91 "The key which's value contains the username in the directory" },
92 { "AuthLDAPPassKey", ap_set_string_slot,
93 (void*)XtOffsetOf(ldap_auth_config_rec, auth_ldappasskey),
94 OR_AUTHCFG, TAKE1,
95 "The key to the user's password" },
96 { "AuthLDAPGroupKey", ap_set_string_slot,
97 (void*)XtOffsetOf(ldap_auth_config_rec, auth_ldapgroupkey),
98 OR_AUTHCFG, TAKE1,
99 "the key to the user's group membership string" },
100 { "AuthLDAPBaseSearch", ap_set_flag_slot,
101 (void*)XtOffsetOf(ldap_auth_config_rec, auth_ldapbasesearch),
102 OR_AUTHCFG, FLAG,
103 "Deprecated. Use 'AuthLDAPSearchScope'. Anyway: Set to 'on' if you do want to do a base search only" },
104 { "AuthLDAPSearchScope", ap_set_string_slot,
105 (void*)XtOffsetOf(ldap_auth_config_rec, auth_ldapsearchscope),
106 OR_AUTHCFG, TAKE1,
107 "Set Scope when searching in LDAP. Can be 'base', 'onelevel' or 'subtree'" },
108 { "AuthLDAPAuthoritative", ap_set_flag_slot,
109 (void*)XtOffsetOf(ldap_auth_config_rec, auth_ldapauthoritative),
110 OR_AUTHCFG, FLAG,
111 "Set to 'off' to allow control to be passed on, if UserID unknow to this module" },
112 { "AuthLDAPCryptPasswords", ap_set_flag_slot,
113 (void*)XtOffsetOf(ldap_auth_config_rec, auth_ldapcryptpasswords),
114 OR_AUTHCFG, FLAG,
115 "Set to 'on' if you do have crypted password strings" },
116 { "AuthLDAPBindAsUser", ap_set_flag_slot,
117 (void*)XtOffsetOf(ldap_auth_config_rec, auth_ldapbindasuser),
118 OR_AUTHCFG, FLAG,
119 "Set to 'on' if you want to bind as the user for authentication" },
120 { "AuthLDAPSchemePrefix", ap_set_flag_slot,
121 (void*)XtOffsetOf(ldap_auth_config_rec, auth_ldapschemeprefix),
122 OR_AUTHCFG, FLAG,
123 "Set to 'on' if you have scheme-prefixed password strings as described in rfc2307" },
124 { NULL }
125 };
126
127 module ldap_auth_module;
128
129 char *get_ldap_val(request_rec *r, char *user, char *pass, ldap_auth_config_rec *conf, char *attr) {
130 char *bindas, *bindpass;
131 LDAP *ldap;
132 LDAPMessage *ld_result, *ld_entry;
133 char ldap_query[200];
134 char ldap_base[200];
135 char **ld_values;
136 char *retval = NULL;
137 int ldap_scope;
138
139 if(!(ldap = ldap_open(conf->auth_ldaphosts, LDAP_PORT))) {
140 printf("ldap host: %s", conf->auth_ldaphosts);
141 ap_log_reason("ldap_open failed", conf->auth_ldaphosts, r);
142 return NULL;
143 }
144 if(conf->auth_ldapbindasuser) {
145 if ((!pass) || (!strcmp(pass,""))) {
146 ap_log_reason("ldap_bind: no password given (BindAsUser enabled)!", NULL, r);
147 return NULL;
148 }
149 ap_snprintf(ldap_base, sizeof ldap_base, "%s=%s,%s", conf->auth_ldapuserkey, user, conf->auth_ldapbasedn);
150 bindas = ldap_base;
151 bindpass = pass;
152 }
153 else {
154 bindas = conf->auth_ldapbinddn;
155 bindpass = conf->auth_ldapbindpassword;
156 }
157 if(ldap_simple_bind_s(ldap, bindas, bindpass)) {
158 ap_log_reason("ldap_bind failed", bindas, r);
159 return NULL;
160 }
161 if(!attr) {
162 ldap_unbind_s(ldap);
163 return "bind";
164 }
165 ap_snprintf(ldap_query, sizeof ldap_query, "%s=%s", conf->auth_ldapuserkey, user);
166 /* check for search scope */
167 if(conf->auth_ldapbasesearch || (conf->auth_ldapsearchscope &&
168 !strcasecmp(conf->auth_ldapsearchscope, "base"))) {
169 ap_snprintf(ldap_base, sizeof ldap_base, "%s=%s,%s", conf->auth_ldapuserkey, user, conf->auth_ldapbasedn);
170 ldap_scope = LDAP_SCOPE_BASE;
171 }
172 else {
173 ap_snprintf(ldap_base, sizeof ldap_base, "%s", conf->auth_ldapbasedn);
174 if(conf->auth_ldapsearchscope) {
175 ldap_scope = strcasecmp(conf->auth_ldapsearchscope, "subtree") ?
176 LDAP_SCOPE_ONELEVEL : LDAP_SCOPE_SUBTREE;
177 }
178 }
179 if(ldap_search_s(ldap, ldap_base, ldap_scope,
180 ldap_query, NULL, 0, &ld_result)) {
181 ap_log_reason("ldap_search failed", ldap_query, r);
182 ldap_unbind_s(ldap);
183 return NULL;
184 }
185 if(!(ld_entry = ldap_first_entry(ldap, ld_result))) {
186 ap_log_reason("user not found", user, r);
187 ldap_unbind_s(ldap);
188 return NULL;
189 }
190 if(!(ld_values = ldap_get_values(ldap, ld_entry, attr))) {
191 ap_log_reason("ldap_get_values failed", attr, r);
192 ldap_unbind_s(ldap);
193 return NULL;
194 }
195
196 retval = ap_palloc (r->pool, strlen(ld_values[0])+1);
197 strcpy(retval,ld_values[0]);
198
199 ldap_value_free(ld_values);
200 ldap_unbind_s(ldap);
201
202 return retval;
203 }
204
205 char *get_ldap_grp(request_rec *r, char *user, char *pass, ldap_auth_config_rec *conf) {
206 return get_ldap_val(r, user, pass, conf, conf->auth_ldapgroupkey);
207 }
208
209 int ldap_authenticate_basic_user (request_rec *r)
210 {
211 ldap_auth_config_rec *sec =
212 (ldap_auth_config_rec *)ap_get_module_config (r->per_dir_config,
213 &ldap_auth_module);
214 conn_rec *c = r->connection;
215 char *sent_pw, *real_pw, *digest;
216 char errstr[MAX_STRING_LEN];
217 int res;
218
219 if ((res = ap_get_basic_auth_pw (r, (const char **)&sent_pw)))
220 return res;
221
222 if(!sec->auth_ldapuserkey)
223 return DECLINED;
224
225 if(sec->auth_ldapbindasuser) {
226 if(!(real_pw = get_ldap_val(r, c->user, sent_pw, sec, sec->auth_ldappasskey))) {
227 if (!(sec->auth_ldapauthoritative))
228 return DECLINED;
229 ap_snprintf(errstr, sizeof(errstr), "LDAP user %s not found or password invalid", c->user);
230 ap_log_reason (errstr, r->filename, r);
231 ap_note_basic_auth_failure (r);
232 return AUTH_REQUIRED;
233 }
234 return OK;
235 }
236 if(!(real_pw = get_ldap_val(r, c->user, sent_pw, sec, sec->auth_ldappasskey))) {
237 if (!(sec->auth_ldapauthoritative))
238 return DECLINED;
239 ap_snprintf(errstr, sizeof(errstr), "LDAP user %s not found", c->user);
240 ap_log_reason (errstr, r->filename, r);
241 ap_note_basic_auth_failure (r);
242 return AUTH_REQUIRED;
243 }
244 if (!sec->auth_ldapbindasuser) {
245 /* We didn't use the credentials to bind to LDAP, so check them.. */
246 if (sec->auth_ldapschemeprefix) {
247 /* we do use scheme prefixes as described in RFC2307 */
248 /* currently sha, crypt are supported */
249 if (!strncasecmp("{crypt}", real_pw, 7)) {
250 if(!strcmp(real_pw+7, crypt(sent_pw,real_pw+7)))
251 return OK;
252 }
253 if (!strncasecmp("{sha}", real_pw, 5)) {
254 digest = ap_palloc (r->pool, SHA1_DIGEST_LENGTH);
255 sha1_digest(sent_pw, strlen(sent_pw), digest);
256 if(!strcmp(real_pw+5, digest))
257 return OK;
258 }
259 ap_snprintf(errstr, sizeof(errstr),
260 "user %s: password mismatch %s, %s", c->user, real_pw+5, digest);
261 ap_log_reason (errstr, r->uri, r);
262 ap_note_basic_auth_failure (r);
263 return AUTH_REQUIRED;
264 }
265
266 if (sec->auth_ldapcryptpasswords) {
267 /* Passwords are crypted */
268 if(strcmp(real_pw,crypt(sent_pw,real_pw))) {
269 ap_snprintf(errstr, sizeof(errstr),
270 "user %s: password mismatch",c->user);
271 ap_log_reason (errstr, r->uri, r);
272 ap_note_basic_auth_failure (r);
273 return AUTH_REQUIRED;
274 }
275 }
276 else {
277 /* We have clear text passwords ... */
278 if(strcmp(real_pw,sent_pw)) {
279 ap_snprintf(errstr, sizeof(errstr),
280 "user %s: password mismatch",c->user);
281 ap_log_reason (errstr, r->uri, r);
282 ap_note_basic_auth_failure (r);
283 return AUTH_REQUIRED;
284 }
285 }
286 }
287 return OK;
288 }
289
290 /* Checking ID */
291
292 int ldap_check_auth(request_rec *r) {
293 ldap_auth_config_rec *sec =
294 (ldap_auth_config_rec *)ap_get_module_config (r->per_dir_config,
295 &ldap_auth_module);
296 char *user = r->connection->user;
297 int m = r->method_number;
298 char errstr[MAX_STRING_LEN];
299
300 const array_header *reqs_arr = ap_requires (r);
301 require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL;
302
303 register int x;
304 const char *t;
305 char *w;
306
307 if (!sec->auth_ldapgroupkey) return DECLINED;
308 if (!reqs_arr) return DECLINED;
309 for(x=0; x < reqs_arr->nelts; x++) {
310
311 if (! (reqs[x].method_mask & (1 << m))) continue;
312
313 t = reqs[x].requirement;
314 w = ap_getword(r->pool, &t, ' ');
315
316 if(!strcmp(w,"group") && sec->auth_ldapgroupkey) {
317 const char *orig_groups,*groups;
318 char *v;
319
320 if (!(groups = get_ldap_grp(r, user, 0, sec))) {
321 if (!(sec->auth_ldapauthoritative))
322 return DECLINED;
323 ap_snprintf(errstr, sizeof(errstr),
324 "groups for user %s not found in LDAP directory (key %s)",
325 user, sec->auth_ldapgroupkey);
326 ap_log_reason (errstr, r->filename, r);
327 ap_note_basic_auth_failure (r);
328 return AUTH_REQUIRED;
329 }
330 orig_groups = groups;
331 while(t[0]) {
332 w = ap_getword(r->pool, &t, ' ');
333 groups = orig_groups;
334 while(groups[0]) {
335 v = ap_getword(r->pool, &groups,',');
336 if(!strcmp(v,w))
337 return OK;
338 }
339 }
340 ap_snprintf(errstr, sizeof(errstr),
341 "user %s not in right group",user);
342 ap_log_reason (errstr, r->filename, r);
343 ap_note_basic_auth_failure(r);
344 return AUTH_REQUIRED;
345 }
346 }
347
348 return DECLINED;
349 }
350
351
352 module ldap_auth_module = {
353 STANDARD_MODULE_STUFF,
354 NULL, /* initializer */
355 create_ldap_auth_dir_config, /* dir config creater */
356 NULL, /* dir merger --- default is to override */
357 NULL, /* server config */
358 NULL, /* merge server config */
359 ldap_auth_cmds, /* command table */
360 NULL, /* handlers */
361 NULL, /* filename translation */
362 ldap_authenticate_basic_user, /* check_user_id */
363 ldap_check_auth, /* check auth */
364 NULL, /* check access */
365 NULL, /* type_checker */
366 NULL, /* fixups */
367 NULL, /* logger */
368 NULL /* header parser */
369 };