Re: [PATCHv4 1/3] Allow creation of arbitrary git-shell commands
- From
Greg Brockman <gdb@mit.edu>
- Date
- Jul 29, 2010, 00:37 UTC
- Message-ID
- <AANLkTikKQb=WZQ=179+qNxn_1=5mJtuOnqb=Cdw78W4e@mail.gmail.com>
- In-Reply-To
- <AANLkTim=iJUCZW+9Ttssnp=NpOpeQEhXsumCPw=HykX=@mail.gmail.com>
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 <gdb@mit.edu> wrote:
Show 104 quoted lines
> 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 <gdb@mit.edu>
> ---
> 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
>