From patchwork Tue Feb 16 11:12:00 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [1,of,3] chg: pass sensitive command line flags to server From: Jun Wu X-Patchwork-Id: 13223 Message-Id: <3fc701a86323ae896371.1455621120@x1c> To: Date: Tue, 16 Feb 2016 11:12:00 +0000 # HG changeset patch # User Jun Wu # Date 1455618922 0 # Tue Feb 16 10:35:22 2016 +0000 # Node ID 3fc701a86323ae896371ec3df375a52bce06b748 # Parent 923500ca4f9a294db25318db07239359ad131348 chg: pass sensitive command line flags to server We are going to make chgserver load repo config, remember what it is, and load repo config again to detect config change. This is the first step that passes config, repo, cwd options to server. Traceback is passed as well to cover errors before hitting chgserver.runcommand. diff --git a/contrib/chg/chg.c b/contrib/chg/chg.c --- a/contrib/chg/chg.c +++ b/contrib/chg/chg.c @@ -32,8 +32,87 @@ char sockname[UNIX_PATH_MAX]; char lockfile[UNIX_PATH_MAX]; char pidfile[UNIX_PATH_MAX]; + int argsize; + const char **args; }; +static void initcmdserveropts(struct cmdserveropts *opts) { + memset(opts, 0, sizeof(struct cmdserveropts)); +} + +static void freecmdserveropts(struct cmdserveropts *opts) { + if (opts->args) { + free(opts->args); + opts->args = NULL; + opts->argsize = 0; + } +} + +/* + * Test if an argument is a sensitive flag that should be passed to the server. + * Return 0 if not, otherwise the number of arguments starting from the current + * one that should be passed to the server. + */ +static int testsensetiveflag(const char *arg) +{ + static struct { + const char *name; + const int narg; + } flags[] = { + {"--config", 1}, + {"--cwd", 1}, + {"--repo", 1}, + {"--repository", 1}, + {"--traceback", 0}, + {"-R", 1}, + }; + size_t i; + for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i) { + int len = strlen(flags[i].name); + int narg = flags[i].narg; + if (!memcmp(arg, flags[i].name, len)) { + if (arg[len] == '\0') { /* --flag (value) */ + return narg + 1; + } else if (arg[len] == '=' && narg > 0) { /* --flag=value */ + return 1; + } else if (flags[i].name[1] != '-') { /* short flag */ + return 1; + } + } + } + return 0; +} + +static void *reallocx(void *ptr, size_t size) +{ + void *result = realloc(ptr, size); + if (!result) abortmsg("failed to realloc"); + return result; +} + +/* + * Parse argv[] and put sensitive flags to opts->args + */ +static void setcmdserverargs(struct cmdserveropts *opts, + int argc, const char *argv[]) +{ + int i, argsize = 0; + const char **args = NULL; + for (i = 0; i < argc; ++i) { + if (!argv[i]) continue; /* pass clang-analyse */ + if (!strcmp(argv[i], "--")) break; + int n = testsensetiveflag(argv[i]); + if (n == 0 || i + n > argc) continue; + args = reallocx(args, (n + argsize) * sizeof(char*)); + memcpy(args + argsize, argv + i, sizeof(char*) * n); + argsize += n; + i += n - 1; + } + if (opts->args) free(opts->args); + opts->args = args; + opts->argsize = argsize; +} + static void preparesockdir(const char *sockdir) { int r; @@ -111,7 +190,7 @@ if (!hgcmd || hgcmd[0] == '\0') hgcmd = "hg"; - const char *argv[] = { + const char *baseargv[] = { hgcmd, "serve", "--cwd", "/", @@ -122,10 +201,19 @@ "--config", "extensions.chgserver=", /* wrap root ui so that it can be disabled/enabled by config */ "--config", "progress.assume-tty=1", - NULL, }; + int baseargvsize = sizeof(baseargv) / sizeof(baseargv[0]); + int argsize = baseargvsize + opts->argsize + 1; + + const char **argv = malloc(sizeof(char*) * argsize); + if (!argv) abortmsg("failed to malloc"); + memcpy(argv, baseargv, sizeof(baseargv)); + memcpy(argv + baseargvsize, opts->args, sizeof(char*) * opts->argsize); + argv[argsize - 1] = NULL; + if (execvp(hgcmd, (char **)argv) < 0) abortmsg("failed to exec cmdserver (errno = %d)", errno); + free(argv); } /* @@ -352,7 +440,9 @@ enabledebugmsg(); struct cmdserveropts opts; + initcmdserveropts(&opts); setcmdserveropts(&opts); + setcmdserverargs(&opts, argc, argv); if (argc == 2) { int sig = 0; @@ -379,5 +469,6 @@ setuppager(hgc, argv + 1, argc - 1); int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1); hgc_close(hgc); + freecmdserveropts(&opts); return exitcode; }