Blob


1 /*
2 * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
3 * Copyright (c) 2020 Ori Bernstein <ori@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
18 #include <sys/types.h>
19 #include <sys/queue.h>
20 #include <sys/uio.h>
21 #include <sys/wait.h>
23 #include <ctype.h>
24 #include <limits.h>
25 #include <signal.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <stdint.h>
31 #include <poll.h>
32 #include <imsg.h>
33 #include <sha1.h>
34 #include <sha2.h>
35 #include <unistd.h>
36 #include <zlib.h>
38 #include "got_compat.h"
40 #include "got_object.h"
41 #include "got_error.h"
42 #include "got_path.h"
43 #include "got_repository.h"
45 #include "got_lib_sha1.h"
46 #include "got_lib_delta.h"
47 #include "got_lib_inflate.h"
48 #include "got_lib_object.h"
49 #include "got_lib_object_parse.h"
50 #include "got_lib_privsep.h"
51 #include "got_lib_pack.h"
52 #include "got_lib_poll.h"
54 #include "got_privsep.h"
56 #ifndef MIN
57 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
58 #endif
60 #ifndef nitems
61 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
62 #endif
64 static const struct got_error *
65 read_imsg(struct imsgbuf *ibuf)
66 {
67 const struct got_error *err;
68 size_t n;
70 err = got_poll_fd(ibuf->fd, POLLIN, INFTIM);
71 if (err) {
72 if (err->code == GOT_ERR_EOF)
73 return got_error(GOT_ERR_PRIVSEP_PIPE);
74 return err;
75 }
77 n = imsg_read(ibuf);
78 if (n == -1) {
79 if (errno == EAGAIN) /* Could be a file-descriptor leak. */
80 return got_error(GOT_ERR_PRIVSEP_NO_FD);
81 return got_error(GOT_ERR_PRIVSEP_READ);
82 }
83 if (n == 0)
84 return got_error(GOT_ERR_PRIVSEP_PIPE);
86 return NULL;
87 }
89 const struct got_error *
90 got_privsep_wait_for_child(pid_t pid)
91 {
92 int child_status;
94 if (waitpid(pid, &child_status, 0) == -1)
95 return got_error_from_errno("waitpid");
97 if (!WIFEXITED(child_status))
98 return got_error(GOT_ERR_PRIVSEP_DIED);
100 if (WEXITSTATUS(child_status) != 0)
101 return got_error(GOT_ERR_PRIVSEP_EXIT);
103 return NULL;
106 static const struct got_error *
107 recv_imsg_error(struct imsg *imsg, size_t datalen)
109 struct got_imsg_error *ierr;
111 if (datalen != sizeof(*ierr))
112 return got_error(GOT_ERR_PRIVSEP_LEN);
114 ierr = imsg->data;
115 if (ierr->code == GOT_ERR_ERRNO) {
116 static struct got_error serr;
117 serr.code = GOT_ERR_ERRNO;
118 serr.msg = strerror(ierr->errno_code);
119 return &serr;
122 return got_error(ierr->code);
125 const struct got_error *
126 got_privsep_recv_imsg(struct imsg *imsg, struct imsgbuf *ibuf,
127 size_t min_datalen)
129 const struct got_error *err;
130 ssize_t n;
132 n = imsg_get(ibuf, imsg);
133 if (n == -1)
134 return got_error_from_errno("imsg_get");
136 while (n == 0) {
137 err = read_imsg(ibuf);
138 if (err)
139 return err;
140 n = imsg_get(ibuf, imsg);
141 if (n == -1)
142 return got_error_from_errno("imsg_get");
145 if (imsg->hdr.len < IMSG_HEADER_SIZE + min_datalen)
146 return got_error(GOT_ERR_PRIVSEP_LEN);
148 if (imsg->hdr.type == GOT_IMSG_ERROR) {
149 size_t datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
150 return recv_imsg_error(imsg, datalen);
153 return NULL;
156 /* Attempt to send an error in an imsg. Complain on stderr as a last resort. */
157 void
158 got_privsep_send_error(struct imsgbuf *ibuf, const struct got_error *err)
160 const struct got_error *poll_err;
161 struct got_imsg_error ierr;
162 int ret;
164 ierr.code = err->code;
165 if (err->code == GOT_ERR_ERRNO)
166 ierr.errno_code = errno;
167 else
168 ierr.errno_code = 0;
169 ret = imsg_compose(ibuf, GOT_IMSG_ERROR, 0, 0, -1, &ierr, sizeof(ierr));
170 if (ret == -1) {
171 fprintf(stderr, "%s: error %d \"%s\": imsg_compose: %s\n",
172 getprogname(), err->code, err->msg, strerror(errno));
173 return;
176 poll_err = got_poll_fd(ibuf->fd, POLLOUT, INFTIM);
177 if (poll_err) {
178 fprintf(stderr, "%s: error %d \"%s\": poll: %s\n",
179 getprogname(), err->code, err->msg, poll_err->msg);
180 return;
183 ret = imsg_flush(ibuf);
184 if (ret == -1) {
185 fprintf(stderr, "%s: error %d \"%s\": imsg_flush: %s\n",
186 getprogname(), err->code, err->msg, strerror(errno));
187 imsg_clear(ibuf);
188 return;
192 static const struct got_error *
193 flush_imsg(struct imsgbuf *ibuf)
195 const struct got_error *err;
197 err = got_poll_fd(ibuf->fd, POLLOUT, INFTIM);
198 if (err)
199 return err;
201 if (imsg_flush(ibuf) == -1) {
202 imsg_clear(ibuf);
203 return got_error_from_errno("imsg_flush");
206 return NULL;
209 const struct got_error *
210 got_privsep_flush_imsg(struct imsgbuf *ibuf)
212 return flush_imsg(ibuf);
215 const struct got_error *
216 got_privsep_send_stop(int fd)
218 const struct got_error *err = NULL;
219 struct imsgbuf ibuf;
221 imsg_init(&ibuf, fd);
223 if (imsg_compose(&ibuf, GOT_IMSG_STOP, 0, 0, -1, NULL, 0) == -1)
224 return got_error_from_errno("imsg_compose STOP");
226 err = flush_imsg(&ibuf);
227 return err;
230 const struct got_error *
231 got_privsep_send_obj_req(struct imsgbuf *ibuf, int fd,
232 struct got_object_id *id)
234 if (imsg_compose(ibuf, GOT_IMSG_OBJECT_REQUEST, 0, 0, fd,
235 id, sizeof(*id)) == -1)
236 return got_error_from_errno("imsg_compose OBJECT_REQUEST");
238 return flush_imsg(ibuf);
241 const struct got_error *
242 got_privsep_send_raw_obj_req(struct imsgbuf *ibuf, int fd,
243 struct got_object_id *id)
245 if (imsg_compose(ibuf, GOT_IMSG_RAW_OBJECT_REQUEST, 0, 0, fd,
246 id, sizeof(*id)) == -1)
247 return got_error_from_errno("imsg_compose RAW_OBJECT_REQUEST");
249 return flush_imsg(ibuf);
252 const struct got_error *
253 got_privsep_send_raw_obj_outfd(struct imsgbuf *ibuf, int outfd)
255 const struct got_error *err = NULL;
257 if (imsg_compose(ibuf, GOT_IMSG_RAW_OBJECT_OUTFD, 0, 0, outfd, NULL, 0)
258 == -1) {
259 err = got_error_from_errno("imsg_compose RAW_OBJECT_OUTFD");
260 close(outfd);
261 return err;
264 return flush_imsg(ibuf);
267 const struct got_error *
268 got_privsep_send_raw_obj(struct imsgbuf *ibuf, off_t size, size_t hdrlen,
269 uint8_t *data)
271 const struct got_error *err = NULL;
272 struct got_imsg_raw_obj iobj;
273 size_t len = sizeof(iobj);
274 struct ibuf *wbuf;
276 memset(&iobj, 0, sizeof(iobj));
277 iobj.hdrlen = hdrlen;
278 iobj.size = size;
280 if (data && size + hdrlen <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX)
281 len += (size_t)size + hdrlen;
283 wbuf = imsg_create(ibuf, GOT_IMSG_RAW_OBJECT, 0, 0, len);
284 if (wbuf == NULL) {
285 err = got_error_from_errno("imsg_create RAW_OBJECT");
286 return err;
289 if (imsg_add(wbuf, &iobj, sizeof(iobj)) == -1)
290 return got_error_from_errno("imsg_add RAW_OBJECT");
292 if (data && size + hdrlen <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX) {
293 if (imsg_add(wbuf, data, size + hdrlen) == -1)
294 return got_error_from_errno("imsg_add RAW_OBJECT");
297 wbuf->fd = -1;
298 imsg_close(ibuf, wbuf);
300 return flush_imsg(ibuf);
303 const struct got_error *
304 got_privsep_recv_raw_obj(uint8_t **outbuf, off_t *size, size_t *hdrlen,
305 struct imsgbuf *ibuf)
307 const struct got_error *err = NULL;
308 struct imsg imsg;
309 struct got_imsg_raw_obj *iobj;
310 size_t datalen;
312 *outbuf = NULL;
314 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
315 if (err)
316 return err;
318 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
320 switch (imsg.hdr.type) {
321 case GOT_IMSG_RAW_OBJECT:
322 if (datalen < sizeof(*iobj)) {
323 err = got_error(GOT_ERR_PRIVSEP_LEN);
324 break;
326 iobj = imsg.data;
327 *size = iobj->size;
328 *hdrlen = iobj->hdrlen;
330 if (datalen == sizeof(*iobj)) {
331 /* Data has been written to file descriptor. */
332 break;
335 if (*size < 0 ||
336 *size + *hdrlen > GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX) {
337 err = got_error(GOT_ERR_PRIVSEP_LEN);
338 break;
341 *outbuf = malloc(*size + *hdrlen);
342 if (*outbuf == NULL) {
343 err = got_error_from_errno("malloc");
344 break;
346 memcpy(*outbuf, imsg.data + sizeof(*iobj), *size + *hdrlen);
347 break;
348 default:
349 err = got_error(GOT_ERR_PRIVSEP_MSG);
350 break;
353 imsg_free(&imsg);
355 return err;
358 const struct got_error *
359 got_privsep_send_commit_req(struct imsgbuf *ibuf, int fd,
360 struct got_object_id *id, int pack_idx)
362 const struct got_error *err = NULL;
363 struct got_imsg_packed_object iobj;
364 void *data;
365 size_t len;
367 memset(&iobj, 0, sizeof(iobj));
368 if (pack_idx != -1) { /* commit is packed */
369 iobj.idx = pack_idx;
370 memcpy(&iobj.id, id, sizeof(iobj.id));
371 data = &iobj;
372 len = sizeof(iobj);
373 } else {
374 data = id;
375 len = sizeof(*id);
378 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_REQUEST, 0, 0, fd, data, len)
379 == -1) {
380 err = got_error_from_errno("imsg_compose COMMIT_REQUEST");
381 close(fd);
382 return err;
385 return flush_imsg(ibuf);
388 const struct got_error *
389 got_privsep_send_tree_req(struct imsgbuf *ibuf, int fd,
390 struct got_object_id *id, int pack_idx)
392 struct ibuf *wbuf;
393 size_t len;
395 if (pack_idx != -1)
396 len = sizeof(struct got_imsg_packed_object);
397 else
398 len = sizeof(*id);
400 wbuf = imsg_create(ibuf, GOT_IMSG_TREE_REQUEST, 0, 0, len);
401 if (wbuf == NULL)
402 return got_error_from_errno("imsg_create TREE_REQUEST");
404 if (imsg_add(wbuf, id, sizeof(*id)) == -1)
405 return got_error_from_errno("imsg_add TREE_REQUEST");
407 if (pack_idx != -1) { /* tree is packed */
408 if (imsg_add(wbuf, &pack_idx, sizeof(pack_idx)) == -1)
409 return got_error_from_errno("imsg_add TREE_REQUEST");
412 wbuf->fd = fd;
413 imsg_close(ibuf, wbuf);
415 return flush_imsg(ibuf);
418 const struct got_error *
419 got_privsep_send_tag_req(struct imsgbuf *ibuf, int fd,
420 struct got_object_id *id, int pack_idx)
422 struct got_imsg_packed_object iobj;
423 void *data;
424 size_t len;
426 memset(&iobj, 0, sizeof(iobj));
427 if (pack_idx != -1) { /* tag is packed */
428 iobj.idx = pack_idx;
429 memcpy(&iobj.id, id, sizeof(iobj.id));
430 data = &iobj;
431 len = sizeof(iobj);
432 } else {
433 data = id;
434 len = sizeof(*id);
437 if (imsg_compose(ibuf, GOT_IMSG_TAG_REQUEST, 0, 0, fd, data, len)
438 == -1)
439 return got_error_from_errno("imsg_compose TAG_REQUEST");
441 return flush_imsg(ibuf);
444 const struct got_error *
445 got_privsep_send_blob_req(struct imsgbuf *ibuf, int infd,
446 struct got_object_id *id, int pack_idx)
448 const struct got_error *err = NULL;
449 struct got_imsg_packed_object iobj;
450 void *data;
451 size_t len;
453 memset(&iobj, 0, sizeof(iobj));
454 if (pack_idx != -1) { /* blob is packed */
455 iobj.idx = pack_idx;
456 memcpy(&iobj.id, id, sizeof(iobj.id));
457 data = &iobj;
458 len = sizeof(iobj);
459 } else {
460 data = id;
461 len = sizeof(*id);
464 if (imsg_compose(ibuf, GOT_IMSG_BLOB_REQUEST, 0, 0, infd, data, len)
465 == -1) {
466 err = got_error_from_errno("imsg_compose BLOB_REQUEST");
467 close(infd);
468 return err;
471 return flush_imsg(ibuf);
474 const struct got_error *
475 got_privsep_send_blob_outfd(struct imsgbuf *ibuf, int outfd)
477 const struct got_error *err = NULL;
479 if (imsg_compose(ibuf, GOT_IMSG_BLOB_OUTFD, 0, 0, outfd, NULL, 0)
480 == -1) {
481 err = got_error_from_errno("imsg_compose BLOB_OUTFD");
482 close(outfd);
483 return err;
486 return flush_imsg(ibuf);
489 static const struct got_error *
490 send_fd(struct imsgbuf *ibuf, int imsg_code, int fd)
492 const struct got_error *err = NULL;
494 if (imsg_compose(ibuf, imsg_code, 0, 0, fd, NULL, 0) == -1) {
495 err = got_error_from_errno("imsg_compose TMPFD");
496 close(fd);
497 return err;
500 return flush_imsg(ibuf);
503 const struct got_error *
504 got_privsep_send_tmpfd(struct imsgbuf *ibuf, int fd)
506 return send_fd(ibuf, GOT_IMSG_TMPFD, fd);
509 const struct got_error *
510 got_privsep_send_obj(struct imsgbuf *ibuf, struct got_object *obj)
512 struct got_imsg_object iobj;
514 memset(&iobj, 0, sizeof(iobj));
516 memcpy(&iobj.id, &obj->id, sizeof(iobj.id));
517 iobj.type = obj->type;
518 iobj.flags = obj->flags;
519 iobj.hdrlen = obj->hdrlen;
520 iobj.size = obj->size;
521 if (iobj.flags & GOT_OBJ_FLAG_PACKED) {
522 iobj.pack_offset = obj->pack_offset;
523 iobj.pack_idx = obj->pack_idx;
526 if (imsg_compose(ibuf, GOT_IMSG_OBJECT, 0, 0, -1, &iobj, sizeof(iobj))
527 == -1)
528 return got_error_from_errno("imsg_compose OBJECT");
530 return flush_imsg(ibuf);
533 const struct got_error *
534 got_privsep_send_fetch_req(struct imsgbuf *ibuf, int fd,
535 struct got_pathlist_head *have_refs, int fetch_all_branches,
536 struct got_pathlist_head *wanted_branches,
537 struct got_pathlist_head *wanted_refs, int list_refs_only,
538 const char *worktree_branch, const char *remote_head,
539 int no_head, int verbosity)
541 const struct got_error *err = NULL;
542 struct ibuf *wbuf;
543 struct got_pathlist_entry *pe;
544 struct got_imsg_fetch_request fetchreq;
545 size_t remote_head_len, worktree_branch_len, len = sizeof(fetchreq);
547 if (worktree_branch) {
548 worktree_branch_len = strlen(worktree_branch);
549 len += worktree_branch_len;
551 if (remote_head) {
552 remote_head_len = strlen(remote_head);
553 len += remote_head_len;
556 if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
557 close(fd);
558 return got_error(GOT_ERR_NO_SPACE);
561 wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_REQUEST, 0, 0, len);
562 if (wbuf == NULL)
563 return got_error_from_errno("imsg_create FETCH_HAVE_REF");
565 memset(&fetchreq, 0, sizeof(fetchreq));
566 fetchreq.no_head = no_head;
567 fetchreq.fetch_all_branches = fetch_all_branches;
568 fetchreq.list_refs_only = list_refs_only;
569 fetchreq.verbosity = verbosity;
570 if (worktree_branch != NULL)
571 fetchreq.worktree_branch_len = worktree_branch_len;
572 if (remote_head != NULL)
573 fetchreq.remote_head_len = remote_head_len;
574 TAILQ_FOREACH(pe, have_refs, entry)
575 fetchreq.n_have_refs++;
576 TAILQ_FOREACH(pe, wanted_branches, entry)
577 fetchreq.n_wanted_branches++;
578 TAILQ_FOREACH(pe, wanted_refs, entry)
579 fetchreq.n_wanted_refs++;
580 if (imsg_add(wbuf, &fetchreq, sizeof(fetchreq)) == -1)
581 return got_error_from_errno("imsg_add FETCH_REQUEST");
582 if (worktree_branch) {
583 if (imsg_add(wbuf, worktree_branch, worktree_branch_len) == -1)
584 return got_error_from_errno("imsg_add FETCH_REQUEST");
586 if (remote_head) {
587 if (imsg_add(wbuf, remote_head, remote_head_len) == -1)
588 return got_error_from_errno("imsg_add FETCH_REQUEST");
590 wbuf->fd = fd;
591 imsg_close(ibuf, wbuf);
593 err = flush_imsg(ibuf);
594 if (err) {
595 close(fd);
596 return err;
598 fd = -1;
600 TAILQ_FOREACH(pe, have_refs, entry) {
601 const char *name = pe->path;
602 size_t name_len = pe->path_len;
603 struct got_object_id *id = pe->data;
605 len = sizeof(struct got_imsg_fetch_have_ref) + name_len;
606 wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_HAVE_REF, 0, 0, len);
607 if (wbuf == NULL)
608 return got_error_from_errno("imsg_create FETCH_HAVE_REF");
610 /* Keep in sync with struct got_imsg_fetch_have_ref! */
611 if (imsg_add(wbuf, id, sizeof(*id)) == -1)
612 return got_error_from_errno("imsg_add FETCH_HAVE_REF");
613 if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1)
614 return got_error_from_errno("imsg_add FETCH_HAVE_REF");
615 if (imsg_add(wbuf, name, name_len) == -1)
616 return got_error_from_errno("imsg_add FETCH_HAVE_REF");
618 wbuf->fd = -1;
619 imsg_close(ibuf, wbuf);
620 err = flush_imsg(ibuf);
621 if (err)
622 return err;
625 TAILQ_FOREACH(pe, wanted_branches, entry) {
626 const char *name = pe->path;
627 size_t name_len = pe->path_len;
629 len = sizeof(struct got_imsg_fetch_wanted_branch) + name_len;
630 wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_WANTED_BRANCH, 0, 0,
631 len);
632 if (wbuf == NULL)
633 return got_error_from_errno(
634 "imsg_create FETCH_WANTED_BRANCH");
636 /* Keep in sync with struct got_imsg_fetch_wanted_branch! */
637 if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1)
638 return got_error_from_errno(
639 "imsg_add FETCH_WANTED_BRANCH");
640 if (imsg_add(wbuf, name, name_len) == -1)
641 return got_error_from_errno(
642 "imsg_add FETCH_WANTED_BRANCH");
644 wbuf->fd = -1;
645 imsg_close(ibuf, wbuf);
646 err = flush_imsg(ibuf);
647 if (err)
648 return err;
651 TAILQ_FOREACH(pe, wanted_refs, entry) {
652 const char *name = pe->path;
653 size_t name_len = pe->path_len;
655 len = sizeof(struct got_imsg_fetch_wanted_ref) + name_len;
656 wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_WANTED_REF, 0, 0,
657 len);
658 if (wbuf == NULL)
659 return got_error_from_errno(
660 "imsg_create FETCH_WANTED_REF");
662 /* Keep in sync with struct got_imsg_fetch_wanted_ref! */
663 if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1)
664 return got_error_from_errno(
665 "imsg_add FETCH_WANTED_REF");
666 if (imsg_add(wbuf, name, name_len) == -1)
667 return got_error_from_errno(
668 "imsg_add FETCH_WANTED_REF");
670 wbuf->fd = -1;
671 imsg_close(ibuf, wbuf);
672 err = flush_imsg(ibuf);
673 if (err)
674 return err;
678 return NULL;
682 const struct got_error *
683 got_privsep_send_fetch_outfd(struct imsgbuf *ibuf, int fd)
685 return send_fd(ibuf, GOT_IMSG_FETCH_OUTFD, fd);
688 const struct got_error *
689 got_privsep_recv_fetch_progress(int *done, struct got_object_id **id,
690 char **refname, struct got_pathlist_head *symrefs, char **server_progress,
691 off_t *packfile_size, uint8_t *pack_sha1, struct imsgbuf *ibuf)
693 const struct got_error *err = NULL;
694 struct imsg imsg;
695 size_t datalen;
696 struct got_imsg_fetch_symrefs *isymrefs = NULL;
697 size_t n, remain;
698 off_t off;
699 int i;
701 *done = 0;
702 *id = NULL;
703 *refname = NULL;
704 *server_progress = NULL;
705 *packfile_size = 0;
706 memset(pack_sha1, 0, SHA1_DIGEST_LENGTH);
708 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
709 if (err)
710 return err;
712 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
713 switch (imsg.hdr.type) {
714 case GOT_IMSG_FETCH_SYMREFS:
715 if (datalen < sizeof(*isymrefs)) {
716 err = got_error(GOT_ERR_PRIVSEP_LEN);
717 break;
719 if (isymrefs != NULL) {
720 err = got_error(GOT_ERR_PRIVSEP_MSG);
721 break;
723 isymrefs = (struct got_imsg_fetch_symrefs *)imsg.data;
724 off = sizeof(*isymrefs);
725 remain = datalen - off;
726 for (n = 0; n < isymrefs->nsymrefs; n++) {
727 struct got_imsg_fetch_symref *s;
728 char *name, *target;
729 if (remain < sizeof(struct got_imsg_fetch_symref)) {
730 err = got_error(GOT_ERR_PRIVSEP_LEN);
731 goto done;
733 s = (struct got_imsg_fetch_symref *)(imsg.data + off);
734 off += sizeof(*s);
735 remain -= sizeof(*s);
736 if (remain < s->name_len) {
737 err = got_error(GOT_ERR_PRIVSEP_LEN);
738 goto done;
740 name = strndup(imsg.data + off, s->name_len);
741 if (name == NULL) {
742 err = got_error_from_errno("strndup");
743 goto done;
745 off += s->name_len;
746 remain -= s->name_len;
747 if (remain < s->target_len) {
748 err = got_error(GOT_ERR_PRIVSEP_LEN);
749 free(name);
750 goto done;
752 target = strndup(imsg.data + off, s->target_len);
753 if (target == NULL) {
754 err = got_error_from_errno("strndup");
755 free(name);
756 goto done;
758 off += s->target_len;
759 remain -= s->target_len;
760 err = got_pathlist_append(symrefs, name, target);
761 if (err) {
762 free(name);
763 free(target);
764 goto done;
767 break;
768 case GOT_IMSG_FETCH_REF:
769 if (datalen <= sizeof(**id)) {
770 err = got_error(GOT_ERR_PRIVSEP_MSG);
771 break;
773 *id = malloc(sizeof(**id));
774 if (*id == NULL) {
775 err = got_error_from_errno("malloc");
776 break;
778 memcpy(*id, imsg.data, sizeof(**id));
779 *refname = strndup(imsg.data + sizeof(**id),
780 datalen - sizeof(**id));
781 if (*refname == NULL) {
782 err = got_error_from_errno("strndup");
783 break;
785 break;
786 case GOT_IMSG_FETCH_SERVER_PROGRESS:
787 if (datalen == 0) {
788 err = got_error(GOT_ERR_PRIVSEP_LEN);
789 break;
791 *server_progress = strndup(imsg.data, datalen);
792 if (*server_progress == NULL) {
793 err = got_error_from_errno("strndup");
794 break;
796 for (i = 0; i < datalen; i++) {
797 if (!isprint((unsigned char)(*server_progress)[i]) &&
798 !isspace((unsigned char)(*server_progress)[i])) {
799 err = got_error(GOT_ERR_PRIVSEP_MSG);
800 free(*server_progress);
801 *server_progress = NULL;
802 goto done;
805 break;
806 case GOT_IMSG_FETCH_DOWNLOAD_PROGRESS:
807 if (datalen < sizeof(*packfile_size)) {
808 err = got_error(GOT_ERR_PRIVSEP_MSG);
809 break;
811 memcpy(packfile_size, imsg.data, sizeof(*packfile_size));
812 break;
813 case GOT_IMSG_FETCH_DONE:
814 if (datalen != SHA1_DIGEST_LENGTH) {
815 err = got_error(GOT_ERR_PRIVSEP_MSG);
816 break;
818 memcpy(pack_sha1, imsg.data, SHA1_DIGEST_LENGTH);
819 *done = 1;
820 break;
821 default:
822 err = got_error(GOT_ERR_PRIVSEP_MSG);
823 break;
825 done:
826 if (err) {
827 free(*id);
828 *id = NULL;
829 free(*refname);
830 *refname = NULL;
832 imsg_free(&imsg);
833 return err;
836 static const struct got_error *
837 send_send_ref(const char *name, size_t name_len, struct got_object_id *id,
838 int delete, struct imsgbuf *ibuf)
840 size_t len;
841 struct ibuf *wbuf;
843 len = sizeof(struct got_imsg_send_ref) + name_len;
844 wbuf = imsg_create(ibuf, GOT_IMSG_SEND_REF, 0, 0, len);
845 if (wbuf == NULL)
846 return got_error_from_errno("imsg_create SEND_REF");
848 /* Keep in sync with struct got_imsg_send_ref! */
849 if (imsg_add(wbuf, id, sizeof(*id)) == -1)
850 return got_error_from_errno("imsg_add SEND_REF");
851 if (imsg_add(wbuf, &delete, sizeof(delete)) == -1)
852 return got_error_from_errno("imsg_add SEND_REF");
853 if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1)
854 return got_error_from_errno("imsg_add SEND_REF");
855 if (imsg_add(wbuf, name, name_len) == -1)
856 return got_error_from_errno("imsg_add SEND_REF");
858 wbuf->fd = -1;
859 imsg_close(ibuf, wbuf);
860 return flush_imsg(ibuf);
863 const struct got_error *
864 got_privsep_send_send_req(struct imsgbuf *ibuf, int fd,
865 struct got_pathlist_head *have_refs,
866 struct got_pathlist_head *delete_refs,
867 int verbosity)
869 const struct got_error *err = NULL;
870 struct got_pathlist_entry *pe;
871 struct got_imsg_send_request sendreq;
872 struct got_object_id zero_id;
874 memset(&zero_id, 0, sizeof(zero_id));
875 memset(&sendreq, 0, sizeof(sendreq));
876 sendreq.verbosity = verbosity;
877 TAILQ_FOREACH(pe, have_refs, entry)
878 sendreq.nrefs++;
879 TAILQ_FOREACH(pe, delete_refs, entry)
880 sendreq.nrefs++;
881 if (imsg_compose(ibuf, GOT_IMSG_SEND_REQUEST, 0, 0, fd,
882 &sendreq, sizeof(sendreq)) == -1) {
883 err = got_error_from_errno(
884 "imsg_compose FETCH_SERVER_PROGRESS");
885 goto done;
888 err = flush_imsg(ibuf);
889 if (err)
890 goto done;
891 fd = -1;
893 TAILQ_FOREACH(pe, have_refs, entry) {
894 const char *name = pe->path;
895 size_t name_len = pe->path_len;
896 struct got_object_id *id = pe->data;
897 err = send_send_ref(name, name_len, id, 0, ibuf);
898 if (err)
899 goto done;
902 TAILQ_FOREACH(pe, delete_refs, entry) {
903 const char *name = pe->path;
904 size_t name_len = pe->path_len;
905 err = send_send_ref(name, name_len, &zero_id, 1, ibuf);
906 if (err)
907 goto done;
909 done:
910 if (fd != -1 && close(fd) == -1 && err == NULL)
911 err = got_error_from_errno("close");
912 return err;
916 const struct got_error *
917 got_privsep_recv_send_remote_refs(struct got_pathlist_head *remote_refs,
918 struct imsgbuf *ibuf)
920 const struct got_error *err = NULL;
921 struct imsg imsg;
922 size_t datalen;
923 int done = 0;
924 struct got_imsg_send_remote_ref iremote_ref;
925 struct got_object_id *id = NULL;
926 char *refname = NULL;
927 struct got_pathlist_entry *new;
929 while (!done) {
930 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
931 if (err)
932 return err;
933 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
934 switch (imsg.hdr.type) {
935 case GOT_IMSG_SEND_REMOTE_REF:
936 if (datalen < sizeof(iremote_ref)) {
937 err = got_error(GOT_ERR_PRIVSEP_MSG);
938 goto done;
940 memcpy(&iremote_ref, imsg.data, sizeof(iremote_ref));
941 if (datalen != sizeof(iremote_ref) +
942 iremote_ref.name_len) {
943 err = got_error(GOT_ERR_PRIVSEP_MSG);
944 goto done;
946 id = malloc(sizeof(*id));
947 if (id == NULL) {
948 err = got_error_from_errno("malloc");
949 goto done;
951 memcpy(id, &iremote_ref.id, sizeof(*id));
952 refname = strndup(imsg.data + sizeof(iremote_ref),
953 datalen - sizeof(iremote_ref));
954 if (refname == NULL) {
955 err = got_error_from_errno("strndup");
956 goto done;
958 err = got_pathlist_insert(&new, remote_refs,
959 refname, id);
960 if (err)
961 goto done;
962 if (new == NULL) { /* duplicate which wasn't inserted */
963 free(id);
964 free(refname);
966 id = NULL;
967 refname = NULL;
968 break;
969 case GOT_IMSG_SEND_PACK_REQUEST:
970 if (datalen != 0) {
971 err = got_error(GOT_ERR_PRIVSEP_MSG);
972 goto done;
974 /* got-send-pack is now waiting for a pack file. */
975 done = 1;
976 break;
977 default:
978 err = got_error(GOT_ERR_PRIVSEP_MSG);
979 break;
982 done:
983 free(id);
984 free(refname);
985 imsg_free(&imsg);
986 return err;
989 const struct got_error *
990 got_privsep_send_packfd(struct imsgbuf *ibuf, int fd)
992 return send_fd(ibuf, GOT_IMSG_SEND_PACKFD, fd);
995 const struct got_error *
996 got_privsep_recv_send_progress(int *done, off_t *bytes_sent,
997 int *success, char **refname, char **errmsg, struct imsgbuf *ibuf)
999 const struct got_error *err = NULL;
1000 struct imsg imsg;
1001 size_t datalen;
1002 struct got_imsg_send_ref_status iref_status;
1004 /* Do not reset the current value of 'bytes_sent', it accumulates. */
1005 *done = 0;
1006 *success = 0;
1007 *refname = NULL;
1008 *errmsg = NULL;
1010 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1011 if (err)
1012 return err;
1014 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1015 switch (imsg.hdr.type) {
1016 case GOT_IMSG_SEND_UPLOAD_PROGRESS:
1017 if (datalen < sizeof(*bytes_sent)) {
1018 err = got_error(GOT_ERR_PRIVSEP_MSG);
1019 break;
1021 memcpy(bytes_sent, imsg.data, sizeof(*bytes_sent));
1022 break;
1023 case GOT_IMSG_SEND_REF_STATUS:
1024 if (datalen < sizeof(iref_status)) {
1025 err = got_error(GOT_ERR_PRIVSEP_MSG);
1026 break;
1028 memcpy(&iref_status, imsg.data, sizeof(iref_status));
1029 if (datalen != sizeof(iref_status) + iref_status.name_len +
1030 iref_status.errmsg_len) {
1031 err = got_error(GOT_ERR_PRIVSEP_MSG);
1032 break;
1034 *success = iref_status.success;
1035 *refname = strndup(imsg.data + sizeof(iref_status),
1036 iref_status.name_len);
1038 if (iref_status.errmsg_len != 0)
1039 *errmsg = strndup(imsg.data + sizeof(iref_status) +
1040 iref_status.name_len, iref_status.errmsg_len);
1041 break;
1042 case GOT_IMSG_SEND_DONE:
1043 if (datalen != 0) {
1044 err = got_error(GOT_ERR_PRIVSEP_MSG);
1045 break;
1047 *done = 1;
1048 break;
1049 default:
1050 err = got_error(GOT_ERR_PRIVSEP_MSG);
1051 break;
1054 imsg_free(&imsg);
1055 return err;
1058 const struct got_error *
1059 got_privsep_send_index_pack_req(struct imsgbuf *ibuf, uint8_t *pack_sha1,
1060 int fd)
1062 const struct got_error *err = NULL;
1064 /* Keep in sync with struct got_imsg_index_pack_request */
1065 if (imsg_compose(ibuf, GOT_IMSG_IDXPACK_REQUEST, 0, 0, fd,
1066 pack_sha1, SHA1_DIGEST_LENGTH) == -1) {
1067 err = got_error_from_errno("imsg_compose INDEX_REQUEST");
1068 close(fd);
1069 return err;
1071 return flush_imsg(ibuf);
1074 const struct got_error *
1075 got_privsep_send_index_pack_outfd(struct imsgbuf *ibuf, int fd)
1077 return send_fd(ibuf, GOT_IMSG_IDXPACK_OUTFD, fd);
1080 const struct got_error *
1081 got_privsep_recv_index_progress(int *done, int *nobj_total,
1082 int *nobj_indexed, int *nobj_loose, int *nobj_resolved,
1083 struct imsgbuf *ibuf)
1085 const struct got_error *err = NULL;
1086 struct imsg imsg;
1087 struct got_imsg_index_pack_progress *iprogress;
1088 size_t datalen;
1090 *done = 0;
1091 *nobj_total = 0;
1092 *nobj_indexed = 0;
1093 *nobj_resolved = 0;
1095 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1096 if (err)
1097 return err;
1099 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1100 switch (imsg.hdr.type) {
1101 case GOT_IMSG_IDXPACK_PROGRESS:
1102 if (datalen < sizeof(*iprogress)) {
1103 err = got_error(GOT_ERR_PRIVSEP_LEN);
1104 break;
1106 iprogress = (struct got_imsg_index_pack_progress *)imsg.data;
1107 if (iprogress->nobj_total < 0 || iprogress->nobj_indexed < 0 ||
1108 iprogress->nobj_loose < 0 || iprogress->nobj_resolved < 0) {
1109 err = got_error(GOT_ERR_RANGE);
1110 break;
1112 *nobj_total = iprogress->nobj_total;
1113 *nobj_indexed = iprogress->nobj_indexed;
1114 *nobj_loose = iprogress->nobj_loose;
1115 *nobj_resolved = iprogress->nobj_resolved;
1116 break;
1117 case GOT_IMSG_IDXPACK_DONE:
1118 if (datalen != 0) {
1119 err = got_error(GOT_ERR_PRIVSEP_LEN);
1120 break;
1122 *done = 1;
1123 break;
1124 default:
1125 err = got_error(GOT_ERR_PRIVSEP_MSG);
1126 break;
1129 imsg_free(&imsg);
1130 return err;
1133 const struct got_error *
1134 got_privsep_get_imsg_obj(struct got_object **obj, struct imsg *imsg,
1135 struct imsgbuf *ibuf)
1137 struct got_imsg_object *iobj;
1138 size_t datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1140 if (datalen != sizeof(*iobj))
1141 return got_error(GOT_ERR_PRIVSEP_LEN);
1142 iobj = imsg->data;
1144 if (iobj->pack_offset < 0)
1145 return got_error(GOT_ERR_PACK_OFFSET);
1147 *obj = calloc(1, sizeof(**obj));
1148 if (*obj == NULL)
1149 return got_error_from_errno("calloc");
1151 memcpy(&(*obj)->id, &iobj->id, sizeof(iobj->id));
1152 (*obj)->type = iobj->type;
1153 (*obj)->flags = iobj->flags;
1154 (*obj)->hdrlen = iobj->hdrlen;
1155 (*obj)->size = iobj->size;
1156 /* path_packfile is handled by caller */
1157 if (iobj->flags & GOT_OBJ_FLAG_PACKED) {
1158 (*obj)->pack_offset = iobj->pack_offset;
1159 (*obj)->pack_idx = iobj->pack_idx;
1161 STAILQ_INIT(&(*obj)->deltas.entries);
1162 return NULL;
1165 const struct got_error *
1166 got_privsep_recv_obj(struct got_object **obj, struct imsgbuf *ibuf)
1168 const struct got_error *err = NULL;
1169 struct imsg imsg;
1170 const size_t min_datalen =
1171 MIN(sizeof(struct got_imsg_error), sizeof(struct got_imsg_object));
1173 *obj = NULL;
1175 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
1176 if (err)
1177 return err;
1179 switch (imsg.hdr.type) {
1180 case GOT_IMSG_OBJECT:
1181 err = got_privsep_get_imsg_obj(obj, &imsg, ibuf);
1182 break;
1183 default:
1184 err = got_error(GOT_ERR_PRIVSEP_MSG);
1185 break;
1188 imsg_free(&imsg);
1190 return err;
1193 static const struct got_error *
1194 send_commit_logmsg(struct imsgbuf *ibuf, struct got_commit_object *commit,
1195 size_t logmsg_len)
1197 const struct got_error *err = NULL;
1198 size_t offset, remain;
1200 offset = 0;
1201 remain = logmsg_len;
1202 while (remain > 0) {
1203 size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE, remain);
1205 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_LOGMSG, 0, 0, -1,
1206 commit->logmsg + offset, n) == -1) {
1207 err = got_error_from_errno("imsg_compose "
1208 "COMMIT_LOGMSG");
1209 break;
1212 err = flush_imsg(ibuf);
1213 if (err)
1214 break;
1216 offset += n;
1217 remain -= n;
1220 return err;
1223 const struct got_error *
1224 got_privsep_send_commit(struct imsgbuf *ibuf, struct got_commit_object *commit)
1226 const struct got_error *err = NULL;
1227 struct got_imsg_commit_object *icommit;
1228 uint8_t *buf;
1229 size_t len, total;
1230 struct got_object_qid *qid;
1231 size_t author_len = strlen(commit->author);
1232 size_t committer_len = strlen(commit->committer);
1233 size_t logmsg_len = strlen(commit->logmsg);
1235 total = sizeof(*icommit) + author_len + committer_len +
1236 commit->nparents * sizeof(struct got_object_id);
1238 buf = malloc(total);
1239 if (buf == NULL)
1240 return got_error_from_errno("malloc");
1242 icommit = (struct got_imsg_commit_object *)buf;
1243 memcpy(&icommit->tree_id, commit->tree_id, sizeof(icommit->tree_id));
1244 icommit->author_len = author_len;
1245 icommit->author_time = commit->author_time;
1246 icommit->author_gmtoff = commit->author_gmtoff;
1247 icommit->committer_len = committer_len;
1248 icommit->committer_time = commit->committer_time;
1249 icommit->committer_gmtoff = commit->committer_gmtoff;
1250 icommit->logmsg_len = logmsg_len;
1251 icommit->nparents = commit->nparents;
1253 len = sizeof(*icommit);
1254 memcpy(buf + len, commit->author, author_len);
1255 len += author_len;
1256 memcpy(buf + len, commit->committer, committer_len);
1257 len += committer_len;
1258 STAILQ_FOREACH(qid, &commit->parent_ids, entry) {
1259 memcpy(buf + len, &qid->id, sizeof(qid->id));
1260 len += sizeof(qid->id);
1263 if (imsg_compose(ibuf, GOT_IMSG_COMMIT, 0, 0, -1, buf, len) == -1) {
1264 err = got_error_from_errno("imsg_compose COMMIT");
1265 goto done;
1268 if (logmsg_len == 0 ||
1269 logmsg_len + len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
1270 err = flush_imsg(ibuf);
1271 if (err)
1272 goto done;
1274 err = send_commit_logmsg(ibuf, commit, logmsg_len);
1275 done:
1276 free(buf);
1277 return err;
1280 static const struct got_error *
1281 get_commit_from_imsg(struct got_commit_object **commit,
1282 struct imsg *imsg, size_t datalen, struct imsgbuf *ibuf)
1284 const struct got_error *err = NULL;
1285 struct got_imsg_commit_object *icommit;
1286 size_t len = 0;
1287 int i;
1289 if (datalen < sizeof(*icommit))
1290 return got_error(GOT_ERR_PRIVSEP_LEN);
1292 icommit = imsg->data;
1293 if (datalen != sizeof(*icommit) + icommit->author_len +
1294 icommit->committer_len +
1295 icommit->nparents * sizeof(struct got_object_id))
1296 return got_error(GOT_ERR_PRIVSEP_LEN);
1298 if (icommit->nparents < 0)
1299 return got_error(GOT_ERR_PRIVSEP_LEN);
1301 len += sizeof(*icommit);
1303 *commit = got_object_commit_alloc_partial();
1304 if (*commit == NULL)
1305 return got_error_from_errno(
1306 "got_object_commit_alloc_partial");
1308 memcpy((*commit)->tree_id, &icommit->tree_id,
1309 sizeof(icommit->tree_id));
1310 (*commit)->author_time = icommit->author_time;
1311 (*commit)->author_gmtoff = icommit->author_gmtoff;
1312 (*commit)->committer_time = icommit->committer_time;
1313 (*commit)->committer_gmtoff = icommit->committer_gmtoff;
1315 (*commit)->author = strndup(imsg->data + len, icommit->author_len);
1316 if ((*commit)->author == NULL) {
1317 err = got_error_from_errno("strndup");
1318 goto done;
1320 len += icommit->author_len;
1322 (*commit)->committer = strndup(imsg->data + len,
1323 icommit->committer_len);
1324 if ((*commit)->committer == NULL) {
1325 err = got_error_from_errno("strndup");
1326 goto done;
1328 len += icommit->committer_len;
1330 if (icommit->logmsg_len == 0) {
1331 (*commit)->logmsg = strdup("");
1332 if ((*commit)->logmsg == NULL) {
1333 err = got_error_from_errno("strdup");
1334 goto done;
1336 } else {
1337 size_t offset = 0, remain = icommit->logmsg_len;
1339 (*commit)->logmsg = malloc(icommit->logmsg_len + 1);
1340 if ((*commit)->logmsg == NULL) {
1341 err = got_error_from_errno("malloc");
1342 goto done;
1344 while (remain > 0) {
1345 struct imsg imsg_log;
1346 size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE,
1347 remain);
1349 err = got_privsep_recv_imsg(&imsg_log, ibuf, n);
1350 if (err)
1351 goto done;
1353 if (imsg_log.hdr.type != GOT_IMSG_COMMIT_LOGMSG) {
1354 err = got_error(GOT_ERR_PRIVSEP_MSG);
1355 goto done;
1358 memcpy((*commit)->logmsg + offset,
1359 imsg_log.data, n);
1360 imsg_free(&imsg_log);
1361 offset += n;
1362 remain -= n;
1364 (*commit)->logmsg[icommit->logmsg_len] = '\0';
1367 for (i = 0; i < icommit->nparents; i++) {
1368 struct got_object_qid *qid;
1370 err = got_object_qid_alloc_partial(&qid);
1371 if (err)
1372 break;
1373 memcpy(&qid->id, imsg->data + len +
1374 i * sizeof(qid->id), sizeof(qid->id));
1375 STAILQ_INSERT_TAIL(&(*commit)->parent_ids, qid, entry);
1376 (*commit)->nparents++;
1378 done:
1379 if (err) {
1380 got_object_commit_close(*commit);
1381 *commit = NULL;
1383 return err;
1386 const struct got_error *
1387 got_privsep_recv_commit(struct got_commit_object **commit, struct imsgbuf *ibuf)
1389 const struct got_error *err = NULL;
1390 struct imsg imsg;
1391 size_t datalen;
1392 const size_t min_datalen =
1393 MIN(sizeof(struct got_imsg_error),
1394 sizeof(struct got_imsg_commit_object));
1396 *commit = NULL;
1398 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
1399 if (err)
1400 return err;
1402 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1404 switch (imsg.hdr.type) {
1405 case GOT_IMSG_COMMIT:
1406 err = get_commit_from_imsg(commit, &imsg, datalen, ibuf);
1407 break;
1408 default:
1409 err = got_error(GOT_ERR_PRIVSEP_MSG);
1410 break;
1413 imsg_free(&imsg);
1415 return err;
1418 static const struct got_error *
1419 send_tree_entries_batch(struct imsgbuf *ibuf,
1420 struct got_parsed_tree_entry *entries, int idx0, int idxN, size_t len)
1422 struct ibuf *wbuf;
1423 struct got_imsg_tree_entries ientries;
1424 int i;
1426 memset(&ientries, 0, sizeof(ientries));
1428 wbuf = imsg_create(ibuf, GOT_IMSG_TREE_ENTRIES, 0, 0, len);
1429 if (wbuf == NULL)
1430 return got_error_from_errno("imsg_create TREE_ENTRY");
1432 ientries.nentries = idxN - idx0 + 1;
1433 if (imsg_add(wbuf, &ientries, sizeof(ientries)) == -1)
1434 return got_error_from_errno("imsg_add TREE_ENTRY");
1436 for (i = idx0; i <= idxN; i++) {
1437 struct got_parsed_tree_entry *pte = &entries[i];
1439 /* Keep in sync with struct got_imsg_tree_entry definition! */
1440 if (imsg_add(wbuf, pte->id, SHA1_DIGEST_LENGTH) == -1)
1441 return got_error_from_errno("imsg_add TREE_ENTRY");
1442 if (imsg_add(wbuf, &pte->mode, sizeof(pte->mode)) == -1)
1443 return got_error_from_errno("imsg_add TREE_ENTRY");
1444 if (imsg_add(wbuf, &pte->namelen, sizeof(pte->namelen)) == -1)
1445 return got_error_from_errno("imsg_add TREE_ENTRY");
1447 /* Remaining bytes are the entry's name. */
1448 if (imsg_add(wbuf, pte->name, pte->namelen) == -1)
1449 return got_error_from_errno("imsg_add TREE_ENTRY");
1452 wbuf->fd = -1;
1453 imsg_close(ibuf, wbuf);
1454 return NULL;
1457 static const struct got_error *
1458 send_tree_entries(struct imsgbuf *ibuf, struct got_parsed_tree_entry *entries,
1459 int nentries)
1461 const struct got_error *err = NULL;
1462 int i, j;
1463 size_t entries_len = sizeof(struct got_imsg_tree_entries);
1465 i = 0;
1466 for (j = 0; j < nentries; j++) {
1467 struct got_parsed_tree_entry *pte = &entries[j];
1468 size_t len = sizeof(struct got_imsg_tree_entry) + pte->namelen;
1470 if (j > 0 &&
1471 entries_len + len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
1472 err = send_tree_entries_batch(ibuf, entries,
1473 i, j - 1, entries_len);
1474 if (err)
1475 return err;
1476 i = j;
1477 entries_len = sizeof(struct got_imsg_tree_entries);
1480 entries_len += len;
1483 if (j > 0) {
1484 err = send_tree_entries_batch(ibuf, entries, i, j - 1,
1485 entries_len);
1486 if (err)
1487 return err;
1490 return NULL;
1493 const struct got_error *
1494 got_privsep_send_tree(struct imsgbuf *ibuf,
1495 struct got_parsed_tree_entry *entries, int nentries)
1497 const struct got_error *err = NULL;
1498 struct got_imsg_tree_object itree;
1500 memset(&itree, 0, sizeof(itree));
1501 itree.nentries = nentries;
1502 if (imsg_compose(ibuf, GOT_IMSG_TREE, 0, 0, -1, &itree, sizeof(itree))
1503 == -1)
1504 return got_error_from_errno("imsg_compose TREE");
1506 err = send_tree_entries(ibuf, entries, nentries);
1507 if (err)
1508 return err;
1510 return flush_imsg(ibuf);
1514 static const struct got_error *
1515 recv_tree_entries(void *data, size_t datalen, struct got_tree_object *tree,
1516 int *nentries)
1518 const struct got_error *err = NULL;
1519 struct got_imsg_tree_entries *ientries;
1520 struct got_tree_entry *te;
1521 size_t te_offset;
1522 size_t i;
1524 if (datalen <= sizeof(*ientries) ||
1525 datalen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
1526 return got_error(GOT_ERR_PRIVSEP_LEN);
1528 ientries = (struct got_imsg_tree_entries *)data;
1529 if (ientries->nentries > INT_MAX) {
1530 return got_error_msg(GOT_ERR_NO_SPACE,
1531 "too many tree entries");
1534 te_offset = sizeof(*ientries);
1535 for (i = 0; i < ientries->nentries; i++) {
1536 struct got_imsg_tree_entry ite;
1537 const char *te_name;
1538 uint8_t *buf = (uint8_t *)data + te_offset;
1540 if (te_offset >= datalen) {
1541 err = got_error(GOT_ERR_PRIVSEP_LEN);
1542 break;
1545 /* Might not be aligned, size is ~32 bytes. */
1546 memcpy(&ite, buf, sizeof(ite));
1548 if (ite.namelen >= sizeof(te->name)) {
1549 err = got_error(GOT_ERR_PRIVSEP_LEN);
1550 break;
1552 if (te_offset + sizeof(ite) + ite.namelen > datalen) {
1553 err = got_error(GOT_ERR_PRIVSEP_LEN);
1554 break;
1557 if (*nentries >= tree->nentries) {
1558 err = got_error(GOT_ERR_PRIVSEP_LEN);
1559 break;
1561 te = &tree->entries[*nentries];
1562 te_name = buf + sizeof(ite);
1563 memcpy(te->name, te_name, ite.namelen);
1564 te->name[ite.namelen] = '\0';
1565 memcpy(te->id.sha1, ite.id, SHA1_DIGEST_LENGTH);
1566 te->mode = ite.mode;
1567 te->idx = *nentries;
1568 (*nentries)++;
1570 te_offset += sizeof(ite) + ite.namelen;
1573 return err;
1576 const struct got_error *
1577 got_privsep_recv_tree(struct got_tree_object **tree, struct imsgbuf *ibuf)
1579 const struct got_error *err = NULL;
1580 const size_t min_datalen =
1581 MIN(sizeof(struct got_imsg_error),
1582 sizeof(struct got_imsg_tree_object));
1583 struct got_imsg_tree_object *itree;
1584 int nentries = 0;
1586 *tree = NULL;
1588 while (*tree == NULL || nentries < (*tree)->nentries) {
1589 struct imsg imsg;
1590 size_t datalen;
1592 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
1593 if (err)
1594 break;
1596 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1598 switch (imsg.hdr.type) {
1599 case GOT_IMSG_TREE:
1600 /* This message should only appear once. */
1601 if (*tree != NULL) {
1602 err = got_error(GOT_ERR_PRIVSEP_MSG);
1603 break;
1605 if (datalen != sizeof(*itree)) {
1606 err = got_error(GOT_ERR_PRIVSEP_LEN);
1607 break;
1609 itree = imsg.data;
1610 if (itree->nentries < 0) {
1611 err = got_error(GOT_ERR_PRIVSEP_LEN);
1612 break;
1614 *tree = malloc(sizeof(**tree));
1615 if (*tree == NULL) {
1616 err = got_error_from_errno("malloc");
1617 break;
1619 (*tree)->entries = calloc(itree->nentries,
1620 sizeof(struct got_tree_entry));
1621 if ((*tree)->entries == NULL) {
1622 err = got_error_from_errno("malloc");
1623 free(*tree);
1624 *tree = NULL;
1625 break;
1627 (*tree)->nentries = itree->nentries;
1628 (*tree)->refcnt = 0;
1629 break;
1630 case GOT_IMSG_TREE_ENTRIES:
1631 /* This message should be preceeded by GOT_IMSG_TREE. */
1632 if (*tree == NULL) {
1633 err = got_error(GOT_ERR_PRIVSEP_MSG);
1634 break;
1636 err = recv_tree_entries(imsg.data, datalen,
1637 *tree, &nentries);
1638 break;
1639 default:
1640 err = got_error(GOT_ERR_PRIVSEP_MSG);
1641 break;
1644 imsg_free(&imsg);
1645 if (err)
1646 break;
1649 if (*tree && (*tree)->nentries != nentries) {
1650 if (err == NULL)
1651 err = got_error(GOT_ERR_PRIVSEP_LEN);
1652 got_object_tree_close(*tree);
1653 *tree = NULL;
1656 return err;
1659 const struct got_error *
1660 got_privsep_send_blob(struct imsgbuf *ibuf, size_t size, size_t hdrlen,
1661 const uint8_t *data)
1663 struct got_imsg_blob iblob;
1665 memset(&iblob, 0, sizeof(iblob));
1666 iblob.size = size;
1667 iblob.hdrlen = hdrlen;
1669 if (data) {
1670 uint8_t *buf;
1672 if (size > GOT_PRIVSEP_INLINE_BLOB_DATA_MAX)
1673 return got_error(GOT_ERR_NO_SPACE);
1675 buf = malloc(sizeof(iblob) + size);
1676 if (buf == NULL)
1677 return got_error_from_errno("malloc");
1679 memcpy(buf, &iblob, sizeof(iblob));
1680 memcpy(buf + sizeof(iblob), data, size);
1681 if (imsg_compose(ibuf, GOT_IMSG_BLOB, 0, 0, -1, buf,
1682 sizeof(iblob) + size) == -1) {
1683 free(buf);
1684 return got_error_from_errno("imsg_compose BLOB");
1686 free(buf);
1687 } else {
1688 /* Data has already been written to file descriptor. */
1689 if (imsg_compose(ibuf, GOT_IMSG_BLOB, 0, 0, -1, &iblob,
1690 sizeof(iblob)) == -1)
1691 return got_error_from_errno("imsg_compose BLOB");
1695 return flush_imsg(ibuf);
1698 const struct got_error *
1699 got_privsep_recv_blob(uint8_t **outbuf, size_t *size, size_t *hdrlen,
1700 struct imsgbuf *ibuf)
1702 const struct got_error *err = NULL;
1703 struct imsg imsg;
1704 struct got_imsg_blob *iblob;
1705 size_t datalen;
1707 *outbuf = NULL;
1709 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1710 if (err)
1711 return err;
1713 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1715 switch (imsg.hdr.type) {
1716 case GOT_IMSG_BLOB:
1717 if (datalen < sizeof(*iblob)) {
1718 err = got_error(GOT_ERR_PRIVSEP_LEN);
1719 break;
1721 iblob = imsg.data;
1722 *size = iblob->size;
1723 *hdrlen = iblob->hdrlen;
1725 if (datalen == sizeof(*iblob)) {
1726 /* Data has been written to file descriptor. */
1727 break;
1730 if (*size > GOT_PRIVSEP_INLINE_BLOB_DATA_MAX ||
1731 *size > datalen + sizeof(*iblob)) {
1732 err = got_error(GOT_ERR_PRIVSEP_LEN);
1733 break;
1736 *outbuf = malloc(*size);
1737 if (*outbuf == NULL) {
1738 err = got_error_from_errno("malloc");
1739 break;
1741 memcpy(*outbuf, imsg.data + sizeof(*iblob), *size);
1742 break;
1743 default:
1744 err = got_error(GOT_ERR_PRIVSEP_MSG);
1745 break;
1748 imsg_free(&imsg);
1750 return err;
1753 static const struct got_error *
1754 send_tagmsg(struct imsgbuf *ibuf, struct got_tag_object *tag, size_t tagmsg_len)
1756 const struct got_error *err = NULL;
1757 size_t offset, remain;
1759 offset = 0;
1760 remain = tagmsg_len;
1761 while (remain > 0) {
1762 size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE, remain);
1764 if (imsg_compose(ibuf, GOT_IMSG_TAG_TAGMSG, 0, 0, -1,
1765 tag->tagmsg + offset, n) == -1) {
1766 err = got_error_from_errno("imsg_compose TAG_TAGMSG");
1767 break;
1770 err = flush_imsg(ibuf);
1771 if (err)
1772 break;
1774 offset += n;
1775 remain -= n;
1778 return err;
1781 const struct got_error *
1782 got_privsep_send_tag(struct imsgbuf *ibuf, struct got_tag_object *tag)
1784 const struct got_error *err = NULL;
1785 struct got_imsg_tag_object *itag;
1786 uint8_t *buf;
1787 size_t len, total;
1788 size_t tag_len = strlen(tag->tag);
1789 size_t tagger_len = strlen(tag->tagger);
1790 size_t tagmsg_len = strlen(tag->tagmsg);
1792 total = sizeof(*itag) + tag_len + tagger_len + tagmsg_len;
1794 buf = malloc(total);
1795 if (buf == NULL)
1796 return got_error_from_errno("malloc");
1798 itag = (struct got_imsg_tag_object *)buf;
1799 memcpy(&itag->id, &tag->id, sizeof(itag->id));
1800 itag->obj_type = tag->obj_type;
1801 itag->tag_len = tag_len;
1802 itag->tagger_len = tagger_len;
1803 itag->tagger_time = tag->tagger_time;
1804 itag->tagger_gmtoff = tag->tagger_gmtoff;
1805 itag->tagmsg_len = tagmsg_len;
1807 len = sizeof(*itag);
1808 memcpy(buf + len, tag->tag, tag_len);
1809 len += tag_len;
1810 memcpy(buf + len, tag->tagger, tagger_len);
1811 len += tagger_len;
1813 if (imsg_compose(ibuf, GOT_IMSG_TAG, 0, 0, -1, buf, len) == -1) {
1814 err = got_error_from_errno("imsg_compose TAG");
1815 goto done;
1818 if (tagmsg_len == 0 ||
1819 tagmsg_len + len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
1820 err = flush_imsg(ibuf);
1821 if (err)
1822 goto done;
1824 err = send_tagmsg(ibuf, tag, tagmsg_len);
1825 done:
1826 free(buf);
1827 return err;
1830 const struct got_error *
1831 got_privsep_recv_tag(struct got_tag_object **tag, struct imsgbuf *ibuf)
1833 const struct got_error *err = NULL;
1834 struct imsg imsg;
1835 struct got_imsg_tag_object *itag;
1836 size_t len, datalen;
1837 const size_t min_datalen =
1838 MIN(sizeof(struct got_imsg_error),
1839 sizeof(struct got_imsg_tag_object));
1841 *tag = NULL;
1843 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
1844 if (err)
1845 return err;
1847 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1848 len = 0;
1850 switch (imsg.hdr.type) {
1851 case GOT_IMSG_TAG:
1852 if (datalen < sizeof(*itag)) {
1853 err = got_error(GOT_ERR_PRIVSEP_LEN);
1854 break;
1856 itag = imsg.data;
1857 if (datalen != sizeof(*itag) + itag->tag_len +
1858 itag->tagger_len) {
1859 err = got_error(GOT_ERR_PRIVSEP_LEN);
1860 break;
1862 len += sizeof(*itag);
1864 *tag = calloc(1, sizeof(**tag));
1865 if (*tag == NULL) {
1866 err = got_error_from_errno("calloc");
1867 break;
1870 memcpy(&(*tag)->id, &itag->id, sizeof(itag->id));
1872 (*tag)->tag = strndup(imsg.data + len, itag->tag_len);
1873 if ((*tag)->tag == NULL) {
1874 err = got_error_from_errno("strndup");
1875 break;
1877 len += itag->tag_len;
1879 (*tag)->obj_type = itag->obj_type;
1880 (*tag)->tagger_time = itag->tagger_time;
1881 (*tag)->tagger_gmtoff = itag->tagger_gmtoff;
1883 (*tag)->tagger = strndup(imsg.data + len, itag->tagger_len);
1884 if ((*tag)->tagger == NULL) {
1885 err = got_error_from_errno("strndup");
1886 break;
1888 len += itag->tagger_len;
1890 if (itag->tagmsg_len == 0) {
1891 (*tag)->tagmsg = strdup("");
1892 if ((*tag)->tagmsg == NULL) {
1893 err = got_error_from_errno("strdup");
1894 break;
1896 } else {
1897 size_t offset = 0, remain = itag->tagmsg_len;
1899 (*tag)->tagmsg = malloc(itag->tagmsg_len + 1);
1900 if ((*tag)->tagmsg == NULL) {
1901 err = got_error_from_errno("malloc");
1902 break;
1904 while (remain > 0) {
1905 struct imsg imsg_log;
1906 size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE,
1907 remain);
1909 err = got_privsep_recv_imsg(&imsg_log, ibuf, n);
1910 if (err)
1911 return err;
1913 if (imsg_log.hdr.type != GOT_IMSG_TAG_TAGMSG)
1914 return got_error(GOT_ERR_PRIVSEP_MSG);
1916 memcpy((*tag)->tagmsg + offset, imsg_log.data,
1917 n);
1918 imsg_free(&imsg_log);
1919 offset += n;
1920 remain -= n;
1922 (*tag)->tagmsg[itag->tagmsg_len] = '\0';
1925 break;
1926 default:
1927 err = got_error(GOT_ERR_PRIVSEP_MSG);
1928 break;
1931 imsg_free(&imsg);
1933 return err;
1936 const struct got_error *
1937 got_privsep_init_pack_child(struct imsgbuf *ibuf, struct got_pack *pack,
1938 struct got_packidx *packidx)
1940 const struct got_error *err = NULL;
1941 struct got_imsg_packidx ipackidx;
1942 struct got_imsg_pack ipack;
1943 int fd;
1945 memset(&ipackidx, 0, sizeof(ipackidx));
1946 memset(&ipack, 0, sizeof(ipack));
1948 ipackidx.len = packidx->len;
1949 ipackidx.packfile_size = pack->filesize;
1950 fd = dup(packidx->fd);
1951 if (fd == -1)
1952 return got_error_from_errno("dup");
1954 if (imsg_compose(ibuf, GOT_IMSG_PACKIDX, 0, 0, fd, &ipackidx,
1955 sizeof(ipackidx)) == -1) {
1956 err = got_error_from_errno("imsg_compose PACKIDX");
1957 close(fd);
1958 return err;
1961 if (strlcpy(ipack.path_packfile, pack->path_packfile,
1962 sizeof(ipack.path_packfile)) >= sizeof(ipack.path_packfile))
1963 return got_error(GOT_ERR_NO_SPACE);
1964 ipack.filesize = pack->filesize;
1966 fd = dup(pack->fd);
1967 if (fd == -1)
1968 return got_error_from_errno("dup");
1970 if (imsg_compose(ibuf, GOT_IMSG_PACK, 0, 0, fd, &ipack, sizeof(ipack))
1971 == -1) {
1972 err = got_error_from_errno("imsg_compose PACK");
1973 close(fd);
1974 return err;
1977 return flush_imsg(ibuf);
1980 const struct got_error *
1981 got_privsep_send_packed_obj_req(struct imsgbuf *ibuf, int idx,
1982 struct got_object_id *id)
1984 struct got_imsg_packed_object iobj;
1986 memset(&iobj, 0, sizeof(iobj));
1987 iobj.idx = idx;
1988 memcpy(&iobj.id, id, sizeof(iobj.id));
1990 if (imsg_compose(ibuf, GOT_IMSG_PACKED_OBJECT_REQUEST, 0, 0, -1,
1991 &iobj, sizeof(iobj)) == -1)
1992 return got_error_from_errno("imsg_compose "
1993 "PACKED_OBJECT_REQUEST");
1995 return flush_imsg(ibuf);
1998 const struct got_error *
1999 got_privsep_send_packed_raw_obj_req(struct imsgbuf *ibuf, int idx,
2000 struct got_object_id *id)
2002 struct got_imsg_packed_object iobj;
2004 memset(&iobj, 0, sizeof(iobj));
2005 iobj.idx = idx;
2006 memcpy(&iobj.id, id, sizeof(iobj.id));
2008 if (imsg_compose(ibuf, GOT_IMSG_PACKED_RAW_OBJECT_REQUEST, 0, 0, -1,
2009 &iobj, sizeof(iobj)) == -1)
2010 return got_error_from_errno("imsg_compose "
2011 "PACKED_OBJECT_REQUEST");
2013 return flush_imsg(ibuf);
2016 const struct got_error *
2017 got_privsep_send_gitconfig_parse_req(struct imsgbuf *ibuf, int fd)
2019 const struct got_error *err = NULL;
2021 if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_PARSE_REQUEST, 0, 0, fd,
2022 NULL, 0) == -1) {
2023 err = got_error_from_errno("imsg_compose "
2024 "GITCONFIG_PARSE_REQUEST");
2025 close(fd);
2026 return err;
2029 return flush_imsg(ibuf);
2032 const struct got_error *
2033 got_privsep_send_gitconfig_repository_format_version_req(struct imsgbuf *ibuf)
2035 if (imsg_compose(ibuf,
2036 GOT_IMSG_GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST, 0, 0, -1,
2037 NULL, 0) == -1)
2038 return got_error_from_errno("imsg_compose "
2039 "GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST");
2041 return flush_imsg(ibuf);
2044 const struct got_error *
2045 got_privsep_send_gitconfig_repository_extensions_req(struct imsgbuf *ibuf)
2047 if (imsg_compose(ibuf,
2048 GOT_IMSG_GITCONFIG_REPOSITORY_EXTENSIONS_REQUEST, 0, 0, -1,
2049 NULL, 0) == -1)
2050 return got_error_from_errno("imsg_compose "
2051 "GITCONFIG_REPOSITORY_EXTENSIONS_REQUEST");
2053 return flush_imsg(ibuf);
2057 const struct got_error *
2058 got_privsep_send_gitconfig_author_name_req(struct imsgbuf *ibuf)
2060 if (imsg_compose(ibuf,
2061 GOT_IMSG_GITCONFIG_AUTHOR_NAME_REQUEST, 0, 0, -1, NULL, 0) == -1)
2062 return got_error_from_errno("imsg_compose "
2063 "GITCONFIG_AUTHOR_NAME_REQUEST");
2065 return flush_imsg(ibuf);
2068 const struct got_error *
2069 got_privsep_send_gitconfig_author_email_req(struct imsgbuf *ibuf)
2071 if (imsg_compose(ibuf,
2072 GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST, 0, 0, -1, NULL, 0) == -1)
2073 return got_error_from_errno("imsg_compose "
2074 "GITCONFIG_AUTHOR_EMAIL_REQUEST");
2076 return flush_imsg(ibuf);
2079 const struct got_error *
2080 got_privsep_send_gitconfig_remotes_req(struct imsgbuf *ibuf)
2082 if (imsg_compose(ibuf,
2083 GOT_IMSG_GITCONFIG_REMOTES_REQUEST, 0, 0, -1, NULL, 0) == -1)
2084 return got_error_from_errno("imsg_compose "
2085 "GITCONFIG_REMOTE_REQUEST");
2087 return flush_imsg(ibuf);
2090 const struct got_error *
2091 got_privsep_send_gitconfig_owner_req(struct imsgbuf *ibuf)
2093 if (imsg_compose(ibuf,
2094 GOT_IMSG_GITCONFIG_OWNER_REQUEST, 0, 0, -1, NULL, 0) == -1)
2095 return got_error_from_errno("imsg_compose "
2096 "GITCONFIG_OWNER_REQUEST");
2098 return flush_imsg(ibuf);
2101 const struct got_error *
2102 got_privsep_recv_gitconfig_str(char **str, struct imsgbuf *ibuf)
2104 const struct got_error *err = NULL;
2105 struct imsg imsg;
2106 size_t datalen;
2108 *str = NULL;
2110 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2111 if (err)
2112 return err;
2113 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2115 switch (imsg.hdr.type) {
2116 case GOT_IMSG_GITCONFIG_STR_VAL:
2117 if (datalen == 0)
2118 break;
2119 *str = strndup(imsg.data, datalen);
2120 if (*str == NULL) {
2121 err = got_error_from_errno("strndup");
2122 break;
2124 break;
2125 default:
2126 err = got_error(GOT_ERR_PRIVSEP_MSG);
2127 break;
2130 imsg_free(&imsg);
2131 return err;
2134 const struct got_error *
2135 got_privsep_recv_gitconfig_pair(char **key, char **val, struct imsgbuf *ibuf)
2137 const struct got_error *err = NULL;
2138 struct got_imsg_gitconfig_pair p;
2139 struct imsg imsg;
2140 size_t datalen;
2141 uint8_t *data;
2143 *key = *val = NULL;
2145 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2146 if (err)
2147 return err;
2149 data = imsg.data;
2150 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2152 if (imsg.hdr.type != GOT_IMSG_GITCONFIG_PAIR) {
2153 err = got_error(GOT_ERR_PRIVSEP_MSG);
2154 goto done;
2157 if (datalen < sizeof(p)) {
2158 err = got_error(GOT_ERR_PRIVSEP_LEN);
2159 goto done;
2162 memcpy(&p, data, sizeof(p));
2163 data += sizeof(p);
2165 if (datalen != sizeof(p) + p.klen + p.vlen) {
2166 err = got_error(GOT_ERR_PRIVSEP_LEN);
2167 goto done;
2170 *key = strndup(data, p.klen);
2171 if (*key == NULL) {
2172 err = got_error_from_errno("strndup");
2173 goto done;
2175 data += p.klen;
2177 *val = strndup(data, p.vlen);
2178 if (*val == NULL) {
2179 err = got_error_from_errno("strndup");
2180 goto done;
2183 done:
2184 imsg_free(&imsg);
2185 return err;
2188 const struct got_error *
2189 got_privsep_recv_gitconfig_int(int *val, struct imsgbuf *ibuf)
2191 const struct got_error *err = NULL;
2192 struct imsg imsg;
2193 size_t datalen;
2194 const size_t min_datalen =
2195 MIN(sizeof(struct got_imsg_error), sizeof(int));
2197 *val = 0;
2199 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
2200 if (err)
2201 return err;
2202 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2204 switch (imsg.hdr.type) {
2205 case GOT_IMSG_GITCONFIG_INT_VAL:
2206 if (datalen != sizeof(*val)) {
2207 err = got_error(GOT_ERR_PRIVSEP_LEN);
2208 break;
2210 memcpy(val, imsg.data, sizeof(*val));
2211 break;
2212 default:
2213 err = got_error(GOT_ERR_PRIVSEP_MSG);
2214 break;
2217 imsg_free(&imsg);
2218 return err;
2221 static void
2222 free_remote_data(struct got_remote_repo *remote)
2224 int i;
2226 free(remote->name);
2227 free(remote->fetch_url);
2228 free(remote->send_url);
2229 for (i = 0; i < remote->nfetch_branches; i++)
2230 free(remote->fetch_branches[i]);
2231 free(remote->fetch_branches);
2232 for (i = 0; i < remote->nsend_branches; i++)
2233 free(remote->send_branches[i]);
2234 free(remote->send_branches);
2235 for (i = 0; i < remote->nfetch_refs; i++)
2236 free(remote->fetch_refs[i]);
2237 free(remote->fetch_refs);
2240 const struct got_error *
2241 got_privsep_recv_gitconfig_remotes(struct got_remote_repo **remotes,
2242 int *nremotes, struct imsgbuf *ibuf)
2244 const struct got_error *err = NULL;
2245 struct imsg imsg;
2246 size_t datalen;
2247 struct got_imsg_remotes iremotes;
2248 struct got_imsg_remote iremote;
2250 *remotes = NULL;
2251 *nremotes = 0;
2252 iremotes.nremotes = 0;
2254 err = got_privsep_recv_imsg(&imsg, ibuf, sizeof(iremotes));
2255 if (err)
2256 return err;
2257 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2259 switch (imsg.hdr.type) {
2260 case GOT_IMSG_GITCONFIG_REMOTES:
2261 if (datalen != sizeof(iremotes)) {
2262 err = got_error(GOT_ERR_PRIVSEP_LEN);
2263 break;
2265 memcpy(&iremotes, imsg.data, sizeof(iremotes));
2266 if (iremotes.nremotes == 0) {
2267 imsg_free(&imsg);
2268 return NULL;
2270 break;
2271 default:
2272 imsg_free(&imsg);
2273 return got_error(GOT_ERR_PRIVSEP_MSG);
2276 imsg_free(&imsg);
2278 *remotes = recallocarray(NULL, 0, iremotes.nremotes, sizeof(**remotes));
2279 if (*remotes == NULL)
2280 return got_error_from_errno("recallocarray");
2282 while (*nremotes < iremotes.nremotes) {
2283 struct got_remote_repo *remote;
2285 err = got_privsep_recv_imsg(&imsg, ibuf, sizeof(iremote));
2286 if (err)
2287 break;
2288 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2290 switch (imsg.hdr.type) {
2291 case GOT_IMSG_GITCONFIG_REMOTE:
2292 remote = &(*remotes)[*nremotes];
2293 memset(remote, 0, sizeof(*remote));
2294 if (datalen < sizeof(iremote)) {
2295 err = got_error(GOT_ERR_PRIVSEP_LEN);
2296 break;
2298 memcpy(&iremote, imsg.data, sizeof(iremote));
2299 if (iremote.name_len == 0 ||
2300 iremote.fetch_url_len == 0 ||
2301 iremote.send_url_len == 0 ||
2302 (sizeof(iremote) + iremote.name_len +
2303 iremote.fetch_url_len + iremote.send_url_len) > datalen) {
2304 err = got_error(GOT_ERR_PRIVSEP_LEN);
2305 break;
2307 remote->name = strndup(imsg.data + sizeof(iremote),
2308 iremote.name_len);
2309 if (remote->name == NULL) {
2310 err = got_error_from_errno("strndup");
2311 break;
2313 remote->fetch_url = strndup(imsg.data + sizeof(iremote) +
2314 iremote.name_len, iremote.fetch_url_len);
2315 if (remote->fetch_url == NULL) {
2316 err = got_error_from_errno("strndup");
2317 free_remote_data(remote);
2318 break;
2320 remote->send_url = strndup(imsg.data + sizeof(iremote) +
2321 iremote.name_len + iremote.fetch_url_len,
2322 iremote.send_url_len);
2323 if (remote->send_url == NULL) {
2324 err = got_error_from_errno("strndup");
2325 free_remote_data(remote);
2326 break;
2328 remote->mirror_references = iremote.mirror_references;
2329 remote->fetch_all_branches = iremote.fetch_all_branches;
2330 remote->nfetch_branches = 0;
2331 remote->fetch_branches = NULL;
2332 remote->nsend_branches = 0;
2333 remote->send_branches = NULL;
2334 remote->nfetch_refs = 0;
2335 remote->fetch_refs = NULL;
2336 (*nremotes)++;
2337 break;
2338 default:
2339 err = got_error(GOT_ERR_PRIVSEP_MSG);
2340 break;
2343 imsg_free(&imsg);
2344 if (err)
2345 break;
2348 if (err) {
2349 int i;
2350 for (i = 0; i < *nremotes; i++)
2351 free_remote_data(&(*remotes)[i]);
2352 free(*remotes);
2353 *remotes = NULL;
2354 *nremotes = 0;
2356 return err;
2359 const struct got_error *
2360 got_privsep_send_gotconfig_parse_req(struct imsgbuf *ibuf, int fd)
2362 const struct got_error *err = NULL;
2364 if (imsg_compose(ibuf, GOT_IMSG_GOTCONFIG_PARSE_REQUEST, 0, 0, fd,
2365 NULL, 0) == -1) {
2366 err = got_error_from_errno("imsg_compose "
2367 "GOTCONFIG_PARSE_REQUEST");
2368 close(fd);
2369 return err;
2372 return flush_imsg(ibuf);
2375 const struct got_error *
2376 got_privsep_send_gotconfig_author_req(struct imsgbuf *ibuf)
2378 if (imsg_compose(ibuf,
2379 GOT_IMSG_GOTCONFIG_AUTHOR_REQUEST, 0, 0, -1, NULL, 0) == -1)
2380 return got_error_from_errno("imsg_compose "
2381 "GOTCONFIG_AUTHOR_REQUEST");
2383 return flush_imsg(ibuf);
2386 const struct got_error *
2387 got_privsep_send_gotconfig_allowed_signers_req(struct imsgbuf *ibuf)
2389 if (imsg_compose(ibuf,
2390 GOT_IMSG_GOTCONFIG_ALLOWEDSIGNERS_REQUEST, 0, 0, -1, NULL, 0) == -1)
2391 return got_error_from_errno("imsg_compose "
2392 "GOTCONFIG_ALLOWEDSIGNERS_REQUEST");
2394 return flush_imsg(ibuf);
2397 const struct got_error *
2398 got_privsep_send_gotconfig_revoked_signers_req(struct imsgbuf *ibuf)
2400 if (imsg_compose(ibuf,
2401 GOT_IMSG_GOTCONFIG_REVOKEDSIGNERS_REQUEST, 0, 0, -1, NULL, 0) == -1)
2402 return got_error_from_errno("imsg_compose "
2403 "GOTCONFIG_REVOKEDSIGNERS_REQUEST");
2405 return flush_imsg(ibuf);
2408 const struct got_error *
2409 got_privsep_send_gotconfig_signer_id_req(struct imsgbuf *ibuf)
2411 if (imsg_compose(ibuf,
2412 GOT_IMSG_GOTCONFIG_SIGNERID_REQUEST, 0, 0, -1, NULL, 0) == -1)
2413 return got_error_from_errno("imsg_compose "
2414 "GOTCONFIG_SIGNERID_REQUEST");
2416 return flush_imsg(ibuf);
2419 const struct got_error *
2420 got_privsep_send_gotconfig_remotes_req(struct imsgbuf *ibuf)
2422 if (imsg_compose(ibuf,
2423 GOT_IMSG_GOTCONFIG_REMOTES_REQUEST, 0, 0, -1, NULL, 0) == -1)
2424 return got_error_from_errno("imsg_compose "
2425 "GOTCONFIG_REMOTE_REQUEST");
2427 return flush_imsg(ibuf);
2430 const struct got_error *
2431 got_privsep_recv_gotconfig_str(char **str, struct imsgbuf *ibuf)
2433 const struct got_error *err = NULL;
2434 struct imsg imsg;
2435 size_t datalen;
2437 *str = NULL;
2439 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2440 if (err)
2441 return err;
2442 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2444 switch (imsg.hdr.type) {
2445 case GOT_IMSG_GOTCONFIG_STR_VAL:
2446 if (datalen == 0)
2447 break;
2448 *str = strndup(imsg.data, datalen);
2449 if (*str == NULL) {
2450 err = got_error_from_errno("strndup");
2451 break;
2453 break;
2454 default:
2455 err = got_error(GOT_ERR_PRIVSEP_MSG);
2456 break;
2459 imsg_free(&imsg);
2460 return err;
2463 const struct got_error *
2464 got_privsep_recv_gotconfig_remotes(struct got_remote_repo **remotes,
2465 int *nremotes, struct imsgbuf *ibuf)
2467 const struct got_error *err = NULL;
2468 struct imsg imsg;
2469 size_t datalen;
2470 struct got_imsg_remotes iremotes;
2471 struct got_imsg_remote iremote;
2472 const size_t min_datalen =
2473 MIN(sizeof(struct got_imsg_error), sizeof(iremotes));
2475 *remotes = NULL;
2476 *nremotes = 0;
2477 iremotes.nremotes = 0;
2479 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
2480 if (err)
2481 return err;
2482 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2484 switch (imsg.hdr.type) {
2485 case GOT_IMSG_GOTCONFIG_REMOTES:
2486 if (datalen != sizeof(iremotes)) {
2487 err = got_error(GOT_ERR_PRIVSEP_LEN);
2488 break;
2490 memcpy(&iremotes, imsg.data, sizeof(iremotes));
2491 if (iremotes.nremotes < 0) {
2492 err = got_error(GOT_ERR_PRIVSEP_LEN);
2493 break;
2495 if (iremotes.nremotes == 0) {
2496 imsg_free(&imsg);
2497 return NULL;
2499 break;
2500 default:
2501 imsg_free(&imsg);
2502 return got_error(GOT_ERR_PRIVSEP_MSG);
2505 imsg_free(&imsg);
2507 *remotes = recallocarray(NULL, 0, iremotes.nremotes, sizeof(**remotes));
2508 if (*remotes == NULL)
2509 return got_error_from_errno("recallocarray");
2511 while (*nremotes < iremotes.nremotes) {
2512 struct got_remote_repo *remote;
2513 const size_t min_datalen =
2514 MIN(sizeof(struct got_imsg_error), sizeof(iremote));
2515 int i;
2517 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
2518 if (err)
2519 break;
2520 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2522 switch (imsg.hdr.type) {
2523 case GOT_IMSG_GOTCONFIG_REMOTE:
2524 remote = &(*remotes)[*nremotes];
2525 memset(remote, 0, sizeof(*remote));
2526 if (datalen < sizeof(iremote)) {
2527 err = got_error(GOT_ERR_PRIVSEP_LEN);
2528 break;
2530 memcpy(&iremote, imsg.data, sizeof(iremote));
2531 if (iremote.name_len == 0 ||
2532 (iremote.fetch_url_len == 0 &&
2533 iremote.send_url_len == 0) ||
2534 (sizeof(iremote) + iremote.name_len +
2535 iremote.fetch_url_len + iremote.send_url_len) >
2536 datalen) {
2537 err = got_error(GOT_ERR_PRIVSEP_LEN);
2538 break;
2540 remote->name = strndup(imsg.data + sizeof(iremote),
2541 iremote.name_len);
2542 if (remote->name == NULL) {
2543 err = got_error_from_errno("strndup");
2544 break;
2546 remote->fetch_url = strndup(imsg.data +
2547 sizeof(iremote) + iremote.name_len,
2548 iremote.fetch_url_len);
2549 if (remote->fetch_url == NULL) {
2550 err = got_error_from_errno("strndup");
2551 free_remote_data(remote);
2552 break;
2554 remote->send_url = strndup(imsg.data +
2555 sizeof(iremote) + iremote.name_len +
2556 iremote.fetch_url_len, iremote.send_url_len);
2557 if (remote->send_url == NULL) {
2558 err = got_error_from_errno("strndup");
2559 free_remote_data(remote);
2560 break;
2562 remote->mirror_references = iremote.mirror_references;
2563 remote->fetch_all_branches = iremote.fetch_all_branches;
2564 if (iremote.nfetch_branches > 0) {
2565 remote->fetch_branches = recallocarray(NULL, 0,
2566 iremote.nfetch_branches, sizeof(char *));
2567 if (remote->fetch_branches == NULL) {
2568 err = got_error_from_errno("calloc");
2569 free_remote_data(remote);
2570 break;
2573 remote->nfetch_branches = 0;
2574 for (i = 0; i < iremote.nfetch_branches; i++) {
2575 char *branch;
2576 err = got_privsep_recv_gotconfig_str(&branch,
2577 ibuf);
2578 if (err) {
2579 free_remote_data(remote);
2580 goto done;
2582 remote->fetch_branches[i] = branch;
2583 remote->nfetch_branches++;
2585 if (iremote.nsend_branches > 0) {
2586 remote->send_branches = recallocarray(NULL, 0,
2587 iremote.nsend_branches, sizeof(char *));
2588 if (remote->send_branches == NULL) {
2589 err = got_error_from_errno("calloc");
2590 free_remote_data(remote);
2591 break;
2594 remote->nsend_branches = 0;
2595 for (i = 0; i < iremote.nsend_branches; i++) {
2596 char *branch;
2597 err = got_privsep_recv_gotconfig_str(&branch,
2598 ibuf);
2599 if (err) {
2600 free_remote_data(remote);
2601 goto done;
2603 remote->send_branches[i] = branch;
2604 remote->nsend_branches++;
2606 if (iremote.nfetch_refs > 0) {
2607 remote->fetch_refs = recallocarray(NULL, 0,
2608 iremote.nfetch_refs, sizeof(char *));
2609 if (remote->fetch_refs == NULL) {
2610 err = got_error_from_errno("calloc");
2611 free_remote_data(remote);
2612 break;
2615 remote->nfetch_refs = 0;
2616 for (i = 0; i < iremote.nfetch_refs; i++) {
2617 char *ref;
2618 err = got_privsep_recv_gotconfig_str(&ref,
2619 ibuf);
2620 if (err) {
2621 free_remote_data(remote);
2622 goto done;
2624 remote->fetch_refs[i] = ref;
2625 remote->nfetch_refs++;
2627 (*nremotes)++;
2628 break;
2629 default:
2630 err = got_error(GOT_ERR_PRIVSEP_MSG);
2631 break;
2634 imsg_free(&imsg);
2635 if (err)
2636 break;
2638 done:
2639 if (err) {
2640 int i;
2641 for (i = 0; i < *nremotes; i++)
2642 free_remote_data(&(*remotes)[i]);
2643 free(*remotes);
2644 *remotes = NULL;
2645 *nremotes = 0;
2647 return err;
2650 const struct got_error *
2651 got_privsep_send_commit_traversal_request(struct imsgbuf *ibuf,
2652 struct got_object_id *id, int idx, const char *path)
2654 struct ibuf *wbuf;
2655 size_t path_len = strlen(path) + 1;
2657 wbuf = imsg_create(ibuf, GOT_IMSG_COMMIT_TRAVERSAL_REQUEST, 0, 0,
2658 sizeof(struct got_imsg_commit_traversal_request) + path_len);
2659 if (wbuf == NULL)
2660 return got_error_from_errno(
2661 "imsg_create COMMIT_TRAVERSAL_REQUEST");
2662 if (imsg_add(wbuf, id->sha1, SHA1_DIGEST_LENGTH) == -1)
2663 return got_error_from_errno("imsg_add "
2664 "COMMIT_TRAVERSAL_REQUEST");
2665 if (imsg_add(wbuf, &idx, sizeof(idx)) == -1)
2666 return got_error_from_errno("imsg_add "
2667 "COMMIT_TRAVERSAL_REQUEST");
2668 if (imsg_add(wbuf, path, path_len) == -1)
2669 return got_error_from_errno("imsg_add "
2670 "COMMIT_TRAVERSAL_REQUEST");
2672 wbuf->fd = -1;
2673 imsg_close(ibuf, wbuf);
2675 return flush_imsg(ibuf);
2678 const struct got_error *
2679 got_privsep_recv_traversed_commits(struct got_commit_object **changed_commit,
2680 struct got_object_id **changed_commit_id,
2681 struct got_object_id_queue *commit_ids, struct imsgbuf *ibuf)
2683 const struct got_error *err = NULL;
2684 struct imsg imsg;
2685 struct got_imsg_traversed_commits *icommits;
2686 struct got_object_id *ids;
2687 size_t datalen;
2688 int i, done = 0;
2690 *changed_commit = NULL;
2691 *changed_commit_id = NULL;
2693 while (!done) {
2694 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2695 if (err)
2696 return err;
2698 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2699 switch (imsg.hdr.type) {
2700 case GOT_IMSG_TRAVERSED_COMMITS:
2701 icommits = imsg.data;
2702 if (datalen != sizeof(*icommits) +
2703 icommits->ncommits * sizeof(*ids)) {
2704 err = got_error(GOT_ERR_PRIVSEP_LEN);
2705 break;
2707 ids = imsg.data + sizeof(*icommits);
2708 for (i = 0; i < icommits->ncommits; i++) {
2709 struct got_object_qid *qid;
2711 err = got_object_qid_alloc_partial(&qid);
2712 if (err)
2713 break;
2714 memcpy(&qid->id, &ids[i], sizeof(ids[i]));
2715 STAILQ_INSERT_TAIL(commit_ids, qid, entry);
2717 /* The last commit may contain a change. */
2718 if (i == icommits->ncommits - 1) {
2719 *changed_commit_id =
2720 got_object_id_dup(&qid->id);
2721 if (*changed_commit_id == NULL) {
2722 err = got_error_from_errno(
2723 "got_object_id_dup");
2724 break;
2728 break;
2729 case GOT_IMSG_COMMIT:
2730 if (*changed_commit_id == NULL) {
2731 err = got_error(GOT_ERR_PRIVSEP_MSG);
2732 break;
2734 err = get_commit_from_imsg(changed_commit, &imsg,
2735 datalen, ibuf);
2736 break;
2737 case GOT_IMSG_COMMIT_TRAVERSAL_DONE:
2738 done = 1;
2739 break;
2740 default:
2741 err = got_error(GOT_ERR_PRIVSEP_MSG);
2742 break;
2745 imsg_free(&imsg);
2746 if (err)
2747 break;
2750 if (err)
2751 got_object_id_queue_free(commit_ids);
2752 return err;
2755 const struct got_error *
2756 got_privsep_send_enumerated_tree(size_t *totlen, struct imsgbuf *ibuf,
2757 struct got_object_id *tree_id, const char *path,
2758 struct got_parsed_tree_entry *entries, int nentries)
2760 const struct got_error *err = NULL;
2761 struct ibuf *wbuf;
2762 size_t path_len = strlen(path);
2763 size_t msglen;
2765 msglen = sizeof(struct got_imsg_enumerated_tree) + path_len;
2766 wbuf = imsg_create(ibuf, GOT_IMSG_ENUMERATED_TREE, 0, 0, msglen);
2767 if (wbuf == NULL)
2768 return got_error_from_errno("imsg_create ENUMERATED_TREE");
2770 if (imsg_add(wbuf, tree_id->sha1, SHA1_DIGEST_LENGTH) == -1)
2771 return got_error_from_errno("imsg_add ENUMERATED_TREE");
2772 if (imsg_add(wbuf, &nentries, sizeof(nentries)) == -1)
2773 return got_error_from_errno("imsg_add ENUMERATED_TREE");
2774 if (imsg_add(wbuf, path, path_len) == -1)
2775 return got_error_from_errno("imsg_add ENUMERATED_TREE");
2777 wbuf->fd = -1;
2778 imsg_close(ibuf, wbuf);
2780 if (entries) {
2781 err = send_tree_entries(ibuf, entries, nentries);
2782 if (err)
2783 return err;
2786 return flush_imsg(ibuf);
2789 const struct got_error *
2790 got_privsep_send_object_enumeration_request(struct imsgbuf *ibuf)
2792 if (imsg_compose(ibuf, GOT_IMSG_OBJECT_ENUMERATION_REQUEST,
2793 0, 0, -1, NULL, 0) == -1)
2794 return got_error_from_errno("imsg_compose "
2795 "OBJECT_ENUMERATION_REQUEST");
2797 return flush_imsg(ibuf);
2800 const struct got_error *
2801 got_privsep_send_object_enumeration_done(struct imsgbuf *ibuf)
2803 if (imsg_compose(ibuf, GOT_IMSG_OBJECT_ENUMERATION_DONE,
2804 0, 0, -1, NULL, 0) == -1)
2805 return got_error_from_errno("imsg_compose "
2806 "OBJECT_ENUMERATION_DONE");
2808 return flush_imsg(ibuf);
2811 const struct got_error *
2812 got_privsep_send_object_enumeration_incomplete(struct imsgbuf *ibuf)
2814 if (imsg_compose(ibuf, GOT_IMSG_OBJECT_ENUMERATION_INCOMPLETE,
2815 0, 0, -1, NULL, 0) == -1)
2816 return got_error_from_errno("imsg_compose "
2817 "OBJECT_ENUMERATION_INCOMPLETE");
2819 return flush_imsg(ibuf);
2822 const struct got_error *
2823 got_privsep_send_enumerated_commit(struct imsgbuf *ibuf,
2824 struct got_object_id *id, time_t mtime)
2826 struct ibuf *wbuf;
2828 wbuf = imsg_create(ibuf, GOT_IMSG_ENUMERATED_COMMIT, 0, 0,
2829 sizeof(struct got_imsg_enumerated_commit) + SHA1_DIGEST_LENGTH);
2830 if (wbuf == NULL)
2831 return got_error_from_errno("imsg_create ENUMERATED_COMMIT");
2833 /* Keep in sync with struct got_imsg_enumerated_commit! */
2834 if (imsg_add(wbuf, id, SHA1_DIGEST_LENGTH) == -1)
2835 return got_error_from_errno("imsg_add ENUMERATED_COMMIT");
2836 if (imsg_add(wbuf, &mtime, sizeof(mtime)) == -1)
2837 return got_error_from_errno("imsg_add ENUMERATED_COMMIT");
2839 wbuf->fd = -1;
2840 imsg_close(ibuf, wbuf);
2841 /* Don't flush yet, tree entries or ENUMERATION_DONE will follow. */
2842 return NULL;
2845 const struct got_error *
2846 got_privsep_recv_enumerated_objects(int *found_all_objects,
2847 struct imsgbuf *ibuf,
2848 got_object_enumerate_commit_cb cb_commit,
2849 got_object_enumerate_tree_cb cb_tree, void *cb_arg,
2850 struct got_repository *repo)
2852 const struct got_error *err = NULL;
2853 struct imsg imsg;
2854 struct got_imsg_enumerated_commit *icommit = NULL;
2855 struct got_object_id commit_id;
2856 int have_commit = 0;
2857 time_t mtime = 0;
2858 struct got_tree_object tree;
2859 struct got_imsg_enumerated_tree *itree;
2860 struct got_object_id tree_id;
2861 char *path = NULL, *canon_path = NULL;
2862 size_t datalen, path_len;
2863 int nentries = -1;
2864 int done = 0;
2866 *found_all_objects = 0;
2867 memset(&tree, 0, sizeof(tree));
2869 while (!done) {
2870 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2871 if (err)
2872 break;
2874 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2875 switch (imsg.hdr.type) {
2876 case GOT_IMSG_ENUMERATED_COMMIT:
2877 if (have_commit && nentries != -1) {
2878 err = got_error(GOT_ERR_PRIVSEP_MSG);
2879 break;
2881 if (datalen != sizeof(*icommit)) {
2882 err = got_error(GOT_ERR_PRIVSEP_LEN);
2883 break;
2885 icommit = (struct got_imsg_enumerated_commit *)imsg.data;
2886 memcpy(commit_id.sha1, icommit->id, SHA1_DIGEST_LENGTH);
2887 mtime = icommit->mtime;
2888 have_commit = 1;
2889 break;
2890 case GOT_IMSG_ENUMERATED_TREE:
2891 /* Should be preceeded by GOT_IMSG_ENUMERATED_COMMIT. */
2892 if (!have_commit) {
2893 err = got_error(GOT_ERR_PRIVSEP_MSG);
2894 break;
2896 if (datalen < sizeof(*itree)) {
2897 err = got_error(GOT_ERR_PRIVSEP_LEN);
2898 break;
2900 itree = imsg.data;
2901 path_len = datalen - sizeof(*itree);
2902 if (path_len == 0) {
2903 err = got_error(GOT_ERR_PRIVSEP_LEN);
2904 break;
2906 memcpy(tree_id.sha1, itree->id, sizeof(tree_id.sha1));
2907 free(path);
2908 path = strndup(imsg.data + sizeof(*itree), path_len);
2909 if (path == NULL) {
2910 err = got_error_from_errno("strndup");
2911 break;
2913 free(canon_path);
2914 canon_path = malloc(path_len + 1);
2915 if (canon_path == NULL) {
2916 err = got_error_from_errno("malloc");
2917 break;
2919 if (!got_path_is_absolute(path)) {
2920 err = got_error(GOT_ERR_BAD_PATH);
2921 break;
2923 if (got_path_is_root_dir(path)) {
2924 /* XXX check what got_canonpath() does wrong */
2925 canon_path[0] = '/';
2926 canon_path[1] = '\0';
2927 } else {
2928 err = got_canonpath(path, canon_path,
2929 path_len + 1);
2930 if (err)
2931 break;
2933 if (strcmp(path, canon_path) != 0) {
2934 err = got_error(GOT_ERR_BAD_PATH);
2935 break;
2937 if (nentries != -1) {
2938 err = got_error(GOT_ERR_PRIVSEP_MSG);
2939 break;
2941 if (itree->nentries < -1) {
2942 err = got_error(GOT_ERR_PRIVSEP_MSG);
2943 break;
2945 if (itree->nentries == -1) {
2946 /* Tree was not found in pack file. */
2947 err = cb_tree(cb_arg, NULL, mtime, &tree_id,
2948 path, repo);
2949 break;
2951 if (itree->nentries > INT_MAX) {
2952 err = got_error(GOT_ERR_PRIVSEP_LEN);
2953 break;
2955 tree.entries = calloc(itree->nentries,
2956 sizeof(struct got_tree_entry));
2957 if (tree.entries == NULL) {
2958 err = got_error_from_errno("calloc");
2959 break;
2961 if (itree->nentries == 0) {
2962 err = cb_tree(cb_arg, &tree, mtime, &tree_id,
2963 path, repo);
2964 if (err)
2965 break;
2967 /* Prepare for next tree. */
2968 free(tree.entries);
2969 memset(&tree, 0, sizeof(tree));
2970 nentries = -1;
2971 } else {
2972 tree.nentries = itree->nentries;
2973 nentries = 0;
2975 break;
2976 case GOT_IMSG_TREE_ENTRIES:
2977 /* Should be preceeded by GOT_IMSG_ENUMERATED_TREE. */
2978 if (nentries <= -1) {
2979 err = got_error(GOT_ERR_PRIVSEP_MSG);
2980 break;
2982 err = recv_tree_entries(imsg.data, datalen,
2983 &tree, &nentries);
2984 if (err)
2985 break;
2986 if (tree.nentries == nentries) {
2987 err = cb_tree(cb_arg, &tree, mtime, &tree_id,
2988 path, repo);
2989 if (err)
2990 break;
2992 /* Prepare for next tree. */
2993 free(tree.entries);
2994 memset(&tree, 0, sizeof(tree));
2995 nentries = -1;
2997 break;
2998 case GOT_IMSG_TREE_ENUMERATION_DONE:
2999 /* All trees have been found and traversed. */
3000 if (!have_commit || path == NULL || nentries != -1) {
3001 err = got_error(GOT_ERR_PRIVSEP_MSG);
3002 break;
3004 err = cb_commit(cb_arg, mtime, &commit_id, repo);
3005 if (err)
3006 break;
3007 have_commit = 0;
3008 break;
3009 case GOT_IMSG_OBJECT_ENUMERATION_DONE:
3010 *found_all_objects = 1;
3011 done = 1;
3012 break;
3013 case GOT_IMSG_OBJECT_ENUMERATION_INCOMPLETE:
3014 done = 1;
3015 break;
3016 default:
3017 err = got_error(GOT_ERR_PRIVSEP_MSG);
3018 break;
3021 imsg_free(&imsg);
3022 if (err)
3023 break;
3026 free(path);
3027 free(canon_path);
3028 free(tree.entries);
3029 return err;
3032 const struct got_error *
3033 got_privsep_send_raw_delta_req(struct imsgbuf *ibuf, int idx,
3034 struct got_object_id *id)
3036 struct got_imsg_raw_delta_request dreq;
3038 memset(&dreq, 0, sizeof(dreq));
3039 dreq.idx = idx;
3040 memcpy(&dreq.id, id, sizeof(dreq.id));
3042 if (imsg_compose(ibuf, GOT_IMSG_RAW_DELTA_REQUEST, 0, 0, -1,
3043 &dreq, sizeof(dreq)) == -1)
3044 return got_error_from_errno("imsg_compose RAW_DELTA_REQUEST");
3046 return flush_imsg(ibuf);
3049 const struct got_error *
3050 got_privsep_send_raw_delta_outfd(struct imsgbuf *ibuf, int fd)
3052 return send_fd(ibuf, GOT_IMSG_RAW_DELTA_OUTFD, fd);
3055 const struct got_error *
3056 got_privsep_send_raw_delta(struct imsgbuf *ibuf, uint64_t base_size,
3057 uint64_t result_size, off_t delta_size, off_t delta_compressed_size,
3058 off_t delta_offset, off_t delta_out_offset, struct got_object_id *base_id)
3060 struct got_imsg_raw_delta idelta;
3061 int ret;
3063 memset(&idelta, 0, sizeof(idelta));
3064 idelta.base_size = base_size;
3065 idelta.result_size = result_size;
3066 idelta.delta_size = delta_size;
3067 idelta.delta_compressed_size = delta_compressed_size;
3068 idelta.delta_offset = delta_offset;
3069 idelta.delta_out_offset = delta_out_offset;
3070 memcpy(&idelta.base_id, &base_id, sizeof(idelta.base_id));
3072 ret = imsg_compose(ibuf, GOT_IMSG_RAW_DELTA, 0, 0, -1,
3073 &idelta, sizeof(idelta));
3074 if (ret == -1)
3075 return got_error_from_errno("imsg_compose RAW_DELTA");
3077 return flush_imsg(ibuf);
3080 const struct got_error *
3081 got_privsep_recv_raw_delta(uint64_t *base_size, uint64_t *result_size,
3082 off_t *delta_size, off_t *delta_compressed_size, off_t *delta_offset,
3083 off_t *delta_out_offset, struct got_object_id **base_id,
3084 struct imsgbuf *ibuf)
3086 const struct got_error *err = NULL;
3087 struct imsg imsg;
3088 struct got_imsg_raw_delta *delta;
3089 size_t datalen;
3091 *base_size = 0;
3092 *result_size = 0;
3093 *delta_size = 0;
3094 *delta_compressed_size = 0;
3095 *delta_offset = 0;
3096 *delta_out_offset = 0;
3097 *base_id = NULL;
3099 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
3100 if (err)
3101 return err;
3103 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
3105 switch (imsg.hdr.type) {
3106 case GOT_IMSG_RAW_DELTA:
3107 if (datalen != sizeof(*delta)) {
3108 err = got_error(GOT_ERR_PRIVSEP_LEN);
3109 break;
3111 delta = imsg.data;
3112 *base_size = delta->base_size;
3113 *result_size = delta->result_size;
3114 *delta_size = delta->delta_size;
3115 *delta_compressed_size = delta->delta_compressed_size;
3116 *delta_offset = delta->delta_offset;
3117 *delta_out_offset = delta->delta_out_offset;
3118 *base_id = calloc(1, sizeof(**base_id));
3119 if (*base_id == NULL) {
3120 err = got_error_from_errno("malloc");
3121 break;
3123 memcpy(*base_id, &delta->base_id, sizeof(**base_id));
3124 break;
3125 default:
3126 err = got_error(GOT_ERR_PRIVSEP_MSG);
3127 break;
3130 imsg_free(&imsg);
3132 if (err) {
3133 free(*base_id);
3134 *base_id = NULL;
3136 return err;
3139 static const struct got_error *
3140 send_idlist(struct imsgbuf *ibuf, struct got_object_id **ids, size_t nids)
3142 const struct got_error *err = NULL;
3143 struct got_imsg_object_idlist idlist;
3144 struct ibuf *wbuf;
3145 size_t i;
3147 memset(&idlist, 0, sizeof(idlist));
3149 if (nids > GOT_IMSG_OBJ_ID_LIST_MAX_NIDS)
3150 return got_error(GOT_ERR_NO_SPACE);
3152 wbuf = imsg_create(ibuf, GOT_IMSG_OBJ_ID_LIST, 0, 0,
3153 sizeof(idlist) + nids * sizeof(**ids));
3154 if (wbuf == NULL) {
3155 err = got_error_from_errno("imsg_create OBJ_ID_LIST");
3156 return err;
3159 idlist.nids = nids;
3160 if (imsg_add(wbuf, &idlist, sizeof(idlist)) == -1)
3161 return got_error_from_errno("imsg_add OBJ_ID_LIST");
3163 for (i = 0; i < nids; i++) {
3164 struct got_object_id *id = ids[i];
3165 if (imsg_add(wbuf, id, sizeof(*id)) == -1)
3166 return got_error_from_errno("imsg_add OBJ_ID_LIST");
3169 wbuf->fd = -1;
3170 imsg_close(ibuf, wbuf);
3172 return flush_imsg(ibuf);
3175 const struct got_error *
3176 got_privsep_send_object_idlist(struct imsgbuf *ibuf,
3177 struct got_object_id **ids, size_t nids)
3179 const struct got_error *err = NULL;
3180 struct got_object_id *idlist[GOT_IMSG_OBJ_ID_LIST_MAX_NIDS];
3181 int i, queued = 0;
3183 for (i = 0; i < nids; i++) {
3184 idlist[i % nitems(idlist)] = ids[i];
3185 queued++;
3186 if (queued >= nitems(idlist)) {
3187 err = send_idlist(ibuf, idlist, queued);
3188 if (err)
3189 return err;
3190 queued = 0;
3194 if (queued > 0) {
3195 err = send_idlist(ibuf, idlist, queued);
3196 if (err)
3197 return err;
3200 return NULL;
3203 const struct got_error *
3204 got_privsep_send_object_idlist_done(struct imsgbuf *ibuf)
3206 if (imsg_compose(ibuf, GOT_IMSG_OBJ_ID_LIST_DONE, 0, 0, -1, NULL, 0)
3207 == -1)
3208 return got_error_from_errno("imsg_compose OBJ_ID_LIST_DONE");
3210 return flush_imsg(ibuf);
3213 const struct got_error *
3214 got_privsep_recv_object_idlist(int *done, struct got_object_id **ids,
3215 size_t *nids, struct imsgbuf *ibuf)
3217 const struct got_error *err = NULL;
3218 struct imsg imsg;
3219 struct got_imsg_object_idlist *idlist;
3220 size_t datalen;
3222 *ids = NULL;
3223 *done = 0;
3224 *nids = 0;
3226 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
3227 if (err)
3228 return err;
3230 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
3231 switch (imsg.hdr.type) {
3232 case GOT_IMSG_OBJ_ID_LIST:
3233 if (datalen < sizeof(*idlist)) {
3234 err = got_error(GOT_ERR_PRIVSEP_LEN);
3235 break;
3237 idlist = imsg.data;
3238 if (idlist->nids > GOT_IMSG_OBJ_ID_LIST_MAX_NIDS ||
3239 idlist->nids * sizeof(**ids) > datalen - sizeof(*idlist)) {
3240 err = got_error(GOT_ERR_PRIVSEP_LEN);
3241 break;
3243 *nids = idlist->nids;
3244 *ids = calloc(*nids, sizeof(**ids));
3245 if (*ids == NULL) {
3246 err = got_error_from_errno("calloc");
3247 break;
3249 memcpy(*ids, (uint8_t *)imsg.data + sizeof(*idlist),
3250 *nids * sizeof(**ids));
3251 break;
3252 case GOT_IMSG_OBJ_ID_LIST_DONE:
3253 *done = 1;
3254 break;
3255 default:
3256 err = got_error(GOT_ERR_PRIVSEP_MSG);
3257 break;
3260 imsg_free(&imsg);
3262 return err;
3265 const struct got_error *
3266 got_privsep_send_delta_reuse_req(struct imsgbuf *ibuf)
3268 if (imsg_compose(ibuf, GOT_IMSG_DELTA_REUSE_REQUEST, 0, 0, -1, NULL, 0)
3269 == -1)
3270 return got_error_from_errno("imsg_compose DELTA_REUSE_REQUEST");
3272 return flush_imsg(ibuf);
3275 const struct got_error *
3276 got_privsep_send_reused_deltas(struct imsgbuf *ibuf,
3277 struct got_imsg_reused_delta *deltas, size_t ndeltas)
3279 const struct got_error *err = NULL;
3280 struct ibuf *wbuf;
3281 struct got_imsg_reused_deltas ideltas;
3282 size_t i;
3284 memset(&ideltas, 0, sizeof(ideltas));
3286 if (ndeltas > GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS)
3287 return got_error(GOT_ERR_NO_SPACE);
3289 wbuf = imsg_create(ibuf, GOT_IMSG_REUSED_DELTAS, 0, 0,
3290 sizeof(ideltas) + ndeltas * sizeof(*deltas));
3291 if (wbuf == NULL) {
3292 err = got_error_from_errno("imsg_create REUSED_DELTAS");
3293 return err;
3296 ideltas.ndeltas = ndeltas;
3297 if (imsg_add(wbuf, &ideltas, sizeof(ideltas)) == -1)
3298 return got_error_from_errno("imsg_add REUSED_DELTAS");
3300 for (i = 0; i < ndeltas; i++) {
3301 struct got_imsg_reused_delta *delta = &deltas[i];
3302 if (imsg_add(wbuf, delta, sizeof(*delta)) == -1)
3303 return got_error_from_errno("imsg_add REUSED_DELTAS");
3306 wbuf->fd = -1;
3307 imsg_close(ibuf, wbuf);
3309 return flush_imsg(ibuf);
3312 const struct got_error *
3313 got_privsep_send_reused_deltas_done(struct imsgbuf *ibuf)
3315 if (imsg_compose(ibuf, GOT_IMSG_DELTA_REUSE_DONE, 0, 0, -1, NULL, 0)
3316 == -1)
3317 return got_error_from_errno("imsg_compose DELTA_REUSE_DONE");
3319 return flush_imsg(ibuf);
3322 const struct got_error *
3323 got_privsep_recv_reused_deltas(int *done, struct got_imsg_reused_delta *deltas,
3324 size_t *ndeltas, struct imsgbuf *ibuf)
3326 const struct got_error *err = NULL;
3327 struct imsg imsg;
3328 struct got_imsg_reused_deltas *ideltas;
3329 size_t datalen;
3331 *done = 0;
3332 *ndeltas = 0;
3334 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
3335 if (err)
3336 return err;
3338 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
3339 switch (imsg.hdr.type) {
3340 case GOT_IMSG_REUSED_DELTAS:
3341 if (datalen < sizeof(*ideltas)) {
3342 err = got_error(GOT_ERR_PRIVSEP_LEN);
3343 break;
3345 ideltas = imsg.data;
3346 if (ideltas->ndeltas > GOT_IMSG_OBJ_ID_LIST_MAX_NIDS ||
3347 ideltas->ndeltas * sizeof(*deltas) >
3348 datalen - sizeof(*ideltas)) {
3349 err = got_error(GOT_ERR_PRIVSEP_LEN);
3350 break;
3352 *ndeltas = ideltas->ndeltas;
3353 memcpy(deltas, (uint8_t *)imsg.data + sizeof(*ideltas),
3354 *ndeltas * sizeof(*deltas));
3355 break;
3356 case GOT_IMSG_DELTA_REUSE_DONE:
3357 *done = 1;
3358 break;
3359 default:
3360 err = got_error(GOT_ERR_PRIVSEP_MSG);
3361 break;
3364 imsg_free(&imsg);
3366 return err;
3369 const struct got_error *
3370 got_privsep_init_commit_painting(struct imsgbuf *ibuf)
3372 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_PAINTING_INIT,
3373 0, 0, -1, NULL, 0)
3374 == -1)
3375 return got_error_from_errno("imsg_compose "
3376 "COMMIT_PAINTING_INIT");
3378 return flush_imsg(ibuf);
3381 const struct got_error *
3382 got_privsep_send_painting_request(struct imsgbuf *ibuf, int idx,
3383 struct got_object_id *id, intptr_t color)
3385 struct got_imsg_commit_painting_request ireq;
3387 memset(&ireq, 0, sizeof(ireq));
3388 memcpy(&ireq.id, id, sizeof(ireq.id));
3389 ireq.idx = idx;
3390 ireq.color = color;
3392 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_PAINTING_REQUEST, 0, 0, -1,
3393 &ireq, sizeof(ireq)) == -1)
3394 return got_error_from_errno("imsg_compose "
3395 "COMMIT_PAINTING_REQUEST");
3397 return flush_imsg(ibuf);
3400 static const struct got_error *
3401 send_painted_commits(struct got_object_id_queue *ids, int *nids,
3402 size_t remain, int present_in_pack, struct imsgbuf *ibuf)
3404 const struct got_error *err = NULL;
3405 struct ibuf *wbuf = NULL;
3406 struct got_object_qid *qid;
3407 size_t msglen;
3408 int ncommits;
3409 intptr_t color;
3411 msglen = MIN(remain, MAX_IMSGSIZE - IMSG_HEADER_SIZE);
3412 ncommits = (msglen - sizeof(struct got_imsg_painted_commits)) /
3413 sizeof(struct got_imsg_painted_commit);
3415 wbuf = imsg_create(ibuf, GOT_IMSG_PAINTED_COMMITS, 0, 0, msglen);
3416 if (wbuf == NULL) {
3417 err = got_error_from_errno("imsg_create PAINTED_COMMITS");
3418 return err;
3421 /* Keep in sync with struct got_imsg_painted_commits! */
3422 if (imsg_add(wbuf, &ncommits, sizeof(ncommits)) == -1)
3423 return got_error_from_errno("imsg_add PAINTED_COMMITS");
3424 if (imsg_add(wbuf, &present_in_pack, sizeof(present_in_pack)) == -1)
3425 return got_error_from_errno("imsg_add PAINTED_COMMITS");
3427 while (ncommits > 0) {
3428 qid = STAILQ_FIRST(ids);
3429 STAILQ_REMOVE_HEAD(ids, entry);
3430 ncommits--;
3431 (*nids)--;
3432 color = (intptr_t)qid->data;
3434 /* Keep in sync with struct got_imsg_painted_commit! */
3435 if (imsg_add(wbuf, qid->id.sha1, SHA1_DIGEST_LENGTH) == -1)
3436 return got_error_from_errno("imsg_add PAINTED_COMMITS");
3437 if (imsg_add(wbuf, &color, sizeof(color)) == -1)
3438 return got_error_from_errno("imsg_add PAINTED_COMMITS");
3440 got_object_qid_free(qid);
3443 wbuf->fd = -1;
3444 imsg_close(ibuf, wbuf);
3446 return flush_imsg(ibuf);
3449 const struct got_error *
3450 got_privsep_send_painted_commits(struct imsgbuf *ibuf,
3451 struct got_object_id_queue *ids, int *nids,
3452 int present_in_pack, int flush)
3454 const struct got_error *err;
3455 size_t remain;
3457 if (*nids <= 0)
3458 return NULL;
3460 do {
3461 remain = (sizeof(struct got_imsg_painted_commits)) +
3462 *nids * sizeof(struct got_imsg_painted_commit);
3463 if (flush || remain >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
3464 err = send_painted_commits(ids, nids, remain,
3465 present_in_pack, ibuf);
3466 if (err)
3467 return err;
3469 } while (flush && *nids > 0);
3471 return NULL;
3474 const struct got_error *
3475 got_privsep_send_painting_commits_done(struct imsgbuf *ibuf)
3477 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_PAINTING_DONE,
3478 0, 0, -1, NULL, 0)
3479 == -1)
3480 return got_error_from_errno("imsg_compose "
3481 "COMMIT_PAINTING_DONE");
3483 return flush_imsg(ibuf);
3486 const struct got_error *
3487 got_privsep_recv_painted_commits(struct got_object_id_queue *new_ids,
3488 got_privsep_recv_painted_commit_cb cb, void *cb_arg, struct imsgbuf *ibuf)
3490 const struct got_error *err = NULL;
3491 struct imsg imsg;
3492 struct got_imsg_painted_commits icommits;
3493 struct got_imsg_painted_commit icommit;
3494 size_t datalen;
3495 int i;
3497 for (;;) {
3498 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
3499 if (err)
3500 return err;
3502 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
3503 if (imsg.hdr.type == GOT_IMSG_COMMIT_PAINTING_DONE)
3504 break;
3505 if (imsg.hdr.type != GOT_IMSG_PAINTED_COMMITS)
3506 return got_error(GOT_ERR_PRIVSEP_MSG);
3508 if (datalen < sizeof(icommits))
3509 return got_error(GOT_ERR_PRIVSEP_LEN);
3510 memcpy(&icommits, imsg.data, sizeof(icommits));
3511 if (icommits.ncommits * sizeof(icommit) < icommits.ncommits ||
3512 datalen < sizeof(icommits) +
3513 icommits.ncommits * sizeof(icommit))
3514 return got_error(GOT_ERR_PRIVSEP_LEN);
3516 for (i = 0; i < icommits.ncommits; i++) {
3517 memcpy(&icommit,
3518 (uint8_t *)imsg.data + sizeof(icommits) + i * sizeof(icommit),
3519 sizeof(icommit));
3521 if (icommits.present_in_pack) {
3522 struct got_object_id id;
3523 memcpy(id.sha1, icommit.id, SHA1_DIGEST_LENGTH);
3524 err = cb(cb_arg, &id, icommit.color);
3525 if (err)
3526 break;
3527 } else {
3528 struct got_object_qid *qid;
3529 err = got_object_qid_alloc_partial(&qid);
3530 if (err)
3531 break;
3532 memcpy(qid->id.sha1, icommit.id,
3533 SHA1_DIGEST_LENGTH);
3534 qid->data = (void *)icommit.color;
3535 STAILQ_INSERT_TAIL(new_ids, qid, entry);
3539 imsg_free(&imsg);
3542 return err;
3545 const struct got_error *
3546 got_privsep_unveil_exec_helpers(void)
3548 const char *helpers[] = {
3549 GOT_PATH_PROG_READ_PACK,
3550 GOT_PATH_PROG_READ_OBJECT,
3551 GOT_PATH_PROG_READ_COMMIT,
3552 GOT_PATH_PROG_READ_TREE,
3553 GOT_PATH_PROG_READ_BLOB,
3554 GOT_PATH_PROG_READ_TAG,
3555 GOT_PATH_PROG_READ_GITCONFIG,
3556 GOT_PATH_PROG_READ_GOTCONFIG,
3557 GOT_PATH_PROG_READ_PATCH,
3558 GOT_PATH_PROG_FETCH_PACK,
3559 GOT_PATH_PROG_INDEX_PACK,
3560 GOT_PATH_PROG_SEND_PACK,
3562 size_t i;
3564 for (i = 0; i < nitems(helpers); i++) {
3565 if (unveil(helpers[i], "x") == 0)
3566 continue;
3567 return got_error_from_errno2("unveil", helpers[i]);
3570 return NULL;
3573 void
3574 got_privsep_exec_child(int imsg_fds[2], const char *path, const char *repo_path)
3576 if (close(imsg_fds[0]) == -1) {
3577 fprintf(stderr, "%s: %s\n", getprogname(), strerror(errno));
3578 _exit(1);
3581 if (dup2(imsg_fds[1], GOT_IMSG_FD_CHILD) == -1) {
3582 fprintf(stderr, "%s: %s\n", getprogname(), strerror(errno));
3583 _exit(1);
3586 closefrom(GOT_IMSG_FD_CHILD + 1);
3588 if (execl(path, path, repo_path, (char *)NULL) == -1) {
3589 fprintf(stderr, "%s: %s: %s\n", getprogname(), path,
3590 strerror(errno));
3591 _exit(1);