From: Greg Brockman Date: Thu, 29 Jul 2010 00:37:29 GMT Subject: Re: [PATCHv4 1/3] Allow creation of arbitrary git-shell commands Message-ID: In-Reply-To: Err, actually it would probably be a good idea to s/char *home = getenv("HOME");/const char *home = getenv("HOME");/ Greg On Wed, Jul 28, 2010 at 5:31 PM, Greg Brockman wrote: > This provides a mechanism for the server to expose custom > functionality to clients.  My particular use case is that I would like > a way of discovering all repositories available for cloning.  A > client that clones via > >  git clone user@example.com > > can invoke a command by > >  ssh user@example.com $command > > Signed-off-by: Greg Brockman > --- >  shell.c |   44 ++++++++++++++++++++++++++++++++++++++++++-- >  1 files changed, 42 insertions(+), 2 deletions(-) > > As discussed on-list, it should be fine to trust the value of HOME. > This patch differs from the previous only in the implementation of > cd_to_homedir. > > diff --git a/shell.c b/shell.c > index e4864e0..1e6077d 100644 > --- a/shell.c > +++ b/shell.c > @@ -3,6 +3,8 @@ >  #include "exec_cmd.h" >  #include "strbuf.h" > > +#define COMMAND_DIR "git-shell-commands" > + >  static int do_generic_cmd(const char *me, char *arg) >  { >        const char *my_argv[4]; > @@ -33,6 +35,29 @@ static int do_cvs_cmd(const char *me, char *arg) >        return execv_git_cmd(cvsserver_argv); >  } > > +static int is_valid_cmd_name(const char *cmd) > +{ > +       /* Test command contains no . or / characters */ > +       return cmd[strcspn(cmd, "./")] == '\0'; > +} > + > +static char *make_cmd(const char *prog) > +{ > +       char *prefix = xmalloc((strlen(prog) + strlen(COMMAND_DIR) + 2)); > +       strcpy(prefix, COMMAND_DIR); > +       strcat(prefix, "/"); > +       strcat(prefix, prog); > +       return prefix; > +} > + > +static void cd_to_homedir(void) > +{ > +       char *home = getenv("HOME"); > +       if (!home) > +               die("could not determine user's home directory; HOME is unset"); > +       if (chdir(home) == -1) > +               die("could not chdir to user's home directory"); > +} > >  static struct commands { >        const char *name; > @@ -48,6 +73,7 @@ static struct commands { >  int main(int argc, char **argv) >  { >        char *prog; > +       const char **user_argv; >        struct commands *cmd; >        int devnull_fd; > > @@ -76,7 +102,7 @@ int main(int argc, char **argv) >        else if (argc != 3 || strcmp(argv[1], "-c")) >                die("What do you think I am? A shell?"); > > -       prog = argv[2]; > +       prog = xstrdup(argv[2]); >        if (!strncmp(prog, "git", 3) && isspace(prog[3])) >                /* Accept "git foo" as if the caller said "git-foo". */ >                prog[3] = '-'; > @@ -99,5 +125,19 @@ int main(int argc, char **argv) >                } >                exit(cmd->exec(cmd->name, arg)); >        } > -       die("unrecognized command '%s'", prog); > + > +       cd_to_homedir(); > +       if (split_cmdline(prog, &user_argv) != -1) { > +               if (is_valid_cmd_name(user_argv[0])) { > +                       prog = make_cmd(user_argv[0]); > +                       user_argv[0] = prog; > +                       execv(user_argv[0], (char *const *) user_argv); > +               } > +               free(prog); > +               free(user_argv); > +               die("unrecognized command '%s'", argv[2]); > +       } else { > +               free(prog); > +               die("invalid command format '%s'", argv[2]); > +       } >  } > -- > 1.7.0.4 >