1 /* ============================================================
2 * Copyright (c) 2003-2006, Ondrej Sury, Piotr Wadas
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 * NOTE: only static members must be "used" to build,
14 * so for time-to-time used routines we don't declare static
15 * mod_vhost_ldap.c --- read virtual host config from LDAP directory
16 * version 2.0 - included ldap-based basic auth & authz
17 * remember to add "-lcrypt" in Makefile if there's a need to generate new password
18 * for now not needed (validation only), this below is almost copy-paste from apache source, htpasswd.c
21 #include "mod_vhost_ldap.h"
23 module AP_MODULE_DECLARE_DATA vhost_ldap_module;
24 /******************************************************************/
25 char *pw_encrypt (const char *clear, const char *salt)
27 //this function encrypts password in unix crypt md5 way
28 extern char *crypt (__const char *__key, __const char *__salt);
29 static char cipher[128];
30 char *cp = crypt (clear, salt);
34 /******************************************************************/
35 static int strschrcount(apr_pool_t * p, const char *src, const char *delim)
40 if(strcasecmp(apr_pstrndup(p, src, i), (char *) delim) == 0) {
46 /******************************************************************/
47 static void *mvhl_dump_config_request ( mvhl_config *currentconf, request_rec *r) {
48 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "BaseDn: %s", currentconf->basedn);
49 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "BindDn: %s", currentconf->binddn);
50 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "BindPw: %s", currentconf->bindpw);
51 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Deref: %d", currentconf->deref);
52 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Enabled: %d", currentconf->enabled);
53 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "UserFilter: %s", currentconf->filter);
54 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "HaveLdapUrl: %d", currentconf->have_ldap_url);
55 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "HaveDeref: %d", currentconf->have_deref);
56 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Url: %s", currentconf->url);
57 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Port: %d", currentconf->port);
58 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Scope: %d", currentconf->scope);
59 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Fallback: %s", currentconf->fallback);
60 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "WucBaseDn: %s", currentconf->wucbasedn);
61 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "WlcBaseDn: %s", currentconf->wlcbasedn);
62 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "AliasesBaseDn: %s", currentconf->aliasesbasedn);
65 /******************************************************************/
66 void log_dump_apr_array(request_rec * r, apr_array_header_t * arr, const char *prefix)
68 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Entering log_dump_apr_array");
70 char **aliases = (char **) arr->elts;
71 for (x = 0; x < arr->nelts; x++) {
72 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " log_dump_apr_array val %d %s %s", x, prefix, aliases[x]);
74 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Leaving log_dump_apr_array");
76 /******************************************************************/
77 static apr_array_header_t *get_parsed_string_atrr_arr(request_rec * r, const char *server_alias_attrvar_line, const char *delim)
80 * This little piece of code creates apr_array from the string seperated by delim.
81 * It's primary usage is to get array of ldap one attribute values, which is
82 * retrieved (when multi-value) as ";" separated string.
84 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Entering get_parsed_string_atrr_arr |%s|", server_alias_attrvar_line);
85 if(server_alias_attrvar_line) {
87 apr_collapse_spaces((char *) server_alias_attrvar_line, server_alias_attrvar_line);
88 int ccount = strschrcount(r->pool, server_alias_attrvar_line, delim) + 1;
90 apr_array_header_t *aliases_arr = apr_array_make(r->pool, ccount, sizeof(char *));
92 curralias = (char **) apr_array_push(aliases_arr);
94 char *curr_server_alias = ap_getword(r->pool, &server_alias_attrvar_line, ';');
95 char *tmp = apr_pstrdup(r->pool, (char *) curr_server_alias);;
99 while(server_alias_attrvar_line[0]) {
100 curr_server_alias = ap_getword(r->pool, &server_alias_attrvar_line, ';');
101 curralias = (char **) apr_array_push(aliases_arr);
102 tmp = apr_pstrdup(r->pool, (char *) curr_server_alias);
105 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Leaving get_parsed_string_atrr_arr OK");
109 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Leaving get_parsed_string_atrr_arr NULL");
112 /******************************************************************/
113 static apr_array_header_t *get_ap_reqs(apr_pool_t * p, mvhl_extconfig_object * extreqc, char *mainservername, char *userlist)
116 ap_log_error(APLOG_MARK, APLOG_DEBUG, OK, NULL," get_ap_reqs Entering");
118 apr_array_header_t *res = apr_array_make(p, 2, sizeof(require_line));
121 apr_int64_t limited = -1;
123 rline = (require_line *) apr_array_push(res);
125 //currently we don't support playing with request types
126 rline->method_mask = limited;
128 if(extreqc->extconftype == 1) {
129 ap_log_error(APLOG_MARK, APLOG_DEBUG, OK, NULL, " get_ap_reqs require valid-user = TRUE server %s",mainservername);
130 rline->requirement = apr_pstrdup(p, (char *) "valid-user");
133 ap_log_error(APLOG_MARK, APLOG_DEBUG, OK, NULL, " get_ap_reqs require valid-user = FALSE server %s",mainservername);
135 rline->requirement = apr_pstrdup(p, userlist);
137 ap_log_error(APLOG_MARK, APLOG_DEBUG, OK, NULL," Leaving get_ap_reqs, returning require line |require %s|", rline->requirement);
140 /******************************************************************/
141 static void mvhl_dovhostconfig(request_rec * r, char *attributes[], const char **vals, mvhl_request * reqc)
143 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Entering vhost configuration");
145 * we got 10 attributes to search for, counting from 0 to 9
148 for ( i = 0; i <= 9; i++ ) {
149 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " VhostConfig Iteration %d :: will get %s", i, attributes[i]);
151 /* 0 apacheServerName */
152 case 0: reqc->name = apr_pstrdup(r->pool, vals[i]); break;
153 /* 1 apacheServerAlias - may be null */
154 case 1: reqc->serveralias = (vals[i]) ? (apr_array_header_t *) get_parsed_string_atrr_arr(r, vals[i],(const char *) ";") : NULL; break;
155 /* 2 apacheDocumentRoot */
156 case 2: reqc->docroot = apr_pstrdup(r->pool, vals[i]); break;
157 /* 3 apacheSuexecUid */
158 case 3: reqc->uid = (vals[i]) ? apr_pstrdup(r->pool, vals[i]) : reqc->uid ; break;
159 /* 4 apacheSuexecGid */
160 case 4: reqc->gid = (vals[i]) ? apr_pstrdup(r->pool, vals[i]): reqc->gid ; break;
161 /* 5 apacheServerAdmin */
162 case 5: reqc->admin = (vals[i]) ? apr_pstrdup(r->pool, vals[i]) : NULL ; break;
163 /* 6 apacheExtConfigHasRequireLine */
164 //if there's no HasRequireLine attribute set we assume we don't have reqlines
165 case 6: reqc->has_reqlines = (vals[i] && strcasecmp("TRUE", apr_pstrdup(r->pool, vals[i])) == 0) ? 1 : 0; break;
166 /* 7 apacheLocationOptionsDn */
167 case 7: reqc->rqlocationlines = (vals[i]) ? reqc->rqlocationlines = (apr_array_header_t *) get_parsed_string_atrr_arr(r, vals[i], (const char *) ";") : NULL ; break;
168 /* 8 apacheAliasesConfigEnabled */
169 case 8: reqc->has_aliaslines = ( vals[i] && strcasecmp("TRUE", apr_pstrdup(r->pool, vals[i])) == 0 ) ? 1 : 0; break;
170 /* 9 apacheAliasConfigOptionsDn */
171 case 9: reqc->aliaseslines = (vals[i]) ? (apr_array_header_t *) get_parsed_string_atrr_arr(r, vals[i], (const char *) ";") : NULL;
174 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Leaving vhost configuration , exit assignments: ");
175 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, " apacheServerName \'%s\'", reqc->name);
176 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, " apacheServerAdmin \'%s\'", reqc->admin);
177 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, " apacheDocumentRoot \'%s\'", reqc->docroot);
178 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, " apacheSuexecUid \'%s\'", reqc->uid);
179 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, " apacheSuexecGid \'%s\'", reqc->gid);
181 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
182 /* following three lines evaluates to one string in which final argument (fourth line) is substituted */
183 (reqc->has_reqlines && reqc->rqlocationlines ) ?
184 apr_pstrdup(r->pool, "vhost \'%s\' has access control") :
185 apr_pstrdup(r->pool, " vhost \'%s\' doesn't have access control"),
188 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
189 /* following three lines evaluates to one string in which final argument (fourth line) is substituted */
190 (reqc->has_aliaslines && reqc->has_aliaslines ) ?
191 apr_pstrdup(r->pool, "vhost \'%s\' has dir aliases") :
192 apr_pstrdup(r->pool, " vhost \'%s\' doesn't have dir aliases"),
195 /******************************************************************/
196 static void mvhl_doextconfig(request_rec * r, char *extconfigattributes[], const char **extconfvals, mvhl_extconfig_object * extreqc)
198 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Entering Access Control config");
200 * we got 6 attributes to search for, counting from 0 to 5
203 for ( i = 0; i <= 4; i++ ) {
204 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Vhost Access Control Iteration %d :: will get %s", i, extconfigattributes[i]);
206 /* 0 apacheExtConfigUri */
207 case 0: extreqc->exturi = (extconfvals[i]) ? (apr_array_header_t *) get_parsed_string_atrr_arr(r, extconfvals[i], (const char *) ";") : NULL ; break;
208 /* 1 apacheExtConfigRequireValidUser
209 * this value determines whether we have "require valid-user" object (TRUE) ,
210 * or (FALSE) object "require user johny mary dorothy witch"
211 * here set retrieved value, regardless what it is, to play with it later.
213 case 1: extreqc->extconftype = (extconfvals[i] && strcasecmp("TRUE", apr_pstrdup(r->pool, extconfvals[i])) == 0) ? 1 : 0; break;
214 /* 2 apacheExtConfigServerName */
215 case 2: extreqc->extservername = (extconfvals[i]) ? (apr_array_header_t *) get_parsed_string_atrr_arr(r, extconfvals[i], (const char *) ";") : NULL ; break;
216 /* 3 apacheExtConfigObjectName */
217 case 3: extreqc->extconfname = apr_pstrdup(r->pool, extconfvals[i]); break;
218 /* 4 apacheExtConfigUserDn */
220 extreqc->extusers = (extconfvals[i]) ? (apr_array_header_t *) get_parsed_string_atrr_arr(r, extconfvals[i], (const char *) ";") : NULL; break;
221 /* 5 apacheExtConfigPath */
223 extreqc->extdir = (extconfvals[i]) ? (apr_array_header_t *) get_parsed_string_atrr_arr(r, extconfvals[i], (const char *) ";") : NULL ; break;
227 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Leaving Access Control config :: exit assignments");
229 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " This Access Object prompt is \'%s\'", extreqc->extconfname);
230 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,
232 apr_pstrdup(r->pool, " \'%s\' extConfigUri has at least one URI value") :
233 apr_pstrdup(r->pool, " \'%s\' has extConfigUri assigned"),
234 extreqc->extconfname);
235 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,
237 apr_pstrdup(r->pool, " \'%s\' extConfigPath has at least one directory value") :
238 apr_pstrdup(r->pool, " \'%s\' has extConfig assigned"),
239 extreqc->extconfname);
240 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
241 /* following three lines evaluates to one string in which final argument (fourth line) is substituted */
242 (extreqc->extconftype) ?
243 apr_pstrdup(r->pool, " \'%s\' requires valid-user") :
244 apr_pstrdup(r->pool, " \'%s\' requires user from userlist"),
245 extreqc->extconfname) ;
246 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
247 /* following three lines evaluates to one string in which final argument (fourth line) is substituted */
248 (extreqc->extservername ) ?
249 apr_pstrdup(r->pool, " \'%s\' has at least one serverName assigned") :
250 apr_pstrdup(r->pool, " \'%s\' has no assigned serverNames"),
251 extreqc->extconfname);
252 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
253 /* following three lines evaluates to one string in which final argument (fourth line) is substituted */
254 (extreqc->extusers ) ?
255 apr_pstrdup(r->pool, " \'%s\' has at least one webuser object assigned") :
256 apr_pstrdup(r->pool, " \'%s\' has no assigned webusers objects"),
257 extreqc->extconfname );
260 /******************************************************************/
261 static void mvhl_doextuserconfig(request_rec * r, char *ldap_webuser_attributes[], const char **extuservals, mvhl_webuser * extuserreqc)
263 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Entering extwebuser Config");
265 * we got 5 attributes to search for, counting from 0 to 4
268 for ( i = 0; i <= 4; i++ ) {
269 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Web user Iteration %d :: will get %s", i, ldap_webuser_attributes[i]);
271 /* 0 apacheExtConfigUserName */
273 extuserreqc->webusername = apr_pstrdup(r->pool, extuservals[i]);
275 /* 1 apacheExtConfigUserServerName */
277 extuserreqc->webuserserver = ( extuservals[i] ) ? (apr_array_header_t *) get_parsed_string_atrr_arr(r, extuservals[i], (const char *) ";") : NULL;
281 extuserreqc->webuserpassword = ( extuservals[i] ) ? (apr_array_header_t *) get_parsed_string_atrr_arr(r, extuservals[i], (const char *) ";") : NULL;
283 /* 3 apacheExtConfigUserDirectoryName */
285 extuserreqc->webuserdirectory = ( extuservals[i] ) ? (apr_array_header_t *) get_parsed_string_atrr_arr(r, extuservals[i], (const char *) ";") : NULL;
288 /* apacheExtConfigUserLocationUri */
289 extuserreqc->webuserlocationuri = ( extuservals[i] ) ? (apr_array_header_t *) get_parsed_string_atrr_arr(r, extuservals[i], (const char *) ";") : NULL;
294 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Leaving extwebuser Config :: exit assignments");
295 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " This webuser name is \'%s\'", extuserreqc->webusername);
296 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,
297 /* following three lines evaluates to one string in which final argument (fourth line) is substituted */
298 ( extuserreqc->webuserserver ) ?
299 apr_pstrdup(r->pool, " \'%s\' has at least one server assigned") :
300 apr_pstrdup(r->pool, " \'%s\' has no serverNames assigned"),
301 extuserreqc->webusername );
302 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
303 /* following three lines evaluates to one string in which final argument (fourth line) is substituted */
304 ( extuserreqc->webuserpassword ) ?
305 apr_pstrdup(r->pool, " \'%s\' has at least one password assigned") :
306 apr_pstrdup(r->pool, " \'%s\' has no passwords assigned"),
307 extuserreqc->webusername );
308 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
309 /* following three lines evaluates to one string in which final argument (fourth line) is substituted */
310 ( extuserreqc->webuserdirectory ) ?
311 apr_pstrdup(r->pool, " \'%s\' has at least one physical directory assigned") :
312 apr_pstrdup(r->pool, " \'%s\' has no physical directories assigned"),
313 extuserreqc->webusername );
314 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
315 /* following three lines evaluates to one string in which final argument (fourth line) is substituted */
316 ( extuserreqc->webuserlocationuri ) ?
317 apr_pstrdup(r->pool, " \'%s\' has at least one location assigned") :
318 apr_pstrdup(r->pool, " \'%s\' has no locations assigned"),
319 extuserreqc->webusername );
322 /******************************************************************/
323 static void mvhl_doaliasesconfig(request_rec * r, char *aliases_attributes[], const char **aliasesvals, mvhl_aliasconf_object * aliasreqc){
325 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Entering aliasObject Config");
327 * we got 4 attributes to search for, counting from 0 to 3
331 for (i = 0; i <= 3; i++ ) {
332 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Alias config Iteration %d :: will get %s", i, aliases_attributes[i]);
334 /* 0 apacheAliasConfigSourceUri */
336 aliasreqc->aliassourceuri = (apr_array_header_t *) get_parsed_string_atrr_arr(r, aliasesvals[i], (const char *) ";");
337 //aliasreqc->aliassourceuri = apr_pstrdup(r->pool, aliasesvals[i]);
339 /* 1 apacheAliasConfigServerName - MULTI-VALUE */
341 aliasreqc->aliasconfservername = (apr_array_header_t *) get_parsed_string_atrr_arr(r, aliasesvals[i], (const char *) ";");
343 /* 2 apacheAliasConfigTargetDir */
345 aliasreqc->aliastargetdir = apr_pstrdup(r->pool, aliasesvals[i]);
347 /* 3 apacheAliasConfigObjectName */
349 aliasreqc->aliasconfname = apr_pstrdup(r->pool, aliasesvals[i]);
353 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Leaving alias Config :: exit assignments");
354 /* defined ldap schema force alias object to have all of these attributes, so there's no way for existing object without any of them*/
355 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " This alias config object name is \'%s\'", aliasreqc->aliasconfname);
356 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " \'%s\' has at least one SourceUri assigned", aliasreqc->aliasconfname);
357 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " \'%s\' target dir is \'%s\'", aliasreqc->aliasconfname, aliasreqc->aliastargetdir);
358 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, apr_pstrdup(r->pool, " \'%s\' has at least one serverName assigned"), aliasreqc->aliasconfname );
360 /******************************************************************/
361 static int mvhl_authenticate_basic_user(request_rec * r)
363 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " Entering mvhl_authenticate_basic_user");
365 mvhl_webuser *extuserreqc;
366 extuserreqc = (mvhl_webuser *) apr_pcalloc(r->pool, sizeof(mvhl_webuser));
367 int rc = ap_get_basic_auth_pw(r, &sent_pw);
368 if(rc != OK) return rc;
370 if(strtrue(r->user) && strtrue(sent_pw)) {
372 char userfilter[FILTER_LENGTH];
373 const char *dn = NULL;
374 const char **extuservals = NULL;
375 util_ldap_connection_t *ldc = NULL;
376 char *ldap_webuser_attributes[] = { "apacheExtConfigUserName", "apacheExtConfigUserServerName", "userPassword", 0 };
377 mvhl_config *conf = (mvhl_config *) ap_get_module_config(r->server->module_config, &vhost_ldap_module);
378 apr_snprintf(userfilter, FILTER_LENGTH, "(&(apacheExtConfigUserName=%s))", r->user);
379 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " AuthUser search filter: %s", userfilter);
380 ldc = util_ldap_connection_find(r, conf->host, conf->port, conf->binddn, conf->bindpw, conf->deref, conf->secure);
381 result = util_ldap_cache_getuserdn(r, ldc, conf->url, conf->wucbasedn, conf->scope, ldap_webuser_attributes, userfilter, &dn, &extuservals);
382 util_ldap_connection_close(ldc);
385 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, " User %s found.", r->user);
387 mvhl_doextuserconfig(r, ldap_webuser_attributes, extuservals, extuserreqc);
390 //we're checking for each password - if any matches, then we return immediately
391 char **passwords = (char **) extuserreqc->webuserpassword->elts;
393 for (x = 0; x < extuserreqc->webuserpassword->nelts; x++) {
394 if ( apr_password_validate(sent_pw, passwords[x]) == OK )
396 ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, " APR authentication for user %s at %s successful.", extuserreqc->webusername, r->server->server_hostname);
400 char *prefix = "{CRYPT}";
402 if ( strcasecmp( apr_pstrndup(r->pool, passwords[x], prefixlen ), prefix ) == 0 ) {
403 char *stripped = passwords[x] + prefixlen;
404 char *userinputhash = pw_encrypt (sent_pw, stripped );
405 ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, " User entered: \'%s\' ", sent_pw );
406 ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, " Retrieved value: \'%s\'", passwords[x] );
407 ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, " Retrieved value (stripped): \'%s\'", stripped );
408 ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, " User input hash: \'%s\'", userinputhash );
409 if ( strcasecmp( userinputhash , stripped ) == 0 )
411 ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, " Unix authentication for user %s at %s successful.", extuserreqc->webusername, r->server->server_hostname);
416 if ( strcasecmp(sent_pw,passwords[x]) == 0 )
418 ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, " Clear text authentication for user %s at %s successful.", extuserreqc->webusername, r->server->server_hostname);
424 ap_log_rerror(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, r, " User %s at %s not found", extuserreqc->webusername, r->server->server_hostname);
425 return HTTP_UNAUTHORIZED;
429 ap_note_basic_auth_failure(r);
430 ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
431 ": Both a username and password must be provided : authentication for user %s at %s failed.",
432 extuserreqc->webusername, r->server->server_hostname);
433 return HTTP_UNAUTHORIZED;
435 ap_note_basic_auth_failure(r);
436 ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, "Authentication for user %s at %s failed.",
437 extuserreqc->webusername, r->server->server_hostname);
438 return HTTP_UNAUTHORIZED;
441 /******************************************************************/
442 static int check_mvhl_auth_require(char *user, const char *t, request_rec * r)
445 w = ap_getword(r->pool, &t, ' ');
446 if(!strcmp(w, "valid-user")) {
451 if(!strcmp(w, "user")) {
453 w = ap_getword_conf(r->pool, &t);
454 if(!strcmp(user, w)) {
460 return HTTP_UNAUTHORIZED;
464 return HTTP_INTERNAL_SERVER_ERROR;
466 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,
467 ": %s : Reached end of check_mvhl_auth_require!", r->server->server_hostname);
468 return HTTP_INTERNAL_SERVER_ERROR;
470 /******************************************************************/
471 static int mvhl_check_auth(request_rec * r)
473 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,
474 ": mvhl_check_auth, parsing existing ap_requires for %s at %s ", r->user, r->server->server_hostname);
475 char *user = r->user;
479 const apr_array_header_t *reqs_arr = ap_requires(r);
482 reqs = (require_line *) reqs_arr->elts;
484 for (x = 0; x < reqs_arr->nelts; x++) {
485 t = reqs[x].requirement;
486 if((rv = check_mvhl_auth_require(user, t, r)) != HTTP_UNAUTHORIZED) {
492 ap_note_basic_auth_failure(r);
493 return HTTP_UNAUTHORIZED;
495 /******************************************************************/
496 static void *mvhl_create_sconfig(apr_pool_t * p, server_rec * s)
498 //ldap://host[:port]/basedn[?attrib[?scope[?filter]]]
499 mvhl_config *conf = (mvhl_config *) apr_pcalloc(p, sizeof(mvhl_config));
501 conf->have_ldap_url = 0;
502 conf->have_deref = 0;
503 conf->scope = LDAP_SCOPE_SUBTREE;
512 conf->wlcbasedn = NULL;
513 conf->wucbasedn = NULL;
514 conf->aliasesbasedn = NULL;
515 conf->fallback = NULL;
517 conf->alias_enabled = 0;
518 conf->loc_auth_enabled = 0;
519 conf->dir_auth_enabled = 0;
522 /******************************************************************/
523 static void *mvhl_merge_sconfig(apr_pool_t * p, void *parentv, void *childv)
525 mvhl_config *parent = (mvhl_config *) parentv;
526 mvhl_config *child = (mvhl_config *) childv;
527 mvhl_config *conf = (mvhl_config *) apr_pcalloc(p, sizeof(mvhl_config));
529 conf->enabled = (child->enabled ? child->enabled : parent->enabled);
530 conf->binddn = (child->binddn ? child->binddn : parent->binddn);
531 conf->bindpw = (child->bindpw ? child->bindpw : parent->bindpw);
532 conf->fallback = (child->fallback ? child->fallback : parent->fallback);
533 conf->alias_enabled = (child->alias_enabled ? child->alias_enabled : parent->alias_enabled);
534 conf->loc_auth_enabled = (child->loc_auth_enabled ? child->loc_auth_enabled : parent->loc_auth_enabled);
535 conf->dir_auth_enabled = (child->dir_auth_enabled ? child->dir_auth_enabled : parent->dir_auth_enabled);
537 if(child->have_ldap_url) {
538 conf->have_ldap_url = child->have_ldap_url;
539 conf->url = child->url;
540 conf->host = child->host;
541 conf->port = child->port;
542 conf->basedn = child->basedn;
543 conf->scope = child->scope;
544 conf->filter = child->filter;
545 conf->secure = child->secure;
546 conf->wlcbasedn = child->wlcbasedn;
547 conf->wucbasedn = child->wucbasedn;
548 conf->aliasesbasedn = child->aliasesbasedn;
552 conf->have_ldap_url = parent->have_ldap_url;
553 conf->url = parent->url;
554 conf->host = parent->host;
555 conf->port = parent->port;
556 conf->basedn = parent->basedn;
557 conf->scope = parent->scope;
558 conf->filter = parent->filter;
559 conf->secure = parent->secure;
560 conf->wlcbasedn = parent->wlcbasedn;
561 conf->wucbasedn = parent->wucbasedn;
562 conf->aliasesbasedn = parent->aliasesbasedn;
564 if(child->have_deref) {
565 conf->have_deref = child->have_deref;
566 conf->deref = child->deref;
570 conf->have_deref = parent->have_deref;
571 conf->deref = parent->deref;
575 /******************************************************************/
576 static const char *conf_mvhl_url(cmd_parms * cmd, void *dummy, const char *url)
579 apr_ldap_url_desc_t *urld;
581 mvhl_config *conf = (mvhl_config *) ap_get_module_config(cmd->server->module_config, &vhost_ldap_module);
582 result = apr_ldap_url_parse(url, &(urld));
584 if(result != LDAP_SUCCESS) {
586 case LDAP_URL_ERR_MEM: return "0x01 can't allocate memory space";
587 case LDAP_URL_ERR_PARAM: return "0x02 parameter is bad";
588 case LDAP_URL_ERR_BADSCHEME: return "0x03 URL doesn't begin with ldap[si]://";
589 case LDAP_URL_ERR_BADENCLOSURE: return "0x04 URL is missing trailing >";
590 case LDAP_URL_ERR_BADURL: return "0x05 URL is bad";
591 case LDAP_URL_ERR_BADHOST: return "0x06 host port is bad";
592 case LDAP_URL_ERR_BADATTRS: return "0x07 bad (or missing) attributes";
593 case LDAP_URL_ERR_BADSCOPE: return "0x08 scope string is invalid (or missing)";
594 case LDAP_URL_ERR_BADFILTER: return "0x09 bad or missing filter";
595 case LDAP_URL_ERR_BADEXTS: return "0x0a bad or missing extensions";
596 default: return "Could not parse LDAP URL";
599 conf->url = apr_pstrdup(cmd->pool, url);
601 /* Set all the values, or at least some sane defaults */
603 char *p = apr_palloc(cmd->pool, strlen(conf->host) + strlen(urld->lud_host) + 2);
604 strcpy(p, urld->lud_host);
606 strcat(p, conf->host);
610 conf->host = urld->lud_host ? apr_pstrdup(cmd->pool, urld->lud_host) : "localhost";
613 conf->basedn = urld->lud_dn ? apr_pstrdup(cmd->pool, urld->lud_dn) : "";
615 conf->scope = urld->lud_scope == LDAP_SCOPE_ONELEVEL ? LDAP_SCOPE_ONELEVEL : LDAP_SCOPE_SUBTREE;
617 if(urld->lud_filter) {
618 if(urld->lud_filter[0] == '(') {
620 * Get rid of the surrounding parentheses;
621 * later on when generating the
622 * filter, they'll be put back.
624 conf->filter = apr_pstrdup(cmd->pool, urld->lud_filter + 1);
625 conf->filter[strlen(conf->filter) - 1] = '\0';
628 conf->filter = apr_pstrdup(cmd->pool, urld->lud_filter);
632 conf->filter = "objectClass=apacheConfig";
635 /* "ldaps" indicates secure ldap connections desired
637 if(strncasecmp(url, "ldaps", 5) == 0) {
639 conf->port = urld->lud_port ? urld->lud_port : LDAPS_PORT;
644 conf->port = urld->lud_port ? urld->lud_port : LDAP_PORT;
647 conf->have_ldap_url = 1;
648 apr_ldap_free_urldesc(urld);
651 /******************************************************************/
652 static const char *conf_mvhl(cmd_parms *cmd, void *dummy, const char *confval) {
654 if ( strlen(confval) == 0 ) { return NULL; }
657 //we're getting currently set (or default from mvhl_create_config if not set already)
658 mvhl_config *conf = (mvhl_config *) ap_get_module_config(cmd->server->module_config, &vhost_ldap_module);
659 int *cmdtype = (int *) cmd->info;
660 char *currval = apr_pstrdup(cmd->pool, confval);
663 conf->enabled = ( strcmp(currval,"On") == 0 )? 1 : 0;
666 conf->binddn = currval;
669 conf->bindpw = currval;
672 //const values: never = 0, searching = 1, finding = 2, always = 3
673 if ( strcmp(currval,"never") == 0 ) { conf->deref = never; conf->have_deref = 1;}
674 if ( strcmp(currval,"searching")== 0 ) { conf->deref = searching; conf->have_deref = 1;}
675 if ( strcmp(currval,"finding") == 0 ) { conf->deref = finding; conf->have_deref = 1;}
676 if ( strcmp(currval,"always") == 0 ) { conf->deref = always; conf->have_deref = 1;}
679 conf->wlcbasedn = currval;
682 conf->wucbasedn = currval;
685 conf->fallback = currval;
688 conf->aliasesbasedn = currval;
691 conf->alias_enabled = ( strcmp(currval,"On") == 0 )? 1 : 0 ;
694 conf->loc_auth_enabled = ( strcmp(currval,"On") == 0 )? 1 : 0;
697 conf->dir_auth_enabled = ( strcmp(currval,"On") == 0 )? 1 : 0;
704 /******************************************************************/
705 static int apply_vhost(mvhl_config *conf, const char *hostname, request_rec * r, util_ldap_connection_t *ldc, const char *dn, mvhl_request *reqc ) {
707 char filtbuf[FILTER_LENGTH];
708 apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(|(apacheServerName=%s)(apacheServerAlias=%s)))", conf->filter, hostname, hostname);
709 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"Server search filter: %s", filtbuf);
710 const char **vals = NULL;
711 char *attributes[] = { "apacheServerName", "apacheServerAlias", "apacheDocumentRoot", "apacheSuexecUid","apacheSuexecGid","apacheServerAdmin","apacheExtConfigHasRequireLine","apacheLocationOptionsDn","apacheAliasesConfigEnabled","apacheAliasConfigOptionsDn",0 };
713 int result = LDAP_SERVER_DOWN;
714 while(failures++ <= 5 && result == LDAP_SERVER_DOWN) {
715 result = util_ldap_cache_getuserdn(r, ldc, conf->url, conf->basedn, conf->scope, attributes, filtbuf, &dn, &vals);
719 * we don't test conf->host nor connection, because if these failed, declined was already returned
720 * instead, we do a search for specified fallback vhost
722 if ( result == LDAP_NO_SUCH_OBJECT )
724 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Vhost %s not found, will try to fall-back to defined vhost: %s", hostname, conf->fallback);
725 hostname = conf->fallback;
726 apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(|(apacheServerName=%s)(apacheServerAlias=%s)))", conf->filter, hostname, hostname);
727 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"Server search filter: %s", filtbuf);
728 result = util_ldap_cache_getuserdn(r, ldc, conf->url, conf->basedn, conf->scope, attributes, filtbuf, &dn, &vals);
731 if(result != LDAP_SUCCESS) {
732 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"Vhost %s defined as fallback not found, err %s", hostname, ldap_err2string(result));
736 reqc->dn = apr_pstrdup(r->pool, dn);
737 if (vals) { mvhl_dovhostconfig(r, attributes, vals, reqc); }
739 if( (reqc->name == NULL) || (reqc->docroot == NULL) || ! (r->uri[0] == '/') ) return 0;
740 r->filename = apr_pstrcat(r->pool, reqc->docroot, r->uri, NULL);
744 /******************************************************************/
745 static void apply_aliasing(mvhl_request *reqc, request_rec * r, mvhl_config *conf, util_ldap_connection_t *ldc, const char *dn) {
747 if(reqc->has_aliaslines == 1 && reqc->aliaseslines ) {
748 const char **aliasesconfvals = NULL;
749 char aliasesfilter[FILTER_LENGTH];
750 char *aliases_attributes[] = { "apacheAliasConfigSourceUri", "apacheAliasConfigServerName", "apacheAliasConfigTargetDir", "apacheAliasConfigObjectName",0 };
751 mvhl_aliasconf_object *aliasreqc = (mvhl_aliasconf_object *) apr_pcalloc(r->pool, sizeof(mvhl_aliasconf_object));
752 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"This vhost has alias configuration, need to check if for current uri");
753 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Original r->filename: %s", r->filename);
754 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Original r->uri: %s", r->uri);
758 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Entering Alias Objects search");
759 while(i <= strlen(apr_pstrdup(r->pool, r->uri)) && !aliasesconfvals ) {
761 char *aliasbuff = apr_pstrndup(r->pool, r->uri, i);
762 apr_snprintf(aliasesfilter, FILTER_LENGTH,"(&(%s)(apacheAliasConfigServerName=%s)(apacheAliasConfigSourceUri=%s))", conf->filter, reqc->name, aliasbuff);
763 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"Alias Object search filter: %s", aliasesfilter);
764 /* we reuse ldap connection opened previously with alias entries,
765 * access control entries and webusers entries searches changing used filter as needed (!!) */
766 result = util_ldap_cache_getuserdn(r, ldc, conf->url, conf->aliasesbasedn, conf->scope, aliases_attributes, aliasesfilter, &dn, &aliasesconfvals);
769 if(result != LDAP_SUCCESS) {
770 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"This vhost aliases config, but probably not for this URI, alias config entry not found");
771 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"Tried with ldap search filter: %s", aliasesfilter);
774 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"This uri has aliases config, configuration object found");
775 if(aliasesconfvals) { mvhl_doaliasesconfig(r, aliases_attributes, aliasesconfvals, aliasreqc); }
776 ap_log_error(APLOG_MARK, APLOG_DEBUG, OK, NULL, "Entering alias substitution");
777 r->filename = apr_pstrcat (r->pool, aliasreqc->aliastargetdir , r->uri + i, NULL);
778 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Final filename r->filename: %s", r->filename);
779 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Final uri (unchanged) r->uri: %s", r->uri);
785 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "This vhost has no aliases, or it is disabled via apacheAliasesConfigEnabled = (FALSE|not set) skipping..");
788 /******************************************************************/
789 static void apply_location_access_control(mvhl_request *reqc, request_rec * r, mvhl_config *conf, util_ldap_connection_t *ldc, const char *dn) {
791 if(reqc->has_reqlines == 1 && reqc->rqlocationlines) {
792 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"This vhost has location access control configured, need to check if it's enabled for current uri");
795 char extconffiltbuf[FILTER_LENGTH];
796 const char **extconfvals = NULL;
797 char *extconfigattributes[] = { "apacheExtConfigUri","apacheExtConfigRequireValidUser","apacheExtConfigServerName","apacheExtConfigObjectName","apacheExtConfigUserDn","apacheExtConfigPath",0};
798 mvhl_extconfig_object *extreqc = (mvhl_extconfig_object *) apr_pcalloc(r->pool, sizeof(mvhl_extconfig_object));
800 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Entering extConfig Location Objects search");
801 while(i <= strlen(apr_pstrdup(r->pool, r->uri)) && !extconfvals) {
803 buff = apr_pstrndup(r->pool, r->uri, i);
805 * ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"Searching for hostname %s and URI %s, origname is %s", hostname, buff, reqc->name);
806 * uncomment this, if You'd like to see in log how uri gets checked
807 * ap_log_error(APLOG_MARK,APLOG_DEBUG,OK,NULL,"%s", buff);
809 * well, we must had been connecting already, so we don't do more ldap server connection checks,
810 * and we're doing a search with cache_getuser instead of using extConfigObject dn apacheConfig object attribute value(s),
811 * because there's no convenient function in apr api.
812 * vhost location RDN attribute is used actually by some GUI to make things easier
813 * TODO: use some generic ldap functions (?) classic search or implement more ldap routines for apr
815 * so, we do a search below locationDnBase for config object with matches current hostname and uri..
816 * note, that we took our current uri, and we're searching starting from / adding one by one chararacter
817 * to match config object - access config is always the same as first matching upper url access config.
818 * and more - if someone defined accessobject for /main and /main/subdir, the first one is used.
819 * when upper is deleted - next below is returned, and so far..
820 * and more - if there are two or more extConfig object for the same combination of server/uri,
821 * then first found is returned and search isn't processed further.
823 * we do a search based on original reqc->name instead of current hostname, to apply rules even if we're accessing
824 * site via ServerAlias name
826 apr_snprintf(extconffiltbuf, FILTER_LENGTH,"(&(%s)(apacheExtConfigServerName=%s)(apacheExtConfigUri=%s))", conf->filter, reqc->name, buff);
827 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"ExtConfig Location Object search filter: %s", extconffiltbuf);
828 result = util_ldap_cache_getuserdn(r, ldc, conf->url, conf->wlcbasedn, conf->scope, extconfigattributes, extconffiltbuf, &dn, &extconfvals);
829 //matched URI, if found, is returned anyway with extconfvals as ldap attribute value.
832 if(result != LDAP_SUCCESS) {
833 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"This vhost has access control, but probably not for this URI, access config entry not found");
834 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"Tried with ldap search filter: %s", extconffiltbuf);
839 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"This uri has access control, configuration object is found");
840 //we set all into extreqc struct
841 //ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Entering extconfig buffer fill");
842 if(extconfvals) { mvhl_doextconfig(r, extconfigattributes, extconfvals, extreqc); }
844 ap_log_error(APLOG_MARK, APLOG_DEBUG, OK, NULL, "Entering ap_requires generation process");
845 core_dir_config *coredirconf = (core_dir_config *) ap_get_module_config(r->per_dir_config, &core_module);
846 coredirconf->ap_auth_name = extreqc->extconfname;
847 coredirconf->ap_auth_type = (char *) "basic";
848 char *userlist = "user nobody";
851 st = (util_ldap_state_t *)ap_get_module_config(r->server->module_config, &ldap_module);
852 st->search_cache_ttl = 0;
854 char userfilter[FILTER_LENGTH];
855 /* we'll search for user object with custom filter applied, which has assigned matched location name and which has assigned current servername */
856 apr_snprintf(userfilter, FILTER_LENGTH, "(&(%s)(objectClass=apacheExtendedConfigUserObject)(apacheExtConfigUserServerName=%s)(apacheExtConfigUserLocationUri=%s))", conf->filter, reqc->name, buff);
857 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"User search filter: %s", userfilter);
859 mvhl_webuser *extuserreqc = (mvhl_webuser *) apr_pcalloc(r->pool, sizeof(mvhl_webuser));
861 if(extreqc->extusers) {
862 log_dump_apr_array(r,extreqc->extusers,"extUser");
863 char **extuserdns = (char **) extreqc->extusers->elts;
864 for (i = 0; i < extreqc->extusers->nelts; i++) {
865 const char **extuservals = NULL;
867 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "User search basedn: %s", extuserdns[i]);
868 //we don't use wucbasedn as we already know what webuser distinguishedname can be
869 char *ldap_webuser_attributes[] = { "apacheExtConfigUserName","apacheExtConfigUserServerName","userPassword", "apacheExtConfigUserDirectoryName", "apacheExtConfigUserLocationUri", 0};
870 result = util_ldap_cache_getuserdn(r, ldc, conf->url, extuserdns[i], LDAP_SCOPE_BASE, ldap_webuser_attributes, userfilter, &dn, &extuservals);
872 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Val 0: %s", extuservals[0]);
873 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Val 1: %s", extuservals[1]);
874 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Val 2: %s", extuservals[2]);
875 mvhl_doextuserconfig(r, ldap_webuser_attributes, extuservals, extuserreqc);
876 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "current username: %s", extuserreqc->webusername);
877 userlist = apr_pstrcat(r->pool, userlist, " ", extuserreqc->webusername, NULL);
878 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "current userlist: %s", userlist);
882 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "final userlist: %s ", userlist);
883 ap_log_error(APLOG_MARK, APLOG_DEBUG, OK, NULL, "AuthName set to %s", coredirconf->ap_auth_name);
884 ap_log_error(APLOG_MARK, APLOG_DEBUG, OK, NULL, "AuthType set to %s", coredirconf->ap_auth_type);
885 ap_log_error(APLOG_MARK, APLOG_DEBUG, OK, NULL, "Preparing access control line");
886 coredirconf->ap_requires = (apr_array_header_t *) get_ap_reqs(r->pool, extreqc, reqc->name, userlist);
890 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "This vhost is not configured for access control, or it is disabled via apacheExtConfigHasRequireLine = ( FALSE|not set) skipping..");
893 /******************************************************************/
894 static void apply_directory_access_control(mvhl_request *reqc, request_rec * r, mvhl_config *conf, util_ldap_connection_t *ldc, const char *dn) {
896 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"This vhost has directory access control configured, need to check if it's enabled for current filename");
899 char extconffiltbuf[FILTER_LENGTH];
900 const char **extconfvals = NULL;
901 char *extconfigattributes[] = { "apacheExtConfigUri","apacheExtConfigRequireValidUser","apacheExtConfigServerName","apacheExtConfigObjectName","apacheExtConfigUserDn","apacheExtConfigPath",0};
902 mvhl_extconfig_object *extreqc = (mvhl_extconfig_object *) apr_pcalloc(r->pool, sizeof(mvhl_extconfig_object));
905 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Entering extConfig Directory Objects search");
906 while(i <= strlen(apr_pstrdup(r->pool, r->filename)) && !extconfvals) {
908 buff = apr_pstrndup(r->pool, r->filename, i);
910 * ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"Searching for hostname %s and URI %s, origname is %s", hostname, buff, reqc->name);
911 * uncomment this, if You'd like to see in log how uri gets checked
912 * ap_log_error(APLOG_MARK,APLOG_DEBUG,OK,NULL,"%s", buff);
914 * well, we must had been connecting already, so we don't do more ldap server connection checks,
915 * and we're doing a search with cache_getuser instead of using extConfigObject dn apacheConfig object attribute value(s),
916 * because there's no convenient function in apr api.
917 * vhost location RDN attribute is used actually by some GUI to make things easier
918 * TODO: use some generic ldap functions (?) classic search or implement more ldap routines for apr
920 * so, we do a search below locationDnBase for config object with matches current hostname and uri..
921 * note, that we took our current uri, and we're searching starting from / adding one by one chararacter
922 * to match config object - access config is always the same as first matching upper url access config.
923 * and more - if someone defined accessobject for /main and /main/subdir, the first one is used.
924 * when upper is deleted - next below is returned, and so far..
925 * and more - if there are two or more extConfig object for the same combination of server/uri,
926 * then first found is returned and search isn't processed further.
928 * we do a search based on original reqc->name instead of current hostname, to apply rules even if we're accessing
929 * site via ServerAlias name
931 apr_snprintf(extconffiltbuf, FILTER_LENGTH,"(&(%s)(apacheExtConfigPath=%s))", conf->filter, buff);
932 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"ExtConfig Directory Object search filter: %s", extconffiltbuf);
933 result = util_ldap_cache_getuserdn(r, ldc, conf->url, conf->wlcbasedn, conf->scope, extconfigattributes, extconffiltbuf, &dn, &extconfvals);
934 //matched dir, if found, is returned anyway with extconfvals as ldap attribute value.
937 if(result != LDAP_SUCCESS) {
938 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"This vhost has access control, but probably not for this directory, access config entry not found");
939 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"Tried with ldap search filter: %s", extconffiltbuf);
944 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"This directory has access control, configuration object is found");
945 //we set all into extreqc struct
946 //ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Entering extconfig buffer fill");
947 if(extconfvals) { mvhl_doextconfig(r, extconfigattributes, extconfvals, extreqc); }
949 ap_log_error(APLOG_MARK, APLOG_DEBUG, OK, NULL, "Entering ap_requires generation process");
950 core_dir_config *coredirconf = (core_dir_config *) ap_get_module_config(r->per_dir_config, &core_module);
951 coredirconf->ap_auth_name = extreqc->extconfname;
952 coredirconf->ap_auth_type = (char *) "basic";
953 char *userlist = "user nobody";
956 st = (util_ldap_state_t *)ap_get_module_config(r->server->module_config, &ldap_module);
957 st->search_cache_ttl = 0;
959 char userfilter[FILTER_LENGTH];
960 /* we'll search for user object with custom filter applied, which has assigned matched directory name */
961 apr_snprintf(userfilter, FILTER_LENGTH, "(&(%s)(objectClass=apacheExtendedConfigUserObject)(apacheExtConfigUserDirectoryName=%s))", conf->filter, buff);
962 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,"User search filter: %s", userfilter);
964 mvhl_webuser *extuserreqc = (mvhl_webuser *) apr_pcalloc(r->pool, sizeof(mvhl_webuser));
966 if(extreqc->extusers) {
967 log_dump_apr_array(r,extreqc->extusers,"extUser");
968 char **extuserdns = (char **) extreqc->extusers->elts;
969 for (i = 0; i < extreqc->extusers->nelts; i++) {
970 const char **extuservals = NULL;
972 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "User search basedn: %s", extuserdns[i]);
973 //we don't use wucbasedn as we already know what webuser distinguishedname can be
974 char *ldap_webuser_attributes[] = { "apacheExtConfigUserName","apacheExtConfigUserServerName","userPassword", "apacheExtConfigUserDirectoryName", "apacheExtConfigUserLocationUri", 0};
975 result = util_ldap_cache_getuserdn(r, ldc, conf->url, extuserdns[i], LDAP_SCOPE_BASE, ldap_webuser_attributes, userfilter, &dn, &extuservals);
977 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Val 0: %s", extuservals[0]);
978 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Val 1: %s", extuservals[1]);
979 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Val 2: %s", extuservals[2]);
980 mvhl_doextuserconfig(r, ldap_webuser_attributes, extuservals, extuserreqc);
981 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "current username: %s", extuserreqc->webusername);
982 userlist = apr_pstrcat(r->pool, userlist, " ", extuserreqc->webusername, NULL);
983 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "current userlist: %s", userlist);
987 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "final userlist: %s ", userlist);
988 ap_log_error(APLOG_MARK, APLOG_DEBUG, OK, NULL, "AuthName set to %s", coredirconf->ap_auth_name);
989 ap_log_error(APLOG_MARK, APLOG_DEBUG, OK, NULL, "AuthType set to %s", coredirconf->ap_auth_type);
990 ap_log_error(APLOG_MARK, APLOG_DEBUG, OK, NULL, "Preparing access control line");
991 coredirconf->ap_requires = (apr_array_header_t *) get_ap_reqs(r->pool, extreqc, reqc->name, userlist);
995 /******************************************************************/
996 static int mvhl_translate_name(request_rec * r)
998 request_rec *top = r->main ? r->main : r;
999 apr_table_t *e = top->subprocess_env;
1001 //module config and current request config objects
1002 mvhl_config *conf = (mvhl_config *) ap_get_module_config(r->server->module_config, &vhost_ldap_module);
1003 mvhl_dump_config_request(conf, r); //debug
1004 // mod_vhost_ldap is disabled or we don't have LDAP Url, we check these as soon as we can (after debugging dump)
1005 if(( conf->enabled == 0) || (! conf->have_ldap_url) || ( ! conf->host ) ) return DECLINED;
1007 //get core config and current request config, then set current request config
1008 core_server_config *core = (core_server_config *) ap_get_module_config(r->server->module_config, &core_module);
1009 mvhl_request *reqc = (mvhl_request *) apr_pcalloc(r->pool, sizeof(mvhl_request));
1010 ap_set_module_config(r->request_config, &vhost_ldap_module, reqc);
1012 const char *hostname = r->hostname;
1013 const char *dn = NULL;
1015 //we'll reuse ldap connection opened here
1016 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Opening LDAP Connection");
1017 util_ldap_connection_t *ldc = util_ldap_connection_find(r, conf->host, conf->port, conf->binddn, conf->bindpw,conf->deref, conf->secure);
1019 //heart of the system :)
1020 if ( conf->enabled == 0 || ! apply_vhost(conf, hostname, r, ldc, dn, reqc ) ) return DECLINED;
1021 if (conf->alias_enabled > 0 ) apply_aliasing(reqc, r, conf, ldc, dn);
1022 if (conf->loc_auth_enabled > 0 ) apply_location_access_control(reqc, r, conf, ldc, dn);
1023 if (conf->dir_auth_enabled > 0 ) apply_directory_access_control(reqc, r, conf, ldc, dn);
1025 ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r, "Closing LDAP Connection");
1026 util_ldap_connection_close(ldc);
1028 /* finished with Access control for location **********************************/
1029 top->server->server_hostname = apr_pstrdup(top->pool, reqc->name);
1030 if(reqc->admin) {top->server->server_admin = apr_pstrdup(top->pool, reqc->admin); }
1032 // set environment variables
1033 apr_table_addn(e, "SERVER_ROOT", reqc->docroot);
1034 core->ap_document_root = apr_pstrdup(top->pool, reqc->docroot);
1037 /******************************************************************/
1038 static ap_unix_identity_t *mvhl_suexec_doer(const request_rec * r)
1040 ap_unix_identity_t *ugid = NULL;
1041 mvhl_config *conf = (mvhl_config *) ap_get_module_config(r->server->module_config, &vhost_ldap_module);
1042 mvhl_request *req = (mvhl_request *) ap_get_module_config(r->request_config, &vhost_ldap_module);
1047 uid = (uid_t) atoll(req->uid);
1048 gid = (gid_t) atoll(req->gid);
1050 // mod_vhost_ldap is disabled or we don't have LDAP Url
1054 ( conf->enabled == 0 ) ||
1055 (!conf->have_ldap_url) ||
1057 (req->uid == NULL) ||
1058 (req->gid == NULL) ||
1059 (ugid = apr_palloc(r->pool, sizeof(ap_unix_identity_t))) == NULL
1067 /******************************************************************/
1068 static int mvhl_post_config(apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, server_rec * s)
1070 /* make sure that mod_ldap (util_ldap) is loaded */
1071 if(ap_find_linked_module("util_ldap.c") == NULL) {return HTTP_INTERNAL_SERVER_ERROR;}
1072 ap_add_version_component(p, MOD_VHOST_LDAP_VERSION);
1075 /******************************************************************/
1076 static const command_rec mvhl_cmds[] = {
1077 AP_INIT_TAKE1("VhostLdapUrl", conf_mvhl_url, NULL, RSRC_CONF,"RFC 2255 URL of the form ldap://host[:port]/basedn[?attrib[?scope[?filter]]]."),
1078 AP_INIT_TAKE1("VhostLdapEnabled", conf_mvhl, MVHL_ENABLED, RSRC_CONF,"Set to off or unset to disable vhost_ldap module completely"),
1079 AP_INIT_TAKE1("VhostAliasesEnabled", conf_mvhl, MVHL_ALIASENABLED, RSRC_CONF,"Set to off or unset to disable ldap-based dir aliases"),
1080 AP_INIT_TAKE1("VhostLocAuthEnabled", conf_mvhl, MVHL_LAUTHENABLED, RSRC_CONF,"Set to off or unset to disable per-location authentication"),
1081 AP_INIT_TAKE1("VhostDirAuthEnabled", conf_mvhl, MVHL_DAUTHENABLED, RSRC_CONF,"Set to off or unset to disable per-location authentication"),
1082 AP_INIT_TAKE1("VhostLdapBindDn", conf_mvhl, MVHL_BINDDN, RSRC_CONF,"DN to use to bind to LDAP server"),
1083 AP_INIT_TAKE1("VhostLdapBindPw", conf_mvhl, MVHL_BINDPW, RSRC_CONF,"Password to use to bind to LDAP server"),
1084 AP_INIT_TAKE1("VhostLdapWlcBaseDn", conf_mvhl, MVHL_WLCBASEDN, RSRC_CONF,"Base DN to do all access control config searches."),
1085 AP_INIT_TAKE1("VhostLdapWucBaseDn", conf_mvhl, MVHL_WUCBASEDN, RSRC_CONF,"Base DN to do all user config searches"),
1086 AP_INIT_TAKE1("VhostLdapAliasesBaseDn", conf_mvhl, MVHL_ALIASBASEDN, RSRC_CONF,"Base DN to do all aliases config searches"),
1087 AP_INIT_TAKE1("VhostLdapFallback", conf_mvhl, MVHL_FALLBACK, RSRC_CONF,"Fallback vhost server name to use - to display not-found info"),
1088 AP_INIT_TAKE1("VhostLdapDeref", conf_mvhl, MVHL_DEREF, RSRC_CONF,"values: never, searching, finding, always"),
1091 /******************************************************************/
1092 static void mvhl_register_hooks(apr_pool_t * p)
1094 ap_hook_post_config(mvhl_post_config, NULL, NULL, APR_HOOK_MIDDLE);
1095 ap_hook_translate_name(mvhl_translate_name, NULL, NULL, APR_HOOK_MIDDLE);
1096 ap_hook_get_suexec_identity(mvhl_suexec_doer, NULL, NULL, APR_HOOK_MIDDLE);
1097 ap_hook_check_user_id(mvhl_authenticate_basic_user, NULL, NULL, APR_HOOK_MIDDLE);
1098 ap_hook_auth_checker(mvhl_check_auth, NULL, NULL, APR_HOOK_MIDDLE);
1100 /******************************************************************/
1101 module AP_MODULE_DECLARE_DATA vhost_ldap_module = {
1102 STANDARD20_MODULE_STUFF,
1103 NULL, // create per-directory config structure
1104 NULL, // merge per-directory config structures, default is to override
1105 mvhl_create_sconfig,// called when module configuration data needs to be created/allocated.
1106 mvhl_merge_sconfig, // merge per-server config structures
1107 mvhl_cmds, // Here we pass in the list of new configuration directives.
1108 mvhl_register_hooks,// register me in apache core