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 <unistd.h>
34 #include <zlib.h>
36 #include "got_compat.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 wbuf->fd = -1;
297 imsg_close(ibuf, wbuf);
299 return flush_imsg(ibuf);
302 const struct got_error *
303 got_privsep_recv_raw_obj(uint8_t **outbuf, off_t *size, size_t *hdrlen,
304 struct imsgbuf *ibuf)
306 const struct got_error *err = NULL;
307 struct imsg imsg;
308 struct got_imsg_raw_obj *iobj;
309 size_t datalen;
311 *outbuf = NULL;
313 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
314 if (err)
315 return err;
317 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
319 switch (imsg.hdr.type) {
320 case GOT_IMSG_RAW_OBJECT:
321 if (datalen < sizeof(*iobj)) {
322 err = got_error(GOT_ERR_PRIVSEP_LEN);
323 break;
325 iobj = imsg.data;
326 *size = iobj->size;
327 *hdrlen = iobj->hdrlen;
329 if (datalen == sizeof(*iobj)) {
330 /* Data has been written to file descriptor. */
331 break;
334 if (*size < 0 ||
335 *size + *hdrlen > GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX) {
336 err = got_error(GOT_ERR_PRIVSEP_LEN);
337 break;
340 *outbuf = malloc(*size + *hdrlen);
341 if (*outbuf == NULL) {
342 err = got_error_from_errno("malloc");
343 break;
345 memcpy(*outbuf, imsg.data + sizeof(*iobj), *size + *hdrlen);
346 break;
347 default:
348 err = got_error(GOT_ERR_PRIVSEP_MSG);
349 break;
352 imsg_free(&imsg);
354 return err;
357 const struct got_error *
358 got_privsep_send_commit_req(struct imsgbuf *ibuf, int fd,
359 struct got_object_id *id, int pack_idx)
361 const struct got_error *err = NULL;
362 struct got_imsg_packed_object iobj;
363 void *data;
364 size_t len;
366 memset(&iobj, 0, sizeof(iobj));
367 if (pack_idx != -1) { /* commit is packed */
368 iobj.idx = pack_idx;
369 memcpy(&iobj.id, id, sizeof(iobj.id));
370 data = &iobj;
371 len = sizeof(iobj);
372 } else {
373 data = id;
374 len = sizeof(*id);
377 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_REQUEST, 0, 0, fd, data, len)
378 == -1) {
379 err = got_error_from_errno("imsg_compose COMMIT_REQUEST");
380 close(fd);
381 return err;
384 return flush_imsg(ibuf);
387 const struct got_error *
388 got_privsep_send_tree_req(struct imsgbuf *ibuf, int fd,
389 struct got_object_id *id, int pack_idx)
391 const struct got_error *err;
392 struct ibuf *wbuf;
393 size_t len;
395 if (pack_idx != -1)
396 len = sizeof(struct got_imsg_packed_object);
397 else
398 len = sizeof(*id);
400 wbuf = imsg_create(ibuf, GOT_IMSG_TREE_REQUEST, 0, 0, len);
401 if (wbuf == NULL) {
402 err = got_error_from_errno("imsg_create TREE_REQUEST");
403 if (fd != -1)
404 close(fd);
405 return err;
408 if (imsg_add(wbuf, id, sizeof(*id)) == -1) {
409 err = got_error_from_errno("imsg_add TREE_REQUEST");
410 if (fd != -1)
411 close(fd);
412 return err;
415 if (pack_idx != -1) { /* tree is packed */
416 if (imsg_add(wbuf, &pack_idx, sizeof(pack_idx)) == -1) {
417 err = got_error_from_errno("imsg_add TREE_REQUEST");
418 if (fd != -1)
419 close(fd);
420 return err;
424 wbuf->fd = fd;
425 imsg_close(ibuf, wbuf);
427 return flush_imsg(ibuf);
430 const struct got_error *
431 got_privsep_send_tag_req(struct imsgbuf *ibuf, int fd,
432 struct got_object_id *id, int pack_idx)
434 const struct got_error *err;
435 struct got_imsg_packed_object iobj;
436 void *data;
437 size_t len;
439 memset(&iobj, 0, sizeof(iobj));
440 if (pack_idx != -1) { /* tag is packed */
441 iobj.idx = pack_idx;
442 memcpy(&iobj.id, id, sizeof(iobj.id));
443 data = &iobj;
444 len = sizeof(iobj);
445 } else {
446 data = id;
447 len = sizeof(*id);
450 if (imsg_compose(ibuf, GOT_IMSG_TAG_REQUEST, 0, 0, fd, data, len)
451 == -1) {
452 err = got_error_from_errno("imsg_compose TAG_REQUEST");
453 if (fd != -1)
454 close(fd);
455 return err;
458 return flush_imsg(ibuf);
461 const struct got_error *
462 got_privsep_send_blob_req(struct imsgbuf *ibuf, int infd,
463 struct got_object_id *id, int pack_idx)
465 const struct got_error *err = NULL;
466 struct got_imsg_packed_object iobj;
467 void *data;
468 size_t len;
470 memset(&iobj, 0, sizeof(iobj));
471 if (pack_idx != -1) { /* blob is packed */
472 iobj.idx = pack_idx;
473 memcpy(&iobj.id, id, sizeof(iobj.id));
474 data = &iobj;
475 len = sizeof(iobj);
476 } else {
477 data = id;
478 len = sizeof(*id);
481 if (imsg_compose(ibuf, GOT_IMSG_BLOB_REQUEST, 0, 0, infd, data, len)
482 == -1) {
483 err = got_error_from_errno("imsg_compose BLOB_REQUEST");
484 close(infd);
485 return err;
488 return flush_imsg(ibuf);
491 const struct got_error *
492 got_privsep_send_blob_outfd(struct imsgbuf *ibuf, int outfd)
494 const struct got_error *err = NULL;
496 if (imsg_compose(ibuf, GOT_IMSG_BLOB_OUTFD, 0, 0, outfd, NULL, 0)
497 == -1) {
498 err = got_error_from_errno("imsg_compose BLOB_OUTFD");
499 close(outfd);
500 return err;
503 return flush_imsg(ibuf);
506 static const struct got_error *
507 send_fd(struct imsgbuf *ibuf, int imsg_code, int fd)
509 const struct got_error *err = NULL;
511 if (imsg_compose(ibuf, imsg_code, 0, 0, fd, NULL, 0) == -1) {
512 err = got_error_from_errno("imsg_compose TMPFD");
513 close(fd);
514 return err;
517 return flush_imsg(ibuf);
520 const struct got_error *
521 got_privsep_send_tmpfd(struct imsgbuf *ibuf, int fd)
523 return send_fd(ibuf, GOT_IMSG_TMPFD, fd);
526 const struct got_error *
527 got_privsep_send_obj(struct imsgbuf *ibuf, struct got_object *obj)
529 struct got_imsg_object iobj;
531 memset(&iobj, 0, sizeof(iobj));
533 memcpy(&iobj.id, &obj->id, sizeof(iobj.id));
534 iobj.type = obj->type;
535 iobj.flags = obj->flags;
536 iobj.hdrlen = obj->hdrlen;
537 iobj.size = obj->size;
538 if (iobj.flags & GOT_OBJ_FLAG_PACKED) {
539 iobj.pack_offset = obj->pack_offset;
540 iobj.pack_idx = obj->pack_idx;
543 if (imsg_compose(ibuf, GOT_IMSG_OBJECT, 0, 0, -1, &iobj, sizeof(iobj))
544 == -1)
545 return got_error_from_errno("imsg_compose OBJECT");
547 return flush_imsg(ibuf);
550 const struct got_error *
551 got_privsep_send_fetch_req(struct imsgbuf *ibuf, int fd,
552 struct got_pathlist_head *have_refs, int fetch_all_branches,
553 struct got_pathlist_head *wanted_branches,
554 struct got_pathlist_head *wanted_refs, int list_refs_only,
555 const char *worktree_branch, const char *remote_head,
556 int no_head, int verbosity)
558 const struct got_error *err = NULL;
559 struct ibuf *wbuf;
560 struct got_pathlist_entry *pe;
561 struct got_imsg_fetch_request fetchreq;
562 size_t remote_head_len, worktree_branch_len, len = sizeof(fetchreq);
564 if (worktree_branch) {
565 worktree_branch_len = strlen(worktree_branch);
566 len += worktree_branch_len;
568 if (remote_head) {
569 remote_head_len = strlen(remote_head);
570 len += remote_head_len;
573 if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
574 close(fd);
575 return got_error(GOT_ERR_NO_SPACE);
578 wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_REQUEST, 0, 0, len);
579 if (wbuf == NULL) {
580 err = got_error_from_errno("imsg_create FETCH_HAVE_REF");
581 close(fd);
582 return err;
585 memset(&fetchreq, 0, sizeof(fetchreq));
586 fetchreq.no_head = no_head;
587 fetchreq.fetch_all_branches = fetch_all_branches;
588 fetchreq.list_refs_only = list_refs_only;
589 fetchreq.verbosity = verbosity;
590 if (worktree_branch != NULL)
591 fetchreq.worktree_branch_len = worktree_branch_len;
592 if (remote_head != NULL)
593 fetchreq.remote_head_len = remote_head_len;
594 TAILQ_FOREACH(pe, have_refs, entry)
595 fetchreq.n_have_refs++;
596 TAILQ_FOREACH(pe, wanted_branches, entry)
597 fetchreq.n_wanted_branches++;
598 TAILQ_FOREACH(pe, wanted_refs, entry)
599 fetchreq.n_wanted_refs++;
600 if (imsg_add(wbuf, &fetchreq, sizeof(fetchreq)) == -1)
601 return got_error_from_errno("imsg_add FETCH_REQUEST");
602 if (worktree_branch) {
603 if (imsg_add(wbuf, worktree_branch, worktree_branch_len)
604 == -1) {
605 err = got_error_from_errno("imsg_add FETCH_REQUEST");
606 close(fd);
607 return err;
610 if (remote_head) {
611 if (imsg_add(wbuf, remote_head, remote_head_len) == -1) {
612 err = got_error_from_errno("imsg_add FETCH_REQUEST");
613 close(fd);
614 return err;
617 wbuf->fd = fd;
618 fd = -1;
619 imsg_close(ibuf, wbuf);
621 err = flush_imsg(ibuf);
622 if (err)
623 return err;
625 TAILQ_FOREACH(pe, have_refs, entry) {
626 const char *name = pe->path;
627 size_t name_len = pe->path_len;
628 struct got_object_id *id = pe->data;
630 len = sizeof(struct got_imsg_fetch_have_ref) + name_len;
631 wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_HAVE_REF, 0, 0, len);
632 if (wbuf == NULL)
633 return got_error_from_errno("imsg_create FETCH_HAVE_REF");
635 /* Keep in sync with struct got_imsg_fetch_have_ref! */
636 if (imsg_add(wbuf, id, sizeof(*id)) == -1)
637 return got_error_from_errno("imsg_add FETCH_HAVE_REF");
638 if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1)
639 return got_error_from_errno("imsg_add FETCH_HAVE_REF");
640 if (imsg_add(wbuf, name, name_len) == -1)
641 return got_error_from_errno("imsg_add FETCH_HAVE_REF");
643 wbuf->fd = -1;
644 imsg_close(ibuf, wbuf);
645 err = flush_imsg(ibuf);
646 if (err)
647 return err;
650 TAILQ_FOREACH(pe, wanted_branches, entry) {
651 const char *name = pe->path;
652 size_t name_len = pe->path_len;
654 len = sizeof(struct got_imsg_fetch_wanted_branch) + name_len;
655 wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_WANTED_BRANCH, 0, 0,
656 len);
657 if (wbuf == NULL)
658 return got_error_from_errno(
659 "imsg_create FETCH_WANTED_BRANCH");
661 /* Keep in sync with struct got_imsg_fetch_wanted_branch! */
662 if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1)
663 return got_error_from_errno(
664 "imsg_add FETCH_WANTED_BRANCH");
665 if (imsg_add(wbuf, name, name_len) == -1)
666 return got_error_from_errno(
667 "imsg_add FETCH_WANTED_BRANCH");
669 wbuf->fd = -1;
670 imsg_close(ibuf, wbuf);
671 err = flush_imsg(ibuf);
672 if (err)
673 return err;
676 TAILQ_FOREACH(pe, wanted_refs, entry) {
677 const char *name = pe->path;
678 size_t name_len = pe->path_len;
680 len = sizeof(struct got_imsg_fetch_wanted_ref) + name_len;
681 wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_WANTED_REF, 0, 0,
682 len);
683 if (wbuf == NULL)
684 return got_error_from_errno(
685 "imsg_create FETCH_WANTED_REF");
687 /* Keep in sync with struct got_imsg_fetch_wanted_ref! */
688 if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1)
689 return got_error_from_errno(
690 "imsg_add FETCH_WANTED_REF");
691 if (imsg_add(wbuf, name, name_len) == -1)
692 return got_error_from_errno(
693 "imsg_add FETCH_WANTED_REF");
695 wbuf->fd = -1;
696 imsg_close(ibuf, wbuf);
697 err = flush_imsg(ibuf);
698 if (err)
699 return err;
702 return NULL;
705 const struct got_error *
706 got_privsep_send_fetch_outfd(struct imsgbuf *ibuf, int fd)
708 return send_fd(ibuf, GOT_IMSG_FETCH_OUTFD, fd);
711 const struct got_error *
712 got_privsep_recv_fetch_progress(int *done, struct got_object_id **id,
713 char **refname, struct got_pathlist_head *symrefs, char **server_progress,
714 off_t *packfile_size, uint8_t *pack_sha1, struct imsgbuf *ibuf)
716 const struct got_error *err = NULL;
717 struct imsg imsg;
718 size_t datalen;
719 struct got_imsg_fetch_symrefs *isymrefs = NULL;
720 size_t n, remain;
721 off_t off;
722 int i;
724 *done = 0;
725 *id = NULL;
726 *refname = NULL;
727 *server_progress = NULL;
728 *packfile_size = 0;
729 memset(pack_sha1, 0, SHA1_DIGEST_LENGTH);
731 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
732 if (err)
733 return err;
735 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
736 switch (imsg.hdr.type) {
737 case GOT_IMSG_FETCH_SYMREFS:
738 if (datalen < sizeof(*isymrefs)) {
739 err = got_error(GOT_ERR_PRIVSEP_LEN);
740 break;
742 if (isymrefs != NULL) {
743 err = got_error(GOT_ERR_PRIVSEP_MSG);
744 break;
746 isymrefs = (struct got_imsg_fetch_symrefs *)imsg.data;
747 off = sizeof(*isymrefs);
748 remain = datalen - off;
749 for (n = 0; n < isymrefs->nsymrefs; n++) {
750 struct got_imsg_fetch_symref *s;
751 char *name, *target;
752 if (remain < sizeof(struct got_imsg_fetch_symref)) {
753 err = got_error(GOT_ERR_PRIVSEP_LEN);
754 goto done;
756 s = (struct got_imsg_fetch_symref *)(imsg.data + off);
757 off += sizeof(*s);
758 remain -= sizeof(*s);
759 if (remain < s->name_len) {
760 err = got_error(GOT_ERR_PRIVSEP_LEN);
761 goto done;
763 name = strndup(imsg.data + off, s->name_len);
764 if (name == NULL) {
765 err = got_error_from_errno("strndup");
766 goto done;
768 off += s->name_len;
769 remain -= s->name_len;
770 if (remain < s->target_len) {
771 err = got_error(GOT_ERR_PRIVSEP_LEN);
772 free(name);
773 goto done;
775 target = strndup(imsg.data + off, s->target_len);
776 if (target == NULL) {
777 err = got_error_from_errno("strndup");
778 free(name);
779 goto done;
781 off += s->target_len;
782 remain -= s->target_len;
783 err = got_pathlist_append(symrefs, name, target);
784 if (err) {
785 free(name);
786 free(target);
787 goto done;
790 break;
791 case GOT_IMSG_FETCH_REF:
792 if (datalen <= sizeof(**id)) {
793 err = got_error(GOT_ERR_PRIVSEP_MSG);
794 break;
796 *id = malloc(sizeof(**id));
797 if (*id == NULL) {
798 err = got_error_from_errno("malloc");
799 break;
801 memcpy(*id, imsg.data, sizeof(**id));
802 *refname = strndup(imsg.data + sizeof(**id),
803 datalen - sizeof(**id));
804 if (*refname == NULL) {
805 err = got_error_from_errno("strndup");
806 break;
808 break;
809 case GOT_IMSG_FETCH_SERVER_PROGRESS:
810 if (datalen == 0) {
811 err = got_error(GOT_ERR_PRIVSEP_LEN);
812 break;
814 *server_progress = strndup(imsg.data, datalen);
815 if (*server_progress == NULL) {
816 err = got_error_from_errno("strndup");
817 break;
819 for (i = 0; i < datalen; i++) {
820 if (!isprint((unsigned char)(*server_progress)[i]) &&
821 !isspace((unsigned char)(*server_progress)[i])) {
822 err = got_error(GOT_ERR_PRIVSEP_MSG);
823 free(*server_progress);
824 *server_progress = NULL;
825 goto done;
828 break;
829 case GOT_IMSG_FETCH_DOWNLOAD_PROGRESS:
830 if (datalen < sizeof(*packfile_size)) {
831 err = got_error(GOT_ERR_PRIVSEP_MSG);
832 break;
834 memcpy(packfile_size, imsg.data, sizeof(*packfile_size));
835 break;
836 case GOT_IMSG_FETCH_DONE:
837 if (datalen != SHA1_DIGEST_LENGTH) {
838 err = got_error(GOT_ERR_PRIVSEP_MSG);
839 break;
841 memcpy(pack_sha1, imsg.data, SHA1_DIGEST_LENGTH);
842 *done = 1;
843 break;
844 default:
845 err = got_error(GOT_ERR_PRIVSEP_MSG);
846 break;
848 done:
849 if (err) {
850 free(*id);
851 *id = NULL;
852 free(*refname);
853 *refname = NULL;
855 imsg_free(&imsg);
856 return err;
859 static const struct got_error *
860 send_send_ref(const char *name, size_t name_len, struct got_object_id *id,
861 int delete, struct imsgbuf *ibuf)
863 size_t len;
864 struct ibuf *wbuf;
866 len = sizeof(struct got_imsg_send_ref) + name_len;
867 wbuf = imsg_create(ibuf, GOT_IMSG_SEND_REF, 0, 0, len);
868 if (wbuf == NULL)
869 return got_error_from_errno("imsg_create SEND_REF");
871 /* Keep in sync with struct got_imsg_send_ref! */
872 if (imsg_add(wbuf, id, sizeof(*id)) == -1)
873 return got_error_from_errno("imsg_add SEND_REF");
874 if (imsg_add(wbuf, &delete, sizeof(delete)) == -1)
875 return got_error_from_errno("imsg_add SEND_REF");
876 if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1)
877 return got_error_from_errno("imsg_add SEND_REF");
878 if (imsg_add(wbuf, name, name_len) == -1)
879 return got_error_from_errno("imsg_add SEND_REF");
881 wbuf->fd = -1;
882 imsg_close(ibuf, wbuf);
883 return flush_imsg(ibuf);
886 const struct got_error *
887 got_privsep_send_send_req(struct imsgbuf *ibuf, int fd,
888 struct got_pathlist_head *have_refs,
889 struct got_pathlist_head *delete_refs,
890 int verbosity)
892 const struct got_error *err = NULL;
893 struct got_pathlist_entry *pe;
894 struct got_imsg_send_request sendreq;
895 struct got_object_id zero_id;
897 memset(&zero_id, 0, sizeof(zero_id));
898 memset(&sendreq, 0, sizeof(sendreq));
899 sendreq.verbosity = verbosity;
900 TAILQ_FOREACH(pe, have_refs, entry)
901 sendreq.nrefs++;
902 TAILQ_FOREACH(pe, delete_refs, entry)
903 sendreq.nrefs++;
904 if (imsg_compose(ibuf, GOT_IMSG_SEND_REQUEST, 0, 0, fd,
905 &sendreq, sizeof(sendreq)) == -1) {
906 err = got_error_from_errno(
907 "imsg_compose FETCH_SERVER_PROGRESS");
908 goto done;
911 fd = -1;
912 err = flush_imsg(ibuf);
913 if (err)
914 goto done;
916 TAILQ_FOREACH(pe, have_refs, entry) {
917 const char *name = pe->path;
918 size_t name_len = pe->path_len;
919 struct got_object_id *id = pe->data;
920 err = send_send_ref(name, name_len, id, 0, ibuf);
921 if (err)
922 goto done;
925 TAILQ_FOREACH(pe, delete_refs, entry) {
926 const char *name = pe->path;
927 size_t name_len = pe->path_len;
928 err = send_send_ref(name, name_len, &zero_id, 1, ibuf);
929 if (err)
930 goto done;
932 done:
933 if (fd != -1 && close(fd) == -1 && err == NULL)
934 err = got_error_from_errno("close");
935 return err;
938 const struct got_error *
939 got_privsep_recv_send_remote_refs(struct got_pathlist_head *remote_refs,
940 struct imsgbuf *ibuf)
942 const struct got_error *err = NULL;
943 struct imsg imsg;
944 size_t datalen;
945 int done = 0;
946 struct got_imsg_send_remote_ref iremote_ref;
947 struct got_object_id *id = NULL;
948 char *refname = NULL;
949 struct got_pathlist_entry *new;
951 while (!done) {
952 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
953 if (err)
954 return err;
955 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
956 switch (imsg.hdr.type) {
957 case GOT_IMSG_SEND_REMOTE_REF:
958 if (datalen < sizeof(iremote_ref)) {
959 err = got_error(GOT_ERR_PRIVSEP_MSG);
960 goto done;
962 memcpy(&iremote_ref, imsg.data, sizeof(iremote_ref));
963 if (datalen != sizeof(iremote_ref) +
964 iremote_ref.name_len) {
965 err = got_error(GOT_ERR_PRIVSEP_MSG);
966 goto done;
968 id = malloc(sizeof(*id));
969 if (id == NULL) {
970 err = got_error_from_errno("malloc");
971 goto done;
973 memcpy(id, &iremote_ref.id, sizeof(*id));
974 refname = strndup(imsg.data + sizeof(iremote_ref),
975 datalen - sizeof(iremote_ref));
976 if (refname == NULL) {
977 err = got_error_from_errno("strndup");
978 goto done;
980 err = got_pathlist_insert(&new, remote_refs,
981 refname, id);
982 if (err)
983 goto done;
984 if (new == NULL) { /* duplicate which wasn't inserted */
985 free(id);
986 free(refname);
988 id = NULL;
989 refname = NULL;
990 break;
991 case GOT_IMSG_SEND_PACK_REQUEST:
992 if (datalen != 0) {
993 err = got_error(GOT_ERR_PRIVSEP_MSG);
994 goto done;
996 /* got-send-pack is now waiting for a pack file. */
997 done = 1;
998 break;
999 default:
1000 err = got_error(GOT_ERR_PRIVSEP_MSG);
1001 break;
1004 done:
1005 free(id);
1006 free(refname);
1007 imsg_free(&imsg);
1008 return err;
1011 const struct got_error *
1012 got_privsep_send_packfd(struct imsgbuf *ibuf, int fd)
1014 return send_fd(ibuf, GOT_IMSG_SEND_PACKFD, fd);
1017 const struct got_error *
1018 got_privsep_recv_send_progress(int *done, off_t *bytes_sent,
1019 int *success, char **refname, char **errmsg, struct imsgbuf *ibuf)
1021 const struct got_error *err = NULL;
1022 struct imsg imsg;
1023 size_t datalen;
1024 struct got_imsg_send_ref_status iref_status;
1026 /* Do not reset the current value of 'bytes_sent', it accumulates. */
1027 *done = 0;
1028 *success = 0;
1029 *refname = NULL;
1030 *errmsg = NULL;
1032 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1033 if (err)
1034 return err;
1036 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1037 switch (imsg.hdr.type) {
1038 case GOT_IMSG_SEND_UPLOAD_PROGRESS:
1039 if (datalen < sizeof(*bytes_sent)) {
1040 err = got_error(GOT_ERR_PRIVSEP_MSG);
1041 break;
1043 memcpy(bytes_sent, imsg.data, sizeof(*bytes_sent));
1044 break;
1045 case GOT_IMSG_SEND_REF_STATUS:
1046 if (datalen < sizeof(iref_status)) {
1047 err = got_error(GOT_ERR_PRIVSEP_MSG);
1048 break;
1050 memcpy(&iref_status, imsg.data, sizeof(iref_status));
1051 if (datalen != sizeof(iref_status) + iref_status.name_len +
1052 iref_status.errmsg_len) {
1053 err = got_error(GOT_ERR_PRIVSEP_MSG);
1054 break;
1056 *success = iref_status.success;
1057 *refname = strndup(imsg.data + sizeof(iref_status),
1058 iref_status.name_len);
1060 if (iref_status.errmsg_len != 0)
1061 *errmsg = strndup(imsg.data + sizeof(iref_status) +
1062 iref_status.name_len, iref_status.errmsg_len);
1063 break;
1064 case GOT_IMSG_SEND_DONE:
1065 if (datalen != 0) {
1066 err = got_error(GOT_ERR_PRIVSEP_MSG);
1067 break;
1069 *done = 1;
1070 break;
1071 default:
1072 err = got_error(GOT_ERR_PRIVSEP_MSG);
1073 break;
1076 imsg_free(&imsg);
1077 return err;
1080 const struct got_error *
1081 got_privsep_send_index_pack_req(struct imsgbuf *ibuf, uint8_t *pack_sha1,
1082 int fd)
1084 const struct got_error *err = NULL;
1086 /* Keep in sync with struct got_imsg_index_pack_request */
1087 if (imsg_compose(ibuf, GOT_IMSG_IDXPACK_REQUEST, 0, 0, fd,
1088 pack_sha1, SHA1_DIGEST_LENGTH) == -1) {
1089 err = got_error_from_errno("imsg_compose INDEX_REQUEST");
1090 close(fd);
1091 return err;
1093 return flush_imsg(ibuf);
1096 const struct got_error *
1097 got_privsep_send_index_pack_outfd(struct imsgbuf *ibuf, int fd)
1099 return send_fd(ibuf, GOT_IMSG_IDXPACK_OUTFD, fd);
1102 const struct got_error *
1103 got_privsep_recv_index_progress(int *done, int *nobj_total,
1104 int *nobj_indexed, int *nobj_loose, int *nobj_resolved,
1105 struct imsgbuf *ibuf)
1107 const struct got_error *err = NULL;
1108 struct imsg imsg;
1109 struct got_imsg_index_pack_progress *iprogress;
1110 size_t datalen;
1112 *done = 0;
1113 *nobj_total = 0;
1114 *nobj_indexed = 0;
1115 *nobj_resolved = 0;
1117 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1118 if (err)
1119 return err;
1121 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1122 switch (imsg.hdr.type) {
1123 case GOT_IMSG_IDXPACK_PROGRESS:
1124 if (datalen < sizeof(*iprogress)) {
1125 err = got_error(GOT_ERR_PRIVSEP_LEN);
1126 break;
1128 iprogress = (struct got_imsg_index_pack_progress *)imsg.data;
1129 if (iprogress->nobj_total < 0 || iprogress->nobj_indexed < 0 ||
1130 iprogress->nobj_loose < 0 || iprogress->nobj_resolved < 0) {
1131 err = got_error(GOT_ERR_RANGE);
1132 break;
1134 *nobj_total = iprogress->nobj_total;
1135 *nobj_indexed = iprogress->nobj_indexed;
1136 *nobj_loose = iprogress->nobj_loose;
1137 *nobj_resolved = iprogress->nobj_resolved;
1138 break;
1139 case GOT_IMSG_IDXPACK_DONE:
1140 if (datalen != 0) {
1141 err = got_error(GOT_ERR_PRIVSEP_LEN);
1142 break;
1144 *done = 1;
1145 break;
1146 default:
1147 err = got_error(GOT_ERR_PRIVSEP_MSG);
1148 break;
1151 imsg_free(&imsg);
1152 return err;
1155 const struct got_error *
1156 got_privsep_get_imsg_obj(struct got_object **obj, struct imsg *imsg,
1157 struct imsgbuf *ibuf)
1159 struct got_imsg_object *iobj;
1160 size_t datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1162 if (datalen != sizeof(*iobj))
1163 return got_error(GOT_ERR_PRIVSEP_LEN);
1164 iobj = imsg->data;
1166 if (iobj->pack_offset < 0)
1167 return got_error(GOT_ERR_PACK_OFFSET);
1169 *obj = calloc(1, sizeof(**obj));
1170 if (*obj == NULL)
1171 return got_error_from_errno("calloc");
1173 memcpy(&(*obj)->id, &iobj->id, sizeof(iobj->id));
1174 (*obj)->type = iobj->type;
1175 (*obj)->flags = iobj->flags;
1176 (*obj)->hdrlen = iobj->hdrlen;
1177 (*obj)->size = iobj->size;
1178 /* path_packfile is handled by caller */
1179 if (iobj->flags & GOT_OBJ_FLAG_PACKED) {
1180 (*obj)->pack_offset = iobj->pack_offset;
1181 (*obj)->pack_idx = iobj->pack_idx;
1183 STAILQ_INIT(&(*obj)->deltas.entries);
1184 return NULL;
1187 const struct got_error *
1188 got_privsep_recv_obj(struct got_object **obj, struct imsgbuf *ibuf)
1190 const struct got_error *err = NULL;
1191 struct imsg imsg;
1192 const size_t min_datalen =
1193 MIN(sizeof(struct got_imsg_error), sizeof(struct got_imsg_object));
1195 *obj = NULL;
1197 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
1198 if (err)
1199 return err;
1201 switch (imsg.hdr.type) {
1202 case GOT_IMSG_OBJECT:
1203 err = got_privsep_get_imsg_obj(obj, &imsg, ibuf);
1204 break;
1205 default:
1206 err = got_error(GOT_ERR_PRIVSEP_MSG);
1207 break;
1210 imsg_free(&imsg);
1212 return err;
1215 static const struct got_error *
1216 send_commit_logmsg(struct imsgbuf *ibuf, struct got_commit_object *commit,
1217 size_t logmsg_len)
1219 const struct got_error *err = NULL;
1220 size_t offset, remain;
1222 offset = 0;
1223 remain = logmsg_len;
1224 while (remain > 0) {
1225 size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE, remain);
1227 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_LOGMSG, 0, 0, -1,
1228 commit->logmsg + offset, n) == -1) {
1229 err = got_error_from_errno("imsg_compose "
1230 "COMMIT_LOGMSG");
1231 break;
1234 err = flush_imsg(ibuf);
1235 if (err)
1236 break;
1238 offset += n;
1239 remain -= n;
1242 return err;
1245 const struct got_error *
1246 got_privsep_send_commit(struct imsgbuf *ibuf, struct got_commit_object *commit)
1248 const struct got_error *err = NULL;
1249 struct got_imsg_commit_object *icommit;
1250 uint8_t *buf;
1251 size_t len, total;
1252 struct got_object_qid *qid;
1253 size_t author_len = strlen(commit->author);
1254 size_t committer_len = strlen(commit->committer);
1255 size_t logmsg_len = strlen(commit->logmsg);
1257 total = sizeof(*icommit) + author_len + committer_len +
1258 commit->nparents * sizeof(struct got_object_id);
1260 buf = malloc(total);
1261 if (buf == NULL)
1262 return got_error_from_errno("malloc");
1264 icommit = (struct got_imsg_commit_object *)buf;
1265 memcpy(&icommit->tree_id, commit->tree_id, sizeof(icommit->tree_id));
1266 icommit->author_len = author_len;
1267 icommit->author_time = commit->author_time;
1268 icommit->author_gmtoff = commit->author_gmtoff;
1269 icommit->committer_len = committer_len;
1270 icommit->committer_time = commit->committer_time;
1271 icommit->committer_gmtoff = commit->committer_gmtoff;
1272 icommit->logmsg_len = logmsg_len;
1273 icommit->nparents = commit->nparents;
1275 len = sizeof(*icommit);
1276 memcpy(buf + len, commit->author, author_len);
1277 len += author_len;
1278 memcpy(buf + len, commit->committer, committer_len);
1279 len += committer_len;
1280 STAILQ_FOREACH(qid, &commit->parent_ids, entry) {
1281 memcpy(buf + len, &qid->id, sizeof(qid->id));
1282 len += sizeof(qid->id);
1285 if (imsg_compose(ibuf, GOT_IMSG_COMMIT, 0, 0, -1, buf, len) == -1) {
1286 err = got_error_from_errno("imsg_compose COMMIT");
1287 goto done;
1290 if (logmsg_len == 0 ||
1291 logmsg_len + len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
1292 err = flush_imsg(ibuf);
1293 if (err)
1294 goto done;
1296 err = send_commit_logmsg(ibuf, commit, logmsg_len);
1297 done:
1298 free(buf);
1299 return err;
1302 static const struct got_error *
1303 get_commit_from_imsg(struct got_commit_object **commit,
1304 struct imsg *imsg, size_t datalen, struct imsgbuf *ibuf)
1306 const struct got_error *err = NULL;
1307 struct got_imsg_commit_object *icommit;
1308 size_t len = 0;
1309 int i;
1311 if (datalen < sizeof(*icommit))
1312 return got_error(GOT_ERR_PRIVSEP_LEN);
1314 icommit = imsg->data;
1315 if (datalen != sizeof(*icommit) + icommit->author_len +
1316 icommit->committer_len +
1317 icommit->nparents * sizeof(struct got_object_id))
1318 return got_error(GOT_ERR_PRIVSEP_LEN);
1320 if (icommit->nparents < 0)
1321 return got_error(GOT_ERR_PRIVSEP_LEN);
1323 len += sizeof(*icommit);
1325 *commit = got_object_commit_alloc_partial();
1326 if (*commit == NULL)
1327 return got_error_from_errno(
1328 "got_object_commit_alloc_partial");
1330 memcpy((*commit)->tree_id, &icommit->tree_id,
1331 sizeof(icommit->tree_id));
1332 (*commit)->author_time = icommit->author_time;
1333 (*commit)->author_gmtoff = icommit->author_gmtoff;
1334 (*commit)->committer_time = icommit->committer_time;
1335 (*commit)->committer_gmtoff = icommit->committer_gmtoff;
1337 (*commit)->author = strndup(imsg->data + len, icommit->author_len);
1338 if ((*commit)->author == NULL) {
1339 err = got_error_from_errno("strndup");
1340 goto done;
1342 len += icommit->author_len;
1344 (*commit)->committer = strndup(imsg->data + len,
1345 icommit->committer_len);
1346 if ((*commit)->committer == NULL) {
1347 err = got_error_from_errno("strndup");
1348 goto done;
1350 len += icommit->committer_len;
1352 if (icommit->logmsg_len == 0) {
1353 (*commit)->logmsg = strdup("");
1354 if ((*commit)->logmsg == NULL) {
1355 err = got_error_from_errno("strdup");
1356 goto done;
1358 } else {
1359 size_t offset = 0, remain = icommit->logmsg_len;
1361 (*commit)->logmsg = malloc(icommit->logmsg_len + 1);
1362 if ((*commit)->logmsg == NULL) {
1363 err = got_error_from_errno("malloc");
1364 goto done;
1366 while (remain > 0) {
1367 struct imsg imsg_log;
1368 size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE,
1369 remain);
1371 err = got_privsep_recv_imsg(&imsg_log, ibuf, n);
1372 if (err)
1373 goto done;
1375 if (imsg_log.hdr.type != GOT_IMSG_COMMIT_LOGMSG) {
1376 err = got_error(GOT_ERR_PRIVSEP_MSG);
1377 goto done;
1380 memcpy((*commit)->logmsg + offset,
1381 imsg_log.data, n);
1382 imsg_free(&imsg_log);
1383 offset += n;
1384 remain -= n;
1386 (*commit)->logmsg[icommit->logmsg_len] = '\0';
1389 for (i = 0; i < icommit->nparents; i++) {
1390 struct got_object_qid *qid;
1392 err = got_object_qid_alloc_partial(&qid);
1393 if (err)
1394 break;
1395 memcpy(&qid->id, imsg->data + len +
1396 i * sizeof(qid->id), sizeof(qid->id));
1397 STAILQ_INSERT_TAIL(&(*commit)->parent_ids, qid, entry);
1398 (*commit)->nparents++;
1400 done:
1401 if (err) {
1402 got_object_commit_close(*commit);
1403 *commit = NULL;
1405 return err;
1408 const struct got_error *
1409 got_privsep_recv_commit(struct got_commit_object **commit, struct imsgbuf *ibuf)
1411 const struct got_error *err = NULL;
1412 struct imsg imsg;
1413 size_t datalen;
1414 const size_t min_datalen =
1415 MIN(sizeof(struct got_imsg_error),
1416 sizeof(struct got_imsg_commit_object));
1418 *commit = NULL;
1420 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
1421 if (err)
1422 return err;
1424 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1426 switch (imsg.hdr.type) {
1427 case GOT_IMSG_COMMIT:
1428 err = get_commit_from_imsg(commit, &imsg, datalen, ibuf);
1429 break;
1430 default:
1431 err = got_error(GOT_ERR_PRIVSEP_MSG);
1432 break;
1435 imsg_free(&imsg);
1437 return err;
1440 static const struct got_error *
1441 send_tree_entries_batch(struct imsgbuf *ibuf,
1442 struct got_parsed_tree_entry *entries, int idx0, int idxN, size_t len)
1444 struct ibuf *wbuf;
1445 struct got_imsg_tree_entries ientries;
1446 int i;
1448 memset(&ientries, 0, sizeof(ientries));
1450 wbuf = imsg_create(ibuf, GOT_IMSG_TREE_ENTRIES, 0, 0, len);
1451 if (wbuf == NULL)
1452 return got_error_from_errno("imsg_create TREE_ENTRY");
1454 ientries.nentries = idxN - idx0 + 1;
1455 if (imsg_add(wbuf, &ientries, sizeof(ientries)) == -1)
1456 return got_error_from_errno("imsg_add TREE_ENTRY");
1458 for (i = idx0; i <= idxN; i++) {
1459 struct got_parsed_tree_entry *pte = &entries[i];
1461 /* Keep in sync with struct got_imsg_tree_entry definition! */
1462 if (imsg_add(wbuf, pte->id, SHA1_DIGEST_LENGTH) == -1)
1463 return got_error_from_errno("imsg_add TREE_ENTRY");
1464 if (imsg_add(wbuf, &pte->mode, sizeof(pte->mode)) == -1)
1465 return got_error_from_errno("imsg_add TREE_ENTRY");
1466 if (imsg_add(wbuf, &pte->namelen, sizeof(pte->namelen)) == -1)
1467 return got_error_from_errno("imsg_add TREE_ENTRY");
1469 /* Remaining bytes are the entry's name. */
1470 if (imsg_add(wbuf, pte->name, pte->namelen) == -1)
1471 return got_error_from_errno("imsg_add TREE_ENTRY");
1474 wbuf->fd = -1;
1475 imsg_close(ibuf, wbuf);
1476 return NULL;
1479 static const struct got_error *
1480 send_tree_entries(struct imsgbuf *ibuf, struct got_parsed_tree_entry *entries,
1481 int nentries)
1483 const struct got_error *err = NULL;
1484 int i, j;
1485 size_t entries_len = sizeof(struct got_imsg_tree_entries);
1487 i = 0;
1488 for (j = 0; j < nentries; j++) {
1489 struct got_parsed_tree_entry *pte = &entries[j];
1490 size_t len = sizeof(struct got_imsg_tree_entry) + pte->namelen;
1492 if (j > 0 &&
1493 entries_len + len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
1494 err = send_tree_entries_batch(ibuf, entries,
1495 i, j - 1, entries_len);
1496 if (err)
1497 return err;
1498 i = j;
1499 entries_len = sizeof(struct got_imsg_tree_entries);
1502 entries_len += len;
1505 if (j > 0) {
1506 err = send_tree_entries_batch(ibuf, entries, i, j - 1,
1507 entries_len);
1508 if (err)
1509 return err;
1512 return NULL;
1515 const struct got_error *
1516 got_privsep_send_tree(struct imsgbuf *ibuf,
1517 struct got_parsed_tree_entry *entries, int nentries)
1519 const struct got_error *err = NULL;
1520 struct got_imsg_tree_object itree;
1522 memset(&itree, 0, sizeof(itree));
1523 itree.nentries = nentries;
1524 if (imsg_compose(ibuf, GOT_IMSG_TREE, 0, 0, -1, &itree, sizeof(itree))
1525 == -1)
1526 return got_error_from_errno("imsg_compose TREE");
1528 err = send_tree_entries(ibuf, entries, nentries);
1529 if (err)
1530 return err;
1532 return flush_imsg(ibuf);
1536 static const struct got_error *
1537 recv_tree_entries(void *data, size_t datalen, struct got_tree_object *tree,
1538 int *nentries)
1540 const struct got_error *err = NULL;
1541 struct got_imsg_tree_entries *ientries;
1542 struct got_tree_entry *te;
1543 size_t te_offset;
1544 size_t i;
1546 if (datalen <= sizeof(*ientries) ||
1547 datalen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
1548 return got_error(GOT_ERR_PRIVSEP_LEN);
1550 ientries = (struct got_imsg_tree_entries *)data;
1551 if (ientries->nentries > INT_MAX) {
1552 return got_error_msg(GOT_ERR_NO_SPACE,
1553 "too many tree entries");
1556 te_offset = sizeof(*ientries);
1557 for (i = 0; i < ientries->nentries; i++) {
1558 struct got_imsg_tree_entry ite;
1559 const char *te_name;
1560 uint8_t *buf = (uint8_t *)data + te_offset;
1562 if (te_offset >= datalen) {
1563 err = got_error(GOT_ERR_PRIVSEP_LEN);
1564 break;
1567 /* Might not be aligned, size is ~32 bytes. */
1568 memcpy(&ite, buf, sizeof(ite));
1570 if (ite.namelen >= sizeof(te->name)) {
1571 err = got_error(GOT_ERR_PRIVSEP_LEN);
1572 break;
1574 if (te_offset + sizeof(ite) + ite.namelen > datalen) {
1575 err = got_error(GOT_ERR_PRIVSEP_LEN);
1576 break;
1579 if (*nentries >= tree->nentries) {
1580 err = got_error(GOT_ERR_PRIVSEP_LEN);
1581 break;
1583 te = &tree->entries[*nentries];
1584 te_name = buf + sizeof(ite);
1585 memcpy(te->name, te_name, ite.namelen);
1586 te->name[ite.namelen] = '\0';
1587 memcpy(te->id.sha1, ite.id, SHA1_DIGEST_LENGTH);
1588 te->mode = ite.mode;
1589 te->idx = *nentries;
1590 (*nentries)++;
1592 te_offset += sizeof(ite) + ite.namelen;
1595 return err;
1598 const struct got_error *
1599 got_privsep_recv_tree(struct got_tree_object **tree, struct imsgbuf *ibuf)
1601 const struct got_error *err = NULL;
1602 const size_t min_datalen =
1603 MIN(sizeof(struct got_imsg_error),
1604 sizeof(struct got_imsg_tree_object));
1605 struct got_imsg_tree_object *itree;
1606 int nentries = 0;
1608 *tree = NULL;
1610 while (*tree == NULL || nentries < (*tree)->nentries) {
1611 struct imsg imsg;
1612 size_t datalen;
1614 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
1615 if (err)
1616 break;
1618 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1620 switch (imsg.hdr.type) {
1621 case GOT_IMSG_TREE:
1622 /* This message should only appear once. */
1623 if (*tree != NULL) {
1624 err = got_error(GOT_ERR_PRIVSEP_MSG);
1625 break;
1627 if (datalen != sizeof(*itree)) {
1628 err = got_error(GOT_ERR_PRIVSEP_LEN);
1629 break;
1631 itree = imsg.data;
1632 if (itree->nentries < 0) {
1633 err = got_error(GOT_ERR_PRIVSEP_LEN);
1634 break;
1636 *tree = malloc(sizeof(**tree));
1637 if (*tree == NULL) {
1638 err = got_error_from_errno("malloc");
1639 break;
1641 (*tree)->entries = calloc(itree->nentries,
1642 sizeof(struct got_tree_entry));
1643 if ((*tree)->entries == NULL) {
1644 err = got_error_from_errno("malloc");
1645 free(*tree);
1646 *tree = NULL;
1647 break;
1649 (*tree)->nentries = itree->nentries;
1650 (*tree)->refcnt = 0;
1651 break;
1652 case GOT_IMSG_TREE_ENTRIES:
1653 /* This message should be preceeded by GOT_IMSG_TREE. */
1654 if (*tree == NULL) {
1655 err = got_error(GOT_ERR_PRIVSEP_MSG);
1656 break;
1658 err = recv_tree_entries(imsg.data, datalen,
1659 *tree, &nentries);
1660 break;
1661 default:
1662 err = got_error(GOT_ERR_PRIVSEP_MSG);
1663 break;
1666 imsg_free(&imsg);
1667 if (err)
1668 break;
1671 if (*tree && (*tree)->nentries != nentries) {
1672 if (err == NULL)
1673 err = got_error(GOT_ERR_PRIVSEP_LEN);
1674 got_object_tree_close(*tree);
1675 *tree = NULL;
1678 return err;
1681 const struct got_error *
1682 got_privsep_send_blob(struct imsgbuf *ibuf, size_t size, size_t hdrlen,
1683 const uint8_t *data)
1685 struct got_imsg_blob iblob;
1687 memset(&iblob, 0, sizeof(iblob));
1688 iblob.size = size;
1689 iblob.hdrlen = hdrlen;
1691 if (data) {
1692 uint8_t *buf;
1694 if (size > GOT_PRIVSEP_INLINE_BLOB_DATA_MAX)
1695 return got_error(GOT_ERR_NO_SPACE);
1697 buf = malloc(sizeof(iblob) + size);
1698 if (buf == NULL)
1699 return got_error_from_errno("malloc");
1701 memcpy(buf, &iblob, sizeof(iblob));
1702 memcpy(buf + sizeof(iblob), data, size);
1703 if (imsg_compose(ibuf, GOT_IMSG_BLOB, 0, 0, -1, buf,
1704 sizeof(iblob) + size) == -1) {
1705 free(buf);
1706 return got_error_from_errno("imsg_compose BLOB");
1708 free(buf);
1709 } else {
1710 /* Data has already been written to file descriptor. */
1711 if (imsg_compose(ibuf, GOT_IMSG_BLOB, 0, 0, -1, &iblob,
1712 sizeof(iblob)) == -1)
1713 return got_error_from_errno("imsg_compose BLOB");
1717 return flush_imsg(ibuf);
1720 const struct got_error *
1721 got_privsep_recv_blob(uint8_t **outbuf, size_t *size, size_t *hdrlen,
1722 struct imsgbuf *ibuf)
1724 const struct got_error *err = NULL;
1725 struct imsg imsg;
1726 struct got_imsg_blob *iblob;
1727 size_t datalen;
1729 *outbuf = NULL;
1731 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1732 if (err)
1733 return err;
1735 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1737 switch (imsg.hdr.type) {
1738 case GOT_IMSG_BLOB:
1739 if (datalen < sizeof(*iblob)) {
1740 err = got_error(GOT_ERR_PRIVSEP_LEN);
1741 break;
1743 iblob = imsg.data;
1744 *size = iblob->size;
1745 *hdrlen = iblob->hdrlen;
1747 if (datalen == sizeof(*iblob)) {
1748 /* Data has been written to file descriptor. */
1749 break;
1752 if (*size > GOT_PRIVSEP_INLINE_BLOB_DATA_MAX ||
1753 *size > datalen + sizeof(*iblob)) {
1754 err = got_error(GOT_ERR_PRIVSEP_LEN);
1755 break;
1758 *outbuf = malloc(*size);
1759 if (*outbuf == NULL) {
1760 err = got_error_from_errno("malloc");
1761 break;
1763 memcpy(*outbuf, imsg.data + sizeof(*iblob), *size);
1764 break;
1765 default:
1766 err = got_error(GOT_ERR_PRIVSEP_MSG);
1767 break;
1770 imsg_free(&imsg);
1772 return err;
1775 static const struct got_error *
1776 send_tagmsg(struct imsgbuf *ibuf, struct got_tag_object *tag, size_t tagmsg_len)
1778 const struct got_error *err = NULL;
1779 size_t offset, remain;
1781 offset = 0;
1782 remain = tagmsg_len;
1783 while (remain > 0) {
1784 size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE, remain);
1786 if (imsg_compose(ibuf, GOT_IMSG_TAG_TAGMSG, 0, 0, -1,
1787 tag->tagmsg + offset, n) == -1) {
1788 err = got_error_from_errno("imsg_compose TAG_TAGMSG");
1789 break;
1792 err = flush_imsg(ibuf);
1793 if (err)
1794 break;
1796 offset += n;
1797 remain -= n;
1800 return err;
1803 const struct got_error *
1804 got_privsep_send_tag(struct imsgbuf *ibuf, struct got_tag_object *tag)
1806 const struct got_error *err = NULL;
1807 struct got_imsg_tag_object *itag;
1808 uint8_t *buf;
1809 size_t len, total;
1810 size_t tag_len = strlen(tag->tag);
1811 size_t tagger_len = strlen(tag->tagger);
1812 size_t tagmsg_len = strlen(tag->tagmsg);
1814 total = sizeof(*itag) + tag_len + tagger_len + tagmsg_len;
1816 buf = malloc(total);
1817 if (buf == NULL)
1818 return got_error_from_errno("malloc");
1820 itag = (struct got_imsg_tag_object *)buf;
1821 memcpy(&itag->id, &tag->id, sizeof(itag->id));
1822 itag->obj_type = tag->obj_type;
1823 itag->tag_len = tag_len;
1824 itag->tagger_len = tagger_len;
1825 itag->tagger_time = tag->tagger_time;
1826 itag->tagger_gmtoff = tag->tagger_gmtoff;
1827 itag->tagmsg_len = tagmsg_len;
1829 len = sizeof(*itag);
1830 memcpy(buf + len, tag->tag, tag_len);
1831 len += tag_len;
1832 memcpy(buf + len, tag->tagger, tagger_len);
1833 len += tagger_len;
1835 if (imsg_compose(ibuf, GOT_IMSG_TAG, 0, 0, -1, buf, len) == -1) {
1836 err = got_error_from_errno("imsg_compose TAG");
1837 goto done;
1840 if (tagmsg_len == 0 ||
1841 tagmsg_len + len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
1842 err = flush_imsg(ibuf);
1843 if (err)
1844 goto done;
1846 err = send_tagmsg(ibuf, tag, tagmsg_len);
1847 done:
1848 free(buf);
1849 return err;
1852 const struct got_error *
1853 got_privsep_recv_tag(struct got_tag_object **tag, struct imsgbuf *ibuf)
1855 const struct got_error *err = NULL;
1856 struct imsg imsg;
1857 struct got_imsg_tag_object *itag;
1858 size_t len, datalen;
1859 const size_t min_datalen =
1860 MIN(sizeof(struct got_imsg_error),
1861 sizeof(struct got_imsg_tag_object));
1863 *tag = NULL;
1865 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
1866 if (err)
1867 return err;
1869 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1870 len = 0;
1872 switch (imsg.hdr.type) {
1873 case GOT_IMSG_TAG:
1874 if (datalen < sizeof(*itag)) {
1875 err = got_error(GOT_ERR_PRIVSEP_LEN);
1876 break;
1878 itag = imsg.data;
1879 if (datalen != sizeof(*itag) + itag->tag_len +
1880 itag->tagger_len) {
1881 err = got_error(GOT_ERR_PRIVSEP_LEN);
1882 break;
1884 len += sizeof(*itag);
1886 *tag = calloc(1, sizeof(**tag));
1887 if (*tag == NULL) {
1888 err = got_error_from_errno("calloc");
1889 break;
1892 memcpy(&(*tag)->id, &itag->id, sizeof(itag->id));
1894 (*tag)->tag = strndup(imsg.data + len, itag->tag_len);
1895 if ((*tag)->tag == NULL) {
1896 err = got_error_from_errno("strndup");
1897 break;
1899 len += itag->tag_len;
1901 (*tag)->obj_type = itag->obj_type;
1902 (*tag)->tagger_time = itag->tagger_time;
1903 (*tag)->tagger_gmtoff = itag->tagger_gmtoff;
1905 (*tag)->tagger = strndup(imsg.data + len, itag->tagger_len);
1906 if ((*tag)->tagger == NULL) {
1907 err = got_error_from_errno("strndup");
1908 break;
1910 len += itag->tagger_len;
1912 if (itag->tagmsg_len == 0) {
1913 (*tag)->tagmsg = strdup("");
1914 if ((*tag)->tagmsg == NULL) {
1915 err = got_error_from_errno("strdup");
1916 break;
1918 } else {
1919 size_t offset = 0, remain = itag->tagmsg_len;
1921 (*tag)->tagmsg = malloc(itag->tagmsg_len + 1);
1922 if ((*tag)->tagmsg == NULL) {
1923 err = got_error_from_errno("malloc");
1924 break;
1926 while (remain > 0) {
1927 struct imsg imsg_log;
1928 size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE,
1929 remain);
1931 err = got_privsep_recv_imsg(&imsg_log, ibuf, n);
1932 if (err)
1933 return err;
1935 if (imsg_log.hdr.type != GOT_IMSG_TAG_TAGMSG)
1936 return got_error(GOT_ERR_PRIVSEP_MSG);
1938 memcpy((*tag)->tagmsg + offset, imsg_log.data,
1939 n);
1940 imsg_free(&imsg_log);
1941 offset += n;
1942 remain -= n;
1944 (*tag)->tagmsg[itag->tagmsg_len] = '\0';
1947 break;
1948 default:
1949 err = got_error(GOT_ERR_PRIVSEP_MSG);
1950 break;
1953 imsg_free(&imsg);
1955 return err;
1958 const struct got_error *
1959 got_privsep_init_pack_child(struct imsgbuf *ibuf, struct got_pack *pack,
1960 struct got_packidx *packidx)
1962 const struct got_error *err = NULL;
1963 struct got_imsg_packidx ipackidx;
1964 struct got_imsg_pack ipack;
1965 int fd;
1967 memset(&ipackidx, 0, sizeof(ipackidx));
1968 memset(&ipack, 0, sizeof(ipack));
1970 ipackidx.len = packidx->len;
1971 ipackidx.packfile_size = pack->filesize;
1972 fd = dup(packidx->fd);
1973 if (fd == -1)
1974 return got_error_from_errno("dup");
1976 if (imsg_compose(ibuf, GOT_IMSG_PACKIDX, 0, 0, fd, &ipackidx,
1977 sizeof(ipackidx)) == -1) {
1978 err = got_error_from_errno("imsg_compose PACKIDX");
1979 close(fd);
1980 return err;
1983 if (strlcpy(ipack.path_packfile, pack->path_packfile,
1984 sizeof(ipack.path_packfile)) >= sizeof(ipack.path_packfile))
1985 return got_error(GOT_ERR_NO_SPACE);
1986 ipack.filesize = pack->filesize;
1988 fd = dup(pack->fd);
1989 if (fd == -1)
1990 return got_error_from_errno("dup");
1992 if (imsg_compose(ibuf, GOT_IMSG_PACK, 0, 0, fd, &ipack, sizeof(ipack))
1993 == -1) {
1994 err = got_error_from_errno("imsg_compose PACK");
1995 close(fd);
1996 return err;
1999 return flush_imsg(ibuf);
2002 const struct got_error *
2003 got_privsep_send_packed_obj_req(struct imsgbuf *ibuf, int idx,
2004 struct got_object_id *id)
2006 struct got_imsg_packed_object iobj;
2008 memset(&iobj, 0, sizeof(iobj));
2009 iobj.idx = idx;
2010 memcpy(&iobj.id, id, sizeof(iobj.id));
2012 if (imsg_compose(ibuf, GOT_IMSG_PACKED_OBJECT_REQUEST, 0, 0, -1,
2013 &iobj, sizeof(iobj)) == -1)
2014 return got_error_from_errno("imsg_compose "
2015 "PACKED_OBJECT_REQUEST");
2017 return flush_imsg(ibuf);
2020 const struct got_error *
2021 got_privsep_send_packed_raw_obj_req(struct imsgbuf *ibuf, int idx,
2022 struct got_object_id *id)
2024 struct got_imsg_packed_object iobj;
2026 memset(&iobj, 0, sizeof(iobj));
2027 iobj.idx = idx;
2028 memcpy(&iobj.id, id, sizeof(iobj.id));
2030 if (imsg_compose(ibuf, GOT_IMSG_PACKED_RAW_OBJECT_REQUEST, 0, 0, -1,
2031 &iobj, sizeof(iobj)) == -1)
2032 return got_error_from_errno("imsg_compose "
2033 "PACKED_OBJECT_REQUEST");
2035 return flush_imsg(ibuf);
2038 const struct got_error *
2039 got_privsep_send_gitconfig_parse_req(struct imsgbuf *ibuf, int fd)
2041 const struct got_error *err = NULL;
2043 if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_PARSE_REQUEST, 0, 0, fd,
2044 NULL, 0) == -1) {
2045 err = got_error_from_errno("imsg_compose "
2046 "GITCONFIG_PARSE_REQUEST");
2047 close(fd);
2048 return err;
2051 return flush_imsg(ibuf);
2054 const struct got_error *
2055 got_privsep_send_gitconfig_repository_format_version_req(struct imsgbuf *ibuf)
2057 if (imsg_compose(ibuf,
2058 GOT_IMSG_GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST, 0, 0, -1,
2059 NULL, 0) == -1)
2060 return got_error_from_errno("imsg_compose "
2061 "GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST");
2063 return flush_imsg(ibuf);
2066 const struct got_error *
2067 got_privsep_send_gitconfig_repository_extensions_req(struct imsgbuf *ibuf)
2069 if (imsg_compose(ibuf,
2070 GOT_IMSG_GITCONFIG_REPOSITORY_EXTENSIONS_REQUEST, 0, 0, -1,
2071 NULL, 0) == -1)
2072 return got_error_from_errno("imsg_compose "
2073 "GITCONFIG_REPOSITORY_EXTENSIONS_REQUEST");
2075 return flush_imsg(ibuf);
2079 const struct got_error *
2080 got_privsep_send_gitconfig_author_name_req(struct imsgbuf *ibuf)
2082 if (imsg_compose(ibuf,
2083 GOT_IMSG_GITCONFIG_AUTHOR_NAME_REQUEST, 0, 0, -1, NULL, 0) == -1)
2084 return got_error_from_errno("imsg_compose "
2085 "GITCONFIG_AUTHOR_NAME_REQUEST");
2087 return flush_imsg(ibuf);
2090 const struct got_error *
2091 got_privsep_send_gitconfig_author_email_req(struct imsgbuf *ibuf)
2093 if (imsg_compose(ibuf,
2094 GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST, 0, 0, -1, NULL, 0) == -1)
2095 return got_error_from_errno("imsg_compose "
2096 "GITCONFIG_AUTHOR_EMAIL_REQUEST");
2098 return flush_imsg(ibuf);
2101 const struct got_error *
2102 got_privsep_send_gitconfig_remotes_req(struct imsgbuf *ibuf)
2104 if (imsg_compose(ibuf,
2105 GOT_IMSG_GITCONFIG_REMOTES_REQUEST, 0, 0, -1, NULL, 0) == -1)
2106 return got_error_from_errno("imsg_compose "
2107 "GITCONFIG_REMOTE_REQUEST");
2109 return flush_imsg(ibuf);
2112 const struct got_error *
2113 got_privsep_send_gitconfig_owner_req(struct imsgbuf *ibuf)
2115 if (imsg_compose(ibuf,
2116 GOT_IMSG_GITCONFIG_OWNER_REQUEST, 0, 0, -1, NULL, 0) == -1)
2117 return got_error_from_errno("imsg_compose "
2118 "GITCONFIG_OWNER_REQUEST");
2120 return flush_imsg(ibuf);
2123 const struct got_error *
2124 got_privsep_recv_gitconfig_str(char **str, struct imsgbuf *ibuf)
2126 const struct got_error *err = NULL;
2127 struct imsg imsg;
2128 size_t datalen;
2130 *str = NULL;
2132 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2133 if (err)
2134 return err;
2135 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2137 switch (imsg.hdr.type) {
2138 case GOT_IMSG_GITCONFIG_STR_VAL:
2139 if (datalen == 0)
2140 break;
2141 *str = strndup(imsg.data, datalen);
2142 if (*str == NULL) {
2143 err = got_error_from_errno("strndup");
2144 break;
2146 break;
2147 default:
2148 err = got_error(GOT_ERR_PRIVSEP_MSG);
2149 break;
2152 imsg_free(&imsg);
2153 return err;
2156 const struct got_error *
2157 got_privsep_recv_gitconfig_pair(char **key, char **val, struct imsgbuf *ibuf)
2159 const struct got_error *err = NULL;
2160 struct got_imsg_gitconfig_pair p;
2161 struct imsg imsg;
2162 size_t datalen;
2163 uint8_t *data;
2165 *key = *val = NULL;
2167 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2168 if (err)
2169 return err;
2171 data = imsg.data;
2172 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2174 if (imsg.hdr.type != GOT_IMSG_GITCONFIG_PAIR) {
2175 err = got_error(GOT_ERR_PRIVSEP_MSG);
2176 goto done;
2179 if (datalen < sizeof(p)) {
2180 err = got_error(GOT_ERR_PRIVSEP_LEN);
2181 goto done;
2184 memcpy(&p, data, sizeof(p));
2185 data += sizeof(p);
2187 if (datalen != sizeof(p) + p.klen + p.vlen) {
2188 err = got_error(GOT_ERR_PRIVSEP_LEN);
2189 goto done;
2192 *key = strndup(data, p.klen);
2193 if (*key == NULL) {
2194 err = got_error_from_errno("strndup");
2195 goto done;
2197 data += p.klen;
2199 *val = strndup(data, p.vlen);
2200 if (*val == NULL) {
2201 err = got_error_from_errno("strndup");
2202 goto done;
2205 done:
2206 imsg_free(&imsg);
2207 return err;
2210 const struct got_error *
2211 got_privsep_recv_gitconfig_int(int *val, struct imsgbuf *ibuf)
2213 const struct got_error *err = NULL;
2214 struct imsg imsg;
2215 size_t datalen;
2216 const size_t min_datalen =
2217 MIN(sizeof(struct got_imsg_error), sizeof(int));
2219 *val = 0;
2221 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
2222 if (err)
2223 return err;
2224 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2226 switch (imsg.hdr.type) {
2227 case GOT_IMSG_GITCONFIG_INT_VAL:
2228 if (datalen != sizeof(*val)) {
2229 err = got_error(GOT_ERR_PRIVSEP_LEN);
2230 break;
2232 memcpy(val, imsg.data, sizeof(*val));
2233 break;
2234 default:
2235 err = got_error(GOT_ERR_PRIVSEP_MSG);
2236 break;
2239 imsg_free(&imsg);
2240 return err;
2243 static void
2244 free_remote_data(struct got_remote_repo *remote)
2246 int i;
2248 free(remote->name);
2249 free(remote->fetch_url);
2250 free(remote->send_url);
2251 for (i = 0; i < remote->nfetch_branches; i++)
2252 free(remote->fetch_branches[i]);
2253 free(remote->fetch_branches);
2254 for (i = 0; i < remote->nsend_branches; i++)
2255 free(remote->send_branches[i]);
2256 free(remote->send_branches);
2257 for (i = 0; i < remote->nfetch_refs; i++)
2258 free(remote->fetch_refs[i]);
2259 free(remote->fetch_refs);
2262 const struct got_error *
2263 got_privsep_recv_gitconfig_remotes(struct got_remote_repo **remotes,
2264 int *nremotes, struct imsgbuf *ibuf)
2266 const struct got_error *err = NULL;
2267 struct imsg imsg;
2268 size_t datalen;
2269 struct got_imsg_remotes iremotes;
2270 struct got_imsg_remote iremote;
2272 *remotes = NULL;
2273 *nremotes = 0;
2274 iremotes.nremotes = 0;
2276 err = got_privsep_recv_imsg(&imsg, ibuf, sizeof(iremotes));
2277 if (err)
2278 return err;
2279 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2281 switch (imsg.hdr.type) {
2282 case GOT_IMSG_GITCONFIG_REMOTES:
2283 if (datalen != sizeof(iremotes)) {
2284 err = got_error(GOT_ERR_PRIVSEP_LEN);
2285 break;
2287 memcpy(&iremotes, imsg.data, sizeof(iremotes));
2288 if (iremotes.nremotes == 0) {
2289 imsg_free(&imsg);
2290 return NULL;
2292 break;
2293 default:
2294 imsg_free(&imsg);
2295 return got_error(GOT_ERR_PRIVSEP_MSG);
2298 imsg_free(&imsg);
2300 *remotes = recallocarray(NULL, 0, iremotes.nremotes, sizeof(**remotes));
2301 if (*remotes == NULL)
2302 return got_error_from_errno("recallocarray");
2304 while (*nremotes < iremotes.nremotes) {
2305 struct got_remote_repo *remote;
2307 err = got_privsep_recv_imsg(&imsg, ibuf, sizeof(iremote));
2308 if (err)
2309 break;
2310 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2312 switch (imsg.hdr.type) {
2313 case GOT_IMSG_GITCONFIG_REMOTE:
2314 remote = &(*remotes)[*nremotes];
2315 memset(remote, 0, sizeof(*remote));
2316 if (datalen < sizeof(iremote)) {
2317 err = got_error(GOT_ERR_PRIVSEP_LEN);
2318 break;
2320 memcpy(&iremote, imsg.data, sizeof(iremote));
2321 if (iremote.name_len == 0 ||
2322 iremote.fetch_url_len == 0 ||
2323 iremote.send_url_len == 0 ||
2324 (sizeof(iremote) + iremote.name_len +
2325 iremote.fetch_url_len + iremote.send_url_len) > datalen) {
2326 err = got_error(GOT_ERR_PRIVSEP_LEN);
2327 break;
2329 remote->name = strndup(imsg.data + sizeof(iremote),
2330 iremote.name_len);
2331 if (remote->name == NULL) {
2332 err = got_error_from_errno("strndup");
2333 break;
2335 remote->fetch_url = strndup(imsg.data + sizeof(iremote) +
2336 iremote.name_len, iremote.fetch_url_len);
2337 if (remote->fetch_url == NULL) {
2338 err = got_error_from_errno("strndup");
2339 free_remote_data(remote);
2340 break;
2342 remote->send_url = strndup(imsg.data + sizeof(iremote) +
2343 iremote.name_len + iremote.fetch_url_len,
2344 iremote.send_url_len);
2345 if (remote->send_url == NULL) {
2346 err = got_error_from_errno("strndup");
2347 free_remote_data(remote);
2348 break;
2350 remote->mirror_references = iremote.mirror_references;
2351 remote->fetch_all_branches = iremote.fetch_all_branches;
2352 remote->nfetch_branches = 0;
2353 remote->fetch_branches = NULL;
2354 remote->nsend_branches = 0;
2355 remote->send_branches = NULL;
2356 remote->nfetch_refs = 0;
2357 remote->fetch_refs = NULL;
2358 (*nremotes)++;
2359 break;
2360 default:
2361 err = got_error(GOT_ERR_PRIVSEP_MSG);
2362 break;
2365 imsg_free(&imsg);
2366 if (err)
2367 break;
2370 if (err) {
2371 int i;
2372 for (i = 0; i < *nremotes; i++)
2373 free_remote_data(&(*remotes)[i]);
2374 free(*remotes);
2375 *remotes = NULL;
2376 *nremotes = 0;
2378 return err;
2381 const struct got_error *
2382 got_privsep_send_gotconfig_parse_req(struct imsgbuf *ibuf, int fd)
2384 const struct got_error *err = NULL;
2386 if (imsg_compose(ibuf, GOT_IMSG_GOTCONFIG_PARSE_REQUEST, 0, 0, fd,
2387 NULL, 0) == -1) {
2388 err = got_error_from_errno("imsg_compose "
2389 "GOTCONFIG_PARSE_REQUEST");
2390 close(fd);
2391 return err;
2394 return flush_imsg(ibuf);
2397 const struct got_error *
2398 got_privsep_send_gotconfig_author_req(struct imsgbuf *ibuf)
2400 if (imsg_compose(ibuf,
2401 GOT_IMSG_GOTCONFIG_AUTHOR_REQUEST, 0, 0, -1, NULL, 0) == -1)
2402 return got_error_from_errno("imsg_compose "
2403 "GOTCONFIG_AUTHOR_REQUEST");
2405 return flush_imsg(ibuf);
2408 const struct got_error *
2409 got_privsep_send_gotconfig_allowed_signers_req(struct imsgbuf *ibuf)
2411 if (imsg_compose(ibuf,
2412 GOT_IMSG_GOTCONFIG_ALLOWEDSIGNERS_REQUEST, 0, 0, -1, NULL, 0) == -1)
2413 return got_error_from_errno("imsg_compose "
2414 "GOTCONFIG_ALLOWEDSIGNERS_REQUEST");
2416 return flush_imsg(ibuf);
2419 const struct got_error *
2420 got_privsep_send_gotconfig_revoked_signers_req(struct imsgbuf *ibuf)
2422 if (imsg_compose(ibuf,
2423 GOT_IMSG_GOTCONFIG_REVOKEDSIGNERS_REQUEST, 0, 0, -1, NULL, 0) == -1)
2424 return got_error_from_errno("imsg_compose "
2425 "GOTCONFIG_REVOKEDSIGNERS_REQUEST");
2427 return flush_imsg(ibuf);
2430 const struct got_error *
2431 got_privsep_send_gotconfig_signer_id_req(struct imsgbuf *ibuf)
2433 if (imsg_compose(ibuf,
2434 GOT_IMSG_GOTCONFIG_SIGNERID_REQUEST, 0, 0, -1, NULL, 0) == -1)
2435 return got_error_from_errno("imsg_compose "
2436 "GOTCONFIG_SIGNERID_REQUEST");
2438 return flush_imsg(ibuf);
2441 const struct got_error *
2442 got_privsep_send_gotconfig_remotes_req(struct imsgbuf *ibuf)
2444 if (imsg_compose(ibuf,
2445 GOT_IMSG_GOTCONFIG_REMOTES_REQUEST, 0, 0, -1, NULL, 0) == -1)
2446 return got_error_from_errno("imsg_compose "
2447 "GOTCONFIG_REMOTE_REQUEST");
2449 return flush_imsg(ibuf);
2452 const struct got_error *
2453 got_privsep_recv_gotconfig_str(char **str, struct imsgbuf *ibuf)
2455 const struct got_error *err = NULL;
2456 struct imsg imsg;
2457 size_t datalen;
2459 *str = NULL;
2461 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2462 if (err)
2463 return err;
2464 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2466 switch (imsg.hdr.type) {
2467 case GOT_IMSG_GOTCONFIG_STR_VAL:
2468 if (datalen == 0)
2469 break;
2470 *str = strndup(imsg.data, datalen);
2471 if (*str == NULL) {
2472 err = got_error_from_errno("strndup");
2473 break;
2475 break;
2476 default:
2477 err = got_error(GOT_ERR_PRIVSEP_MSG);
2478 break;
2481 imsg_free(&imsg);
2482 return err;
2485 const struct got_error *
2486 got_privsep_recv_gotconfig_remotes(struct got_remote_repo **remotes,
2487 int *nremotes, struct imsgbuf *ibuf)
2489 const struct got_error *err = NULL;
2490 struct imsg imsg;
2491 size_t datalen;
2492 struct got_imsg_remotes iremotes;
2493 struct got_imsg_remote iremote;
2494 const size_t min_datalen =
2495 MIN(sizeof(struct got_imsg_error), sizeof(iremotes));
2497 *remotes = NULL;
2498 *nremotes = 0;
2499 iremotes.nremotes = 0;
2501 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
2502 if (err)
2503 return err;
2504 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2506 switch (imsg.hdr.type) {
2507 case GOT_IMSG_GOTCONFIG_REMOTES:
2508 if (datalen != sizeof(iremotes)) {
2509 err = got_error(GOT_ERR_PRIVSEP_LEN);
2510 break;
2512 memcpy(&iremotes, imsg.data, sizeof(iremotes));
2513 if (iremotes.nremotes < 0) {
2514 err = got_error(GOT_ERR_PRIVSEP_LEN);
2515 break;
2517 if (iremotes.nremotes == 0) {
2518 imsg_free(&imsg);
2519 return NULL;
2521 break;
2522 default:
2523 imsg_free(&imsg);
2524 return got_error(GOT_ERR_PRIVSEP_MSG);
2527 imsg_free(&imsg);
2529 *remotes = recallocarray(NULL, 0, iremotes.nremotes, sizeof(**remotes));
2530 if (*remotes == NULL)
2531 return got_error_from_errno("recallocarray");
2533 while (*nremotes < iremotes.nremotes) {
2534 struct got_remote_repo *remote;
2535 const size_t min_datalen =
2536 MIN(sizeof(struct got_imsg_error), sizeof(iremote));
2537 int i;
2539 err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
2540 if (err)
2541 break;
2542 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2544 switch (imsg.hdr.type) {
2545 case GOT_IMSG_GOTCONFIG_REMOTE:
2546 remote = &(*remotes)[*nremotes];
2547 memset(remote, 0, sizeof(*remote));
2548 if (datalen < sizeof(iremote)) {
2549 err = got_error(GOT_ERR_PRIVSEP_LEN);
2550 break;
2552 memcpy(&iremote, imsg.data, sizeof(iremote));
2553 if (iremote.name_len == 0 ||
2554 (iremote.fetch_url_len == 0 &&
2555 iremote.send_url_len == 0) ||
2556 (sizeof(iremote) + iremote.name_len +
2557 iremote.fetch_url_len + iremote.send_url_len) >
2558 datalen) {
2559 err = got_error(GOT_ERR_PRIVSEP_LEN);
2560 break;
2562 remote->name = strndup(imsg.data + sizeof(iremote),
2563 iremote.name_len);
2564 if (remote->name == NULL) {
2565 err = got_error_from_errno("strndup");
2566 break;
2568 remote->fetch_url = strndup(imsg.data +
2569 sizeof(iremote) + iremote.name_len,
2570 iremote.fetch_url_len);
2571 if (remote->fetch_url == NULL) {
2572 err = got_error_from_errno("strndup");
2573 free_remote_data(remote);
2574 break;
2576 remote->send_url = strndup(imsg.data +
2577 sizeof(iremote) + iremote.name_len +
2578 iremote.fetch_url_len, iremote.send_url_len);
2579 if (remote->send_url == NULL) {
2580 err = got_error_from_errno("strndup");
2581 free_remote_data(remote);
2582 break;
2584 remote->mirror_references = iremote.mirror_references;
2585 remote->fetch_all_branches = iremote.fetch_all_branches;
2586 if (iremote.nfetch_branches > 0) {
2587 remote->fetch_branches = recallocarray(NULL, 0,
2588 iremote.nfetch_branches, sizeof(char *));
2589 if (remote->fetch_branches == NULL) {
2590 err = got_error_from_errno("calloc");
2591 free_remote_data(remote);
2592 break;
2595 remote->nfetch_branches = 0;
2596 for (i = 0; i < iremote.nfetch_branches; i++) {
2597 char *branch;
2598 err = got_privsep_recv_gotconfig_str(&branch,
2599 ibuf);
2600 if (err) {
2601 free_remote_data(remote);
2602 goto done;
2604 remote->fetch_branches[i] = branch;
2605 remote->nfetch_branches++;
2607 if (iremote.nsend_branches > 0) {
2608 remote->send_branches = recallocarray(NULL, 0,
2609 iremote.nsend_branches, sizeof(char *));
2610 if (remote->send_branches == NULL) {
2611 err = got_error_from_errno("calloc");
2612 free_remote_data(remote);
2613 break;
2616 remote->nsend_branches = 0;
2617 for (i = 0; i < iremote.nsend_branches; i++) {
2618 char *branch;
2619 err = got_privsep_recv_gotconfig_str(&branch,
2620 ibuf);
2621 if (err) {
2622 free_remote_data(remote);
2623 goto done;
2625 remote->send_branches[i] = branch;
2626 remote->nsend_branches++;
2628 if (iremote.nfetch_refs > 0) {
2629 remote->fetch_refs = recallocarray(NULL, 0,
2630 iremote.nfetch_refs, sizeof(char *));
2631 if (remote->fetch_refs == NULL) {
2632 err = got_error_from_errno("calloc");
2633 free_remote_data(remote);
2634 break;
2637 remote->nfetch_refs = 0;
2638 for (i = 0; i < iremote.nfetch_refs; i++) {
2639 char *ref;
2640 err = got_privsep_recv_gotconfig_str(&ref,
2641 ibuf);
2642 if (err) {
2643 free_remote_data(remote);
2644 goto done;
2646 remote->fetch_refs[i] = ref;
2647 remote->nfetch_refs++;
2649 (*nremotes)++;
2650 break;
2651 default:
2652 err = got_error(GOT_ERR_PRIVSEP_MSG);
2653 break;
2656 imsg_free(&imsg);
2657 if (err)
2658 break;
2660 done:
2661 if (err) {
2662 int i;
2663 for (i = 0; i < *nremotes; i++)
2664 free_remote_data(&(*remotes)[i]);
2665 free(*remotes);
2666 *remotes = NULL;
2667 *nremotes = 0;
2669 return err;
2672 const struct got_error *
2673 got_privsep_send_commit_traversal_request(struct imsgbuf *ibuf,
2674 struct got_object_id *id, int idx, const char *path)
2676 struct ibuf *wbuf;
2677 size_t path_len = strlen(path);
2679 wbuf = imsg_create(ibuf, GOT_IMSG_COMMIT_TRAVERSAL_REQUEST, 0, 0,
2680 sizeof(struct got_imsg_commit_traversal_request) + path_len);
2681 if (wbuf == NULL)
2682 return got_error_from_errno(
2683 "imsg_create COMMIT_TRAVERSAL_REQUEST");
2685 * Keep in sync with struct got_imsg_commit_traversal_request
2686 * and struct got_imsg_packed_object.
2688 if (imsg_add(wbuf, id, sizeof(*id)) == -1)
2689 return got_error_from_errno("imsg_add "
2690 "COMMIT_TRAVERSAL_REQUEST");
2691 if (imsg_add(wbuf, &idx, sizeof(idx)) == -1)
2692 return got_error_from_errno("imsg_add "
2693 "COMMIT_TRAVERSAL_REQUEST");
2694 if (imsg_add(wbuf, &path_len, sizeof(path_len)) == -1)
2695 return got_error_from_errno("imsg_add "
2696 "COMMIT_TRAVERSAL_REQUEST");
2697 if (imsg_add(wbuf, path, path_len) == -1)
2698 return got_error_from_errno("imsg_add "
2699 "COMMIT_TRAVERSAL_REQUEST");
2701 wbuf->fd = -1;
2702 imsg_close(ibuf, wbuf);
2704 return flush_imsg(ibuf);
2707 const struct got_error *
2708 got_privsep_recv_traversed_commits(struct got_commit_object **changed_commit,
2709 struct got_object_id **changed_commit_id,
2710 struct got_object_id_queue *commit_ids, struct imsgbuf *ibuf)
2712 const struct got_error *err = NULL;
2713 struct imsg imsg;
2714 struct got_imsg_traversed_commits *icommits;
2715 struct got_object_id *ids;
2716 size_t datalen;
2717 int i, done = 0;
2719 *changed_commit = NULL;
2720 *changed_commit_id = NULL;
2722 while (!done) {
2723 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2724 if (err)
2725 return err;
2727 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2728 switch (imsg.hdr.type) {
2729 case GOT_IMSG_TRAVERSED_COMMITS:
2730 icommits = imsg.data;
2731 if (datalen != sizeof(*icommits) +
2732 icommits->ncommits * sizeof(*ids)) {
2733 err = got_error(GOT_ERR_PRIVSEP_LEN);
2734 break;
2736 ids = imsg.data + sizeof(*icommits);
2737 for (i = 0; i < icommits->ncommits; i++) {
2738 struct got_object_qid *qid;
2740 err = got_object_qid_alloc_partial(&qid);
2741 if (err)
2742 break;
2743 memcpy(&qid->id, &ids[i], sizeof(ids[i]));
2744 STAILQ_INSERT_TAIL(commit_ids, qid, entry);
2746 /* The last commit may contain a change. */
2747 if (i == icommits->ncommits - 1) {
2748 *changed_commit_id =
2749 got_object_id_dup(&qid->id);
2750 if (*changed_commit_id == NULL) {
2751 err = got_error_from_errno(
2752 "got_object_id_dup");
2753 break;
2757 break;
2758 case GOT_IMSG_COMMIT:
2759 if (*changed_commit_id == NULL) {
2760 err = got_error(GOT_ERR_PRIVSEP_MSG);
2761 break;
2763 err = get_commit_from_imsg(changed_commit, &imsg,
2764 datalen, ibuf);
2765 break;
2766 case GOT_IMSG_COMMIT_TRAVERSAL_DONE:
2767 done = 1;
2768 break;
2769 default:
2770 err = got_error(GOT_ERR_PRIVSEP_MSG);
2771 break;
2774 imsg_free(&imsg);
2775 if (err)
2776 break;
2779 if (err)
2780 got_object_id_queue_free(commit_ids);
2781 return err;
2784 const struct got_error *
2785 got_privsep_send_enumerated_tree(size_t *totlen, struct imsgbuf *ibuf,
2786 struct got_object_id *tree_id, const char *path,
2787 struct got_parsed_tree_entry *entries, int nentries)
2789 const struct got_error *err = NULL;
2790 struct ibuf *wbuf;
2791 size_t path_len = strlen(path);
2792 size_t msglen;
2794 msglen = sizeof(struct got_imsg_enumerated_tree) + path_len;
2795 wbuf = imsg_create(ibuf, GOT_IMSG_ENUMERATED_TREE, 0, 0, msglen);
2796 if (wbuf == NULL)
2797 return got_error_from_errno("imsg_create ENUMERATED_TREE");
2799 if (imsg_add(wbuf, tree_id->sha1, SHA1_DIGEST_LENGTH) == -1)
2800 return got_error_from_errno("imsg_add ENUMERATED_TREE");
2801 if (imsg_add(wbuf, &nentries, sizeof(nentries)) == -1)
2802 return got_error_from_errno("imsg_add ENUMERATED_TREE");
2803 if (imsg_add(wbuf, path, path_len) == -1)
2804 return got_error_from_errno("imsg_add ENUMERATED_TREE");
2806 wbuf->fd = -1;
2807 imsg_close(ibuf, wbuf);
2809 if (entries) {
2810 err = send_tree_entries(ibuf, entries, nentries);
2811 if (err)
2812 return err;
2815 return flush_imsg(ibuf);
2818 const struct got_error *
2819 got_privsep_send_object_enumeration_request(struct imsgbuf *ibuf)
2821 if (imsg_compose(ibuf, GOT_IMSG_OBJECT_ENUMERATION_REQUEST,
2822 0, 0, -1, NULL, 0) == -1)
2823 return got_error_from_errno("imsg_compose "
2824 "OBJECT_ENUMERATION_REQUEST");
2826 return flush_imsg(ibuf);
2829 const struct got_error *
2830 got_privsep_send_object_enumeration_done(struct imsgbuf *ibuf)
2832 if (imsg_compose(ibuf, GOT_IMSG_OBJECT_ENUMERATION_DONE,
2833 0, 0, -1, NULL, 0) == -1)
2834 return got_error_from_errno("imsg_compose "
2835 "OBJECT_ENUMERATION_DONE");
2837 return flush_imsg(ibuf);
2840 const struct got_error *
2841 got_privsep_send_object_enumeration_incomplete(struct imsgbuf *ibuf)
2843 if (imsg_compose(ibuf, GOT_IMSG_OBJECT_ENUMERATION_INCOMPLETE,
2844 0, 0, -1, NULL, 0) == -1)
2845 return got_error_from_errno("imsg_compose "
2846 "OBJECT_ENUMERATION_INCOMPLETE");
2848 return flush_imsg(ibuf);
2851 const struct got_error *
2852 got_privsep_send_enumerated_commit(struct imsgbuf *ibuf,
2853 struct got_object_id *id, time_t mtime)
2855 struct ibuf *wbuf;
2857 wbuf = imsg_create(ibuf, GOT_IMSG_ENUMERATED_COMMIT, 0, 0,
2858 sizeof(struct got_imsg_enumerated_commit) + SHA1_DIGEST_LENGTH);
2859 if (wbuf == NULL)
2860 return got_error_from_errno("imsg_create ENUMERATED_COMMIT");
2862 /* Keep in sync with struct got_imsg_enumerated_commit! */
2863 if (imsg_add(wbuf, id, SHA1_DIGEST_LENGTH) == -1)
2864 return got_error_from_errno("imsg_add ENUMERATED_COMMIT");
2865 if (imsg_add(wbuf, &mtime, sizeof(mtime)) == -1)
2866 return got_error_from_errno("imsg_add ENUMERATED_COMMIT");
2868 wbuf->fd = -1;
2869 imsg_close(ibuf, wbuf);
2870 /* Don't flush yet, tree entries or ENUMERATION_DONE will follow. */
2871 return NULL;
2874 const struct got_error *
2875 got_privsep_recv_enumerated_objects(int *found_all_objects,
2876 struct imsgbuf *ibuf,
2877 got_object_enumerate_commit_cb cb_commit,
2878 got_object_enumerate_tree_cb cb_tree, void *cb_arg,
2879 struct got_repository *repo)
2881 const struct got_error *err = NULL;
2882 struct imsg imsg;
2883 struct got_imsg_enumerated_commit *icommit = NULL;
2884 struct got_object_id commit_id;
2885 int have_commit = 0;
2886 time_t mtime = 0;
2887 struct got_tree_object tree;
2888 struct got_imsg_enumerated_tree *itree;
2889 struct got_object_id tree_id;
2890 char *path = NULL, *canon_path = NULL;
2891 size_t datalen, path_len;
2892 int nentries = -1;
2893 int done = 0;
2895 *found_all_objects = 0;
2896 memset(&tree, 0, sizeof(tree));
2898 while (!done) {
2899 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2900 if (err)
2901 break;
2903 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2904 switch (imsg.hdr.type) {
2905 case GOT_IMSG_ENUMERATED_COMMIT:
2906 if (have_commit && nentries != -1) {
2907 err = got_error(GOT_ERR_PRIVSEP_MSG);
2908 break;
2910 if (datalen != sizeof(*icommit)) {
2911 err = got_error(GOT_ERR_PRIVSEP_LEN);
2912 break;
2914 icommit = (struct got_imsg_enumerated_commit *)imsg.data;
2915 memcpy(commit_id.sha1, icommit->id, SHA1_DIGEST_LENGTH);
2916 mtime = icommit->mtime;
2917 have_commit = 1;
2918 break;
2919 case GOT_IMSG_ENUMERATED_TREE:
2920 /* Should be preceeded by GOT_IMSG_ENUMERATED_COMMIT. */
2921 if (!have_commit) {
2922 err = got_error(GOT_ERR_PRIVSEP_MSG);
2923 break;
2925 if (datalen < sizeof(*itree)) {
2926 err = got_error(GOT_ERR_PRIVSEP_LEN);
2927 break;
2929 itree = imsg.data;
2930 path_len = datalen - sizeof(*itree);
2931 if (path_len == 0) {
2932 err = got_error(GOT_ERR_PRIVSEP_LEN);
2933 break;
2935 memcpy(tree_id.sha1, itree->id, sizeof(tree_id.sha1));
2936 free(path);
2937 path = strndup(imsg.data + sizeof(*itree), path_len);
2938 if (path == NULL) {
2939 err = got_error_from_errno("strndup");
2940 break;
2942 free(canon_path);
2943 canon_path = malloc(path_len + 1);
2944 if (canon_path == NULL) {
2945 err = got_error_from_errno("malloc");
2946 break;
2948 if (!got_path_is_absolute(path)) {
2949 err = got_error(GOT_ERR_BAD_PATH);
2950 break;
2952 if (got_path_is_root_dir(path)) {
2953 /* XXX check what got_canonpath() does wrong */
2954 canon_path[0] = '/';
2955 canon_path[1] = '\0';
2956 } else {
2957 err = got_canonpath(path, canon_path,
2958 path_len + 1);
2959 if (err)
2960 break;
2962 if (strcmp(path, canon_path) != 0) {
2963 err = got_error(GOT_ERR_BAD_PATH);
2964 break;
2966 if (nentries != -1) {
2967 err = got_error(GOT_ERR_PRIVSEP_MSG);
2968 break;
2970 if (itree->nentries < -1) {
2971 err = got_error(GOT_ERR_PRIVSEP_MSG);
2972 break;
2974 if (itree->nentries == -1) {
2975 /* Tree was not found in pack file. */
2976 err = cb_tree(cb_arg, NULL, mtime, &tree_id,
2977 path, repo);
2978 break;
2980 if (itree->nentries > INT_MAX) {
2981 err = got_error(GOT_ERR_PRIVSEP_LEN);
2982 break;
2984 tree.entries = calloc(itree->nentries,
2985 sizeof(struct got_tree_entry));
2986 if (tree.entries == NULL) {
2987 err = got_error_from_errno("calloc");
2988 break;
2990 if (itree->nentries == 0) {
2991 err = cb_tree(cb_arg, &tree, mtime, &tree_id,
2992 path, repo);
2993 if (err)
2994 break;
2996 /* Prepare for next tree. */
2997 free(tree.entries);
2998 memset(&tree, 0, sizeof(tree));
2999 nentries = -1;
3000 } else {
3001 tree.nentries = itree->nentries;
3002 nentries = 0;
3004 break;
3005 case GOT_IMSG_TREE_ENTRIES:
3006 /* Should be preceeded by GOT_IMSG_ENUMERATED_TREE. */
3007 if (nentries <= -1) {
3008 err = got_error(GOT_ERR_PRIVSEP_MSG);
3009 break;
3011 err = recv_tree_entries(imsg.data, datalen,
3012 &tree, &nentries);
3013 if (err)
3014 break;
3015 if (tree.nentries == nentries) {
3016 err = cb_tree(cb_arg, &tree, mtime, &tree_id,
3017 path, repo);
3018 if (err)
3019 break;
3021 /* Prepare for next tree. */
3022 free(tree.entries);
3023 memset(&tree, 0, sizeof(tree));
3024 nentries = -1;
3026 break;
3027 case GOT_IMSG_TREE_ENUMERATION_DONE:
3028 /* All trees have been found and traversed. */
3029 if (!have_commit || path == NULL || nentries != -1) {
3030 err = got_error(GOT_ERR_PRIVSEP_MSG);
3031 break;
3033 err = cb_commit(cb_arg, mtime, &commit_id, repo);
3034 if (err)
3035 break;
3036 have_commit = 0;
3037 break;
3038 case GOT_IMSG_OBJECT_ENUMERATION_DONE:
3039 *found_all_objects = 1;
3040 done = 1;
3041 break;
3042 case GOT_IMSG_OBJECT_ENUMERATION_INCOMPLETE:
3043 done = 1;
3044 break;
3045 default:
3046 err = got_error(GOT_ERR_PRIVSEP_MSG);
3047 break;
3050 imsg_free(&imsg);
3051 if (err)
3052 break;
3055 free(path);
3056 free(canon_path);
3057 free(tree.entries);
3058 return err;
3061 const struct got_error *
3062 got_privsep_send_raw_delta_req(struct imsgbuf *ibuf, int idx,
3063 struct got_object_id *id)
3065 struct got_imsg_raw_delta_request dreq;
3067 memset(&dreq, 0, sizeof(dreq));
3068 dreq.idx = idx;
3069 memcpy(&dreq.id, id, sizeof(dreq.id));
3071 if (imsg_compose(ibuf, GOT_IMSG_RAW_DELTA_REQUEST, 0, 0, -1,
3072 &dreq, sizeof(dreq)) == -1)
3073 return got_error_from_errno("imsg_compose RAW_DELTA_REQUEST");
3075 return flush_imsg(ibuf);
3078 const struct got_error *
3079 got_privsep_send_raw_delta_outfd(struct imsgbuf *ibuf, int fd)
3081 return send_fd(ibuf, GOT_IMSG_RAW_DELTA_OUTFD, fd);
3084 const struct got_error *
3085 got_privsep_send_raw_delta(struct imsgbuf *ibuf, uint64_t base_size,
3086 uint64_t result_size, off_t delta_size, off_t delta_compressed_size,
3087 off_t delta_offset, off_t delta_out_offset, struct got_object_id *base_id)
3089 struct got_imsg_raw_delta idelta;
3090 int ret;
3092 memset(&idelta, 0, sizeof(idelta));
3093 idelta.base_size = base_size;
3094 idelta.result_size = result_size;
3095 idelta.delta_size = delta_size;
3096 idelta.delta_compressed_size = delta_compressed_size;
3097 idelta.delta_offset = delta_offset;
3098 idelta.delta_out_offset = delta_out_offset;
3099 memcpy(&idelta.base_id, &base_id, sizeof(idelta.base_id));
3101 ret = imsg_compose(ibuf, GOT_IMSG_RAW_DELTA, 0, 0, -1,
3102 &idelta, sizeof(idelta));
3103 if (ret == -1)
3104 return got_error_from_errno("imsg_compose RAW_DELTA");
3106 return flush_imsg(ibuf);
3109 const struct got_error *
3110 got_privsep_recv_raw_delta(uint64_t *base_size, uint64_t *result_size,
3111 off_t *delta_size, off_t *delta_compressed_size, off_t *delta_offset,
3112 off_t *delta_out_offset, struct got_object_id **base_id,
3113 struct imsgbuf *ibuf)
3115 const struct got_error *err = NULL;
3116 struct imsg imsg;
3117 struct got_imsg_raw_delta *delta;
3118 size_t datalen;
3120 *base_size = 0;
3121 *result_size = 0;
3122 *delta_size = 0;
3123 *delta_compressed_size = 0;
3124 *delta_offset = 0;
3125 *delta_out_offset = 0;
3126 *base_id = NULL;
3128 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
3129 if (err)
3130 return err;
3132 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
3134 switch (imsg.hdr.type) {
3135 case GOT_IMSG_RAW_DELTA:
3136 if (datalen != sizeof(*delta)) {
3137 err = got_error(GOT_ERR_PRIVSEP_LEN);
3138 break;
3140 delta = imsg.data;
3141 *base_size = delta->base_size;
3142 *result_size = delta->result_size;
3143 *delta_size = delta->delta_size;
3144 *delta_compressed_size = delta->delta_compressed_size;
3145 *delta_offset = delta->delta_offset;
3146 *delta_out_offset = delta->delta_out_offset;
3147 *base_id = calloc(1, sizeof(**base_id));
3148 if (*base_id == NULL) {
3149 err = got_error_from_errno("malloc");
3150 break;
3152 memcpy(*base_id, &delta->base_id, sizeof(**base_id));
3153 break;
3154 default:
3155 err = got_error(GOT_ERR_PRIVSEP_MSG);
3156 break;
3159 imsg_free(&imsg);
3161 if (err) {
3162 free(*base_id);
3163 *base_id = NULL;
3165 return err;
3168 static const struct got_error *
3169 send_idlist(struct imsgbuf *ibuf, struct got_object_id **ids, size_t nids)
3171 const struct got_error *err = NULL;
3172 struct got_imsg_object_idlist idlist;
3173 struct ibuf *wbuf;
3174 size_t i;
3176 memset(&idlist, 0, sizeof(idlist));
3178 if (nids > GOT_IMSG_OBJ_ID_LIST_MAX_NIDS)
3179 return got_error(GOT_ERR_NO_SPACE);
3181 wbuf = imsg_create(ibuf, GOT_IMSG_OBJ_ID_LIST, 0, 0,
3182 sizeof(idlist) + nids * sizeof(**ids));
3183 if (wbuf == NULL) {
3184 err = got_error_from_errno("imsg_create OBJ_ID_LIST");
3185 return err;
3188 idlist.nids = nids;
3189 if (imsg_add(wbuf, &idlist, sizeof(idlist)) == -1)
3190 return got_error_from_errno("imsg_add OBJ_ID_LIST");
3192 for (i = 0; i < nids; i++) {
3193 struct got_object_id *id = ids[i];
3194 if (imsg_add(wbuf, id, sizeof(*id)) == -1)
3195 return got_error_from_errno("imsg_add OBJ_ID_LIST");
3198 wbuf->fd = -1;
3199 imsg_close(ibuf, wbuf);
3201 return flush_imsg(ibuf);
3204 const struct got_error *
3205 got_privsep_send_object_idlist(struct imsgbuf *ibuf,
3206 struct got_object_id **ids, size_t nids)
3208 const struct got_error *err = NULL;
3209 struct got_object_id *idlist[GOT_IMSG_OBJ_ID_LIST_MAX_NIDS];
3210 int i, queued = 0;
3212 for (i = 0; i < nids; i++) {
3213 idlist[i % nitems(idlist)] = ids[i];
3214 queued++;
3215 if (queued >= nitems(idlist)) {
3216 err = send_idlist(ibuf, idlist, queued);
3217 if (err)
3218 return err;
3219 queued = 0;
3223 if (queued > 0) {
3224 err = send_idlist(ibuf, idlist, queued);
3225 if (err)
3226 return err;
3229 return NULL;
3232 const struct got_error *
3233 got_privsep_send_object_idlist_done(struct imsgbuf *ibuf)
3235 if (imsg_compose(ibuf, GOT_IMSG_OBJ_ID_LIST_DONE, 0, 0, -1, NULL, 0)
3236 == -1)
3237 return got_error_from_errno("imsg_compose OBJ_ID_LIST_DONE");
3239 return flush_imsg(ibuf);
3242 const struct got_error *
3243 got_privsep_recv_object_idlist(int *done, struct got_object_id **ids,
3244 size_t *nids, struct imsgbuf *ibuf)
3246 const struct got_error *err = NULL;
3247 struct imsg imsg;
3248 struct got_imsg_object_idlist *idlist;
3249 size_t datalen;
3251 *ids = NULL;
3252 *done = 0;
3253 *nids = 0;
3255 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
3256 if (err)
3257 return err;
3259 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
3260 switch (imsg.hdr.type) {
3261 case GOT_IMSG_OBJ_ID_LIST:
3262 if (datalen < sizeof(*idlist)) {
3263 err = got_error(GOT_ERR_PRIVSEP_LEN);
3264 break;
3266 idlist = imsg.data;
3267 if (idlist->nids > GOT_IMSG_OBJ_ID_LIST_MAX_NIDS ||
3268 idlist->nids * sizeof(**ids) > datalen - sizeof(*idlist)) {
3269 err = got_error(GOT_ERR_PRIVSEP_LEN);
3270 break;
3272 *nids = idlist->nids;
3273 *ids = calloc(*nids, sizeof(**ids));
3274 if (*ids == NULL) {
3275 err = got_error_from_errno("calloc");
3276 break;
3278 memcpy(*ids, (uint8_t *)imsg.data + sizeof(*idlist),
3279 *nids * sizeof(**ids));
3280 break;
3281 case GOT_IMSG_OBJ_ID_LIST_DONE:
3282 *done = 1;
3283 break;
3284 default:
3285 err = got_error(GOT_ERR_PRIVSEP_MSG);
3286 break;
3289 imsg_free(&imsg);
3291 return err;
3294 const struct got_error *
3295 got_privsep_send_delta_reuse_req(struct imsgbuf *ibuf)
3297 if (imsg_compose(ibuf, GOT_IMSG_DELTA_REUSE_REQUEST, 0, 0, -1, NULL, 0)
3298 == -1)
3299 return got_error_from_errno("imsg_compose DELTA_REUSE_REQUEST");
3301 return flush_imsg(ibuf);
3304 const struct got_error *
3305 got_privsep_send_reused_deltas(struct imsgbuf *ibuf,
3306 struct got_imsg_reused_delta *deltas, size_t ndeltas)
3308 const struct got_error *err = NULL;
3309 struct ibuf *wbuf;
3310 struct got_imsg_reused_deltas ideltas;
3311 size_t i;
3313 memset(&ideltas, 0, sizeof(ideltas));
3315 if (ndeltas > GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS)
3316 return got_error(GOT_ERR_NO_SPACE);
3318 wbuf = imsg_create(ibuf, GOT_IMSG_REUSED_DELTAS, 0, 0,
3319 sizeof(ideltas) + ndeltas * sizeof(*deltas));
3320 if (wbuf == NULL) {
3321 err = got_error_from_errno("imsg_create REUSED_DELTAS");
3322 return err;
3325 ideltas.ndeltas = ndeltas;
3326 if (imsg_add(wbuf, &ideltas, sizeof(ideltas)) == -1)
3327 return got_error_from_errno("imsg_add REUSED_DELTAS");
3329 for (i = 0; i < ndeltas; i++) {
3330 struct got_imsg_reused_delta *delta = &deltas[i];
3331 if (imsg_add(wbuf, delta, sizeof(*delta)) == -1)
3332 return got_error_from_errno("imsg_add REUSED_DELTAS");
3335 wbuf->fd = -1;
3336 imsg_close(ibuf, wbuf);
3338 return flush_imsg(ibuf);
3341 const struct got_error *
3342 got_privsep_send_reused_deltas_done(struct imsgbuf *ibuf)
3344 if (imsg_compose(ibuf, GOT_IMSG_DELTA_REUSE_DONE, 0, 0, -1, NULL, 0)
3345 == -1)
3346 return got_error_from_errno("imsg_compose DELTA_REUSE_DONE");
3348 return flush_imsg(ibuf);
3351 const struct got_error *
3352 got_privsep_recv_reused_deltas(int *done, struct got_imsg_reused_delta *deltas,
3353 size_t *ndeltas, struct imsgbuf *ibuf)
3355 const struct got_error *err = NULL;
3356 struct imsg imsg;
3357 struct got_imsg_reused_deltas *ideltas;
3358 size_t datalen;
3360 *done = 0;
3361 *ndeltas = 0;
3363 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
3364 if (err)
3365 return err;
3367 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
3368 switch (imsg.hdr.type) {
3369 case GOT_IMSG_REUSED_DELTAS:
3370 if (datalen < sizeof(*ideltas)) {
3371 err = got_error(GOT_ERR_PRIVSEP_LEN);
3372 break;
3374 ideltas = imsg.data;
3375 if (ideltas->ndeltas > GOT_IMSG_OBJ_ID_LIST_MAX_NIDS ||
3376 ideltas->ndeltas * sizeof(*deltas) >
3377 datalen - sizeof(*ideltas)) {
3378 err = got_error(GOT_ERR_PRIVSEP_LEN);
3379 break;
3381 *ndeltas = ideltas->ndeltas;
3382 memcpy(deltas, (uint8_t *)imsg.data + sizeof(*ideltas),
3383 *ndeltas * sizeof(*deltas));
3384 break;
3385 case GOT_IMSG_DELTA_REUSE_DONE:
3386 *done = 1;
3387 break;
3388 default:
3389 err = got_error(GOT_ERR_PRIVSEP_MSG);
3390 break;
3393 imsg_free(&imsg);
3395 return err;
3398 const struct got_error *
3399 got_privsep_init_commit_painting(struct imsgbuf *ibuf)
3401 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_PAINTING_INIT,
3402 0, 0, -1, NULL, 0)
3403 == -1)
3404 return got_error_from_errno("imsg_compose "
3405 "COMMIT_PAINTING_INIT");
3407 return flush_imsg(ibuf);
3410 const struct got_error *
3411 got_privsep_send_painting_request(struct imsgbuf *ibuf, int idx,
3412 struct got_object_id *id, intptr_t color)
3414 struct got_imsg_commit_painting_request ireq;
3416 memset(&ireq, 0, sizeof(ireq));
3417 memcpy(&ireq.id, id, sizeof(ireq.id));
3418 ireq.idx = idx;
3419 ireq.color = color;
3421 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_PAINTING_REQUEST, 0, 0, -1,
3422 &ireq, sizeof(ireq)) == -1)
3423 return got_error_from_errno("imsg_compose "
3424 "COMMIT_PAINTING_REQUEST");
3426 return flush_imsg(ibuf);
3429 static const struct got_error *
3430 send_painted_commits(struct got_object_id_queue *ids, int *nids,
3431 size_t remain, int present_in_pack, struct imsgbuf *ibuf)
3433 const struct got_error *err = NULL;
3434 struct ibuf *wbuf = NULL;
3435 struct got_object_qid *qid;
3436 size_t msglen;
3437 int ncommits;
3438 intptr_t color;
3440 msglen = MIN(remain, MAX_IMSGSIZE - IMSG_HEADER_SIZE);
3441 ncommits = (msglen - sizeof(struct got_imsg_painted_commits)) /
3442 sizeof(struct got_imsg_painted_commit);
3444 wbuf = imsg_create(ibuf, GOT_IMSG_PAINTED_COMMITS, 0, 0, msglen);
3445 if (wbuf == NULL) {
3446 err = got_error_from_errno("imsg_create PAINTED_COMMITS");
3447 return err;
3450 /* Keep in sync with struct got_imsg_painted_commits! */
3451 if (imsg_add(wbuf, &ncommits, sizeof(ncommits)) == -1)
3452 return got_error_from_errno("imsg_add PAINTED_COMMITS");
3453 if (imsg_add(wbuf, &present_in_pack, sizeof(present_in_pack)) == -1)
3454 return got_error_from_errno("imsg_add PAINTED_COMMITS");
3456 while (ncommits > 0) {
3457 qid = STAILQ_FIRST(ids);
3458 STAILQ_REMOVE_HEAD(ids, entry);
3459 ncommits--;
3460 (*nids)--;
3461 color = (intptr_t)qid->data;
3463 /* Keep in sync with struct got_imsg_painted_commit! */
3464 if (imsg_add(wbuf, qid->id.sha1, SHA1_DIGEST_LENGTH) == -1)
3465 return got_error_from_errno("imsg_add PAINTED_COMMITS");
3466 if (imsg_add(wbuf, &color, sizeof(color)) == -1)
3467 return got_error_from_errno("imsg_add PAINTED_COMMITS");
3469 got_object_qid_free(qid);
3472 wbuf->fd = -1;
3473 imsg_close(ibuf, wbuf);
3475 return flush_imsg(ibuf);
3478 const struct got_error *
3479 got_privsep_send_painted_commits(struct imsgbuf *ibuf,
3480 struct got_object_id_queue *ids, int *nids,
3481 int present_in_pack, int flush)
3483 const struct got_error *err;
3484 size_t remain;
3486 if (*nids <= 0)
3487 return NULL;
3489 do {
3490 remain = (sizeof(struct got_imsg_painted_commits)) +
3491 *nids * sizeof(struct got_imsg_painted_commit);
3492 if (flush || remain >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
3493 err = send_painted_commits(ids, nids, remain,
3494 present_in_pack, ibuf);
3495 if (err)
3496 return err;
3498 } while (flush && *nids > 0);
3500 return NULL;
3503 const struct got_error *
3504 got_privsep_send_painting_commits_done(struct imsgbuf *ibuf)
3506 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_PAINTING_DONE,
3507 0, 0, -1, NULL, 0)
3508 == -1)
3509 return got_error_from_errno("imsg_compose "
3510 "COMMIT_PAINTING_DONE");
3512 return flush_imsg(ibuf);
3515 const struct got_error *
3516 got_privsep_recv_painted_commits(struct got_object_id_queue *new_ids,
3517 got_privsep_recv_painted_commit_cb cb, void *cb_arg, struct imsgbuf *ibuf)
3519 const struct got_error *err = NULL;
3520 struct imsg imsg;
3521 struct got_imsg_painted_commits icommits;
3522 struct got_imsg_painted_commit icommit;
3523 size_t datalen;
3524 int i;
3526 for (;;) {
3527 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
3528 if (err)
3529 return err;
3531 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
3532 if (imsg.hdr.type == GOT_IMSG_COMMIT_PAINTING_DONE)
3533 break;
3534 if (imsg.hdr.type != GOT_IMSG_PAINTED_COMMITS)
3535 return got_error(GOT_ERR_PRIVSEP_MSG);
3537 if (datalen < sizeof(icommits))
3538 return got_error(GOT_ERR_PRIVSEP_LEN);
3539 memcpy(&icommits, imsg.data, sizeof(icommits));
3540 if (icommits.ncommits * sizeof(icommit) < icommits.ncommits ||
3541 datalen < sizeof(icommits) +
3542 icommits.ncommits * sizeof(icommit))
3543 return got_error(GOT_ERR_PRIVSEP_LEN);
3545 for (i = 0; i < icommits.ncommits; i++) {
3546 memcpy(&icommit,
3547 (uint8_t *)imsg.data + sizeof(icommits) + i * sizeof(icommit),
3548 sizeof(icommit));
3550 if (icommits.present_in_pack) {
3551 struct got_object_id id;
3552 memcpy(id.sha1, icommit.id, SHA1_DIGEST_LENGTH);
3553 err = cb(cb_arg, &id, icommit.color);
3554 if (err)
3555 break;
3556 } else {
3557 struct got_object_qid *qid;
3558 err = got_object_qid_alloc_partial(&qid);
3559 if (err)
3560 break;
3561 memcpy(qid->id.sha1, icommit.id,
3562 SHA1_DIGEST_LENGTH);
3563 qid->data = (void *)icommit.color;
3564 STAILQ_INSERT_TAIL(new_ids, qid, entry);
3568 imsg_free(&imsg);
3571 return err;
3574 const struct got_error *
3575 got_privsep_unveil_exec_helpers(void)
3577 const char *helpers[] = {
3578 GOT_PATH_PROG_READ_PACK,
3579 GOT_PATH_PROG_READ_OBJECT,
3580 GOT_PATH_PROG_READ_COMMIT,
3581 GOT_PATH_PROG_READ_TREE,
3582 GOT_PATH_PROG_READ_BLOB,
3583 GOT_PATH_PROG_READ_TAG,
3584 GOT_PATH_PROG_READ_GITCONFIG,
3585 GOT_PATH_PROG_READ_GOTCONFIG,
3586 GOT_PATH_PROG_READ_PATCH,
3587 GOT_PATH_PROG_FETCH_PACK,
3588 GOT_PATH_PROG_INDEX_PACK,
3589 GOT_PATH_PROG_SEND_PACK,
3591 size_t i;
3593 for (i = 0; i < nitems(helpers); i++) {
3594 if (unveil(helpers[i], "x") == 0)
3595 continue;
3596 return got_error_from_errno2("unveil", helpers[i]);
3599 return NULL;
3602 void
3603 got_privsep_exec_child(int imsg_fds[2], const char *path, const char *repo_path)
3605 if (close(imsg_fds[0]) == -1) {
3606 fprintf(stderr, "%s: %s\n", getprogname(), strerror(errno));
3607 _exit(1);
3610 if (dup2(imsg_fds[1], GOT_IMSG_FD_CHILD) == -1) {
3611 fprintf(stderr, "%s: %s\n", getprogname(), strerror(errno));
3612 _exit(1);
3615 closefrom(GOT_IMSG_FD_CHILD + 1);
3617 if (execl(path, path, repo_path, (char *)NULL) == -1) {
3618 fprintf(stderr, "%s: %s: %s\n", getprogname(), path,
3619 strerror(errno));
3620 _exit(1);