]> git.ipfire.org Git - thirdparty/git.git/blobdiff - builtin/receive-pack.c
push: the beginning of "git push --signed"
[thirdparty/git.git] / builtin / receive-pack.c
index 18458e81c6351d53afe1a50efff183889e5ab81b..610b085e3d88a4ca07132b1e991222179eaae276 100644 (file)
@@ -46,6 +46,9 @@ static void *head_name_to_free;
 static int sent_capabilities;
 static int shallow_update;
 static const char *alt_shallow_file;
+static int accept_push_cert = 1;
+static struct strbuf push_cert = STRBUF_INIT;
+static unsigned char push_cert_sha1[20];
 
 static enum deny_action parse_deny_action(const char *var, const char *value)
 {
@@ -129,6 +132,11 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
+       if (strcmp(var, "receive.acceptpushcert") == 0) {
+               accept_push_cert = git_config_bool(var, value);
+               return 0;
+       }
+
        return git_default_config(var, value, cb);
 }
 
@@ -137,15 +145,23 @@ static void show_ref(const char *path, const unsigned char *sha1)
        if (ref_is_hidden(path))
                return;
 
-       if (sent_capabilities)
+       if (sent_capabilities) {
                packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
-       else
-               packet_write(1, "%s %s%c%s%s agent=%s\n",
-                            sha1_to_hex(sha1), path, 0,
-                            " report-status delete-refs side-band-64k quiet",
-                            prefer_ofs_delta ? " ofs-delta" : "",
-                            git_user_agent_sanitized());
-       sent_capabilities = 1;
+       } else {
+               struct strbuf cap = STRBUF_INIT;
+
+               strbuf_addstr(&cap,
+                             "report-status delete-refs side-band-64k quiet");
+               if (prefer_ofs_delta)
+                       strbuf_addstr(&cap, " ofs-delta");
+               if (accept_push_cert)
+                       strbuf_addstr(&cap, " push-cert");
+               strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized());
+               packet_write(1, "%s %s%c%s\n",
+                            sha1_to_hex(sha1), path, 0, cap.buf);
+               strbuf_release(&cap);
+               sent_capabilities = 1;
+       }
 }
 
 static int show_ref_cb(const char *path, const unsigned char *sha1, int flag, void *unused)
@@ -252,6 +268,25 @@ static int copy_to_sideband(int in, int out, void *arg)
        return 0;
 }
 
