Hi, Using SSH access with restricted git-shell as login shell and using the script from the update-hook-example.txt works fine, but it requres that every Git user has a separate system account on the server, which is often frowned upon by system administrators, who would prefer to have a single system account for access to Git repo. I have looked on gitosis, but it requires normal shell account for the git user, which was vetoed by sysadmin. Also, I found its configuration more complex than necessary and not flexible enough to differentiate what branches can have non-fast-forward pushes on it and what cannot. In fact, the simple solution for me would be to have authorized_key for the git user being like this: environment="GIT_USER=user1" ssh-rsa USER1-SSH-PUBLIC-KEY environment="GIT_USER=user2" ssh-rsa USER2-SSH-PUBLIC-KEY ... In this case, with one line change to update-hook-example from username=$(id -u -n) to username="$GIT_USER" I would get exactly what I want. However, the environment option in authorized_key works only if PermitUserEnvironment is set in sshd configuration, and this option will allow _all_ users to overwrite their environment, which may be not desirable in some settings for security reasons. So, instead, I have to write a simple program, which is placed as the login shell and interprets the given command as user name, sets GIT_USER to it, and invokes git-shell with SSH_ORIGINAL_COMMAND. Thus authorized_key looks like that: command="git-su user1" ssh-rsa USER1-SSH-PUBLIC-KEY command="git-su user2" ssh-rsa USER2-SSH-PUBLIC-KEY ... But then I realized that it is simpler and more efficient to add some built-in command to git-shell to do that. You can see my patch below. I hope it will be useful for people who wants to user git on server with a single system account for all git users. Dmitry -- 8< -- From: Dmitry Potapov <dpotapov@xxxxxxxxx> Date: Wed, 25 Jun 2008 08:14:22 +0400 Subject: [PATCH] git-shell: add git-su command git-su interprets the given command as a user name that must be set to the GIT_USER environment variable and then executing SSH_ORIGINAL_COMMAND as it were the command given to git-shell. This allows to have different values for GIT_USER variable for different ssh public keys, which is necessary to have a single system for many Git users. With this command the typical authorized_key will for git user will be look like this: command="git-su user1" ssh-rsa USER1-SSH-PUBLIC-KEY command="git-su user2" ssh-rsa USER2-SSH-PUBLIC-KEY ... The alternative of using the "environment" option in authorized_key may be problematic as it requires that the PermitUserEnvironment option was set in sshd_config and by default this option is not enabled, because it may allow some users to bypass access restrictions. Signed-off-by: Dmitry Potapov <dpotapov@xxxxxxxxx> --- I moved command parsing logic from main() to a separate function, (which makes the patch a bit bigger than it actually is) and then added do_su_cmd(), which reuses this functionality. shell.c | 51 ++++++++++++++++++++++++++++++++++----------------- 1 files changed, 34 insertions(+), 17 deletions(-) diff --git a/shell.c b/shell.c index 91ca7de..05bd3cc 100644 --- a/shell.c +++ b/shell.c @@ -41,6 +41,19 @@ static int do_cvs_cmd(const char *me, char *arg) return execv_git_cmd(cvsserver_argv); } +static int exec_cmd(char *prog); + +static int do_su_cmd(const char *me, char *arg) +{ + char *cmd = getenv("SSH_ORIGINAL_COMMAND"); + if (!cmd) + die("SSH_ORIGINAL_COMMAND is not set"); + if (setenv("GIT_USER", arg, 1)) + die ("setenv failed: %s", strerror(errno)); + if (unsetenv("SSH_ORIGINAL_COMMAND")) + die ("unsetenv failed: %s", strerror(errno)); + return exec_cmd(cmd); +} static struct commands { const char *name; @@ -49,28 +62,14 @@ static struct commands { { "git-receive-pack", do_generic_cmd }, { "git-upload-pack", do_generic_cmd }, { "cvs", do_cvs_cmd }, + { "git-su", do_su_cmd }, { NULL }, }; -int main(int argc, char **argv) +static int exec_cmd(char *prog) { - char *prog; struct commands *cmd; - /* - * Special hack to pretend to be a CVS server - */ - if (argc == 2 && !strcmp(argv[1], "cvs server")) - argv--; - - /* - * We do not accept anything but "-c" followed by "cmd arg", - * where "cmd" is a very limited subset of git commands. - */ - else if (argc != 3 || strcmp(argv[1], "-c")) - die("What do you think I am? A shell?"); - - prog = argv[2]; if (!strncmp(prog, "git", 3) && isspace(prog[3])) /* Accept "git foo" as if the caller said "git-foo". */ prog[3] = '-'; @@ -91,7 +90,25 @@ int main(int argc, char **argv) default: continue; } - exit(cmd->exec(cmd->name, arg)); + return cmd->exec(cmd->name, arg); } die("unrecognized command '%s'", prog); } + +int main(int argc, char **argv) +{ + /* + * Special hack to pretend to be a CVS server + */ + if (argc == 2 && !strcmp(argv[1], "cvs server")) + argv--; + + /* + * We do not accept anything but "-c" followed by "cmd arg", + * where "cmd" is a very limited subset of git commands. + */ + else if (argc != 3 || strcmp(argv[1], "-c")) + die("What do you think I am? A shell?"); + + return exec_cmd(argv[2]); +} -- 1.5.6.1 -- 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