git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[RFC] Single system account for multiple git users

From
Dmitry Potapov <dpotapov@gmail.com>
Date
Jun 30, 2008, 15:11 UTC
Message-ID
<20080630151113.GO5737@dpotapov.dyndns.org>
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@gmail.com>
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@gmail.com>
---

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
Next: Asheesh Laroia
Message 1 of 9 in “[RFC] Single system account for multiple git users”
  1. Dmitry PotapovJun 30, 2008
  2. Asheesh LaroiaJun 30, 2008
  3. Dmitry PotapovJun 30, 2008
  4. Jon LoeligerJun 30, 2008
  5. Dmitry PotapovJun 30, 2008
  6. Jakub NarebskiJun 30, 2008
  7. Dmitry PotapovJun 30, 2008
  8. Melchior FRANZJul 1, 2008
  9. Dmitry PotapovJul 2, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.