+static void prepare_push_cert_sha1(struct child_process *proc)
+{
+       static int already_done;
+       struct argv_array env = ARGV_ARRAY_INIT;
+
+       if (!push_cert.len)
+               return;
+
+       if (!already_done) {
+               already_done = 1;
+               if (write_sha1_file(push_cert.buf, push_cert.len, "blob", push_cert_sha1))
+                       hashclr(push_cert_sha1);
+       }
+       if (!is_null_sha1(push_cert_sha1)) {
+               argv_array_pushf(&env, "GIT_PUSH_CERT=%s", sha1_to_hex(push_cert_sha1));
+               proc->env = env.argv;
+       }
+}
+
 typedef int (*feed_fn)(void *, const char **, size_t *);
 static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_state)
 {
@@ -271,6 +306,8 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta
        proc.in = -1;
        proc.stdout_to_stderr = 1;
 
+       prepare_push_cert_sha1(&proc);
+
        if (use_sideband) {
                memset(&muxer, 0, sizeof(muxer));
                muxer.proc = copy_to_sideband;
@@ -438,7 +475,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
        uint32_t mask = 1 << (cmd->index % 32);
        int i;
 
-       trace_printf_key("GIT_TRACE_SHALLOW",
+       trace_printf_key(&trace_shallow,
                         "shallow: update_shallow_ref %s\n", cmd->ref_name);
        for (i = 0; i < si->shallow->nr; i++)
                if (si->used_shallow[i] &&
@@ -831,40 +868,57 @@ static void execute_commands(struct command *commands,
                      "the reported refs above");
 }
 
+static struct command **queue_command(struct command **tail,
+                                     const char *line,
+                                     int linelen)
+{
+       unsigned char old_sha1[20], new_sha1[20];
+       struct command *cmd;
+       const char *refname;
+       int reflen;
+
+       if (linelen < 83 ||
+           line[40] != ' ' ||
+           line[81] != ' ' ||
+           get_sha1_hex(line, old_sha1) ||
+           get_sha1_hex(line + 41, new_sha1))
+               die("protocol error: expected old/new/ref, got '%s'", line);
+
+       refname = line + 82;
+       reflen = linelen - 82;
+       cmd = xcalloc(1, sizeof(struct command) + reflen + 1);
+       hashcpy(cmd->old_sha1, old_sha1);
+       hashcpy(cmd->new_sha1, new_sha1);
+       memcpy(cmd->ref_name, refname, reflen);
+       cmd->ref_name[reflen] = '\0';
+       *tail = cmd;
+       return &cmd->next;
+}
+
 static struct command *read_head_info(struct sha1_array *shallow)
 {
        struct command *commands = NULL;
        struct command **p = &commands;
        for (;;) {
                char *line;
-               unsigned char old_sha1[20], new_sha1[20];
-               struct command *cmd;
-               char *refname;
-               int len, reflen;
+               int len, linelen;
 
                line = packet_read_line(0, &len);
                if (!line)
                        break;
 
                if (len == 48 && starts_with(line, "shallow ")) {
-                       if (get_sha1_hex(line + 8, old_sha1))
-                               die("protocol error: expected shallow sha, got '%s'", line + 8);
-                       sha1_array_append(shallow, old_sha1);
+                       unsigned char sha1[20];
+                       if (get_sha1_hex(line + 8, sha1))
+                               die("protocol error: expected shallow sha, got '%s'",
+                                   line + 8);
+                       sha1_array_append(shallow, sha1);
                        continue;
                }
 
-               if (len < 83 ||
-                   line[40] != ' ' ||
-                   line[81] != ' ' ||
-                   get_sha1_hex(line, old_sha1) ||
-                   get_sha1_hex(line + 41, new_sha1))
-                       die("protocol error: expected old/new/ref, got '%s'",
-                           line);
-
-               refname = line + 82;
-               reflen = strlen(refname);
-               if (reflen + 82 < len) {
-                       const char *feature_list = refname + reflen + 1;
+               linelen = strlen(line);
+               if (linelen < len) {
+                       const char *feature_list = line + linelen + 1;
                        if (parse_feature_request(feature_list, "report-status"))
                                report_status = 1;
                        if (parse_feature_request(feature_list, "side-band-64k"))
@@ -872,12 +926,29 @@ static struct command *read_head_info(struct sha1_array *shallow)
                        if (parse_feature_request(feature_list, "quiet"))
                                quiet = 1;
                }
-               cmd = xcalloc(1, sizeof(struct command) + len - 80);
-               hashcpy(cmd->old_sha1, old_sha1);
-               hashcpy(cmd->new_sha1, new_sha1);
-               memcpy(cmd->ref_name, line + 82, len - 81);
-               *p = cmd;
-               p = &cmd->next;
+
+               if (!strcmp(line, "push-cert")) {
+                       int true_flush = 0;
+                       char certbuf[1024];
+
+                       for (;;) {
+                               len = packet_read(0, NULL, NULL,
+                                                 certbuf, sizeof(certbuf), 0);
+                               if (!len) {
+                                       true_flush = 1;
+                                       break;
+                               }
+                               if (!strcmp(certbuf, "push-cert-end\n"))
+                                       break; /* end of cert */
+                               strbuf_addstr(&push_cert, certbuf);
+                       }
+
+                       if (true_flush)
+                               break;
+                       continue;
+               }
+
+               p = queue_command(p, line, linelen);
        }
        return commands;
 }
@@ -1122,7 +1193,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
        int advertise_refs = 0;
        int stateless_rpc = 0;
        int i;
-       char *dir = NULL;
+       const char *dir = NULL;
        struct command *commands;
        struct sha1_array shallow = SHA1_ARRAY_INIT;
        struct sha1_array ref = SHA1_ARRAY_INIT;
@@ -1157,7 +1228,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                }
                if (dir)
                        usage(receive_pack_usage);
-               dir = xstrdup(arg);
+               dir = arg;
        }
        if (!dir)
                usage(receive_pack_usage);