diff options
author | Junio C Hamano <gitster@pobox.com> | 2017-05-23 13:46:07 +0900 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2017-05-23 13:46:07 +0900 |
commit | 3c980083bc404cb62fb87c76d331c48a44c5f50d (patch) | |
tree | 7f2fe624f1737885de03efc891363401341bcf39 /builtin | |
parent | Merge branch 'ab/doc-replace-gmane-links' (diff) | |
parent | receive-pack: verify push options in cert (diff) | |
download | tgif-3c980083bc404cb62fb87c76d331c48a44c5f50d.tar.xz |
Merge branch 'jt/push-options-doc'
The receive-pack program now makes sure that the push certificate
records the same set of push options used for pushing.
* jt/push-options-doc:
receive-pack: verify push options in cert
docs: correct receive.advertisePushOptions default
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/receive-pack.c | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 0bb36d584d..1b29975c52 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -473,7 +473,8 @@ static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp) * after dropping "_commit" from its name and possibly moving it out * of commit.c */ -static char *find_header(const char *msg, size_t len, const char *key) +static char *find_header(const char *msg, size_t len, const char *key, + const char **next_line) { int key_len = strlen(key); const char *line = msg; @@ -486,6 +487,8 @@ static char *find_header(const char *msg, size_t len, const char *key) if (line + key_len < eol && !memcmp(line, key, key_len) && line[key_len] == ' ') { int offset = key_len + 1; + if (next_line) + *next_line = *eol ? eol + 1 : eol; return xmemdupz(line + offset, (eol - line) - offset); } line = *eol ? eol + 1 : NULL; @@ -495,7 +498,7 @@ static char *find_header(const char *msg, size_t len, const char *key) static const char *check_nonce(const char *buf, size_t len) { - char *nonce = find_header(buf, len, "nonce"); + char *nonce = find_header(buf, len, "nonce", NULL); timestamp_t stamp, ostamp; char *bohmac, *expect = NULL; const char *retval = NONCE_BAD; @@ -575,6 +578,45 @@ leave: return retval; } +/* + * Return 1 if there is no push_cert or if the push options in push_cert are + * the same as those in the argument; 0 otherwise. + */ +static int check_cert_push_options(const struct string_list *push_options) +{ + const char *buf = push_cert.buf; + int len = push_cert.len; + + char *option; + const char *next_line; + int options_seen = 0; + + int retval = 1; + + if (!len) + return 1; + + while ((option = find_header(buf, len, "push-option", &next_line))) { + len -= (next_line - buf); + buf = next_line; + options_seen++; + if (options_seen > push_options->nr + || strcmp(option, + push_options->items[options_seen - 1].string)) { + retval = 0; + goto leave; + } + free(option); + } + + if (options_seen != push_options->nr) + retval = 0; + +leave: + free(option); + return retval; +} + static void prepare_push_cert_sha1(struct child_process *proc) { static int already_done; @@ -1929,6 +1971,11 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) if (use_push_options) read_push_options(&push_options); + if (!check_cert_push_options(&push_options)) { + struct command *cmd; + for (cmd = commands; cmd; cmd = cmd->next) + cmd->error_string = "inconsistent push options"; + } prepare_shallow_info(&si, &shallow); if (!si.nr_ours && !si.nr_theirs) |