daemon: extend user-relative path notation.
authorJunio C Hamano <junkio@cox.net>
Sun, 5 Feb 2006 06:27:29 +0000 (22:27 -0800)
committerJunio C Hamano <junkio@cox.net>
Mon, 6 Feb 2006 00:51:01 +0000 (16:51 -0800)
Earlier, we made --base-path to automatically forbid
user-relative paths, which was probably a mistake.  This
introduces --user-path (or --user-path=path) option to control
the use of user-relative paths independently.  The latter form
of the option can be used to restrict accesses to a part of each
user's home directory, similar to "public_html" some webservers
supports.

If we're invoked with --user-path=FOO option, then a URL of the
form git://~USER/PATH/... resolves to the path HOME/FOO/PATH/...,
where HOME is USER's home directory.

[jc: This is much reworked by me so bugs are mine, but the
 original patch was done by Mark Wooding.]

Signed-off-by: Junio C Hamano <junkio@cox.net>
Documentation/git-daemon.txt
daemon.c

index a20e053..2cc6075 100644 (file)
@@ -10,7 +10,8 @@ SYNOPSIS
 [verse]
 'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]
              [--timeout=n] [--init-timeout=n] [--strict-paths]
-             [--base-path=path] [directory...]
+             [--base-path=path] [--user-path | --user-path=path]
+            [directory...]
 
 DESCRIPTION
 -----------
@@ -42,8 +43,7 @@ OPTIONS
        This is sort of "GIT root" - if you run git-daemon with
        '--base-path=/srv/git' on example.com, then if you later try to pull
        'git://example.com/hello.git', `git-daemon` will interpret the path
-       as '/srv/git/hello.git'. Home directories (the '~login' notation)
-       access is disabled.
+       as '/srv/git/hello.git'.
 
 --export-all::
        Allow pulling from all directories that look like GIT repositories
@@ -70,6 +70,15 @@ OPTIONS
        Log to syslog instead of stderr. Note that this option does not imply
        --verbose, thus by default only error conditions will be logged.
 
+--user-path, --user-path=path::
+       Allow ~user notation to be used in requests.  When
+       specified with no parameter, requests to
+       git://host/~alice/foo is taken as a request to access
+       'foo' repository in the home directory of user `alice`.
+       If `--user-path=path` is specified, the same request is
+       taken as a request to access `path/foo` repository in
+       the home directory of user `alice`.
+
 --verbose::
        Log details about the incoming connections and requested files.
 
index dab8c2c..a1ccda3 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -18,7 +18,8 @@ static int reuseaddr;
 static const char daemon_usage[] =
 "git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
 "           [--timeout=n] [--init-timeout=n] [--strict-paths]\n"
-"           [--base-path=path] [--reuseaddr] [directory...]";
+"           [--base-path=path] [--user-path | --user-path=path]\n"
+"           [--reuseaddr] [directory...]";
 
 /* List of acceptable pathname prefixes */
 static char **ok_paths = NULL;
@@ -30,6 +31,12 @@ static int export_all_trees = 0;
 /* Take all paths relative to this one if non-NULL */
 static char *base_path = NULL;
 
+/* If defined, ~user notation is allowed and the string is inserted
+ * after ~user/.  E.g. a request to git://host/~alice/frotz would
+ * go to /home/alice/pub_git/frotz with --user-path=pub_git.
+ */
+static char *user_path = NULL;
+
 /* Timeout, and initial timeout */
 static unsigned int timeout = 0;
 static unsigned int init_timeout = 0;
@@ -137,6 +144,7 @@ static int avoid_alias(char *p)
 
 static char *path_ok(char *dir)
 {
+       static char rpath[PATH_MAX];
        char *path;
 
        if (avoid_alias(dir)) {
@@ -144,12 +152,31 @@ static char *path_ok(char *dir)
                return NULL;
        }
 
-       if (base_path) {
-               static char rpath[PATH_MAX];
-               if (!strict_paths && *dir == '~')
-                       ; /* allow user relative paths */
-               else if (*dir != '/') {
-                       /* otherwise allow only absolute */
+       if (*dir == '~') {
+               if (!user_path) {
+                       logerror("'%s': User-path not allowed", dir);
+                       return NULL;
+               }
+               if (*user_path) {
+                       /* Got either "~alice" or "~alice/foo";
+                        * rewrite them to "~alice/%s" or
+                        * "~alice/%s/foo".
+                        */
+                       int namlen, restlen = strlen(dir);
+                       char *slash = strchr(dir, '/');
+                       if (!slash)
+                               slash = dir + restlen;
+                       namlen = slash - dir;
+                       restlen -= namlen;
+                       loginfo("userpath <%s>, request <%s>, namlen %d, restlen %d, slash <%s>", user_path, dir, namlen, restlen, slash);
+                       snprintf(rpath, PATH_MAX, "%.*s/%s%.*s",
+                                namlen, dir, user_path, restlen, slash);
+                       dir = rpath;
+               }
+       }
+       else if (base_path) {
+               if (*dir != '/') {
+                       /* Allow only absolute */
                        logerror("'%s': Non-absolute path denied (base-path active)", dir);
                        return NULL;
                }
@@ -688,6 +715,14 @@ int main(int argc, char **argv)
                        reuseaddr = 1;
                        continue;
                }
+               if (!strcmp(arg, "--user-path")) {
+                       user_path = "";
+                       continue;
+               }
+               if (!strncmp(arg, "--user-path=", 12)) {
+                       user_path = arg + 12;
+                       continue;
+               }
                if (!strcmp(arg, "--")) {
                        ok_paths = &argv[i+1];
                        break;