Documentation/config.txt | 5 +++++ builtin-upload-archive.c | 39 +++++++++++++++++++++++++++++++++++++++ daemon.c | 2 ++ 3 files changed, 46 insertions(+) diff --git a/Documentation/config.txt b/Documentation/config.txt index ce722a2..5c3c6c7 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -236,6 +236,11 @@ tar.umask:: the same permissions as gitlink:git-checkout[1] would use. The default value remains 0, which means world read-write. +uploadarchive.daemonformats:: + A comma-separated list of the git-archive formats allowed for upload + via git-daemon. If this parameter is missing all formats are allowed + for upload. + user.email:: Your email address to be recorded in any newly created commits. Can be overridden by the 'GIT_AUTHOR_EMAIL' and 'GIT_COMMITTER_EMAIL' diff --git a/builtin-upload-archive.c b/builtin-upload-archive.c index 96f96bd..6a5245a 100644 --- a/builtin-upload-archive.c +++ b/builtin-upload-archive.c @@ -16,6 +16,37 @@ static const char upload_archive_usage[] static const char deadchild[] = "git-upload-archive: archiver died with error"; +static char *daemon_formats; + +static int upload_format_config(const char *var, const char *value) +{ + if (!strcmp(var, "uploadarchive.daemonformats")) + daemon_formats = xstrdup(value); + return 0; +} + +static int is_in(const char *needle, const char *haystack, const char *delim) +{ + int len = strlen(needle); + const char *search = haystack; + + for (;;) { + char *pos = strstr(search, needle); + if (!pos) + return 0; + search++; + if ((pos == haystack || strchr(delim, pos[-1])) && + (pos[len] == '\0' || strchr(delim, pos[len]))) + return 1; + } +} + +static int upload_format_allowed(const char *fmt) +{ + if (getenv("GIT_DAEMON")) + return daemon_formats ? is_in(fmt, daemon_formats, " \t,") : 1; + return 1; +} static int run_upload_archive(int argc, const char **argv, const char *prefix) { @@ -38,6 +69,8 @@ static int run_upload_archive(int argc, if (!enter_repo(buf, 0)) die("not a git archive"); + git_config(upload_format_config); + /* put received options in sent_argv[] */ sent_argc = 1; sent_argv[0] = "git-upload-archive"; @@ -67,6 +100,12 @@ static int run_upload_archive(int argc, /* parse all options sent by the client */ treeish_idx = parse_archive_args(sent_argc, sent_argv, &ar); + if (!upload_format_allowed(ar.name)) { + free(daemon_formats); + die("upload of %s format forbidden\n", ar.name); + } + free(daemon_formats); + parse_treeish_arg(sent_argv + treeish_idx, &ar.args, prefix); parse_pathspec_arg(sent_argv + treeish_idx + 1, &ar.args); diff --git a/daemon.c b/daemon.c index a2954a0..2d58abe 100644 --- a/daemon.c +++ b/daemon.c @@ -304,6 +304,8 @@ static int run_service(char *dir, struct return -1; } + setenv("GIT_DAEMON", "I am your father.", 1); + /* * We'll ignore SIGTERM from now on, we have a * good client. - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html