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

[PATCH] Add git-shell.

From
Junio C Hamano <junkio@cox.net>
Date
Oct 24, 2005, 00:21 UTC
Message-ID
<7vhdb7vk64.fsf_-_@assigned-by-dhcp.cox.net>
In-Reply-To
<Pine.LNX.4.64.0510231427230.10477@g5.osdl.org>

This adds a very git specific restricted shell, that can be added to /etc/shells and set to the pw_shell in the /etc/passwd file, to give users ability to push into repositories over ssh without giving them full interactive shell acount.

[jc: I updated Linus' patch to match what the current sq_quote()
 does.]
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
   This one has the '!' dequoting I mentioned earlier, and
   actually has been tested twice.
   The system administrator should set things up so that the
   system default PATH environment variable lets users run the
   supported commands.
   We currently rely on the user to have a full shell access for
   repository administrative actions (e.g. git-init-db to create
   a repository, git-repack, and hooks management).  Probably
   some of them may need to become accessible from git-shell,
   but I do not know which ones offhand:
   - Creating a repository.  Probably wherever the user has
     write privilege, or maybe only under the home directory --
     the policy would be up to the system administrator, with
     usual filesystem quota applied.
   - I think setting up hooks should be forbidden -- the user
     can execute arbitrary commands if we allowed it.  Instead,
     the administrator can set things up for people, and would
     probably make creative use of hooks/update to implement
     access control (e.g. forbidding non-fast-forward pushes).
   - Similarly, packing can be left to hooks/post-update or cron
     job, either of which is under administrator control.
 Makefile |    2 +-
 quote.c  |   41 ++++++++++++++++++++++++++++++++++++++++-
 quote.h  |    6 ++++++
 shell.c  |   59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 106 insertions(+), 2 deletions(-)
 create mode 100644 shell.c

applies-to: c043f0993afe5c057409ef748ce313c89c20c7dc f176536e2cd5949fa134d8b24dc07dd1f0744b6f

diff --git a/Makefile b/Makefile
index 5bdf3cc..5b0306d 100644
--- a/Makefile
+++ b/Makefile
@@ -116,7 +116,7 @@ PROGRAMS = \
 	git-merge-index$X git-mktag$X git-pack-objects$X git-patch-id$X \
 	git-peek-remote$X git-prune-packed$X git-read-tree$X \
 	git-receive-pack$X git-rev-list$X git-rev-parse$X \
-	git-send-pack$X git-show-branch$X \
+	git-send-pack$X git-show-branch$X git-shell$X \
 	git-show-index$X git-ssh-fetch$X \
 	git-ssh-upload$X git-tar-tree$X git-unpack-file$X \
 	git-unpack-objects$X git-update-index$X git-update-server-info$X \
diff --git a/quote.c b/quote.c
index 009e694..e662a7d 100644
--- a/quote.c
+++ b/quote.c
@@ -15,6 +15,11 @@
 #undef EMIT
 #define EMIT(x) ( (++len < n) && (*bp++ = (x)) )
 
+static inline int need_bs_quote(char c)
+{
+	return (c == '\'' || c == '!');
+}
+
 size_t sq_quote_buf(char *dst, size_t n, const char *src)
 {
 	char c;
@@ -23,7 +28,7 @@ size_t sq_quote_buf(char *dst, size_t n,
 
 	EMIT('\'');
 	while ((c = *src++)) {
-		if (c == '\'' || c == '!') {
+		if (need_bs_quote(c)) {
 			EMIT('\'');
 			EMIT('\\');
 			EMIT(c);
@@ -52,6 +57,40 @@ char *sq_quote(const char *src)
 	return buf;
 }
 
+char *sq_dequote(char *arg)
+{
+	char *dst = arg;
+	char *src = arg;
+	char c;
+
+	if (*src != '\'')
+		return NULL;
+	for (;;) {
+		c = *++src;
+		if (!c)
+			return NULL;
+		if (c != '\'') {
+			*dst++ = c;
+			continue;
+		}
+		/* We stepped out of sq */
+		switch (*++src) {
+		case '\0':
+			*dst = 0;
+			return arg;
+		case '\\':
+			c = *++src;
+			if (need_bs_quote(c) && *++src == '\'') {
+				*dst++ = c;
+				continue;
+			}
+		/* Fallthrough */
+		default:
+			return NULL;
+		}
+	}
+}
+
 /*
  * C-style name quoting.
  *
diff --git a/quote.h b/quote.h
index 2fdde3b..2486e6e 100644
--- a/quote.h
+++ b/quote.h
@@ -31,6 +31,12 @@
 extern char *sq_quote(const char *src);
 extern size_t sq_quote_buf(char *dst, size_t n, const char *src);
 
+/* This unwraps what sq_quote() produces in place, but returns
+ * NULL if the input does not look like what sq_quote would have
+ * produced.
+ */
+extern char *sq_dequote(char *);
+
 extern int quote_c_style(const char *name, char *outbuf, FILE *outfp,
 			 int nodq);
 extern char *unquote_c_style(const char *quoted, const char **endp);
diff --git a/shell.c b/shell.c
new file mode 100644
index 0000000..2c4789e
--- /dev/null
+++ b/shell.c
@@ -0,0 +1,59 @@
+#include "cache.h"
+#include "quote.h"
+
+static int do_generic_cmd(const char *me, char *arg)
+{
+	const char *my_argv[4];
+
+	arg = sq_dequote(arg);
+	if (!arg)
+		die("bad argument");
+
+	my_argv[0] = me;
+	my_argv[1] = arg;
+	my_argv[2] = NULL;
+
+	return execvp(me, (char**) my_argv);
+}
+
+static struct commands {
+	const char *name;
+	int (*exec)(const char *me, char *arg);
+} cmd_list[] = {
+	{ "git-receive-pack", do_generic_cmd },
+	{ "git-upload-pack", do_generic_cmd },
+	{ NULL },
+};
+
+int main(int argc, char **argv)
+{
+	char *prog;
+	struct commands *cmd;
+
+	/* We want to see "-c cmd args", and nothing else */
+	if (argc != 3 || strcmp(argv[1], "-c"))
+		die("What do you think I am? A shell?");
+
+	prog = argv[2];
+	argv += 2;
+	argc -= 2;
+	for (cmd = cmd_list ; cmd->name ; cmd++) {
+		int len = strlen(cmd->name);
+		char *arg;
+		if (strncmp(cmd->name, prog, len))
+			continue;
+		arg = NULL;
+		switch (prog[len]) {
+		case '\0':
+			arg = NULL;
+			break;
+		case ' ':
+			arg = prog + len + 1;
+			break;
+		default:
+			continue;
+		}
+		exit(cmd->exec(cmd->name, arg));
+	}
+	die("unrecognized command '%s'", prog);
+}
---
0.99.8.GIT
Previous: Junio C HamanoNext: Linus Torvalds
Message 18 of 30 in “Server side programs”
  1. Andreas EricssonOct 22, 2005
  2. Junio C HamanoOct 23, 2005
  3. Andreas EricssonOct 23, 2005
  4. Petr BaudisOct 23, 2005
  5. Junio C HamanoOct 23, 2005
  6. Petr BaudisOct 23, 2005
  7. Junio C HamanoOct 23, 2005
  8. Daniel BarkalowOct 24, 2005
  9. Andreas EricssonOct 25, 2005
  10. Junio C HamanoOct 23, 2005
  11. Linus TorvaldsOct 23, 2005
  12. Junio C HamanoOct 23, 2005
  13. Junio C HamanoOct 23, 2005
  14. H. Peter AnvinOct 24, 2005
  15. Linus TorvaldsOct 24, 2005
  16. H. Peter AnvinOct 24, 2005
  17. Junio C HamanoOct 24, 2005
  18. Add git-shell.Junio C Hamano, Oct 24, 2005
  19. Linus TorvaldsOct 24, 2005
  20. Linus TorvaldsOct 24, 2005
  21. Junio C HamanoOct 24, 2005
  22. Junio C HamanoOct 24, 2005
  23. git_progname (was: Re: User-relative paths)Andreas Ericsson, Oct 25, 2005
  24. Petr BaudisOct 25, 2005
  25. Andreas EricssonOct 25, 2005
  26. Andreas EricssonOct 25, 2005
  27. Petr BaudisOct 25, 2005
  28. Junio C HamanoOct 26, 2005
  29. Matthias UrlichsOct 27, 2005
  30. Linus TorvaldsOct 23, 2005

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.