By default, paths that are forwarded to git-shell when users try to pull from an ssh:// URI are relative to the server's root folder (/). Add support for an environment variable, GIT_SHELL_BASE_PATH, to allow sysadmins to make these paths relative to somewhere else (e.g. /srv/git). Expand a leading "~/" to the value of $HOME. Allow an additional leading slash to specify a path relative to the root folder (/). This change does not improve security in the slightest, just makes ssh:// URIs prettier. Signed-off-by: Dan Charney <git@xxxxxxxxxxx> --- I should point out that I've not tested the the behavior with the "cvs emulator" mode, in large part because CVS remains thoroughly baffling to me. Despite many attempts to learn how to use it, I never did move beyond the "copy and paste somebody else's pre-written commands" phase. This is my first attempt at contributing to a project this big, and this is the first time this year I've written any C. Free to tear me a new one if I've done something stupid :-) Documentation/git-shell.txt | 25 ++++++++++++++++++++++++- shell.c | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/Documentation/git-shell.txt b/Documentation/git-shell.txt index 9b92506..280282e 100644 --- a/Documentation/git-shell.txt +++ b/Documentation/git-shell.txt @@ -22,13 +22,36 @@ is started in interactive mode when no arguments are given; in this case, COMMAND_DIR must exist, and any of the executables in it can be invoked. -'cvs server' is a special command which executes git-cvsserver. +'cvs server' is a special command which executes git-cvsserver. If +"$GIT_SHELL_BASE_PATH" is set, it will be passed to git-cvsserver as +the --base-path parameter. COMMAND_DIR is the path "$HOME/git-shell-commands". The user must have read and execute permissions to the directory in order to execute the programs in it. The programs are executed with a cwd of $HOME, and <argument> is parsed as a command-line string. +PATH MAPPING +------------ + +If the environment variable "$GIT_SHELL_BASE_PATH" is set and the shell +is not in interactive mode, $GIT_SHELL_BASE_PATH will be prepended to +the front the <argument> passed to <command>. This is analogous to +the --base-path switch from link:git-daemon[1] - if your environment +variables include GIT_SHELL_BASE_PATH=/srv/git on example.com, and later +someone pulls ssh://example.com/my.git, it will be interpreted as +/srv/git/my.git. This feature does not restrict clients to subfolders +of the base path; path elements such as .. are allowed. + +If the environment variable "$HOME" is set, git-shell will replace a leading +"~/" in the <argument> with the value of "$HOME". + +Example:: + If GIT_SHELL_BASE_PATH=/srv/git and HOME=/home/joeuser, then:: + ssh://example.com/some.git will map to /srv/git/some.git + ssh://example.com/~/my.git will map to /home/joeuser/my.git + ssh://example.com//var/git/x.git will map to /var/git/x.git + GIT --- Part of the linkgit:git[1] suite diff --git a/shell.c b/shell.c index abb8622..e250b2a 100644 --- a/shell.c +++ b/shell.c @@ -6,6 +6,37 @@ #define COMMAND_DIR "git-shell-commands" #define HELP_COMMAND COMMAND_DIR "/help" +#define BASE_PATH_VARIABLE "GIT_SHELL_BASE_PATH" +#define DEFAULT_PATH "/" + +static const char *adjust_argument_path(const char *arg) +{ + struct strbuf path = STRBUF_INIT; + const char *env; + const char *prefix_variable = NULL; + + if (arg == NULL || arg[0] != '/') + prefix_variable = BASE_PATH_VARIABLE; + else if (arg[1] == '/') + ++arg; + else if (arg[1] == '~' && arg[2] == '/') { + prefix_variable = "HOME"; + arg += 2; + } else + prefix_variable = BASE_PATH_VARIABLE; + + if (NULL != prefix_variable) { + env = getenv(prefix_variable); + if (NULL != env) + strbuf_addstr(&path, env); + } + + if (NULL != arg) + strbuf_addstr(&path, arg); + if (NULL == path.buf || path.buf[0] == '\0') + return DEFAULT_PATH; + return path.buf; +} static int do_generic_cmd(const char *me, char *arg) { @@ -18,7 +49,7 @@ static int do_generic_cmd(const char *me, char *arg) die("bad command"); my_argv[0] = me + 4; - my_argv[1] = arg; + my_argv[1] = adjust_argument_path(arg); my_argv[2] = NULL; return execv_git_cmd(my_argv); @@ -30,6 +61,10 @@ static int do_cvs_cmd(const char *me, char *arg) "cvsserver", "server", NULL }; + const char *base_path; + base_path = adjust_argument_path(NULL); + setenv("GIT_CVSSERVER_BASE_PATH", base_path, 1); + if (!arg || strcmp(arg, "server")) die("git-cvsserver only handles server: %s", arg); -- 1.7.4 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html