From 35eb2d36418a25f9e956b116a622d8d99f4abad9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 23 Oct 2005 14:30:45 -0700 Subject: [PATCH] Add git-shell. 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: Linus Torvalds Signed-off-by: Junio C Hamano --- Makefile | 2 +- quote.c | 41 ++++++++++++++++++++++++++++++++++++++++- quote.h | 6 ++++++ shell.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 shell.c diff --git a/Makefile b/Makefile index 5bdf3cc8..5b0306d3 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 009e6949..e662a7da 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, const char *src) 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 2fdde3b6..2486e6e6 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 00000000..2c4789e9 --- /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); +} -- 2.11.0