* disabled, except those explicitly turned on with the "enabled" keyword.
*/
+#include "apr_strings.h"
+#include "apr_user.h"
+
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
#include "ap_config.h"
#include "httpd.h"
#include "http_config.h"
#include "http_request.h"
-#ifdef HAVE_PWD_H
-#include <pwd.h>
+
+#if !defined(WIN32) && !defined(OS2) && !defined(BEOS)
+#define HAVE_UNIX_SUEXEC
+#endif
+
+#ifdef HAVE_UNIX_SUEXEC
+#include "unixd.h" /* Contains the suexec_identity hook used on Unix */
#endif
+
/* The default directory in user's home dir */
#ifndef DEFAULT_USER_DIR
#define DEFAULT_USER_DIR "public_html"
typedef struct userdir_config {
int globally_disabled;
char *userdir;
- ap_table_t *enabled_users;
- ap_table_t *disabled_users;
+ apr_table_t *enabled_users;
+ apr_table_t *disabled_users;
} userdir_config;
/*
* explicit) disablement, and the replacement string for all others.
*/
-static void *create_userdir_config(ap_pool_t *p, server_rec *s)
+static void *create_userdir_config(apr_pool_t *p, server_rec *s)
{
userdir_config
- * newcfg = (userdir_config *) ap_pcalloc(p, sizeof(userdir_config));
+ * newcfg = (userdir_config *) apr_pcalloc(p, sizeof(userdir_config));
newcfg->globally_disabled = 0;
newcfg->userdir = DEFAULT_USER_DIR;
- newcfg->enabled_users = ap_make_table(p, 4);
- newcfg->disabled_users = ap_make_table(p, 4);
+ newcfg->enabled_users = apr_table_make(p, 4);
+ newcfg->disabled_users = apr_table_make(p, 4);
return (void *) newcfg;
}
const char
*usernames = arg;
char *kw = ap_getword_conf(cmd->pool, &usernames);
- ap_table_t *usertable;
+ apr_table_t *usertable;
/*
* Let's do the comparisons once.
* If the first (only?) value isn't one of our keywords, just copy
* the string to the userdir string.
*/
- s_cfg->userdir = ap_pstrdup(cmd->pool, arg);
+ s_cfg->userdir = apr_pstrdup(cmd->pool, arg);
return NULL;
}
/*
*/
while (*usernames) {
username = ap_getword_conf(cmd->pool, &usernames);
- ap_table_setn(usertable, username, kw);
+ apr_table_setn(usertable, username, kw);
}
return NULL;
}
const char *w, *dname;
char *redirect;
char *x = NULL;
- ap_finfo_t statbuf;
+ apr_finfo_t statbuf;
/*
* If the URI doesn't match our basic pattern, we've nothing to do with
/*
* Nor if there's an username but it's in the disabled list.
*/
- if (ap_table_get(s_cfg->disabled_users, w) != NULL) {
+ if (apr_table_get(s_cfg->disabled_users, w) != NULL) {
return DECLINED;
}
/*
*/
if (
s_cfg->globally_disabled &&
- (ap_table_get(s_cfg->enabled_users, w) == NULL)
+ (apr_table_get(s_cfg->enabled_users, w) == NULL)
) {
return DECLINED;
}
while (*userdirs) {
const char *userdir = ap_getword_conf(r->pool, &userdirs);
char *filename = NULL;
+ apr_status_t rv;
if (ap_strchr_c(userdir, '*'))
x = ap_getword(r->pool, &userdir, '*');
/*
* Crummy hack. Need to figure out whether we have been
* redirected to a URL or to a file on some drive. Since I
- * know of no protocols that are a single letter, if the : is
- * the second character, I will assume a file was specified
+ * know of no protocols that are a single letter, ignore
+ * a : as the first or second character, and assume a file
+ * was specified
+ *
+ * XXX: Still no good for NETWARE, since : is embedded (sys:/home)
*/
if (strchr(x + 2, ':'))
#else
if (strchr(x, ':'))
-#endif /* WIN32 */
+#endif /* HAVE_DRIVE_LETTERS */
{
- redirect = ap_pstrcat(r->pool, x, w, userdir, dname, NULL);
- ap_table_setn(r->headers_out, "Location", redirect);
- return REDIRECT;
+ redirect = apr_pstrcat(r->pool, x, w, userdir, dname, NULL);
+ apr_table_setn(r->headers_out, "Location", redirect);
+ return HTTP_MOVED_TEMPORARILY;
}
else
- filename = ap_pstrcat(r->pool, x, w, userdir, NULL);
+ filename = apr_pstrcat(r->pool, x, w, userdir, NULL);
}
else
- filename = ap_pstrcat(r->pool, userdir, "/", w, NULL);
+ filename = apr_pstrcat(r->pool, userdir, "/", w, NULL);
}
else if (ap_strchr_c(userdir, ':')) {
- redirect = ap_pstrcat(r->pool, userdir, "/", w, dname, NULL);
- ap_table_setn(r->headers_out, "Location", redirect);
- return REDIRECT;
+ redirect = apr_pstrcat(r->pool, userdir, "/", w, dname, NULL);
+ apr_table_setn(r->headers_out, "Location", redirect);
+ return HTTP_MOVED_TEMPORARILY;
}
else {
-#ifdef WIN32
- /* Need to figure out home dirs on NT */
- return DECLINED;
-#else /* WIN32 */
- struct passwd *pw;
- if ((pw = getpwnam(w))) {
-#ifdef OS2
- /* Need to manually add user name for OS/2 */
- filename = ap_pstrcat(r->pool, pw->pw_dir, w, "/", userdir, NULL);
+#if APR_HAS_USER
+ char *homedir;
+
+ if (apr_get_home_directory(&homedir, w, r->pool) == APR_SUCCESS) {
+ filename = apr_pstrcat(r->pool, homedir, "/", userdir, NULL);
+ }
+ else {
+ return DECLINED;
+ }
#else
- filename = ap_pstrcat(r->pool, pw->pw_dir, "/", userdir, NULL);
+ return DECLINED;
#endif
- }
-#endif /* WIN32 */
}
/*
* anyway, in the hope that some handler might handle it. This can be
* used, for example, to run a CGI script for the user.
*/
- if (filename && (!*userdirs ||
- ap_stat(&statbuf, filename, r->pool) == APR_SUCCESS)) {
- r->filename = ap_pstrcat(r->pool, filename, dname, NULL);
- /* when statbuf contains info on r->filename we can save a syscall
+ if (filename && (!*userdirs
+ || ((rv = apr_stat(&statbuf, filename, APR_FINFO_MIN,
+ r->pool)) == APR_SUCCESS
+ || rv == APR_INCOMPLETE))) {
+ r->filename = apr_pstrcat(r->pool, filename, dname, NULL);
+ /* XXX: Does this walk us around FollowSymLink rules?
+ * When statbuf contains info on r->filename we can save a syscall
* by copying it to r->finfo
*/
if (*userdirs && dname[0] == 0)
r->finfo = statbuf;
+
+ /* For use in the get_suexec_identity phase */
+ apr_table_setn(r->notes, "mod_userdir_user", w);
+
return OK;
}
}
return DECLINED;
}
-static void register_hooks(void)
+#ifdef HAVE_UNIX_SUEXEC
+static ap_unix_identity_t *get_suexec_id_doer(const request_rec *r)
+{
+ const char *username = apr_table_get(r->notes, "mod_userdir_user");
+ struct passwd *pw = NULL;
+ ap_unix_identity_t *ugid = NULL;
+
+ if (username == NULL) {
+ return NULL;
+ }
+
+ if ((ugid = apr_palloc(r->pool, sizeof(ap_unix_identity_t *))) == NULL) {
+ return NULL;
+ }
+
+ ugid->uid = pw->pw_uid;
+ ugid->gid = pw->pw_gid;
+
+ return ugid;
+}
+#endif /* HAVE_UNIX_SUEXEC */
+
+static void register_hooks(apr_pool_t *p)
{
static const char * const aszSucc[]={ "mod_alias.c",NULL };
- ap_hook_translate_name(translate_userdir,NULL,aszSucc,AP_HOOK_MIDDLE);
+ ap_hook_translate_name(translate_userdir,NULL,aszSucc,APR_HOOK_MIDDLE);
+#ifdef HAVE_UNIX_SUEXEC
+ ap_hook_get_suexec_identity(get_suexec_id_doer,NULL,NULL,APR_HOOK_MIDDLE);
+#endif
}
module userdir_module = {
NULL, /* dir merger --- default is to override */
create_userdir_config, /* server config */
NULL, /* merge server config */
- userdir_cmds, /* command ap_table_t */
- NULL, /* handlers */
+ userdir_cmds, /* command apr_table_t */
register_hooks /* register hooks */
};