[RFC] Single system account for multiple git users

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux