]> granicus.if.org Git - apache/blobdiff - modules/mappers/mod_userdir.c
*) continued header revamping
[apache] / modules / mappers / mod_userdir.c
index 7e83bb1fb380c6b1e9d2a4c7a9882ea018361b91..d7c7299cf1c06c974fecc94062178223dcc649d4 100644 (file)
  * 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"
@@ -109,8 +125,8 @@ module userdir_module;
 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;
 
 /*
@@ -119,15 +135,15 @@ typedef struct 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;
 }
 
@@ -147,7 +163,7 @@ static const char *set_user_dir(cmd_parms *cmd, void *dummy, const char *arg)
     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.
@@ -179,7 +195,7 @@ static const char *set_user_dir(cmd_parms *cmd, void *dummy, const char *arg)
          * 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;
     }
     /*
@@ -188,7 +204,7 @@ static const char *set_user_dir(cmd_parms *cmd, void *dummy, const char *arg)
      */
     while (*usernames) {
         username = ap_getword_conf(cmd->pool, &usernames);
-        ap_table_setn(usertable, username, kw);
+        apr_table_setn(usertable, username, kw);
     }
     return NULL;
 }
@@ -211,7 +227,7 @@ static int translate_userdir(request_rec *r)
     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
@@ -248,7 +264,7 @@ static int translate_userdir(request_rec *r)
     /*
      * 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;
     }
     /*
@@ -257,7 +273,7 @@ static int translate_userdir(request_rec *r)
      */
     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;
     }
@@ -269,6 +285,7 @@ static int translate_userdir(request_rec *r)
     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, '*');
@@ -279,44 +296,45 @@ static int translate_userdir(request_rec *r)
                 /*
                  * 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 */
         }
 
         /*
@@ -325,14 +343,21 @@ static int translate_userdir(request_rec *r)
          * 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;
         }
     }
@@ -340,11 +365,36 @@ static int translate_userdir(request_rec *r)
     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 = {
@@ -353,7 +403,6 @@ 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 */
 };