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_object.h"
39 #include "got_error.h"
40 #include "got_path.h"
41 #include "got_repository.h"
43 #include "got_lib_hash.h"
44 #include "got_lib_delta.h"
45 #include "got_lib_inflate.h"
46 #include "got_lib_object.h"
47 #include "got_lib_object_parse.h"
48 #include "got_lib_object_qid.h"
49 #include "got_lib_privsep.h"
50 #include "got_lib_pack.h"
51 #include "got_lib_poll.h"
53 #include "got_privsep.h"
55 #ifndef MIN
56 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
57 #endif
59 #ifndef nitems
60 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
61 #endif
63 static const struct got_error *
64 read_imsg(struct imsgbuf *ibuf)
65 {
66 const struct got_error *err;
67 size_t n;
69 err = got_poll_fd(ibuf->fd, POLLIN, INFTIM);
70 if (err) {
71 if (err->code == GOT_ERR_EOF)
72 return got_error(GOT_ERR_PRIVSEP_PIPE);
73 return err;
74 }
76 n = imsg_read(ibuf);
77 if (n == -1) {
78 if (errno == EAGAIN) /* Could be a file-descriptor leak. */
79 return got_error(GOT_ERR_PRIVSEP_NO_FD);
80 return got_error(GOT_ERR_PRIVSEP_READ);
81 }
82 if (n == 0)
83 return got_error(GOT_ERR_PRIVSEP_PIPE);
85 return NULL;
86 }
88 const struct got_error *
89 got_privsep_wait_for_child(pid_t pid)
90 {
91 int child_status;
93 if (waitpid(pid, &child_status, 0) == -1)
94 return got_error_from_errno("waitpid");
96 if (!WIFEXITED(child_status))
97 return got_error(GOT_ERR_PRIVSEP_DIED);
99 if (WEXITSTATUS(child_status) != 0)
100 return got_error(GOT_ERR_PRIVSEP_EXIT);
102 return NULL;
105 static const struct got_error *
106 recv_imsg_error(struct imsg *imsg, size_t datalen)
108 struct got_imsg_error *ierr;
110 if (datalen != sizeof(*ierr))
111 return got_error(GOT_ERR_PRIVSEP_LEN);
113 ierr = imsg->data;
114 if (ierr->code == GOT_ERR_ERRNO) {
115 static struct got_error serr;
116 serr.code = GOT_ERR_ERRNO;
117 serr.msg = strerror(ierr->errno_code);
118 return &serr;
121 return got_error(ierr->code);
124 const struct got_error *
125 got_privsep_recv_imsg(struct imsg *imsg, struct imsgbuf *ibuf,
126 size_t min_datalen)
128 const struct got_error *err;
129 ssize_t n;
131 n = imsg_get(ibuf, imsg);
132 if (n == -1)
133 return got_error_from_errno("imsg_get");
135 while (n == 0) {
136 err = read_imsg(ibuf);
137 if (err)
138 return err;
139 n = imsg_get(ibuf, imsg);
140 if (n == -1)
141 return got_error_from_errno("imsg_get");
144 if (imsg->hdr.len < IMSG_HEADER_SIZE + min_datalen)
145 return got_error(GOT_ERR_PRIVSEP_LEN);
147 if (imsg->hdr.type == GOT_IMSG_ERROR) {
148 size_t datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
149 return recv_imsg_error(imsg, datalen);
152 return NULL;
155 /* Attempt to send an error in an imsg. Complain on stderr as a last resort. */
156 void
157 got_privsep_send_error(struct imsgbuf *ibuf, const struct got_error *err)
159 const struct got_error *poll_err;
160 struct got_imsg_error ierr;
161 int ret;
163 ierr.code = err->code;
164 if (err->code == GOT_ERR_ERRNO)
165 ierr.errno_code = errno;
166 else
167 ierr.errno_code = 0;
168 ret = imsg_compose(ibuf, GOT_IMSG_ERROR, 0, 0, -1, &ierr, sizeof(ierr));
169 if (ret == -1) {
170 fprintf(stderr, "%s: error %d \"%s\": imsg_compose: %s\n",
171 getprogname(), err->code, err->msg, strerror(errno));
172 return;
175 poll_err = got_poll_fd(ibuf->fd, POLLOUT, INFTIM);
176 if (poll_err) {
177 fprintf(stderr, "%s: error %d \"%s\": poll: %s\n",
178 getprogname(), err->code, err->msg, poll_err->msg);
179 return;
182 ret = imsg_flush(ibuf);
183 if (ret == -1) {
184 fprintf(stderr, "%s: error %d \"%s\": imsg_flush: %s\n",
185 getprogname(), err->code, err->msg, strerror(errno));
186 imsg_clear(ibuf);
187 return;
191 static const struct got_error *
192 flush_imsg(struct imsgbuf *ibuf)
194 const struct got_error *err;
196 err = got_poll_fd(ibuf->fd, POLLOUT, INFTIM);
197 if (err)
198 return err;
200 if (imsg_flush(ibuf) == -1) {
201 imsg_clear(ibuf);
202 return got_error_from_errno("imsg_flush");
205 return NULL;
208 const struct got_error *
209 got_privsep_flush_imsg(struct imsgbuf *ibuf)
211 return flush_imsg(ibuf);
214 const struct got_error *
215 got_privsep_send_stop(int fd)
217 struct imsgbuf ibuf;
219 imsg_init(&ibuf, fd);
221 if (imsg_compose(&ibuf, GOT_IMSG_STOP, 0, 0, -1, NULL, 0) == -1)
222 return got_error_from_errno("imsg_compose STOP");
224 return flush_imsg(&ibuf);
227 const struct got_error *
228 got_privsep_send_obj_req(struct imsgbuf *ibuf, int fd,
229 struct got_object_id *id)
231 if (imsg_compose(ibuf, GOT_IMSG_OBJECT_REQUEST, 0, 0, fd,
232 id, sizeof(*id)) == -1)
233 return got_error_from_errno("imsg_compose OBJECT_REQUEST");
235 return flush_imsg(ibuf);
238 const struct got_error *
239 got_privsep_send_raw_obj_req(struct imsgbuf *ibuf, int fd,
240 struct got_object_id *id)
242 const struct got_error *err;
244 if (imsg_compose(ibuf, GOT_IMSG_RAW_OBJECT_REQUEST, 0, 0, fd,
245 id, sizeof(*id)) == -1) {
246 err = got_error_from_errno("imsg_compose RAW_OBJECT_REQUEST");
247 close(fd);
248 return err;
251 return flush_imsg(ibuf);
254 const struct got_error *
255 got_privsep_send_raw_obj_outfd(struct imsgbuf *ibuf, int outfd)
257 const struct got_error *err = NULL;
259 if (imsg_compose(ibuf, GOT_IMSG_RAW_OBJECT_OUTFD, 0, 0, outfd, NULL, 0)
260 == -1) {
261 err = got_error_from_errno("imsg_compose RAW_OBJECT_OUTFD");
262 close(outfd);
263 return err;
266 return flush_imsg(ibuf);
269 const struct got_error *
270 got_privsep_send_raw_obj(struct imsgbuf *ibuf, off_t size, size_t hdrlen,
271 uint8_t *data)
273 struct got_imsg_raw_obj iobj;
274 size_t len = sizeof(iobj);
275 struct ibuf *wbuf;
277 memset(&iobj, 0, sizeof(iobj));
278 iobj.hdrlen = hdrlen;
279 iobj.size = size;
281 if (data && size + hdrlen <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX)
282 len += (size_t)size + hdrlen;
284 wbuf = imsg_create(ibuf, GOT_IMSG_RAW_OBJECT, 0, 0, len);
285 if (wbuf == NULL)
286 return got_error_from_errno("imsg_create RAW_OBJECT");
288 if (imsg_add(wbuf, &iobj, sizeof(iobj)) == -1)
289 return got_error_from_errno("imsg_add RAW_OBJECT");
291 if (data && size + hdrlen <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX) {
292 if (imsg_add(wbuf, data, size + hdrlen) == -1)
293 return got_error_from_errno("imsg_add RAW_OBJECT");
296 imsg_close(ibuf, wbuf);
297 return flush_imsg(ibuf);
300 const struct got_error *
301 got_privsep_recv_raw_obj(uint8_t **outbuf, off_t *size, size_t *hdrlen,
302 struct imsgbuf *ibuf)
304 const struct got_error *err = NULL;
305 struct imsg imsg;
306 struct got_imsg_raw_obj *iobj;
307 size_t datalen;
309 *outbuf = NULL;
311 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
312 if (err)
313 return err;
315 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
317 switch (imsg.hdr.type) {
318 case GOT_IMSG_RAW_OBJECT:
319 if (datalen < sizeof(*iobj)) {
320 err = got_error(GOT_ERR_PRIVSEP_LEN);
321 break;
323 iobj = imsg.data;
324 *size = iobj->size;
325 *hdrlen = iobj->hdrlen;
327 if (datalen == sizeof(*iobj)) {
328 /* Data has been written to file descriptor. */
329 break;
332 if (*size < 0 ||
333 *size + *hdrlen > GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX) {
334 err = got_error(GOT_ERR_PRIVSEP_LEN);
335 break;
338 *outbuf = malloc(*size + *hdrlen);
339 if (*outbuf == NULL) {
340 err = got_error_from_errno("malloc");
341 break;
343 memcpy(*outbuf, imsg.data + sizeof(*iobj), *size + *hdrlen);
344 break;
345 default:
346 err = got_error(GOT_ERR_PRIVSEP_MSG);
347 break;
350 imsg_free(&imsg);
352 return err;
355 const struct got_error *
356 got_privsep_send_commit_req(struct imsgbuf *ibuf, int fd,
357 struct got_object_id *id, int pack_idx)
359 const struct got_error *err = NULL;
360 struct got_imsg_packed_object iobj;
361 void *data;
362 size_t len;
364 memset(&iobj, 0, sizeof(iobj));
365 if (pack_idx != -1) { /* commit is packed */
366 iobj.idx = pack_idx;
367 memcpy(&iobj.id, id, sizeof(iobj.id));
368 data = &iobj;
369 len = sizeof(iobj);
370 } else {
371 data = id;
372 len = sizeof(*id);
375 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_REQUEST, 0, 0, fd, data, len)
376 == -1) {
377 err = got_error_from_errno("imsg_compose COMMIT_REQUEST");
378 close(fd);
379 return err;
382 return flush_imsg(ibuf);
385 const struct got_error *
386 got_privsep_send_tree_req(struct imsgbuf *ibuf, int fd,
387 struct got_object_id *id, int pack_idx)
389 const struct got_error *err;
390 struct ibuf *wbuf;
391 size_t len;
393 if (pack_idx != -1)
394 len = sizeof(struct got_imsg_packed_object);
395 else
396 len = sizeof(*id);
398 wbuf = imsg_create(ibuf, GOT_IMSG_TREE_REQUEST, 0, 0, len);
399 if (wbuf == NULL) {
400 err = got_error_from_errno("imsg_create TREE_REQUEST");
401 if (fd != -1)
402 close(fd);
403 return err;
406 if (imsg_add(wbuf, id, sizeof(*id)) == -1) {
407 err = got_error_from_errno("imsg_add TREE_REQUEST");
408 if (fd != -1)
409 close(fd);
410 return err;
413 if (pack_idx != -1) { /* tree is packed */
414 if (imsg_add(wbuf, &pack_idx, sizeof(pack_idx)) == -1) {
415 err = got_error_from_errno("imsg_add TREE_REQUEST");
416 if (fd != -1)
417 close(fd);
418 return err;
422 ibuf_fd_set(wbuf, fd);
423 imsg_close(ibuf, wbuf);
425 return flush_imsg(ibuf);
428 const struct got_error *
429 got_privsep_send_tag_req(struct imsgbuf *ibuf, int fd,
430 struct got_object_id *id, int pack_idx)
432 const struct got_error *err;
433 struct got_imsg_packed_object iobj;
434 void *data;
435 size_t len;
437 memset(&iobj, 0, sizeof(iobj));
438 if (pack_idx != -1) { /* tag is packed */
439 iobj.idx = pack_idx;
440 memcpy(&iobj.id, id, sizeof(iobj.id));
441 data = &iobj;
442 len = sizeof(iobj);
443 } else {
444 data = id;
445 len = sizeof(*id);
448 if (imsg_compose(ibuf, GOT_IMSG_TAG_REQUEST, 0, 0, fd, data, len)
449 == -1) {
450 err = got_error_from_errno("imsg_compose TAG_REQUEST");
451 if (fd != -1)
452 close(fd);
453 return err;
456 return flush_imsg(ibuf);
459 const struct got_error *
460 got_privsep_send_blob_req(struct imsgbuf *ibuf, int infd,
461 struct got_object_id *id, int pack_idx)
463 const struct got_error *err = NULL;
464 struct got_imsg_packed_object iobj;
465 void *data;
466 size_t len;
468 memset(&iobj, 0, sizeof(iobj));
469 if (pack_idx != -1) { /* blob is packed */
470 iobj.idx = pack_idx;
471 memcpy(&iobj.id, id, sizeof(iobj.id));
472 data = &iobj;
473 len = sizeof(iobj);
474 } else {
475 data = id;
476 len = sizeof(*id);
479 if (imsg_compose(ibuf, GOT_IMSG_BLOB_REQUEST, 0, 0, infd, data, len)
480 == -1) {
481 err = got_error_from_errno("imsg_compose BLOB_REQUEST");
482 close(infd);
483 return err;
486 return flush_imsg(ibuf);
489 const struct got_error *
490 got_privsep_send_blob_outfd(struct imsgbuf *ibuf, int outfd)
492 const struct got_error *err = NULL;
494 if (imsg_compose(ibuf, GOT_IMSG_BLOB_OUTFD, 0, 0, outfd, NULL, 0)
495 == -1) {
496 err = got_error_from_errno("imsg_compose BLOB_OUTFD");
497 close(outfd);
498 return err;
501 return flush_imsg(ibuf);
504 static const struct got_error *
505 send_fd(struct imsgbuf *ibuf, int imsg_code, int fd)
507 const struct got_error *err = NULL;
509 if (imsg_compose(ibuf, imsg_code, 0, 0, fd, NULL, 0) == -1) {
510 err = got_error_from_errno("imsg_compose TMPFD");
511 close(fd);
512 return err;
515 return flush_imsg(ibuf);
518 const struct got_error *
519 got_privsep_send_tmpfd(struct imsgbuf *ibuf, int fd)
521 return send_fd(ibuf, GOT_IMSG_TMPFD, fd);
524 const struct got_error *
525 got_privsep_send_obj(struct imsgbuf *ibuf, struct got_object *obj)
527 struct got_imsg_object iobj;
529 memset(&iobj, 0, sizeof(iobj));
531 memcpy(&iobj.id, &obj->id, sizeof(iobj.id));
532 iobj.type = obj->type;
533 iobj.flags = obj->flags;
534 iobj.hdrlen = obj->hdrlen;
535 iobj.size = obj->size;
536 if (iobj.flags & GOT_OBJ_FLAG_PACKED) {
537 iobj.pack_offset = obj->pack_offset;
538 iobj.pack_idx = obj->pack_idx;
541 if (imsg_compose(ibuf, GOT_IMSG_OBJECT, 0, 0, -1, &iobj, sizeof(iobj))
542 == -1)
543 return got_error_from_errno("imsg_compose OBJECT");
545 return flush_imsg(ibuf);
548 const struct got_error *
549 got_privsep_send_fetch_req(struct imsgbuf *ibuf, int fd,
550 struct got_pathlist_head *have_refs, int fetch_all_branches,
551 struct got_pathlist_head *wanted_branches,
552 struct got_pathlist_head *wanted_refs, int list_refs_only,
553 const char *worktree_branch, const char *remote_head,
554 int no_head, int verbosity)
556 const struct got_error *err = NULL;
557 struct ibuf *wbuf;
558 struct got_pathlist_entry *pe;
559 struct got_imsg_fetch_request fetchreq;
560 size_t remote_head_len, worktree_branch_len, len = sizeof(fetchreq);
562 if (worktree_branch) {
563 worktree_branch_len = strlen(worktree_branch);
564 len += worktree_branch_len;
566 if (remote_head) {
567 remote_head_len = strlen(remote_head);
568 len += remote_head_len;
571 if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
572 close(fd);
573 return got_error(GOT_ERR_NO_SPACE);
576 wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_REQUEST, 0, 0, len);
577 if (wbuf == NULL) {
578 err = got_error_from_errno("imsg_create FETCH_HAVE_REF");
579 close(fd);
580 return err;
583 memset(&fetchreq, 0, sizeof(fetchreq));
584 fetchreq.no_head = no_head;
585 fetchreq.fetch_all_branches = fetch_all_branches;
586 fetchreq.list_refs_only = list_refs_only;
587 fetchreq.verbosity = verbosity;
588 if (worktree_branch != NULL)
589 fetchreq.worktree_branch_len = worktree_branch_len;
590 if (remote_head != NULL)
591 fetchreq.remote_head_len = remote_head_len;
592 TAILQ_FOREACH(pe, have_refs, entry)
593 fetchreq.n_have_refs++;
594 TAILQ_FOREACH(pe, wanted_branches, entry)
595 fetchreq.n_wanted_branches++;
596 TAILQ_FOREACH(pe, wanted_refs, entry)
597 fetchreq.n_wanted_refs++;
598 if (imsg_add(wbuf, &fetchreq, sizeof(fetchreq)) == -1)
599 return got_error_from_errno("imsg_add FETCH_REQUEST");
600 if (worktree_branch) {
601 if (imsg_add(wbuf, worktree_branch, worktree_branch_len)
602 == -1) {
603 err = got_error_from_errno("imsg_add FETCH_REQUEST");
604 close(fd);
605 return err;
608 if (remote_head) {
609 if (imsg_add(wbuf, remote_head, remote_head_len) == -1) {
610 err = got_error_from_errno("imsg_add FETCH_REQUEST");
611 close(fd);
612 return err;
615 ibuf_fd_set(wbuf, fd);
616 fd = -1;
617 imsg_close(ibuf, wbuf);
619 err = flush_imsg(ibuf);
620 if (err)
621 return err;
623 TAILQ_FOREACH(pe, have_refs, entry) {
624 const char *name = pe->path;
625 size_t name_len = pe->path_len;
626 struct got_object_id *id = pe->data;
628 len = sizeof(struct got_imsg_fetch_have_ref) + name_len;
629 wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_HAVE_REF, 0, 0, len);
630 if (wbuf == NULL)
631 return got_error_from_errno("imsg_create FETCH_HAVE_REF");
633 /* Keep in sync with struct got_imsg_fetch_have_ref! */
634 if (imsg_add(wbuf, id, sizeof(*id)) == -1)
635 return got_error_from_errno("imsg_add FETCH_HAVE_REF");
636 if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1)
637 return got_error_from_errno("imsg_add FETCH_HAVE_REF");
638 if (imsg_add(wbuf, name, name_len) == -1)
639 return got_error_from_errno("imsg_add FETCH_HAVE_REF");
641 imsg_close(ibuf, wbuf);
642 err = flush_imsg(ibuf);
643 if (err)
644 return err;
647 TAILQ_FOREACH(pe, wanted_branches, entry) {
648 const char *name = pe->path;
649 size_t name_len = pe->path_len;
651 len = sizeof(struct got_imsg_fetch_wanted_branch) + name_len;
652 wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_WANTED_BRANCH, 0, 0,
653 len);
654 if (wbuf == NULL)
655 return got_error_from_errno(
656 "imsg_create FETCH_WANTED_BRANCH");
658 /* Keep in sync with struct got_imsg_fetch_wanted_branch! */
659 if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1)
660 return got_error_from_errno(
661 "imsg_add FETCH_WANTED_BRANCH");
662 if (imsg_add(wbuf, name, name_len) == -1)
663 return got_error_from_errno(
664 "imsg_add FETCH_WANTED_BRANCH");
666 imsg_close(ibuf, wbuf);
667 err = flush_imsg(ibuf);
668 if (err)
669 return err;
672 TAILQ_FOREACH(pe, wanted_refs, entry) {
673 const char *name = pe->path;
674 size_t name_len = pe->path_len;
676 len = sizeof(struct got_imsg_fetch_wanted_ref) + name_len;
677 wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_WANTED_REF, 0, 0,
678 len);
679 if (wbuf == NULL)
680 return got_error_from_errno(
681 "imsg_create FETCH_WANTED_REF");
683 /* Keep in sync with struct got_imsg_fetch_wanted_ref! */
684 if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1)
685 return got_error_from_errno(
686 "imsg_add FETCH_WANTED_REF");
687 if (imsg_add(wbuf, name, name_len) == -1)
688 return got_error_from_errno(
689 "imsg_add FETCH_WANTED_REF");
691 imsg_close(ibuf, wbuf);
692 err = flush_imsg(ibuf);
693 if (err)
694 return err;
697 return NULL;
700 const struct got_error *
701 got_privsep_send_fetch_outfd(struct imsgbuf *ibuf, int fd)
703 return send_fd(ibuf, GOT_IMSG_FETCH_OUTFD, fd);
706 const struct got_error *
707 got_privsep_recv_fetch_progress(int *done, struct got_object_id **id,
708 char **refname, struct got_pathlist_head *symrefs, char **server_progress,
709 off_t *packfile_size, uint8_t *pack_sha1, struct imsgbuf *ibuf)
711 const struct got_error *err = NULL;
712 struct imsg imsg;
713 size_t datalen;
714 struct got_imsg_fetch_symrefs *isymrefs = NULL;
715 size_t n, remain;
716 off_t off;
717 int i;
719 *done = 0;
720 *id = NULL;
721 *refname = NULL;
722 *server_progress = NULL;
723 *packfile_size = 0;
724 memset(pack_sha1, 0, SHA1_DIGEST_LENGTH);
726 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
727 if (err)
728 return err;
730 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
731 switch (imsg.hdr.type) {
732 case GOT_IMSG_FETCH_SYMREFS:
733 if (datalen < sizeof(*isymrefs)) {
734 err = got_error(GOT_ERR_PRIVSEP_LEN);
735 break;
737 if (isymrefs != NULL) {
738 err = got_error(GOT_ERR_PRIVSEP_MSG);
739 break;
741 isymrefs = (struct got_imsg_fetch_symrefs *)imsg.data;
742 off = sizeof(*isymrefs);
743 remain = datalen - off;
744 for (n = 0; n < isymrefs->nsymrefs; n++) {
745 struct got_imsg_fetch_symref *s;
746 char *name, *target;
747 if (remain < sizeof(struct got_imsg_fetch_symref)) {
748 err = got_error(GOT_ERR_PRIVSEP_LEN);
749 goto done;
751 s = (struct got_imsg_fetch_symref *)(imsg.data + off);
752 off += sizeof(*s);
753 remain -= sizeof(*s);
754 if (remain < s->name_len) {
755 err = got_error(GOT_ERR_PRIVSEP_LEN);
756 goto done;
758 name = strndup(imsg.data + off, s->name_len);
759 if (name == NULL) {
760 err = got_error_from_errno("strndup");
761 goto done;
763 off += s->name_len;
764 remain -= s->name_len;
765 if (remain < s->target_len) {
766 err = got_error(GOT_ERR_PRIVSEP_LEN);
767 free(name);
768 goto done;
770 target = strndup(imsg.data + off, s->target_len);
771 if (target == NULL) {
772 err = got_error_from_errno("strndup");
773 free(name);
774 goto done;
776 off += s->target_len;
777 remain -= s->target_len;
778 err = got_pathlist_append(symrefs, name, target);
779 if (err) {
780 free(name);
781 free(target);
782 goto done;
785 break;
786 case GOT_IMSG_FETCH_REF:
787 if (datalen <= sizeof(**id)) {
788 err = got_error(GOT_ERR_PRIVSEP_MSG);
789 break;
791 *id = malloc(sizeof(**id));
792 if (*id == NULL) {
793 err = got_error_from_errno("malloc");
794 break;
796 memcpy(*id, imsg.data, sizeof(**id));
797 *refname = strndup(imsg.data + sizeof(**id),
798 datalen - sizeof(**id));
799 if (*refname == NULL) {
800 err = got_error_from_errno("strndup");
801 break;
803 break;
804 case GOT_IMSG_FETCH_SERVER_PROGRESS:
805 if (datalen == 0) {
806 err = got_error(GOT_ERR_PRIVSEP_LEN);
807 break;
809 *server_progress = strndup(imsg.data, datalen);
810 if (*server_progress == NULL) {
811 err = got_error_from_errno("strndup");
812 break;
814 for (i = 0; i < datalen; i++) {
815 if (!isprint((unsigned char)(*server_progress)[i]) &&
816 !isspace((unsigned char)(*server_progress)[i])) {
817 err = got_error(GOT_ERR_PRIVSEP_MSG);
818 free(*server_progress);
819 *server_progress = NULL;
820 goto done;
823 break;
824 case GOT_IMSG_FETCH_DOWNLOAD_PROGRESS:
825 if (datalen < sizeof(*packfile_size)) {
826 err = got_error(GOT_ERR_PRIVSEP_MSG);
827 break;
829 memcpy(packfile_size, imsg.data, sizeof(*packfile_size));
830 break;
831 case GOT_IMSG_FETCH_DONE:
832 if (datalen != SHA1_DIGEST_LENGTH) {
833 err = got_error(GOT_ERR_PRIVSEP_MSG);
834 break;
836 memcpy(pack_sha1, imsg.data, SHA1_DIGEST_LENGTH);
837 *done = 1;
838 break;
839 default:
840 err = got_error(GOT_ERR_PRIVSEP_MSG);
841 break;
843 done:
844 if (err) {
845 free(*id);
846 *id = NULL;
847 free(*refname);
848 *refname = NULL;
850 imsg_free(&imsg);
851 return err;
854 static const struct got_error *
855 send_send_ref(const char *name, size_t name_len, struct got_object_id *id,
856 int delete, struct imsgbuf *ibuf)
858 size_t len;
859 struct ibuf *wbuf;
861 len = sizeof(struct got_imsg_send_ref) + name_len;
862 wbuf = imsg_create(ibuf, GOT_IMSG_SEND_REF, 0, 0, len);
863 if (wbuf == NULL)
864 return got_error_from_errno("imsg_create SEND_REF");
866 /* Keep in sync with struct got_imsg_send_ref! */
867 if (imsg_add(wbuf, id, sizeof(*id)) == -1)
868 return got_error_from_errno("imsg_add SEND_REF");
869 if (imsg_add(wbuf, &delete, sizeof(delete)) == -1)
870 return got_error_from_errno("imsg_add SEND_REF");
871 if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1)
872 return got_error_from_errno("imsg_add SEND_REF");
873 if (imsg_add(wbuf, name, name_len) == -1)
874 return got_error_from_errno("imsg_add SEND_REF");
876 imsg_close(ibuf, wbuf);
877 return flush_imsg(ibuf);
880 const struct got_error *
881 got_privsep_send_send_req(struct imsgbuf *ibuf, int fd,
882 struct got_pathlist_head *have_refs,
883 struct got_pathlist_head *delete_refs,
884 int verbosity)
886 const struct got_error *err = NULL;
887 struct got_pathlist_entry *pe;
888 struct got_imsg_send_request sendreq;
889 struct got_object_id zero_id;
891 memset(&zero_id, 0, sizeof(zero_id));
892 memset(&sendreq, 0, sizeof(sendreq));
893 sendreq.verbosity = verbosity;
894 TAILQ_FOREACH(pe, have_refs, entry)
895 sendreq.nrefs++;
896 TAILQ_FOREACH(pe, delete_refs, entry)
897 sendreq.nrefs++;
898 if (imsg_compose(ibuf, GOT_IMSG_SEND_REQUEST, 0, 0, fd,
899 &sendreq, sizeof(sendreq)) == -1) {
900 err = got_error_from_errno(
901 "imsg_compose FETCH_SERVER_PROGRESS");
902 goto done;
905 fd = -1;
906 err = flush_imsg(ibuf);
907 if (err)
908 goto done;
910 TAILQ_FOREACH(pe, have_refs, entry) {
911 const char *name = pe->path;
912 size_t name_len = pe->path_len;
913 struct got_object_id *id = pe->data;
914 err = send_send_ref(name, name_len, id, 0, ibuf);
915 if (err)
916 goto done;
919 TAILQ_FOREACH(pe, delete_refs, entry) {
920 const char *name = pe->path;
921 size_t name_len = pe->path_len;
922 err = send_send_ref(name, name_len, &zero_id, 1, ibuf);
923 if (err)
924 goto done;
926 done:
927 if (fd != -1 && close(fd) == -1 && err == NULL)
928 err = got_error_from_errno("close");
929 return err;
932 const struct got_error *
933 got_privsep_recv_send_remote_refs(struct got_pathlist_head *remote_refs,
934 struct imsgbuf *ibuf)
936 const struct got_error *err = NULL;
937 struct imsg imsg;
938 size_t datalen;
939 int done = 0;
940 struct got_imsg_send_remote_ref iremote_ref;
941 struct got_object_id *id = NULL;
942 char *refname = NULL;
943 struct got_pathlist_entry *new;
945 while (!done) {
946 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
947 if (err)
948 return err;
949 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
950 switch (imsg.hdr.type) {
951 case GOT_IMSG_SEND_REMOTE_REF:
952 if (datalen < sizeof(iremote_ref)) {
953 err = got_error(GOT_ERR_PRIVSEP_MSG);
954 goto done;
956 memcpy(&iremote_ref, imsg.data, sizeof(iremote_ref));
957 if (datalen != sizeof(iremote_ref) +
958 iremote_ref.name_len) {
959 err = got_error(GOT_ERR_PRIVSEP_MSG);
960 goto done;
962 id = malloc(sizeof(*id));
963 if (id == NULL) {
964 err = got_error_from_errno("malloc");
965 goto done;
967 memcpy(id, &iremote_ref.id, sizeof(*id));
968 refname = strndup(imsg.data + sizeof(iremote_ref),
969 datalen - sizeof(iremote_ref));
970 if (refname == NULL) {
971 err = got_error_from_errno("strndup");
972 goto done;
974 err = got_pathlist_insert(&new, remote_refs,
975 refname, id);
976 if (err)
977 goto done;
978 if (new == NULL) { /* duplicate which wasn't inserted */
979 free(id);
980 free(refname);
982 id = NULL;
983 refname = NULL;
984 break;
985 case GOT_IMSG_SEND_PACK_REQUEST:
986 if (datalen != 0) {
987 err = got_error(GOT_ERR_PRIVSEP_MSG);
988 goto done;
990 /* got-send-pack is now waiting for a pack file. */
991 done = 1;
992 break;
993 default:
994 err = got_error(GOT_ERR_PRIVSEP_MSG);
995 break;
998 done:
999 free(id);
1000 free(refname);
1001 imsg_free(&imsg);
1002 return err;
1005 const struct got_error *
1006 got_privsep_send_packfd(struct imsgbuf *ibuf, int fd)
1008 return send_fd(ibuf, GOT_IMSG_SEND_PACKFD, fd);
1011 const struct got_error *
1012 got_privsep_recv_send_progress(int *done, off_t *bytes_sent,
1013 int *success, char **refname, char **errmsg, struct imsgbuf *ibuf)
1015 const struct got_error *err = NULL;
1016 struct imsg imsg;
1017 size_t datalen;
1018 struct got_imsg_send_ref_status iref_status;
1020 /* Do not reset the current value of 'bytes_sent', it accumulates. */
1021 *done = 0;
1022 *success = 0;
1023 *refname = NULL;
1024 *errmsg = NULL;
1026 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1027 if (err)
1028 return err;
1030 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1031 switch (imsg.hdr.type) {
1032 case GOT_IMSG_SEND_UPLOAD_PROGRESS:
1033 if (datalen < sizeof(*bytes_sent)) {
1034 err = got_error(GOT_ERR_PRIVSEP_MSG);
1035 break;
1037 memcpy(bytes_sent, imsg.data, sizeof(*bytes_sent));
1038 break;
1039 case GOT_IMSG_SEND_REF_STATUS:
1040 if (datalen < sizeof(iref_status)) {
1041 err = got_error(GOT_ERR_PRIVSEP_MSG);
1042 break;
1044 memcpy(&iref_status, imsg.data, sizeof(iref_status));
1045 if (datalen != sizeof(iref_status) + iref_status.name_len +
1046 iref_status.errmsg_len) {
1047 err = got_error(GOT_ERR_PRIVSEP_MSG);
1048 break;
1050 *success = iref_status.success;
1051 *refname = strndup(imsg.data + sizeof(iref_status),
1052 iref_status.name_len);
1054 if (iref_status.errmsg_len != 0)
1055 *errmsg = strndup(imsg.data + sizeof(iref_status) +
1056 iref_status.name_len, iref_status.errmsg_len);
1057 break;
1058 case GOT_IMSG_SEND_DONE:
1059 if (datalen != 0) {
1060 err = got_error(GOT_ERR_PRIVSEP_MSG);
1061 break;
1063 *done = 1;
1064 break;
1065 default:
1066 err = got_error(GOT_ERR_PRIVSEP_MSG);
1067 break;
1070 imsg_free(&imsg);
1071 return err;
1074 const struct got_error *
1075 got_privsep_send_index_pack_req(struct imsgbuf *ibuf, uint8_t *pack_sha1,
1076 int fd)
1078 const struct got_error *err = NULL;
1080 /* Keep in sync with struct got_imsg_index_pack_request */
1081 if (imsg_compose(ibuf, GOT_IMSG_IDXPACK_REQUEST, 0, 0, fd,
1082 pack_sha1, SHA1_DIGEST_LENGTH) == -1) {
1083 err = got_error_from_errno("imsg_compose INDEX_REQUEST");
1084 close(fd);
1085 return err;
1087 return flush_imsg(ibuf);
1090 const struct got_error *
1091 got_privsep_send_index_pack_outfd(struct imsgbuf *ibuf, int fd)
1093 return send_fd(ibuf, GOT_IMSG_IDXPACK_OUTFD, fd);
1096 const struct got_error *
1097 got_privsep_recv_index_progress(int *done, int *nobj_total,
1098 int *nobj_indexed, int *nobj_loose, int *nobj_resolved,
1099 struct imsgbuf *ibuf)
1101 const struct got_error *err = NULL;
1102 struct imsg imsg;
1103 struct got_imsg_index_pack_progress *iprogress;
1104 size_t datalen;
1106 *done = 0;
1107 *nobj_total = 0;
1108 *nobj_indexed = 0;
1109 *nobj_resolved = 0;
1111 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1112 if (err)
1113 return err;
1115 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1116 switch (imsg.hdr.type) {
1117 case GOT_IMSG_IDXPACK_PROGRESS:
1118 if (datalen < sizeof(*iprogress)) {
1119 err = got_error(GOT_ERR_PRIVSEP_LEN);
1120 break;
1122 iprogress = (struct got_imsg_index_pack_progress *)imsg.data;
1123 if (iprogress->nobj_total < 0 || iprogress->nobj_indexed < 0 ||
1124 iprogress->nobj_loose < 0 || iprogress->nobj_resolved < 0) {
1125 err = got_error(GOT_ERR_RANGE);
1126 break;
1128 *nobj_total = iprogress->nobj_total;
1129 *nobj_indexed = iprogress->nobj_indexed;
1130 *nobj_loose = iprogress->nobj_loose;
1131 *nobj_resolved = iprogress->nobj_resolved;
1132 break;
1133 case GOT_IMSG_IDXPACK_DONE:
1134 if (datalen != 0) {
1135 err = got_error(GOT_ERR_PRIVSEP_LEN);
1136 break;
1138 *done = 1;
1139 break;
1140 default:
1141 err = got_error(GOT_ERR_PRIVSEP_MSG);
1142 break;
1145 imsg_free(&imsg);
1146 return err;
1149 const struct got_error *
1150 got_privsep_get_imsg_obj(struct got_object **obj, struct imsg *imsg,
1151 struct imsgbuf *ibuf)
1153 struct got_imsg_object *iobj;
1154 size_t datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1156 if (datalen != sizeof(*iobj))
1157 return got_error(GOT_ERR_PRIVSEP_LEN);
1158 iobj = imsg->data;
1160 if (iobj->pack_offset < 0)
1161 return got_error(GOT_ERR_PACK_OFFSET);
1163 *obj = calloc(1, sizeof(**obj));
1164 if (*obj == NULL)
1165 return got_error_from_errno("calloc");
1167 memcpy(&(*obj)->id, &iobj->id, sizeof(iobj->id));
1168 (*obj)->type = iobj->type;
1169 (*obj)->flags = iobj->flags;
1170 (*obj)->hdrlen = iobj->hdrlen;
1171 (*obj)->size = iobj->size;
1172 /* path_packfile is handled by caller */
1173 if (iobj->flags & GOT_OBJ_FLAG_PACKED) {
1174 (*obj)->pack_offset = iobj->pack_offset;
1175 (*obj)->pack_idx = iobj->pack_idx;
1177 STAILQ_INIT(&(*obj)->deltas.entries);
1178 return NULL;
1181 const struct got_error *
1182 got_privsep_recv_obj(struct got_object **obj, struct imsgbuf *ibuf)
1184 const struct got_error *err = NULL;
1185 struct imsg imsg;
1186 const size_t min_datalen =
1187 MIN(sizeof(struct got_imsg_error), sizeof(struct got_imsg_object));
1189 *obj = NULL;
1191 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
1192 if (err)
1193 return err;
1195 switch (imsg.hdr.type) {
1196 case GOT_IMSG_OBJECT:
1197 err = got_privsep_get_imsg_obj(obj, &imsg, ibuf);
1198 break;
1199 default:
1200 err = got_error(GOT_ERR_PRIVSEP_MSG);
1201 break;
1204 imsg_free(&imsg);
1206 return err;
1209 static const struct got_error *
1210 send_commit_logmsg(struct imsgbuf *ibuf, struct got_commit_object *commit,
1211 size_t logmsg_len)
1213 const struct got_error *err = NULL;
1214 size_t offset, remain;
1216 offset = 0;
1217 remain = logmsg_len;
1218 while (remain > 0) {
1219 size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE, remain);
1221 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_LOGMSG, 0, 0, -1,
1222 commit->logmsg + offset, n) == -1) {
1223 err = got_error_from_errno("imsg_compose "
1224 "COMMIT_LOGMSG");
1225 break;
1228 err = flush_imsg(ibuf);
1229 if (err)
1230 break;
1232 offset += n;
1233 remain -= n;
1236 return err;
1239 const struct got_error *
1240 got_privsep_send_commit(struct imsgbuf *ibuf, struct got_commit_object *commit)
1242 const struct got_error *err = NULL;
1243 struct got_imsg_commit_object *icommit;
1244 uint8_t *buf;
1245 size_t len, total;
1246 struct got_object_qid *qid;
1247 size_t author_len = strlen(commit->author);
1248 size_t committer_len = strlen(commit->committer);
1249 size_t logmsg_len = strlen(commit->logmsg);
1251 total = sizeof(*icommit) + author_len + committer_len +
1252 commit->nparents * sizeof(struct got_object_id);
1254 buf = malloc(total);
1255 if (buf == NULL)
1256 return got_error_from_errno("malloc");
1258 icommit = (struct got_imsg_commit_object *)buf;
1259 memcpy(&icommit->tree_id, commit->tree_id, sizeof(icommit->tree_id));
1260 icommit->author_len = author_len;
1261 icommit->author_time = commit->author_time;
1262 icommit->author_gmtoff = commit->author_gmtoff;
1263 icommit->committer_len = committer_len;
1264 icommit->committer_time = commit->committer_time;
1265 icommit->committer_gmtoff = commit->committer_gmtoff;
1266 icommit->logmsg_len = logmsg_len;
1267 icommit->nparents = commit->nparents;
1269 len = sizeof(*icommit);
1270 memcpy(buf + len, commit->author, author_len);
1271 len += author_len;
1272 memcpy(buf + len, commit->committer, committer_len);
1273 len += committer_len;
1274 STAILQ_FOREACH(qid, &commit->parent_ids, entry) {
1275 memcpy(buf + len, &qid->id, sizeof(qid->id));
1276 len += sizeof(qid->id);
1279 if (imsg_compose(ibuf, GOT_IMSG_COMMIT, 0, 0, -1, buf, len) == -1) {
1280 err = got_error_from_errno("imsg_compose COMMIT");
1281 goto done;
1284 if (logmsg_len == 0 ||
1285 logmsg_len + len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
1286 err = flush_imsg(ibuf);
1287 if (err)
1288 goto done;
1290 err = send_commit_logmsg(ibuf, commit, logmsg_len);
1291 done:
1292 free(buf);
1293 return err;
1296 static const struct got_error *
1297 get_commit_from_imsg(struct got_commit_object **commit,
1298 struct imsg *imsg, size_t datalen, struct imsgbuf *ibuf)
1300 const struct got_error *err = NULL;
1301 struct got_imsg_commit_object *icommit;
1302 size_t len = 0;
1303 int i;
1305 if (datalen < sizeof(*icommit))
1306 return got_error(GOT_ERR_PRIVSEP_LEN);
1308 icommit = imsg->data;
1309 if (datalen != sizeof(*icommit) + icommit->author_len +
1310 icommit->committer_len +
1311 icommit->nparents * sizeof(struct got_object_id))
1312 return got_error(GOT_ERR_PRIVSEP_LEN);
1314 if (icommit->nparents < 0)
1315 return got_error(GOT_ERR_PRIVSEP_LEN);
1317 len += sizeof(*icommit);
1319 *commit = got_object_commit_alloc_partial();
1320 if (*commit == NULL)
1321 return got_error_from_errno(
1322 "got_object_commit_alloc_partial");
1324 memcpy((*commit)->tree_id, &icommit->tree_id,
1325 sizeof(icommit->tree_id));
1326 (*commit)->author_time = icommit->author_time;
1327 (*commit)->author_gmtoff = icommit->author_gmtoff;
1328 (*commit)->committer_time = icommit->committer_time;
1329 (*commit)->committer_gmtoff = icommit->committer_gmtoff;
1331 (*commit)->author = strndup(imsg->data + len, icommit->author_len);
1332 if ((*commit)->author == NULL) {
1333 err = got_error_from_errno("strndup");
1334 goto done;
1336 len += icommit->author_len;
1338 (*commit)->committer = strndup(imsg->data + len,
1339 icommit->committer_len);
1340 if ((*commit)->committer == NULL) {
1341 err = got_error_from_errno("strndup");
1342 goto done;
1344 len += icommit->committer_len;
1346 if (icommit->logmsg_len == 0) {
1347 (*commit)->logmsg = strdup("");
1348 if ((*commit)->logmsg == NULL) {
1349 err = got_error_from_errno("strdup");
1350 goto done;
1352 } else {
1353 size_t offset = 0, remain = icommit->logmsg_len;
1355 (*commit)->logmsg = malloc(icommit->logmsg_len + 1);
1356 if ((*commit)->logmsg == NULL) {
1357 err = got_error_from_errno("malloc");
1358 goto done;
1360 while (remain > 0) {
1361 struct imsg imsg_log;
1362 size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE,
1363 remain);
1365 err = got_privsep_recv_imsg(&imsg_log, ibuf, n);
1366 if (err)
1367 goto done;
1369 if (imsg_log.hdr.type != GOT_IMSG_COMMIT_LOGMSG) {
1370 err = got_error(GOT_ERR_PRIVSEP_MSG);
1371 goto done;
1374 memcpy((*commit)->logmsg + offset,
1375 imsg_log.data, n);
1376 imsg_free(&imsg_log);
1377 offset += n;
1378 remain -= n;
1380 (*commit)->logmsg[icommit->logmsg_len] = '\0';
1383 for (i = 0; i < icommit->nparents; i++) {
1384 struct got_object_qid *qid;
1386 err = got_object_qid_alloc_partial(&qid);
1387 if (err)
1388 break;
1389 memcpy(&qid->id, imsg->data + len +
1390 i * sizeof(qid->id), sizeof(qid->id));
1391 STAILQ_INSERT_TAIL(&(*commit)->parent_ids, qid, entry);
1392 (*commit)->nparents++;
1394 done:
1395 if (err) {
1396 got_object_commit_close(*commit);
1397 *commit = NULL;
1399 return err;
1402 const struct got_error *
1403 got_privsep_recv_commit(struct got_commit_object **commit, struct imsgbuf *ibuf)
1405 const struct got_error *err = NULL;
1406 struct imsg imsg;
1407 size_t datalen;
1408 const size_t min_datalen =
1409 MIN(sizeof(struct got_imsg_error),
1410 sizeof(struct got_imsg_commit_object));
1412 *commit = NULL;
1414 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
1415 if (err)
1416 return err;
1418 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1420 switch (imsg.hdr.type) {
1421 case GOT_IMSG_COMMIT:
1422 err = get_commit_from_imsg(commit, &imsg, datalen, ibuf);
1423 break;
1424 default:
1425 err = got_error(GOT_ERR_PRIVSEP_MSG);
1426 break;
1429 imsg_free(&imsg);
1431 return err;
1434 static const struct got_error *
1435 send_tree_entries_batch(struct imsgbuf *ibuf,
1436 struct got_parsed_tree_entry *entries, int idx0, int idxN, size_t len)
1438 struct ibuf *wbuf;
1439 struct got_imsg_tree_entries ientries;
1440 int i;
1442 memset(&ientries, 0, sizeof(ientries));
1444 wbuf = imsg_create(ibuf, GOT_IMSG_TREE_ENTRIES, 0, 0, len);
1445 if (wbuf == NULL)
1446 return got_error_from_errno("imsg_create TREE_ENTRY");
1448 ientries.nentries = idxN - idx0 + 1;
1449 if (imsg_add(wbuf, &ientries, sizeof(ientries)) == -1)
1450 return got_error_from_errno("imsg_add TREE_ENTRY");
1452 for (i = idx0; i <= idxN; i++) {
1453 struct got_parsed_tree_entry *pte = &entries[i];
1455 /* Keep in sync with struct got_imsg_tree_entry definition! */
1456 if (imsg_add(wbuf, pte->id, SHA1_DIGEST_LENGTH) == -1)
1457 return got_error_from_errno("imsg_add TREE_ENTRY");
1458 if (imsg_add(wbuf, &pte->mode, sizeof(pte->mode)) == -1)
1459 return got_error_from_errno("imsg_add TREE_ENTRY");
1460 if (imsg_add(wbuf, &pte->namelen, sizeof(pte->namelen)) == -1)
1461 return got_error_from_errno("imsg_add TREE_ENTRY");
1463 /* Remaining bytes are the entry's name. */
1464 if (imsg_add(wbuf, pte->name, pte->namelen) == -1)
1465 return got_error_from_errno("imsg_add TREE_ENTRY");
1468 imsg_close(ibuf, wbuf);
1469 return NULL;
1472 static const struct got_error *
1473 send_tree_entries(struct imsgbuf *ibuf, struct got_parsed_tree_entry *entries,
1474 int nentries)
1476 const struct got_error *err = NULL;
1477 int i, j;
1478 size_t entries_len = sizeof(struct got_imsg_tree_entries);
1480 i = 0;
1481 for (j = 0; j < nentries; j++) {
1482 struct got_parsed_tree_entry *pte = &entries[j];
1483 size_t len = sizeof(struct got_imsg_tree_entry) + pte->namelen;
1485 if (j > 0 &&
1486 entries_len + len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
1487 err = send_tree_entries_batch(ibuf, entries,
1488 i, j - 1, entries_len);
1489 if (err)
1490 return err;
1491 i = j;
1492 entries_len = sizeof(struct got_imsg_tree_entries);
1495 entries_len += len;
1498 if (j > 0) {
1499 err = send_tree_entries_batch(ibuf, entries, i, j - 1,
1500 entries_len);
1501 if (err)
1502 return err;
1505 return NULL;
1508 const struct got_error *
1509 got_privsep_send_tree(struct imsgbuf *ibuf,
1510 struct got_parsed_tree_entry *entries, int nentries)
1512 const struct got_error *err = NULL;
1513 struct got_imsg_tree_object itree;
1515 memset(&itree, 0, sizeof(itree));
1516 itree.nentries = nentries;
1517 if (imsg_compose(ibuf, GOT_IMSG_TREE, 0, 0, -1, &itree, sizeof(itree))
1518 == -1)
1519 return got_error_from_errno("imsg_compose TREE");
1521 err = send_tree_entries(ibuf, entries, nentries);
1522 if (err)
1523 return err;
1525 return flush_imsg(ibuf);
1529 static const struct got_error *
1530 recv_tree_entries(void *data, size_t datalen, struct got_tree_object *tree,
1531 int *nentries)
1533 const struct got_error *err = NULL;
1534 struct got_imsg_tree_entries *ientries;
1535 struct got_tree_entry *te;
1536 size_t te_offset;
1537 size_t i;
1539 if (datalen <= sizeof(*ientries) ||
1540 datalen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
1541 return got_error(GOT_ERR_PRIVSEP_LEN);
1543 ientries = (struct got_imsg_tree_entries *)data;
1544 if (ientries->nentries > INT_MAX) {
1545 return got_error_msg(GOT_ERR_NO_SPACE,
1546 "too many tree entries");
1549 te_offset = sizeof(*ientries);
1550 for (i = 0; i < ientries->nentries; i++) {
1551 struct got_imsg_tree_entry ite;
1552 const char *te_name;
1553 uint8_t *buf = (uint8_t *)data + te_offset;
1555 if (te_offset >= datalen) {
1556 err = got_error(GOT_ERR_PRIVSEP_LEN);
1557 break;
1560 /* Might not be aligned, size is ~32 bytes. */
1561 memcpy(&ite, buf, sizeof(ite));
1563 if (ite.namelen >= sizeof(te->name)) {
1564 err = got_error(GOT_ERR_PRIVSEP_LEN);
1565 break;
1567 if (te_offset + sizeof(ite) + ite.namelen > datalen) {
1568 err = got_error(GOT_ERR_PRIVSEP_LEN);
1569 break;
1572 if (*nentries >= tree->nentries) {
1573 err = got_error(GOT_ERR_PRIVSEP_LEN);
1574 break;
1576 te = &tree->entries[*nentries];
1577 te_name = buf + sizeof(ite);
1578 memcpy(te->name, te_name, ite.namelen);
1579 te->name[ite.namelen] = '\0';
1580 memcpy(te->id.sha1, ite.id, SHA1_DIGEST_LENGTH);
1581 te->mode = ite.mode;
1582 te->idx = *nentries;
1583 (*nentries)++;
1585 te_offset += sizeof(ite) + ite.namelen;
1588 return err;
1591 const struct got_error *
1592 got_privsep_recv_tree(struct got_tree_object **tree, struct imsgbuf *ibuf)
1594 const struct got_error *err = NULL;
1595 const size_t min_datalen =
1596 MIN(sizeof(struct got_imsg_error),
1597 sizeof(struct got_imsg_tree_object));
1598 struct got_imsg_tree_object *itree;
1599 int nentries = 0;
1601 *tree = NULL;
1603 while (*tree == NULL || nentries < (*tree)->nentries) {
1604 struct imsg imsg;
1605 size_t datalen;
1607 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
1608 if (err)
1609 break;
1611 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1613 switch (imsg.hdr.type) {
1614 case GOT_IMSG_TREE:
1615 /* This message should only appear once. */
1616 if (*tree != NULL) {
1617 err = got_error(GOT_ERR_PRIVSEP_MSG);
1618 break;
1620 if (datalen != sizeof(*itree)) {
1621 err = got_error(GOT_ERR_PRIVSEP_LEN);
1622 break;
1624 itree = imsg.data;
1625 if (itree->nentries < 0) {
1626 err = got_error(GOT_ERR_PRIVSEP_LEN);
1627 break;
1629 *tree = malloc(sizeof(**tree));
1630 if (*tree == NULL) {
1631 err = got_error_from_errno("malloc");
1632 break;
1634 (*tree)->entries = calloc(itree->nentries,
1635 sizeof(struct got_tree_entry));
1636 if ((*tree)->entries == NULL) {
1637 err = got_error_from_errno("malloc");
1638 free(*tree);
1639 *tree = NULL;
1640 break;
1642 (*tree)->nentries = itree->nentries;
1643 (*tree)->refcnt = 0;
1644 break;
1645 case GOT_IMSG_TREE_ENTRIES:
1646 /* This message should be preceeded by GOT_IMSG_TREE. */
1647 if (*tree == NULL) {
1648 err = got_error(GOT_ERR_PRIVSEP_MSG);
1649 break;
1651 err = recv_tree_entries(imsg.data, datalen,
1652 *tree, &nentries);
1653 break;
1654 default:
1655 err = got_error(GOT_ERR_PRIVSEP_MSG);
1656 break;
1659 imsg_free(&imsg);
1660 if (err)
1661 break;
1664 if (*tree && (*tree)->nentries != nentries) {
1665 if (err == NULL)
1666 err = got_error(GOT_ERR_PRIVSEP_LEN);
1667 got_object_tree_close(*tree);
1668 *tree = NULL;
1671 return err;
1674 const struct got_error *
1675 got_privsep_send_blob(struct imsgbuf *ibuf, size_t size, size_t hdrlen,
1676 const uint8_t *data)
1678 struct got_imsg_blob iblob;
1680 memset(&iblob, 0, sizeof(iblob));
1681 iblob.size = size;
1682 iblob.hdrlen = hdrlen;
1684 if (data) {
1685 uint8_t *buf;
1687 if (size > GOT_PRIVSEP_INLINE_BLOB_DATA_MAX)
1688 return got_error(GOT_ERR_NO_SPACE);
1690 buf = malloc(sizeof(iblob) + size);
1691 if (buf == NULL)
1692 return got_error_from_errno("malloc");
1694 memcpy(buf, &iblob, sizeof(iblob));
1695 memcpy(buf + sizeof(iblob), data, size);
1696 if (imsg_compose(ibuf, GOT_IMSG_BLOB, 0, 0, -1, buf,
1697 sizeof(iblob) + size) == -1) {
1698 free(buf);
1699 return got_error_from_errno("imsg_compose BLOB");
1701 free(buf);
1702 } else {
1703 /* Data has already been written to file descriptor. */
1704 if (imsg_compose(ibuf, GOT_IMSG_BLOB, 0, 0, -1, &iblob,
1705 sizeof(iblob)) == -1)
1706 return got_error_from_errno("imsg_compose BLOB");
1710 return flush_imsg(ibuf);
1713 const struct got_error *
1714 got_privsep_recv_blob(uint8_t **outbuf, size_t *size, size_t *hdrlen,
1715 struct imsgbuf *ibuf)
1717 const struct got_error *err = NULL;
1718 struct imsg imsg;
1719 struct got_imsg_blob *iblob;
1720 size_t datalen;
1722 *outbuf = NULL;
1724 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1725 if (err)
1726 return err;
1728 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1730 switch (imsg.hdr.type) {
1731 case GOT_IMSG_BLOB:
1732 if (datalen < sizeof(*iblob)) {
1733 err = got_error(GOT_ERR_PRIVSEP_LEN);
1734 break;
1736 iblob = imsg.data;
1737 *size = iblob->size;
1738 *hdrlen = iblob->hdrlen;
1740 if (datalen == sizeof(*iblob)) {
1741 /* Data has been written to file descriptor. */
1742 break;
1745 if (*size > GOT_PRIVSEP_INLINE_BLOB_DATA_MAX ||
1746 *size > datalen + sizeof(*iblob)) {
1747 err = got_error(GOT_ERR_PRIVSEP_LEN);
1748 break;
1751 *outbuf = malloc(*size);
1752 if (*outbuf == NULL) {
1753 err = got_error_from_errno("malloc");
1754 break;
1756 memcpy(*outbuf, imsg.data + sizeof(*iblob), *size);
1757 break;
1758 default:
1759 err = got_error(GOT_ERR_PRIVSEP_MSG);
1760 break;
1763 imsg_free(&imsg);
1765 return err;
1768 static const struct got_error *
1769 send_tagmsg(struct imsgbuf *ibuf, struct got_tag_object *tag, size_t tagmsg_len)
1771 const struct got_error *err = NULL;
1772 size_t offset, remain;
1774 offset = 0;
1775 remain = tagmsg_len;
1776 while (remain > 0) {
1777 size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE, remain);
1779 if (imsg_compose(ibuf, GOT_IMSG_TAG_TAGMSG, 0, 0, -1,
1780 tag->tagmsg + offset, n) == -1) {
1781 err = got_error_from_errno("imsg_compose TAG_TAGMSG");
1782 break;
1785 err = flush_imsg(ibuf);
1786 if (err)
1787 break;
1789 offset += n;
1790 remain -= n;
1793 return err;
1796 const struct got_error *
1797 got_privsep_send_tag(struct imsgbuf *ibuf, struct got_tag_object *tag)
1799 const struct got_error *err = NULL;
1800 struct got_imsg_tag_object *itag;
1801 uint8_t *buf;
1802 size_t len, total;
1803 size_t tag_len = strlen(tag->tag);
1804 size_t tagger_len = strlen(tag->tagger);
1805 size_t tagmsg_len = strlen(tag->tagmsg);
1807 total = sizeof(*itag) + tag_len + tagger_len + tagmsg_len;
1809 buf = malloc(total);
1810 if (buf == NULL)
1811 return got_error_from_errno("malloc");
1813 itag = (struct got_imsg_tag_object *)buf;
1814 memcpy(&itag->id, &tag->id, sizeof(itag->id));
1815 itag->obj_type = tag->obj_type;
1816 itag->tag_len = tag_len;
1817 itag->tagger_len = tagger_len;
1818 itag->tagger_time = tag->tagger_time;
1819 itag->tagger_gmtoff = tag->tagger_gmtoff;
1820 itag->tagmsg_len = tagmsg_len;
1822 len = sizeof(*itag);
1823 memcpy(buf + len, tag->tag, tag_len);
1824 len += tag_len;
1825 memcpy(buf + len, tag->tagger, tagger_len);
1826 len += tagger_len;
1828 if (imsg_compose(ibuf, GOT_IMSG_TAG, 0, 0, -1, buf, len) == -1) {
1829 err = got_error_from_errno("imsg_compose TAG");
1830 goto done;
1833 if (tagmsg_len == 0 ||
1834 tagmsg_len + len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
1835 err = flush_imsg(ibuf);
1836 if (err)
1837 goto done;
1839 err = send_tagmsg(ibuf, tag, tagmsg_len);
1840 done:
1841 free(buf);
1842 return err;
1845 const struct got_error *
1846 got_privsep_recv_tag(struct got_tag_object **tag, struct imsgbuf *ibuf)
1848 const struct got_error *err = NULL;
1849 struct imsg imsg;
1850 struct got_imsg_tag_object *itag;
1851 size_t len, datalen;
1852 const size_t min_datalen =
1853 MIN(sizeof(struct got_imsg_error),
1854 sizeof(struct got_imsg_tag_object));
1856 *tag = NULL;
1858 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
1859 if (err)
1860 return err;
1862 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1863 len = 0;
1865 switch (imsg.hdr.type) {
1866 case GOT_IMSG_TAG:
1867 if (datalen < sizeof(*itag)) {
1868 err = got_error(GOT_ERR_PRIVSEP_LEN);
1869 break;
1871 itag = imsg.data;
1872 if (datalen != sizeof(*itag) + itag->tag_len +
1873 itag->tagger_len) {
1874 err = got_error(GOT_ERR_PRIVSEP_LEN);
1875 break;
1877 len += sizeof(*itag);
1879 *tag = calloc(1, sizeof(**tag));
1880 if (*tag == NULL) {
1881 err = got_error_from_errno("calloc");
1882 break;
1885 memcpy(&(*tag)->id, &itag->id, sizeof(itag->id));
1887 (*tag)->tag = strndup(imsg.data + len, itag->tag_len);
1888 if ((*tag)->tag == NULL) {
1889 err = got_error_from_errno("strndup");
1890 break;
1892 len += itag->tag_len;
1894 (*tag)->obj_type = itag->obj_type;
1895 (*tag)->tagger_time = itag->tagger_time;
1896 (*tag)->tagger_gmtoff = itag->tagger_gmtoff;
1898 (*tag)->tagger = strndup(imsg.data + len, itag->tagger_len);
1899 if ((*tag)->tagger == NULL) {
1900 err = got_error_from_errno("strndup");
1901 break;
1903 len += itag->tagger_len;
1905 if (itag->tagmsg_len == 0) {
1906 (*tag)->tagmsg = strdup("");
1907 if ((*tag)->tagmsg == NULL) {
1908 err = got_error_from_errno("strdup");
1909 break;
1911 } else {
1912 size_t offset = 0, remain = itag->tagmsg_len;
1914 (*tag)->tagmsg = malloc(itag->tagmsg_len + 1);
1915 if ((*tag)->tagmsg == NULL) {
1916 err = got_error_from_errno("malloc");
1917 break;
1919 while (remain > 0) {
1920 struct imsg imsg_log;
1921 size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE,
1922 remain);
1924 err = got_privsep_recv_imsg(&imsg_log, ibuf, n);
1925 if (err)
1926 return err;
1928 if (imsg_log.hdr.type != GOT_IMSG_TAG_TAGMSG)
1929 return got_error(GOT_ERR_PRIVSEP_MSG);
1931 memcpy((*tag)->tagmsg + offset, imsg_log.data,
1932 n);
1933 imsg_free(&imsg_log);
1934 offset += n;
1935 remain -= n;
1937 (*tag)->tagmsg[itag->tagmsg_len] = '\0';
1940 break;
1941 default:
1942 err = got_error(GOT_ERR_PRIVSEP_MSG);
1943 break;
1946 imsg_free(&imsg);
1948 return err;
1951 const struct got_error *
1952 got_privsep_init_pack_child(struct imsgbuf *ibuf, struct got_pack *pack,
1953 struct got_packidx *packidx)
1955 const struct got_error *err = NULL;
1956 struct got_imsg_packidx ipackidx;
1957 struct got_imsg_pack ipack;
1958 int fd;
1960 memset(&ipackidx, 0, sizeof(ipackidx));
1961 memset(&ipack, 0, sizeof(ipack));
1963 ipackidx.len = packidx->len;
1964 ipackidx.packfile_size = pack->filesize;
1965 fd = dup(packidx->fd);
1966 if (fd == -1)
1967 return got_error_from_errno("dup");
1969 if (imsg_compose(ibuf, GOT_IMSG_PACKIDX, 0, 0, fd, &ipackidx,
1970 sizeof(ipackidx)) == -1) {
1971 err = got_error_from_errno("imsg_compose PACKIDX");
1972 close(fd);
1973 return err;
1976 if (strlcpy(ipack.path_packfile, pack->path_packfile,
1977 sizeof(ipack.path_packfile)) >= sizeof(ipack.path_packfile))
1978 return got_error(GOT_ERR_NO_SPACE);
1979 ipack.filesize = pack->filesize;
1981 fd = dup(pack->fd);
1982 if (fd == -1)
1983 return got_error_from_errno("dup");
1985 if (imsg_compose(ibuf, GOT_IMSG_PACK, 0, 0, fd, &ipack, sizeof(ipack))
1986 == -1) {
1987 err = got_error_from_errno("imsg_compose PACK");
1988 close(fd);
1989 return err;
1992 return flush_imsg(ibuf);
1995 const struct got_error *
1996 got_privsep_send_packed_obj_req(struct imsgbuf *ibuf, int idx,
1997 struct got_object_id *id)
1999 struct got_imsg_packed_object iobj;
2001 memset(&iobj, 0, sizeof(iobj));
2002 iobj.idx = idx;
2003 memcpy(&iobj.id, id, sizeof(iobj.id));
2005 if (imsg_compose(ibuf, GOT_IMSG_PACKED_OBJECT_REQUEST, 0, 0, -1,
2006 &iobj, sizeof(iobj)) == -1)
2007 return got_error_from_errno("imsg_compose "
2008 "PACKED_OBJECT_REQUEST");
2010 return flush_imsg(ibuf);
2013 const struct got_error *
2014 got_privsep_send_packed_raw_obj_req(struct imsgbuf *ibuf, int idx,
2015 struct got_object_id *id)
2017 struct got_imsg_packed_object iobj;
2019 memset(&iobj, 0, sizeof(iobj));
2020 iobj.idx = idx;
2021 memcpy(&iobj.id, id, sizeof(iobj.id));
2023 if (imsg_compose(ibuf, GOT_IMSG_PACKED_RAW_OBJECT_REQUEST, 0, 0, -1,
2024 &iobj, sizeof(iobj)) == -1)
2025 return got_error_from_errno("imsg_compose "
2026 "PACKED_OBJECT_REQUEST");
2028 return flush_imsg(ibuf);
2031 const struct got_error *
2032 got_privsep_send_gitconfig_parse_req(struct imsgbuf *ibuf, int fd)
2034 const struct got_error *err = NULL;
2036 if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_PARSE_REQUEST, 0, 0, fd,
2037 NULL, 0) == -1) {
2038 err = got_error_from_errno("imsg_compose "
2039 "GITCONFIG_PARSE_REQUEST");
2040 close(fd);
2041 return err;
2044 return flush_imsg(ibuf);
2047 const struct got_error *
2048 got_privsep_send_gitconfig_repository_format_version_req(struct imsgbuf *ibuf)
2050 if (imsg_compose(ibuf,
2051 GOT_IMSG_GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST, 0, 0, -1,
2052 NULL, 0) == -1)
2053 return got_error_from_errno("imsg_compose "
2054 "GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST");
2056 return flush_imsg(ibuf);
2059 const struct got_error *
2060 got_privsep_send_gitconfig_repository_extensions_req(struct imsgbuf *ibuf)
2062 if (imsg_compose(ibuf,
2063 GOT_IMSG_GITCONFIG_REPOSITORY_EXTENSIONS_REQUEST, 0, 0, -1,
2064 NULL, 0) == -1)
2065 return got_error_from_errno("imsg_compose "
2066 "GITCONFIG_REPOSITORY_EXTENSIONS_REQUEST");
2068 return flush_imsg(ibuf);
2072 const struct got_error *
2073 got_privsep_send_gitconfig_author_name_req(struct imsgbuf *ibuf)
2075 if (imsg_compose(ibuf,
2076 GOT_IMSG_GITCONFIG_AUTHOR_NAME_REQUEST, 0, 0, -1, NULL, 0) == -1)
2077 return got_error_from_errno("imsg_compose "
2078 "GITCONFIG_AUTHOR_NAME_REQUEST");
2080 return flush_imsg(ibuf);
2083 const struct got_error *
2084 got_privsep_send_gitconfig_author_email_req(struct imsgbuf *ibuf)
2086 if (imsg_compose(ibuf,
2087 GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST, 0, 0, -1, NULL, 0) == -1)
2088 return got_error_from_errno("imsg_compose "
2089 "GITCONFIG_AUTHOR_EMAIL_REQUEST");
2091 return flush_imsg(ibuf);
2094 const struct got_error *
2095 got_privsep_send_gitconfig_remotes_req(struct imsgbuf *ibuf)
2097 if (imsg_compose(ibuf,
2098 GOT_IMSG_GITCONFIG_REMOTES_REQUEST, 0, 0, -1, NULL, 0) == -1)
2099 return got_error_from_errno("imsg_compose "
2100 "GITCONFIG_REMOTE_REQUEST");
2102 return flush_imsg(ibuf);
2105 const struct got_error *
2106 got_privsep_send_gitconfig_owner_req(struct imsgbuf *ibuf)
2108 if (imsg_compose(ibuf,
2109 GOT_IMSG_GITCONFIG_OWNER_REQUEST, 0, 0, -1, NULL, 0) == -1)
2110 return got_error_from_errno("imsg_compose "
2111 "GITCONFIG_OWNER_REQUEST");
2113 return flush_imsg(ibuf);
2116 const struct got_error *
2117 got_privsep_recv_gitconfig_str(char **str, struct imsgbuf *ibuf)
2119 const struct got_error *err = NULL;
2120 struct imsg imsg;
2121 size_t datalen;
2123 *str = NULL;
2125 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2126 if (err)
2127 return err;
2128 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2130 switch (imsg.hdr.type) {
2131 case GOT_IMSG_GITCONFIG_STR_VAL:
2132 if (datalen == 0)
2133 break;
2134 *str = strndup(imsg.data, datalen);
2135 if (*str == NULL) {
2136 err = got_error_from_errno("strndup");
2137 break;
2139 break;
2140 default:
2141 err = got_error(GOT_ERR_PRIVSEP_MSG);
2142 break;
2145 imsg_free(&imsg);
2146 return err;
2149 const struct got_error *
2150 got_privsep_recv_gitconfig_pair(char **key, char **val, struct imsgbuf *ibuf)
2152 const struct got_error *err = NULL;
2153 struct got_imsg_gitconfig_pair p;
2154 struct imsg imsg;
2155 size_t datalen;
2156 uint8_t *data;
2158 *key = *val = NULL;
2160 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2161 if (err)
2162 return err;
2164 data = imsg.data;
2165 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2167 if (imsg.hdr.type != GOT_IMSG_GITCONFIG_PAIR) {
2168 err = got_error(GOT_ERR_PRIVSEP_MSG);
2169 goto done;
2172 if (datalen < sizeof(p)) {
2173 err = got_error(GOT_ERR_PRIVSEP_LEN);
2174 goto done;
2177 memcpy(&p, data, sizeof(p));
2178 data += sizeof(p);
2180 if (datalen != sizeof(p) + p.klen + p.vlen) {
2181 err = got_error(GOT_ERR_PRIVSEP_LEN);
2182 goto done;
2185 *key = strndup(data, p.klen);
2186 if (*key == NULL) {
2187 err = got_error_from_errno("strndup");
2188 goto done;
2190 data += p.klen;
2192 *val = strndup(data, p.vlen);
2193 if (*val == NULL) {
2194 err = got_error_from_errno("strndup");
2195 goto done;
2198 done:
2199 imsg_free(&imsg);
2200 return err;
2203 const struct got_error *
2204 got_privsep_recv_gitconfig_int(int *val, struct imsgbuf *ibuf)
2206 const struct got_error *err = NULL;
2207 struct imsg imsg;
2208 size_t datalen;
2209 const size_t min_datalen =
2210 MIN(sizeof(struct got_imsg_error), sizeof(int));
2212 *val = 0;
2214 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
2215 if (err)
2216 return err;
2217 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2219 switch (imsg.hdr.type) {
2220 case GOT_IMSG_GITCONFIG_INT_VAL:
2221 if (datalen != sizeof(*val)) {
2222 err = got_error(GOT_ERR_PRIVSEP_LEN);
2223 break;
2225 memcpy(val, imsg.data, sizeof(*val));
2226 break;
2227 default:
2228 err = got_error(GOT_ERR_PRIVSEP_MSG);
2229 break;
2232 imsg_free(&imsg);
2233 return err;
2236 static void
2237 free_remote_data(struct got_remote_repo *remote)
2239 int i;
2241 free(remote->name);
2242 free(remote->fetch_url);
2243 free(remote->send_url);
2244 for (i = 0; i < remote->nfetch_branches; i++)
2245 free(remote->fetch_branches[i]);
2246 free(remote->fetch_branches);
2247 for (i = 0; i < remote->nsend_branches; i++)
2248 free(remote->send_branches[i]);
2249 free(remote->send_branches);
2250 for (i = 0; i < remote->nfetch_refs; i++)
2251 free(remote->fetch_refs[i]);
2252 free(remote->fetch_refs);
2255 const struct got_error *
2256 got_privsep_recv_gitconfig_remotes(struct got_remote_repo **remotes,
2257 int *nremotes, struct imsgbuf *ibuf)
2259 const struct got_error *err = NULL;
2260 struct imsg imsg;
2261 size_t datalen;
2262 struct got_imsg_remotes iremotes;
2263 struct got_imsg_remote iremote;
2265 *remotes = NULL;
2266 *nremotes = 0;
2267 iremotes.nremotes = 0;
2269 err = got_privsep_recv_imsg(&imsg, ibuf, sizeof(iremotes));
2270 if (err)
2271 return err;
2272 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2274 switch (imsg.hdr.type) {
2275 case GOT_IMSG_GITCONFIG_REMOTES:
2276 if (datalen != sizeof(iremotes)) {
2277 err = got_error(GOT_ERR_PRIVSEP_LEN);
2278 break;
2280 memcpy(&iremotes, imsg.data, sizeof(iremotes));
2281 if (iremotes.nremotes == 0) {
2282 imsg_free(&imsg);
2283 return NULL;
2285 break;
2286 default:
2287 imsg_free(&imsg);
2288 return got_error(GOT_ERR_PRIVSEP_MSG);
2291 imsg_free(&imsg);
2293 *remotes = recallocarray(NULL, 0, iremotes.nremotes, sizeof(**remotes));
2294 if (*remotes == NULL)
2295 return got_error_from_errno("recallocarray");
2297 while (*nremotes < iremotes.nremotes) {
2298 struct got_remote_repo *remote;
2300 err = got_privsep_recv_imsg(&imsg, ibuf, sizeof(iremote));
2301 if (err)
2302 break;
2303 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2305 switch (imsg.hdr.type) {
2306 case GOT_IMSG_GITCONFIG_REMOTE:
2307 remote = &(*remotes)[*nremotes];
2308 memset(remote, 0, sizeof(*remote));
2309 if (datalen < sizeof(iremote)) {
2310 err = got_error(GOT_ERR_PRIVSEP_LEN);
2311 break;
2313 memcpy(&iremote, imsg.data, sizeof(iremote));
2314 if (iremote.name_len == 0 ||
2315 iremote.fetch_url_len == 0 ||
2316 iremote.send_url_len == 0 ||
2317 (sizeof(iremote) + iremote.name_len +
2318 iremote.fetch_url_len + iremote.send_url_len) > datalen) {
2319 err = got_error(GOT_ERR_PRIVSEP_LEN);
2320 break;
2322 remote->name = strndup(imsg.data + sizeof(iremote),
2323 iremote.name_len);
2324 if (remote->name == NULL) {
2325 err = got_error_from_errno("strndup");
2326 break;
2328 remote->fetch_url = strndup(imsg.data + sizeof(iremote) +
2329 iremote.name_len, iremote.fetch_url_len);
2330 if (remote->fetch_url == NULL) {
2331 err = got_error_from_errno("strndup");
2332 free_remote_data(remote);
2333 break;
2335 remote->send_url = strndup(imsg.data + sizeof(iremote) +
2336 iremote.name_len + iremote.fetch_url_len,
2337 iremote.send_url_len);
2338 if (remote->send_url == NULL) {
2339 err = got_error_from_errno("strndup");
2340 free_remote_data(remote);
2341 break;
2343 remote->mirror_references = iremote.mirror_references;
2344 remote->fetch_all_branches = iremote.fetch_all_branches;
2345 remote->nfetch_branches = 0;
2346 remote->fetch_branches = NULL;
2347 remote->nsend_branches = 0;
2348 remote->send_branches = NULL;
2349 remote->nfetch_refs = 0;
2350 remote->fetch_refs = NULL;
2351 (*nremotes)++;
2352 break;
2353 default:
2354 err = got_error(GOT_ERR_PRIVSEP_MSG);
2355 break;
2358 imsg_free(&imsg);
2359 if (err)
2360 break;
2363 if (err) {
2364 int i;
2365 for (i = 0; i < *nremotes; i++)
2366 free_remote_data(&(*remotes)[i]);
2367 free(*remotes);
2368 *remotes = NULL;
2369 *nremotes = 0;
2371 return err;
2374 const struct got_error *
2375 got_privsep_send_gotconfig_parse_req(struct imsgbuf *ibuf, int fd)
2377 const struct got_error *err = NULL;
2379 if (imsg_compose(ibuf, GOT_IMSG_GOTCONFIG_PARSE_REQUEST, 0, 0, fd,
2380 NULL, 0) == -1) {
2381 err = got_error_from_errno("imsg_compose "
2382 "GOTCONFIG_PARSE_REQUEST");
2383 close(fd);
2384 return err;
2387 return flush_imsg(ibuf);
2390 const struct got_error *
2391 got_privsep_send_gotconfig_author_req(struct imsgbuf *ibuf)
2393 if (imsg_compose(ibuf,
2394 GOT_IMSG_GOTCONFIG_AUTHOR_REQUEST, 0, 0, -1, NULL, 0) == -1)
2395 return got_error_from_errno("imsg_compose "
2396 "GOTCONFIG_AUTHOR_REQUEST");
2398 return flush_imsg(ibuf);
2401 const struct got_error *
2402 got_privsep_send_gotconfig_allowed_signers_req(struct imsgbuf *ibuf)
2404 if (imsg_compose(ibuf,
2405 GOT_IMSG_GOTCONFIG_ALLOWEDSIGNERS_REQUEST, 0, 0, -1, NULL, 0) == -1)
2406 return got_error_from_errno("imsg_compose "
2407 "GOTCONFIG_ALLOWEDSIGNERS_REQUEST");
2409 return flush_imsg(ibuf);
2412 const struct got_error *
2413 got_privsep_send_gotconfig_revoked_signers_req(struct imsgbuf *ibuf)
2415 if (imsg_compose(ibuf,
2416 GOT_IMSG_GOTCONFIG_REVOKEDSIGNERS_REQUEST, 0, 0, -1, NULL, 0) == -1)
2417 return got_error_from_errno("imsg_compose "
2418 "GOTCONFIG_REVOKEDSIGNERS_REQUEST");
2420 return flush_imsg(ibuf);
2423 const struct got_error *
2424 got_privsep_send_gotconfig_signer_id_req(struct imsgbuf *ibuf)
2426 if (imsg_compose(ibuf,
2427 GOT_IMSG_GOTCONFIG_SIGNERID_REQUEST, 0, 0, -1, NULL, 0) == -1)
2428 return got_error_from_errno("imsg_compose "
2429 "GOTCONFIG_SIGNERID_REQUEST");
2431 return flush_imsg(ibuf);
2434 const struct got_error *
2435 got_privsep_send_gotconfig_remotes_req(struct imsgbuf *ibuf)
2437 if (imsg_compose(ibuf,
2438 GOT_IMSG_GOTCONFIG_REMOTES_REQUEST, 0, 0, -1, NULL, 0) == -1)
2439 return got_error_from_errno("imsg_compose "
2440 "GOTCONFIG_REMOTE_REQUEST");
2442 return flush_imsg(ibuf);
2445 const struct got_error *
2446 got_privsep_recv_gotconfig_str(char **str, struct imsgbuf *ibuf)
2448 const struct got_error *err = NULL;
2449 struct imsg imsg;
2450 size_t datalen;
2452 *str = NULL;
2454 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2455 if (err)
2456 return err;
2457 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2459 switch (imsg.hdr.type) {
2460 case GOT_IMSG_GOTCONFIG_STR_VAL:
2461 if (datalen == 0)
2462 break;
2463 *str = strndup(imsg.data, datalen);
2464 if (*str == NULL) {
2465 err = got_error_from_errno("strndup");
2466 break;
2468 break;
2469 default:
2470 err = got_error(GOT_ERR_PRIVSEP_MSG);
2471 break;
2474 imsg_free(&imsg);
2475 return err;
2478 const struct got_error *
2479 got_privsep_recv_gotconfig_remotes(struct got_remote_repo **remotes,
2480 int *nremotes, struct imsgbuf *ibuf)
2482 const struct got_error *err = NULL;
2483 struct imsg imsg;
2484 size_t datalen;
2485 struct got_imsg_remotes iremotes;
2486 struct got_imsg_remote iremote;
2487 const size_t min_datalen =
2488 MIN(sizeof(struct got_imsg_error), sizeof(iremotes));
2490 *remotes = NULL;
2491 *nremotes = 0;
2492 iremotes.nremotes = 0;
2494 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
2495 if (err)
2496 return err;
2497 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2499 switch (imsg.hdr.type) {
2500 case GOT_IMSG_GOTCONFIG_REMOTES:
2501 if (datalen != sizeof(iremotes)) {
2502 err = got_error(GOT_ERR_PRIVSEP_LEN);
2503 break;
2505 memcpy(&iremotes, imsg.data, sizeof(iremotes));
2506 if (iremotes.nremotes < 0) {
2507 err = got_error(GOT_ERR_PRIVSEP_LEN);
2508 break;
2510 if (iremotes.nremotes == 0) {
2511 imsg_free(&imsg);
2512 return NULL;
2514 break;
2515 default:
2516 imsg_free(&imsg);
2517 return got_error(GOT_ERR_PRIVSEP_MSG);
2520 imsg_free(&imsg);
2522 *remotes = recallocarray(NULL, 0, iremotes.nremotes, sizeof(**remotes));
2523 if (*remotes == NULL)
2524 return got_error_from_errno("recallocarray");
2526 while (*nremotes < iremotes.nremotes) {
2527 struct got_remote_repo *remote;
2528 const size_t min_datalen =
2529 MIN(sizeof(struct got_imsg_error), sizeof(iremote));
2530 int i;
2532 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
2533 if (err)
2534 break;
2535 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2537 switch (imsg.hdr.type) {
2538 case GOT_IMSG_GOTCONFIG_REMOTE:
2539 remote = &(*remotes)[*nremotes];
2540 memset(remote, 0, sizeof(*remote));
2541 if (datalen < sizeof(iremote)) {
2542 err = got_error(GOT_ERR_PRIVSEP_LEN);
2543 break;
2545 memcpy(&iremote, imsg.data, sizeof(iremote));
2546 if (iremote.name_len == 0 ||
2547 (iremote.fetch_url_len == 0 &&
2548 iremote.send_url_len == 0) ||
2549 (sizeof(iremote) + iremote.name_len +
2550 iremote.fetch_url_len + iremote.send_url_len) >
2551 datalen) {
2552 err = got_error(GOT_ERR_PRIVSEP_LEN);
2553 break;
2555 remote->name = strndup(imsg.data + sizeof(iremote),
2556 iremote.name_len);
2557 if (remote->name == NULL) {
2558 err = got_error_from_errno("strndup");
2559 break;
2561 remote->fetch_url = strndup(imsg.data +
2562 sizeof(iremote) + iremote.name_len,
2563 iremote.fetch_url_len);
2564 if (remote->fetch_url == NULL) {
2565 err = got_error_from_errno("strndup");
2566 free_remote_data(remote);
2567 break;
2569 remote->send_url = strndup(imsg.data +
2570 sizeof(iremote) + iremote.name_len +
2571 iremote.fetch_url_len, iremote.send_url_len);
2572 if (remote->send_url == NULL) {
2573 err = got_error_from_errno("strndup");
2574 free_remote_data(remote);
2575 break;
2577 remote->mirror_references = iremote.mirror_references;
2578 remote->fetch_all_branches = iremote.fetch_all_branches;
2579 if (iremote.nfetch_branches > 0) {
2580 remote->fetch_branches = recallocarray(NULL, 0,
2581 iremote.nfetch_branches, sizeof(char *));
2582 if (remote->fetch_branches == NULL) {
2583 err = got_error_from_errno("calloc");
2584 free_remote_data(remote);
2585 break;
2588 remote->nfetch_branches = 0;
2589 for (i = 0; i < iremote.nfetch_branches; i++) {
2590 char *branch;
2591 err = got_privsep_recv_gotconfig_str(&branch,
2592 ibuf);
2593 if (err) {
2594 free_remote_data(remote);
2595 goto done;
2597 remote->fetch_branches[i] = branch;
2598 remote->nfetch_branches++;
2600 if (iremote.nsend_branches > 0) {
2601 remote->send_branches = recallocarray(NULL, 0,
2602 iremote.nsend_branches, sizeof(char *));
2603 if (remote->send_branches == NULL) {
2604 err = got_error_from_errno("calloc");
2605 free_remote_data(remote);
2606 break;
2609 remote->nsend_branches = 0;
2610 for (i = 0; i < iremote.nsend_branches; i++) {
2611 char *branch;
2612 err = got_privsep_recv_gotconfig_str(&branch,
2613 ibuf);
2614 if (err) {
2615 free_remote_data(remote);
2616 goto done;
2618 remote->send_branches[i] = branch;
2619 remote->nsend_branches++;
2621 if (iremote.nfetch_refs > 0) {
2622 remote->fetch_refs = recallocarray(NULL, 0,
2623 iremote.nfetch_refs, sizeof(char *));
2624 if (remote->fetch_refs == NULL) {
2625 err = got_error_from_errno("calloc");
2626 free_remote_data(remote);
2627 break;
2630 remote->nfetch_refs = 0;
2631 for (i = 0; i < iremote.nfetch_refs; i++) {
2632 char *ref;
2633 err = got_privsep_recv_gotconfig_str(&ref,
2634 ibuf);
2635 if (err) {
2636 free_remote_data(remote);
2637 goto done;
2639 remote->fetch_refs[i] = ref;
2640 remote->nfetch_refs++;
2642 (*nremotes)++;
2643 break;
2644 default:
2645 err = got_error(GOT_ERR_PRIVSEP_MSG);
2646 break;
2649 imsg_free(&imsg);
2650 if (err)
2651 break;
2653 done:
2654 if (err) {
2655 int i;
2656 for (i = 0; i < *nremotes; i++)
2657 free_remote_data(&(*remotes)[i]);
2658 free(*remotes);
2659 *remotes = NULL;
2660 *nremotes = 0;
2662 return err;
2665 const struct got_error *
2666 got_privsep_send_commit_traversal_request(struct imsgbuf *ibuf,
2667 struct got_object_id *id, int idx, const char *path)
2669 struct ibuf *wbuf;
2670 size_t path_len = strlen(path);
2672 wbuf = imsg_create(ibuf, GOT_IMSG_COMMIT_TRAVERSAL_REQUEST, 0, 0,
2673 sizeof(struct got_imsg_commit_traversal_request) + path_len);
2674 if (wbuf == NULL)
2675 return got_error_from_errno(
2676 "imsg_create COMMIT_TRAVERSAL_REQUEST");
2678 * Keep in sync with struct got_imsg_commit_traversal_request
2679 * and struct got_imsg_packed_object.
2681 if (imsg_add(wbuf, id, sizeof(*id)) == -1)
2682 return got_error_from_errno("imsg_add "
2683 "COMMIT_TRAVERSAL_REQUEST");
2684 if (imsg_add(wbuf, &idx, sizeof(idx)) == -1)
2685 return got_error_from_errno("imsg_add "
2686 "COMMIT_TRAVERSAL_REQUEST");
2687 if (imsg_add(wbuf, &path_len, sizeof(path_len)) == -1)
2688 return got_error_from_errno("imsg_add "
2689 "COMMIT_TRAVERSAL_REQUEST");
2690 if (imsg_add(wbuf, path, path_len) == -1)
2691 return got_error_from_errno("imsg_add "
2692 "COMMIT_TRAVERSAL_REQUEST");
2694 imsg_close(ibuf, wbuf);
2695 return flush_imsg(ibuf);
2698 const struct got_error *
2699 got_privsep_recv_traversed_commits(struct got_commit_object **changed_commit,
2700 struct got_object_id **changed_commit_id,
2701 struct got_object_id_queue *commit_ids, struct imsgbuf *ibuf)
2703 const struct got_error *err = NULL;
2704 struct imsg imsg;
2705 struct got_imsg_traversed_commits *icommits;
2706 struct got_object_id *ids;
2707 size_t datalen;
2708 int i, done = 0;
2710 *changed_commit = NULL;
2711 *changed_commit_id = NULL;
2713 while (!done) {
2714 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2715 if (err)
2716 return err;
2718 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2719 switch (imsg.hdr.type) {
2720 case GOT_IMSG_TRAVERSED_COMMITS:
2721 icommits = imsg.data;
2722 if (datalen != sizeof(*icommits) +
2723 icommits->ncommits * sizeof(*ids)) {
2724 err = got_error(GOT_ERR_PRIVSEP_LEN);
2725 break;
2727 ids = imsg.data + sizeof(*icommits);
2728 for (i = 0; i < icommits->ncommits; i++) {
2729 struct got_object_qid *qid;
2731 err = got_object_qid_alloc_partial(&qid);
2732 if (err)
2733 break;
2734 memcpy(&qid->id, &ids[i], sizeof(ids[i]));
2735 STAILQ_INSERT_TAIL(commit_ids, qid, entry);
2737 /* The last commit may contain a change. */
2738 if (i == icommits->ncommits - 1) {
2739 *changed_commit_id =
2740 got_object_id_dup(&qid->id);
2741 if (*changed_commit_id == NULL) {
2742 err = got_error_from_errno(
2743 "got_object_id_dup");
2744 break;
2748 break;
2749 case GOT_IMSG_COMMIT:
2750 if (*changed_commit_id == NULL) {
2751 err = got_error(GOT_ERR_PRIVSEP_MSG);
2752 break;
2754 err = get_commit_from_imsg(changed_commit, &imsg,
2755 datalen, ibuf);
2756 break;
2757 case GOT_IMSG_COMMIT_TRAVERSAL_DONE:
2758 done = 1;
2759 break;
2760 default:
2761 err = got_error(GOT_ERR_PRIVSEP_MSG);
2762 break;
2765 imsg_free(&imsg);
2766 if (err)
2767 break;
2770 if (err)
2771 got_object_id_queue_free(commit_ids);
2772 return err;
2775 const struct got_error *
2776 got_privsep_send_enumerated_tree(size_t *totlen, struct imsgbuf *ibuf,
2777 struct got_object_id *tree_id, const char *path,
2778 struct got_parsed_tree_entry *entries, int nentries)
2780 const struct got_error *err = NULL;
2781 struct ibuf *wbuf;
2782 size_t path_len = strlen(path);
2783 size_t msglen;
2785 msglen = sizeof(struct got_imsg_enumerated_tree) + path_len;
2786 wbuf = imsg_create(ibuf, GOT_IMSG_ENUMERATED_TREE, 0, 0, msglen);
2787 if (wbuf == NULL)
2788 return got_error_from_errno("imsg_create ENUMERATED_TREE");
2790 if (imsg_add(wbuf, tree_id->sha1, SHA1_DIGEST_LENGTH) == -1)
2791 return got_error_from_errno("imsg_add ENUMERATED_TREE");
2792 if (imsg_add(wbuf, &nentries, sizeof(nentries)) == -1)
2793 return got_error_from_errno("imsg_add ENUMERATED_TREE");
2794 if (imsg_add(wbuf, path, path_len) == -1)
2795 return got_error_from_errno("imsg_add ENUMERATED_TREE");
2797 imsg_close(ibuf, wbuf);
2799 if (entries) {
2800 err = send_tree_entries(ibuf, entries, nentries);
2801 if (err)
2802 return err;
2805 return flush_imsg(ibuf);
2808 const struct got_error *
2809 got_privsep_send_object_enumeration_request(struct imsgbuf *ibuf)
2811 if (imsg_compose(ibuf, GOT_IMSG_OBJECT_ENUMERATION_REQUEST,
2812 0, 0, -1, NULL, 0) == -1)
2813 return got_error_from_errno("imsg_compose "
2814 "OBJECT_ENUMERATION_REQUEST");
2816 return flush_imsg(ibuf);
2819 const struct got_error *
2820 got_privsep_send_object_enumeration_done(struct imsgbuf *ibuf)
2822 if (imsg_compose(ibuf, GOT_IMSG_OBJECT_ENUMERATION_DONE,
2823 0, 0, -1, NULL, 0) == -1)
2824 return got_error_from_errno("imsg_compose "
2825 "OBJECT_ENUMERATION_DONE");
2827 return flush_imsg(ibuf);
2830 const struct got_error *
2831 got_privsep_send_object_enumeration_incomplete(struct imsgbuf *ibuf)
2833 if (imsg_compose(ibuf, GOT_IMSG_OBJECT_ENUMERATION_INCOMPLETE,
2834 0, 0, -1, NULL, 0) == -1)
2835 return got_error_from_errno("imsg_compose "
2836 "OBJECT_ENUMERATION_INCOMPLETE");
2838 return flush_imsg(ibuf);
2841 const struct got_error *
2842 got_privsep_send_enumerated_commit(struct imsgbuf *ibuf,
2843 struct got_object_id *id, time_t mtime)
2845 struct ibuf *wbuf;
2847 wbuf = imsg_create(ibuf, GOT_IMSG_ENUMERATED_COMMIT, 0, 0,
2848 sizeof(struct got_imsg_enumerated_commit) + SHA1_DIGEST_LENGTH);
2849 if (wbuf == NULL)
2850 return got_error_from_errno("imsg_create ENUMERATED_COMMIT");
2852 /* Keep in sync with struct got_imsg_enumerated_commit! */
2853 if (imsg_add(wbuf, id, SHA1_DIGEST_LENGTH) == -1)
2854 return got_error_from_errno("imsg_add ENUMERATED_COMMIT");
2855 if (imsg_add(wbuf, &mtime, sizeof(mtime)) == -1)
2856 return got_error_from_errno("imsg_add ENUMERATED_COMMIT");
2858 imsg_close(ibuf, wbuf);
2859 /* Don't flush yet, tree entries or ENUMERATION_DONE will follow. */
2860 return NULL;
2863 const struct got_error *
2864 got_privsep_recv_enumerated_objects(int *found_all_objects,
2865 struct imsgbuf *ibuf,
2866 got_object_enumerate_commit_cb cb_commit,
2867 got_object_enumerate_tree_cb cb_tree, void *cb_arg,
2868 struct got_repository *repo)
2870 const struct got_error *err = NULL;
2871 struct imsg imsg;
2872 struct got_imsg_enumerated_commit *icommit = NULL;
2873 struct got_object_id commit_id;
2874 int have_commit = 0;
2875 time_t mtime = 0;
2876 struct got_tree_object tree;
2877 struct got_imsg_enumerated_tree *itree;
2878 struct got_object_id tree_id;
2879 char *path = NULL, *canon_path = NULL;
2880 size_t datalen, path_len;
2881 int nentries = -1;
2882 int done = 0;
2884 *found_all_objects = 0;
2885 memset(&tree, 0, sizeof(tree));
2887 while (!done) {
2888 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2889 if (err)
2890 break;
2892 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2893 switch (imsg.hdr.type) {
2894 case GOT_IMSG_ENUMERATED_COMMIT:
2895 if (have_commit && nentries != -1) {
2896 err = got_error(GOT_ERR_PRIVSEP_MSG);
2897 break;
2899 if (datalen != sizeof(*icommit)) {
2900 err = got_error(GOT_ERR_PRIVSEP_LEN);
2901 break;
2903 icommit = (struct got_imsg_enumerated_commit *)imsg.data;
2904 memcpy(commit_id.sha1, icommit->id, SHA1_DIGEST_LENGTH);
2905 mtime = icommit->mtime;
2906 have_commit = 1;
2907 break;
2908 case GOT_IMSG_ENUMERATED_TREE:
2909 /* Should be preceeded by GOT_IMSG_ENUMERATED_COMMIT. */
2910 if (!have_commit) {
2911 err = got_error(GOT_ERR_PRIVSEP_MSG);
2912 break;
2914 if (datalen < sizeof(*itree)) {
2915 err = got_error(GOT_ERR_PRIVSEP_LEN);
2916 break;
2918 itree = imsg.data;
2919 path_len = datalen - sizeof(*itree);
2920 if (path_len == 0) {
2921 err = got_error(GOT_ERR_PRIVSEP_LEN);
2922 break;
2924 memcpy(tree_id.sha1, itree->id, sizeof(tree_id.sha1));
2925 free(path);
2926 path = strndup(imsg.data + sizeof(*itree), path_len);
2927 if (path == NULL) {
2928 err = got_error_from_errno("strndup");
2929 break;
2931 free(canon_path);
2932 canon_path = malloc(path_len + 1);
2933 if (canon_path == NULL) {
2934 err = got_error_from_errno("malloc");
2935 break;
2937 if (!got_path_is_absolute(path)) {
2938 err = got_error(GOT_ERR_BAD_PATH);
2939 break;
2941 if (got_path_is_root_dir(path)) {
2942 /* XXX check what got_canonpath() does wrong */
2943 canon_path[0] = '/';
2944 canon_path[1] = '\0';
2945 } else {
2946 err = got_canonpath(path, canon_path,
2947 path_len + 1);
2948 if (err)
2949 break;
2951 if (strcmp(path, canon_path) != 0) {
2952 err = got_error(GOT_ERR_BAD_PATH);
2953 break;
2955 if (nentries != -1) {
2956 err = got_error(GOT_ERR_PRIVSEP_MSG);
2957 break;
2959 if (itree->nentries < -1) {
2960 err = got_error(GOT_ERR_PRIVSEP_MSG);
2961 break;
2963 if (itree->nentries == -1) {
2964 /* Tree was not found in pack file. */
2965 err = cb_tree(cb_arg, NULL, mtime, &tree_id,
2966 path, repo);
2967 break;
2969 if (itree->nentries > INT_MAX) {
2970 err = got_error(GOT_ERR_PRIVSEP_LEN);
2971 break;
2973 tree.entries = calloc(itree->nentries,
2974 sizeof(struct got_tree_entry));
2975 if (tree.entries == NULL) {
2976 err = got_error_from_errno("calloc");
2977 break;
2979 if (itree->nentries == 0) {
2980 err = cb_tree(cb_arg, &tree, mtime, &tree_id,
2981 path, repo);
2982 if (err)
2983 break;
2985 /* Prepare for next tree. */
2986 free(tree.entries);
2987 memset(&tree, 0, sizeof(tree));
2988 nentries = -1;
2989 } else {
2990 tree.nentries = itree->nentries;
2991 nentries = 0;
2993 break;
2994 case GOT_IMSG_TREE_ENTRIES:
2995 /* Should be preceeded by GOT_IMSG_ENUMERATED_TREE. */
2996 if (nentries <= -1) {
2997 err = got_error(GOT_ERR_PRIVSEP_MSG);
2998 break;
3000 err = recv_tree_entries(imsg.data, datalen,
3001 &tree, &nentries);
3002 if (err)
3003 break;
3004 if (tree.nentries == nentries) {
3005 err = cb_tree(cb_arg, &tree, mtime, &tree_id,
3006 path, repo);
3007 if (err)
3008 break;
3010 /* Prepare for next tree. */
3011 free(tree.entries);
3012 memset(&tree, 0, sizeof(tree));
3013 nentries = -1;
3015 break;
3016 case GOT_IMSG_TREE_ENUMERATION_DONE:
3017 /* All trees have been found and traversed. */
3018 if (!have_commit || path == NULL || nentries != -1) {
3019 err = got_error(GOT_ERR_PRIVSEP_MSG);
3020 break;
3022 err = cb_commit(cb_arg, mtime, &commit_id, repo);
3023 if (err)
3024 break;
3025 have_commit = 0;
3026 break;
3027 case GOT_IMSG_OBJECT_ENUMERATION_DONE:
3028 *found_all_objects = 1;
3029 done = 1;
3030 break;
3031 case GOT_IMSG_OBJECT_ENUMERATION_INCOMPLETE:
3032 done = 1;
3033 break;
3034 default:
3035 err = got_error(GOT_ERR_PRIVSEP_MSG);
3036 break;
3039 imsg_free(&imsg);
3040 if (err)
3041 break;
3044 free(path);
3045 free(canon_path);
3046 free(tree.entries);
3047 return err;
3050 const struct got_error *
3051 got_privsep_send_raw_delta_req(struct imsgbuf *ibuf, int idx,
3052 struct got_object_id *id)
3054 struct got_imsg_raw_delta_request dreq;
3056 memset(&dreq, 0, sizeof(dreq));
3057 dreq.idx = idx;
3058 memcpy(&dreq.id, id, sizeof(dreq.id));
3060 if (imsg_compose(ibuf, GOT_IMSG_RAW_DELTA_REQUEST, 0, 0, -1,
3061 &dreq, sizeof(dreq)) == -1)
3062 return got_error_from_errno("imsg_compose RAW_DELTA_REQUEST");
3064 return flush_imsg(ibuf);
3067 const struct got_error *
3068 got_privsep_send_raw_delta_outfd(struct imsgbuf *ibuf, int fd)
3070 return send_fd(ibuf, GOT_IMSG_RAW_DELTA_OUTFD, fd);
3073 const struct got_error *
3074 got_privsep_send_raw_delta(struct imsgbuf *ibuf, uint64_t base_size,
3075 uint64_t result_size, off_t delta_size, off_t delta_compressed_size,
3076 off_t delta_offset, off_t delta_out_offset, struct got_object_id *base_id)
3078 struct got_imsg_raw_delta idelta;
3079 int ret;
3081 memset(&idelta, 0, sizeof(idelta));
3082 idelta.base_size = base_size;
3083 idelta.result_size = result_size;
3084 idelta.delta_size = delta_size;
3085 idelta.delta_compressed_size = delta_compressed_size;
3086 idelta.delta_offset = delta_offset;
3087 idelta.delta_out_offset = delta_out_offset;
3088 memcpy(&idelta.base_id, &base_id, sizeof(idelta.base_id));
3090 ret = imsg_compose(ibuf, GOT_IMSG_RAW_DELTA, 0, 0, -1,
3091 &idelta, sizeof(idelta));
3092 if (ret == -1)
3093 return got_error_from_errno("imsg_compose RAW_DELTA");
3095 return flush_imsg(ibuf);
3098 const struct got_error *
3099 got_privsep_recv_raw_delta(uint64_t *base_size, uint64_t *result_size,
3100 off_t *delta_size, off_t *delta_compressed_size, off_t *delta_offset,
3101 off_t *delta_out_offset, struct got_object_id **base_id,
3102 struct imsgbuf *ibuf)
3104 const struct got_error *err = NULL;
3105 struct imsg imsg;
3106 struct got_imsg_raw_delta *delta;
3107 size_t datalen;
3109 *base_size = 0;
3110 *result_size = 0;
3111 *delta_size = 0;
3112 *delta_compressed_size = 0;
3113 *delta_offset = 0;
3114 *delta_out_offset = 0;
3115 *base_id = NULL;
3117 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
3118 if (err)
3119 return err;
3121 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
3123 switch (imsg.hdr.type) {
3124 case GOT_IMSG_RAW_DELTA:
3125 if (datalen != sizeof(*delta)) {
3126 err = got_error(GOT_ERR_PRIVSEP_LEN);
3127 break;
3129 delta = imsg.data;
3130 *base_size = delta->base_size;
3131 *result_size = delta->result_size;
3132 *delta_size = delta->delta_size;
3133 *delta_compressed_size = delta->delta_compressed_size;
3134 *delta_offset = delta->delta_offset;
3135 *delta_out_offset = delta->delta_out_offset;
3136 *base_id = calloc(1, sizeof(**base_id));
3137 if (*base_id == NULL) {
3138 err = got_error_from_errno("malloc");
3139 break;
3141 memcpy(*base_id, &delta->base_id, sizeof(**base_id));
3142 break;
3143 default:
3144 err = got_error(GOT_ERR_PRIVSEP_MSG);
3145 break;
3148 imsg_free(&imsg);
3150 if (err) {
3151 free(*base_id);
3152 *base_id = NULL;
3154 return err;
3157 static const struct got_error *
3158 send_idlist(struct imsgbuf *ibuf, struct got_object_id **ids, size_t nids)
3160 const struct got_error *err = NULL;
3161 struct got_imsg_object_idlist idlist;
3162 struct ibuf *wbuf;
3163 size_t i;
3165 memset(&idlist, 0, sizeof(idlist));
3167 if (nids > GOT_IMSG_OBJ_ID_LIST_MAX_NIDS)
3168 return got_error(GOT_ERR_NO_SPACE);
3170 wbuf = imsg_create(ibuf, GOT_IMSG_OBJ_ID_LIST, 0, 0,
3171 sizeof(idlist) + nids * sizeof(**ids));
3172 if (wbuf == NULL) {
3173 err = got_error_from_errno("imsg_create OBJ_ID_LIST");
3174 return err;
3177 idlist.nids = nids;
3178 if (imsg_add(wbuf, &idlist, sizeof(idlist)) == -1)
3179 return got_error_from_errno("imsg_add OBJ_ID_LIST");
3181 for (i = 0; i < nids; i++) {
3182 struct got_object_id *id = ids[i];
3183 if (imsg_add(wbuf, id, sizeof(*id)) == -1)
3184 return got_error_from_errno("imsg_add OBJ_ID_LIST");
3187 imsg_close(ibuf, wbuf);
3189 return flush_imsg(ibuf);
3192 const struct got_error *
3193 got_privsep_send_object_idlist(struct imsgbuf *ibuf,
3194 struct got_object_id **ids, size_t nids)
3196 const struct got_error *err = NULL;
3197 struct got_object_id *idlist[GOT_IMSG_OBJ_ID_LIST_MAX_NIDS];
3198 int i, queued = 0;
3200 for (i = 0; i < nids; i++) {
3201 idlist[i % nitems(idlist)] = ids[i];
3202 queued++;
3203 if (queued >= nitems(idlist)) {
3204 err = send_idlist(ibuf, idlist, queued);
3205 if (err)
3206 return err;
3207 queued = 0;
3211 if (queued > 0) {
3212 err = send_idlist(ibuf, idlist, queued);
3213 if (err)
3214 return err;
3217 return NULL;
3220 const struct got_error *
3221 got_privsep_send_object_idlist_done(struct imsgbuf *ibuf)
3223 if (imsg_compose(ibuf, GOT_IMSG_OBJ_ID_LIST_DONE, 0, 0, -1, NULL, 0)
3224 == -1)
3225 return got_error_from_errno("imsg_compose OBJ_ID_LIST_DONE");
3227 return flush_imsg(ibuf);
3230 const struct got_error *
3231 got_privsep_recv_object_idlist(int *done, struct got_object_id **ids,
3232 size_t *nids, struct imsgbuf *ibuf)
3234 const struct got_error *err = NULL;
3235 struct imsg imsg;
3236 struct got_imsg_object_idlist *idlist;
3237 size_t datalen;
3239 *ids = NULL;
3240 *done = 0;
3241 *nids = 0;
3243 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
3244 if (err)
3245 return err;
3247 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
3248 switch (imsg.hdr.type) {
3249 case GOT_IMSG_OBJ_ID_LIST:
3250 if (datalen < sizeof(*idlist)) {
3251 err = got_error(GOT_ERR_PRIVSEP_LEN);
3252 break;
3254 idlist = imsg.data;
3255 if (idlist->nids > GOT_IMSG_OBJ_ID_LIST_MAX_NIDS ||
3256 idlist->nids * sizeof(**ids) > datalen - sizeof(*idlist)) {
3257 err = got_error(GOT_ERR_PRIVSEP_LEN);
3258 break;
3260 *nids = idlist->nids;
3261 *ids = calloc(*nids, sizeof(**ids));
3262 if (*ids == NULL) {
3263 err = got_error_from_errno("calloc");
3264 break;
3266 memcpy(*ids, (uint8_t *)imsg.data + sizeof(*idlist),
3267 *nids * sizeof(**ids));
3268 break;
3269 case GOT_IMSG_OBJ_ID_LIST_DONE:
3270 *done = 1;
3271 break;
3272 default:
3273 err = got_error(GOT_ERR_PRIVSEP_MSG);
3274 break;
3277 imsg_free(&imsg);
3279 return err;
3282 const struct got_error *
3283 got_privsep_send_delta_reuse_req(struct imsgbuf *ibuf)
3285 if (imsg_compose(ibuf, GOT_IMSG_DELTA_REUSE_REQUEST, 0, 0, -1, NULL, 0)
3286 == -1)
3287 return got_error_from_errno("imsg_compose DELTA_REUSE_REQUEST");
3289 return flush_imsg(ibuf);
3292 const struct got_error *
3293 got_privsep_send_reused_deltas(struct imsgbuf *ibuf,
3294 struct got_imsg_reused_delta *deltas, size_t ndeltas)
3296 const struct got_error *err = NULL;
3297 struct ibuf *wbuf;
3298 struct got_imsg_reused_deltas ideltas;
3299 size_t i;
3301 memset(&ideltas, 0, sizeof(ideltas));
3303 if (ndeltas > GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS)
3304 return got_error(GOT_ERR_NO_SPACE);
3306 wbuf = imsg_create(ibuf, GOT_IMSG_REUSED_DELTAS, 0, 0,
3307 sizeof(ideltas) + ndeltas * sizeof(*deltas));
3308 if (wbuf == NULL) {
3309 err = got_error_from_errno("imsg_create REUSED_DELTAS");
3310 return err;
3313 ideltas.ndeltas = ndeltas;
3314 if (imsg_add(wbuf, &ideltas, sizeof(ideltas)) == -1)
3315 return got_error_from_errno("imsg_add REUSED_DELTAS");
3317 for (i = 0; i < ndeltas; i++) {
3318 struct got_imsg_reused_delta *delta = &deltas[i];
3319 if (imsg_add(wbuf, delta, sizeof(*delta)) == -1)
3320 return got_error_from_errno("imsg_add REUSED_DELTAS");
3323 imsg_close(ibuf, wbuf);
3325 return flush_imsg(ibuf);
3328 const struct got_error *
3329 got_privsep_send_reused_deltas_done(struct imsgbuf *ibuf)
3331 if (imsg_compose(ibuf, GOT_IMSG_DELTA_REUSE_DONE, 0, 0, -1, NULL, 0)
3332 == -1)
3333 return got_error_from_errno("imsg_compose DELTA_REUSE_DONE");
3335 return flush_imsg(ibuf);
3338 const struct got_error *
3339 got_privsep_recv_reused_deltas(int *done, struct got_imsg_reused_delta *deltas,
3340 size_t *ndeltas, struct imsgbuf *ibuf)
3342 const struct got_error *err = NULL;
3343 struct imsg imsg;
3344 struct got_imsg_reused_deltas *ideltas;
3345 size_t datalen;
3347 *done = 0;
3348 *ndeltas = 0;
3350 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
3351 if (err)
3352 return err;
3354 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
3355 switch (imsg.hdr.type) {
3356 case GOT_IMSG_REUSED_DELTAS:
3357 if (datalen < sizeof(*ideltas)) {
3358 err = got_error(GOT_ERR_PRIVSEP_LEN);
3359 break;
3361 ideltas = imsg.data;
3362 if (ideltas->ndeltas > GOT_IMSG_OBJ_ID_LIST_MAX_NIDS ||
3363 ideltas->ndeltas * sizeof(*deltas) >
3364 datalen - sizeof(*ideltas)) {
3365 err = got_error(GOT_ERR_PRIVSEP_LEN);
3366 break;
3368 *ndeltas = ideltas->ndeltas;
3369 memcpy(deltas, (uint8_t *)imsg.data + sizeof(*ideltas),
3370 *ndeltas * sizeof(*deltas));
3371 break;
3372 case GOT_IMSG_DELTA_REUSE_DONE:
3373 *done = 1;
3374 break;
3375 default:
3376 err = got_error(GOT_ERR_PRIVSEP_MSG);
3377 break;
3380 imsg_free(&imsg);
3382 return err;
3385 const struct got_error *
3386 got_privsep_init_commit_painting(struct imsgbuf *ibuf)
3388 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_PAINTING_INIT,
3389 0, 0, -1, NULL, 0)
3390 == -1)
3391 return got_error_from_errno("imsg_compose "
3392 "COMMIT_PAINTING_INIT");
3394 return flush_imsg(ibuf);
3397 const struct got_error *
3398 got_privsep_send_painting_request(struct imsgbuf *ibuf, int idx,
3399 struct got_object_id *id, intptr_t color)
3401 struct got_imsg_commit_painting_request ireq;
3403 memset(&ireq, 0, sizeof(ireq));
3404 memcpy(&ireq.id, id, sizeof(ireq.id));
3405 ireq.idx = idx;
3406 ireq.color = color;
3408 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_PAINTING_REQUEST, 0, 0, -1,
3409 &ireq, sizeof(ireq)) == -1)
3410 return got_error_from_errno("imsg_compose "
3411 "COMMIT_PAINTING_REQUEST");
3413 return flush_imsg(ibuf);
3416 static const struct got_error *
3417 send_painted_commits(struct got_object_id_queue *ids, int *nids,
3418 size_t remain, int present_in_pack, struct imsgbuf *ibuf)
3420 const struct got_error *err = NULL;
3421 struct ibuf *wbuf = NULL;
3422 struct got_object_qid *qid;
3423 size_t msglen;
3424 int ncommits;
3425 intptr_t color;
3427 msglen = MIN(remain, MAX_IMSGSIZE - IMSG_HEADER_SIZE);
3428 ncommits = (msglen - sizeof(struct got_imsg_painted_commits)) /
3429 sizeof(struct got_imsg_painted_commit);
3431 wbuf = imsg_create(ibuf, GOT_IMSG_PAINTED_COMMITS, 0, 0, msglen);
3432 if (wbuf == NULL) {
3433 err = got_error_from_errno("imsg_create PAINTED_COMMITS");
3434 return err;
3437 /* Keep in sync with struct got_imsg_painted_commits! */
3438 if (imsg_add(wbuf, &ncommits, sizeof(ncommits)) == -1)
3439 return got_error_from_errno("imsg_add PAINTED_COMMITS");
3440 if (imsg_add(wbuf, &present_in_pack, sizeof(present_in_pack)) == -1)
3441 return got_error_from_errno("imsg_add PAINTED_COMMITS");
3443 while (ncommits > 0) {
3444 qid = STAILQ_FIRST(ids);
3445 STAILQ_REMOVE_HEAD(ids, entry);
3446 ncommits--;
3447 (*nids)--;
3448 color = (intptr_t)qid->data;
3450 /* Keep in sync with struct got_imsg_painted_commit! */
3451 if (imsg_add(wbuf, qid->id.sha1, SHA1_DIGEST_LENGTH) == -1)
3452 return got_error_from_errno("imsg_add PAINTED_COMMITS");
3453 if (imsg_add(wbuf, &color, sizeof(color)) == -1)
3454 return got_error_from_errno("imsg_add PAINTED_COMMITS");
3456 got_object_qid_free(qid);
3459 imsg_close(ibuf, wbuf);
3460 return flush_imsg(ibuf);
3463 const struct got_error *
3464 got_privsep_send_painted_commits(struct imsgbuf *ibuf,
3465 struct got_object_id_queue *ids, int *nids,
3466 int present_in_pack, int flush)
3468 const struct got_error *err;
3469 size_t remain;
3471 if (*nids <= 0)
3472 return NULL;
3474 do {
3475 remain = (sizeof(struct got_imsg_painted_commits)) +
3476 *nids * sizeof(struct got_imsg_painted_commit);
3477 if (flush || remain >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
3478 err = send_painted_commits(ids, nids, remain,
3479 present_in_pack, ibuf);
3480 if (err)
3481 return err;
3483 } while (flush && *nids > 0);
3485 return NULL;
3488 const struct got_error *
3489 got_privsep_send_painting_commits_done(struct imsgbuf *ibuf)
3491 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_PAINTING_DONE,
3492 0, 0, -1, NULL, 0)
3493 == -1)
3494 return got_error_from_errno("imsg_compose "
3495 "COMMIT_PAINTING_DONE");
3497 return flush_imsg(ibuf);
3500 const struct got_error *
3501 got_privsep_recv_painted_commits(struct got_object_id_queue *new_ids,
3502 got_privsep_recv_painted_commit_cb cb, void *cb_arg, struct imsgbuf *ibuf)
3504 const struct got_error *err = NULL;
3505 struct imsg imsg;
3506 struct got_imsg_painted_commits icommits;
3507 struct got_imsg_painted_commit icommit;
3508 size_t datalen;
3509 int i;
3511 for (;;) {
3512 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
3513 if (err){
3514 imsg_free(&imsg);
3515 return err;
3518 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
3519 if (imsg.hdr.type == GOT_IMSG_COMMIT_PAINTING_DONE) {
3520 imsg_free(&imsg);
3521 return NULL;
3523 if (imsg.hdr.type != GOT_IMSG_PAINTED_COMMITS){
3524 imsg_free(&imsg);
3525 return got_error(GOT_ERR_PRIVSEP_MSG);
3528 if (datalen < sizeof(icommits)){
3529 imsg_free(&imsg);
3530 return got_error(GOT_ERR_PRIVSEP_LEN);
3532 memcpy(&icommits, imsg.data, sizeof(icommits));
3533 if (icommits.ncommits * sizeof(icommit) < icommits.ncommits ||
3534 datalen < sizeof(icommits) +
3535 icommits.ncommits * sizeof(icommit)){
3536 imsg_free(&imsg);
3537 return got_error(GOT_ERR_PRIVSEP_LEN);
3540 for (i = 0; i < icommits.ncommits; i++) {
3541 memcpy(&icommit,
3542 (uint8_t *)imsg.data + sizeof(icommits) + i * sizeof(icommit),
3543 sizeof(icommit));
3545 if (icommits.present_in_pack) {
3546 struct got_object_id id;
3547 memcpy(id.sha1, icommit.id, SHA1_DIGEST_LENGTH);
3548 err = cb(cb_arg, &id, icommit.color);
3549 if (err)
3550 break;
3551 } else {
3552 struct got_object_qid *qid;
3553 err = got_object_qid_alloc_partial(&qid);
3554 if (err)
3555 break;
3556 memcpy(qid->id.sha1, icommit.id,
3557 SHA1_DIGEST_LENGTH);
3558 qid->data = (void *)icommit.color;
3559 STAILQ_INSERT_TAIL(new_ids, qid, entry);
3563 imsg_free(&imsg);
3564 if (err)
3565 return err;
3569 const struct got_error *
3570 got_privsep_unveil_exec_helpers(void)
3572 const char *helpers[] = {
3573 GOT_PATH_PROG_READ_PACK,
3574 GOT_PATH_PROG_READ_OBJECT,
3575 GOT_PATH_PROG_READ_COMMIT,
3576 GOT_PATH_PROG_READ_TREE,
3577 GOT_PATH_PROG_READ_BLOB,
3578 GOT_PATH_PROG_READ_TAG,
3579 GOT_PATH_PROG_READ_GITCONFIG,
3580 GOT_PATH_PROG_READ_GOTCONFIG,
3581 GOT_PATH_PROG_READ_PATCH,
3582 GOT_PATH_PROG_FETCH_PACK,
3583 GOT_PATH_PROG_INDEX_PACK,
3584 GOT_PATH_PROG_SEND_PACK,
3586 size_t i;
3588 for (i = 0; i < nitems(helpers); i++) {
3589 if (unveil(helpers[i], "x") == 0)
3590 continue;
3591 return got_error_from_errno2("unveil", helpers[i]);
3594 return NULL;
3597 void
3598 got_privsep_exec_child(int imsg_fds[2], const char *path, const char *repo_path)
3600 if (close(imsg_fds[0]) == -1) {
3601 fprintf(stderr, "%s: %s\n", getprogname(), strerror(errno));
3602 _exit(1);
3605 if (dup2(imsg_fds[1], GOT_IMSG_FD_CHILD) == -1) {
3606 fprintf(stderr, "%s: %s\n", getprogname(), strerror(errno));
3607 _exit(1);
3610 closefrom(GOT_IMSG_FD_CHILD + 1);
3612 if (execl(path, path, repo_path, (char *)NULL) == -1) {
3613 fprintf(stderr, "%s: %s: %s\n", getprogname(), path,
3614 strerror(errno));
3615 _exit(1);