Blob


1 /*
2 * Copyright (c) 2022 Stefan Sperling <stsp@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include "got_compat.h"
19 #include <sys/queue.h>
20 #include <sys/time.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <sys/wait.h>
26 #include <sys/resource.h>
28 #include <fcntl.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <event.h>
32 #include <limits.h>
33 #include <pwd.h>
34 #include <imsg.h>
35 #include <signal.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <syslog.h>
41 #include <unistd.h>
43 #include "got_error.h"
44 #include "got_opentemp.h"
45 #include "got_path.h"
46 #include "got_repository.h"
47 #include "got_object.h"
48 #include "got_reference.h"
49 #include "got_diff.h"
51 #include "got_lib_delta.h"
52 #include "got_lib_object.h"
53 #include "got_lib_object_cache.h"
54 #include "got_lib_hash.h"
55 #include "got_lib_gitproto.h"
56 #include "got_lib_pack.h"
57 #include "got_lib_repository.h"
59 #include "gotd.h"
60 #include "log.h"
61 #include "listen.h"
62 #include "auth.h"
63 #include "session.h"
64 #include "repo_read.h"
65 #include "repo_write.h"
66 #include "notify.h"
68 #ifndef nitems
69 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
70 #endif
72 enum gotd_client_state {
73 GOTD_CLIENT_STATE_NEW,
74 GOTD_CLIENT_STATE_ACCESS_GRANTED,
75 };
77 struct gotd_child_proc {
78 pid_t pid;
79 enum gotd_procid type;
80 char repo_name[NAME_MAX];
81 char repo_path[PATH_MAX];
82 int pipe[2];
83 struct gotd_imsgev iev;
84 struct event tmo;
86 TAILQ_ENTRY(gotd_child_proc) entry;
87 };
88 TAILQ_HEAD(gotd_procs, gotd_child_proc) procs;
90 struct gotd_client {
91 STAILQ_ENTRY(gotd_client) entry;
92 enum gotd_client_state state;
93 uint32_t id;
94 int fd;
95 struct gotd_imsgev iev;
96 struct event tmo;
97 uid_t euid;
98 gid_t egid;
99 char *username;
100 struct gotd_child_proc *repo;
101 struct gotd_child_proc *auth;
102 struct gotd_child_proc *session;
103 int required_auth;
104 };
105 STAILQ_HEAD(gotd_clients, gotd_client);
107 static struct gotd_clients gotd_clients[GOTD_CLIENT_TABLE_SIZE];
108 static SIPHASH_KEY clients_hash_key;
109 volatile int client_cnt;
110 static struct timeval auth_timeout = { 5, 0 };
111 static struct gotd gotd;
113 void gotd_sighdlr(int sig, short event, void *arg);
114 static void gotd_shutdown(void);
115 static const struct got_error *start_session_child(struct gotd_client *,
116 struct gotd_repo *, char *, const char *, int, int);
117 static const struct got_error *start_repo_child(struct gotd_client *,
118 enum gotd_procid, struct gotd_repo *, char *, const char *, int, int);
119 static const struct got_error *start_auth_child(struct gotd_client *, int,
120 struct gotd_repo *, char *, const char *, int, int);
121 static void kill_proc(struct gotd_child_proc *, int);
122 static void disconnect(struct gotd_client *);
123 static void drop_privs(struct passwd *);
125 __dead static void
126 usage(void)
128 fprintf(stderr, "usage: %s [-dnv] [-f config-file]\n", getprogname());
129 exit(1);
132 static void
133 drop_privs(struct passwd *pw)
135 /* Drop root privileges. */
136 if (setgid(pw->pw_gid) == -1)
137 fatal("setgid %d failed", pw->pw_gid);
138 if (setuid(pw->pw_uid) == -1)
139 fatal("setuid %d failed", pw->pw_uid);
142 static int
143 unix_socket_listen(const char *unix_socket_path, uid_t uid, gid_t gid)
145 struct sockaddr_un sun;
146 int fd = -1;
147 mode_t old_umask, mode;
148 int sock_flags = SOCK_STREAM | SOCK_NONBLOCK;
150 #ifdef SOCK_CLOEXEC
151 sock_flags |= SOCK_CLOEXEC;
152 #endif
154 fd = socket(AF_UNIX, sock_flags, 0);
155 if (fd == -1) {
156 log_warn("socket");
157 return -1;
160 sun.sun_family = AF_UNIX;
161 if (strlcpy(sun.sun_path, unix_socket_path,
162 sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) {
163 log_warnx("%s: name too long", unix_socket_path);
164 close(fd);
165 return -1;
168 if (unlink(unix_socket_path) == -1) {
169 if (errno != ENOENT) {
170 log_warn("unlink %s", unix_socket_path);
171 close(fd);
172 return -1;
176 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
177 mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
179 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
180 log_warn("bind: %s", unix_socket_path);
181 close(fd);
182 umask(old_umask);
183 return -1;
186 umask(old_umask);
188 if (chmod(unix_socket_path, mode) == -1) {
189 log_warn("chmod %o %s", mode, unix_socket_path);
190 close(fd);
191 unlink(unix_socket_path);
192 return -1;
195 if (chown(unix_socket_path, uid, gid) == -1) {
196 log_warn("chown %s uid=%d gid=%d", unix_socket_path, uid, gid);
197 close(fd);
198 unlink(unix_socket_path);
199 return -1;
202 if (listen(fd, GOTD_UNIX_SOCKET_BACKLOG) == -1) {
203 log_warn("listen");
204 close(fd);
205 unlink(unix_socket_path);
206 return -1;
209 return fd;
212 static uint64_t
213 client_hash(uint32_t client_id)
215 return SipHash24(&clients_hash_key, &client_id, sizeof(client_id));
218 static void
219 add_client(struct gotd_client *client)
221 uint64_t slot = client_hash(client->id) % nitems(gotd_clients);
222 STAILQ_INSERT_HEAD(&gotd_clients[slot], client, entry);
223 client_cnt++;
226 static struct gotd_client *
227 find_client(uint32_t client_id)
229 uint64_t slot;
230 struct gotd_client *c;
232 slot = client_hash(client_id) % nitems(gotd_clients);
233 STAILQ_FOREACH(c, &gotd_clients[slot], entry) {
234 if (c->id == client_id)
235 return c;
238 return NULL;
241 static struct gotd_client *
242 find_client_by_proc_fd(int fd)
244 uint64_t slot;
246 for (slot = 0; slot < nitems(gotd_clients); slot++) {
247 struct gotd_client *c;
249 STAILQ_FOREACH(c, &gotd_clients[slot], entry) {
250 if (c->repo && c->repo->iev.ibuf.fd == fd)
251 return c;
252 if (c->auth && c->auth->iev.ibuf.fd == fd)
253 return c;
254 if (c->session && c->session->iev.ibuf.fd == fd)
255 return c;
259 return NULL;
262 static int
263 client_is_reading(struct gotd_client *client)
265 return (client->required_auth &
266 (GOTD_AUTH_READ | GOTD_AUTH_WRITE)) == GOTD_AUTH_READ;
269 static int
270 client_is_writing(struct gotd_client *client)
272 return (client->required_auth &
273 (GOTD_AUTH_READ | GOTD_AUTH_WRITE)) ==
274 (GOTD_AUTH_READ | GOTD_AUTH_WRITE);
277 static const struct got_error *
278 ensure_client_is_not_writing(struct gotd_client *client)
280 if (client_is_writing(client)) {
281 return got_error_fmt(GOT_ERR_BAD_PACKET,
282 "uid %d made a read-request but is writing to "
283 "a repository", client->euid);
286 return NULL;
289 static const struct got_error *
290 ensure_client_is_not_reading(struct gotd_client *client)
292 if (client_is_reading(client)) {
293 return got_error_fmt(GOT_ERR_BAD_PACKET,
294 "uid %d made a write-request but is reading from "
295 "a repository", client->euid);
298 return NULL;
301 static void
302 proc_done(struct gotd_child_proc *proc)
304 struct gotd_client *client;
306 TAILQ_REMOVE(&procs, proc, entry);
308 client = find_client_by_proc_fd(proc->iev.ibuf.fd);
309 if (client != NULL) {
310 if (proc == client->repo)
311 client->repo = NULL;
312 if (proc == client->auth)
313 client->auth = NULL;
314 if (proc == client->session)
315 client->session = NULL;
316 disconnect(client);
319 if (proc == gotd.notify_proc)
320 gotd.notify_proc = NULL;
322 evtimer_del(&proc->tmo);
324 if (proc->iev.ibuf.fd != -1) {
325 event_del(&proc->iev.ev);
326 msgbuf_clear(&proc->iev.ibuf.w);
327 close(proc->iev.ibuf.fd);
330 free(proc);
333 static void
334 kill_repo_proc(struct gotd_client *client)
336 if (client->repo == NULL)
337 return;
339 kill_proc(client->repo, 0);
340 client->repo = NULL;
343 static void
344 kill_auth_proc(struct gotd_client *client)
346 if (client->auth == NULL)
347 return;
349 kill_proc(client->auth, 0);
350 client->auth = NULL;
353 static void
354 kill_session_proc(struct gotd_client *client)
356 if (client->session == NULL)
357 return;
359 kill_proc(client->session, 0);
360 client->session = NULL;
363 static void
364 disconnect(struct gotd_client *client)
366 struct gotd_imsg_disconnect idisconnect;
367 struct gotd_child_proc *listen_proc = gotd.listen_proc;
368 uint64_t slot;
370 log_debug("uid %d: disconnecting", client->euid);
372 kill_auth_proc(client);
373 kill_session_proc(client);
374 kill_repo_proc(client);
376 idisconnect.client_id = client->id;
377 if (gotd_imsg_compose_event(&listen_proc->iev,
378 GOTD_IMSG_DISCONNECT, PROC_GOTD, -1,
379 &idisconnect, sizeof(idisconnect)) == -1)
380 log_warn("imsg compose DISCONNECT");
382 slot = client_hash(client->id) % nitems(gotd_clients);
383 STAILQ_REMOVE(&gotd_clients[slot], client, gotd_client, entry);
384 imsg_clear(&client->iev.ibuf);
385 event_del(&client->iev.ev);
386 evtimer_del(&client->tmo);
387 if (client->fd != -1)
388 close(client->fd);
389 else if (client->iev.ibuf.fd != -1)
390 close(client->iev.ibuf.fd);
391 free(client->username);
392 free(client);
393 client_cnt--;
396 static void
397 disconnect_on_error(struct gotd_client *client, const struct got_error *err)
399 struct imsgbuf ibuf;
401 if (err->code != GOT_ERR_EOF) {
402 log_warnx("uid %d: %s", client->euid, err->msg);
403 if (client->fd != -1) {
404 imsg_init(&ibuf, client->fd);
405 gotd_imsg_send_error(&ibuf, 0, PROC_GOTD, err);
406 imsg_clear(&ibuf);
409 disconnect(client);
412 static const struct got_error *
413 send_repo_info(struct gotd_imsgev *iev, struct gotd_repo *repo)
415 const struct got_error *err = NULL;
416 struct gotd_imsg_info_repo irepo;
418 memset(&irepo, 0, sizeof(irepo));
420 if (strlcpy(irepo.repo_name, repo->name, sizeof(irepo.repo_name))
421 >= sizeof(irepo.repo_name))
422 return got_error_msg(GOT_ERR_NO_SPACE, "repo name too long");
423 if (strlcpy(irepo.repo_path, repo->path, sizeof(irepo.repo_path))
424 >= sizeof(irepo.repo_path))
425 return got_error_msg(GOT_ERR_NO_SPACE, "repo path too long");
427 if (gotd_imsg_compose_event(iev, GOTD_IMSG_INFO_REPO, PROC_GOTD, -1,
428 &irepo, sizeof(irepo)) == -1) {
429 err = got_error_from_errno("imsg compose INFO_REPO");
430 if (err)
431 return err;
434 return NULL;
437 static const struct got_error *
438 send_client_info(struct gotd_imsgev *iev, struct gotd_client *client)
440 const struct got_error *err = NULL;
441 struct gotd_imsg_info_client iclient;
442 struct gotd_child_proc *proc;
444 memset(&iclient, 0, sizeof(iclient));
445 iclient.euid = client->euid;
446 iclient.egid = client->egid;
448 proc = client->repo;
449 if (proc) {
450 if (strlcpy(iclient.repo_name, proc->repo_path,
451 sizeof(iclient.repo_name)) >= sizeof(iclient.repo_name)) {
452 return got_error_msg(GOT_ERR_NO_SPACE,
453 "repo name too long");
455 if (client_is_writing(client))
456 iclient.is_writing = 1;
458 iclient.repo_child_pid = proc->pid;
461 if (client->session)
462 iclient.session_child_pid = client->session->pid;
464 if (gotd_imsg_compose_event(iev, GOTD_IMSG_INFO_CLIENT, PROC_GOTD, -1,
465 &iclient, sizeof(iclient)) == -1) {
466 err = got_error_from_errno("imsg compose INFO_CLIENT");
467 if (err)
468 return err;
471 return NULL;
474 static const struct got_error *
475 send_info(struct gotd_client *client)
477 const struct got_error *err = NULL;
478 struct gotd_imsg_info info;
479 uint64_t slot;
480 struct gotd_repo *repo;
482 if (client->euid != 0)
483 return got_error_set_errno(EPERM, "info");
485 info.pid = gotd.pid;
486 info.verbosity = gotd.verbosity;
487 info.nrepos = gotd.nrepos;
488 info.nclients = client_cnt - 1;
490 if (gotd_imsg_compose_event(&client->iev, GOTD_IMSG_INFO, PROC_GOTD, -1,
491 &info, sizeof(info)) == -1) {
492 err = got_error_from_errno("imsg compose INFO");
493 if (err)
494 return err;
497 TAILQ_FOREACH(repo, &gotd.repos, entry) {
498 err = send_repo_info(&client->iev, repo);
499 if (err)
500 return err;
503 for (slot = 0; slot < nitems(gotd_clients); slot++) {
504 struct gotd_client *c;
505 STAILQ_FOREACH(c, &gotd_clients[slot], entry) {
506 if (c->id == client->id)
507 continue;
508 err = send_client_info(&client->iev, c);
509 if (err)
510 return err;
514 return NULL;
517 static const struct got_error *
518 stop_gotd(struct gotd_client *client)
521 if (client->euid != 0)
522 return got_error_set_errno(EPERM, "stop");
524 gotd_shutdown();
525 /* NOTREACHED */
526 return NULL;
529 static const struct got_error *
530 start_client_authentication(struct gotd_client *client, struct imsg *imsg)
532 const struct got_error *err;
533 struct gotd_imsg_list_refs ireq;
534 struct gotd_repo *repo = NULL;
535 size_t datalen;
537 log_debug("list-refs request from uid %d", client->euid);
539 if (client->state != GOTD_CLIENT_STATE_NEW)
540 return got_error_msg(GOT_ERR_BAD_REQUEST,
541 "unexpected list-refs request received");
543 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
544 if (datalen != sizeof(ireq))
545 return got_error(GOT_ERR_PRIVSEP_LEN);
547 memcpy(&ireq, imsg->data, datalen);
549 if (ireq.client_is_reading) {
550 err = ensure_client_is_not_writing(client);
551 if (err)
552 return err;
553 repo = gotd_find_repo_by_name(ireq.repo_name, &gotd.repos);
554 if (repo == NULL)
555 return got_error(GOT_ERR_NOT_GIT_REPO);
556 err = start_auth_child(client, GOTD_AUTH_READ, repo,
557 gotd.argv0, gotd.confpath, gotd.daemonize,
558 gotd.verbosity);
559 if (err)
560 return err;
561 } else {
562 err = ensure_client_is_not_reading(client);
563 if (err)
564 return err;
565 repo = gotd_find_repo_by_name(ireq.repo_name, &gotd.repos);
566 if (repo == NULL)
567 return got_error(GOT_ERR_NOT_GIT_REPO);
568 err = start_auth_child(client,
569 GOTD_AUTH_READ | GOTD_AUTH_WRITE,
570 repo, gotd.argv0, gotd.confpath, gotd.daemonize,
571 gotd.verbosity);
572 if (err)
573 return err;
576 evtimer_add(&client->tmo, &auth_timeout);
578 /* Flow continues upon authentication success/failure or timeout. */
579 return NULL;
582 static void
583 gotd_request(int fd, short events, void *arg)
585 struct gotd_imsgev *iev = arg;
586 struct imsgbuf *ibuf = &iev->ibuf;
587 struct gotd_client *client = iev->handler_arg;
588 const struct got_error *err = NULL;
589 struct imsg imsg;
590 ssize_t n;
592 if (events & EV_WRITE) {
593 while (ibuf->w.queued) {
594 n = msgbuf_write(&ibuf->w);
595 if (n == -1 && errno == EPIPE) {
596 /*
597 * The client has closed its socket.
598 * This can happen when Git clients are
599 * done sending pack file data.
600 */
601 msgbuf_clear(&ibuf->w);
602 continue;
603 } else if (n == -1 && errno != EAGAIN) {
604 err = got_error_from_errno("imsg_flush");
605 disconnect_on_error(client, err);
606 return;
608 if (n == 0) {
609 /* Connection closed. */
610 err = got_error(GOT_ERR_EOF);
611 disconnect_on_error(client, err);
612 return;
616 /* Disconnect gotctl(8) now that messages have been sent. */
617 if (!client_is_reading(client) && !client_is_writing(client)) {
618 disconnect(client);
619 return;
623 if ((events & EV_READ) == 0)
624 return;
626 memset(&imsg, 0, sizeof(imsg));
628 while (err == NULL) {
629 err = gotd_imsg_recv(&imsg, ibuf, 0);
630 if (err) {
631 if (err->code == GOT_ERR_PRIVSEP_READ)
632 err = NULL;
633 break;
636 evtimer_del(&client->tmo);
638 switch (imsg.hdr.type) {
639 case GOTD_IMSG_INFO:
640 err = send_info(client);
641 break;
642 case GOTD_IMSG_STOP:
643 err = stop_gotd(client);
644 break;
645 case GOTD_IMSG_LIST_REFS:
646 err = start_client_authentication(client, &imsg);
647 break;
648 default:
649 log_debug("unexpected imsg %d", imsg.hdr.type);
650 err = got_error(GOT_ERR_PRIVSEP_MSG);
651 break;
654 imsg_free(&imsg);
657 if (err) {
658 disconnect_on_error(client, err);
659 } else {
660 gotd_imsg_event_add(&client->iev);
664 static void
665 gotd_auth_timeout(int fd, short events, void *arg)
667 struct gotd_client *client = arg;
669 log_debug("disconnecting uid %d due to authentication timeout",
670 client->euid);
671 disconnect(client);
674 static const struct got_error *
675 recv_connect(uint32_t *client_id, struct imsg *imsg)
677 const struct got_error *err = NULL;
678 struct gotd_imsg_connect iconnect;
679 size_t datalen;
680 int s = -1;
681 struct gotd_client *client = NULL;
683 *client_id = 0;
685 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
686 if (datalen != sizeof(iconnect))
687 return got_error(GOT_ERR_PRIVSEP_LEN);
688 memcpy(&iconnect, imsg->data, sizeof(iconnect));
690 s = imsg_get_fd(imsg);
691 if (s == -1) {
692 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
693 goto done;
696 if (find_client(iconnect.client_id)) {
697 err = got_error_msg(GOT_ERR_CLIENT_ID, "duplicate client ID");
698 goto done;
701 client = calloc(1, sizeof(*client));
702 if (client == NULL) {
703 err = got_error_from_errno("calloc");
704 goto done;
707 *client_id = iconnect.client_id;
709 client->state = GOTD_CLIENT_STATE_NEW;
710 client->id = iconnect.client_id;
711 client->fd = s;
712 s = -1;
713 /* The auth process will verify UID/GID for us. */
714 client->euid = iconnect.euid;
715 client->egid = iconnect.egid;
717 imsg_init(&client->iev.ibuf, client->fd);
718 client->iev.handler = gotd_request;
719 client->iev.events = EV_READ;
720 client->iev.handler_arg = client;
722 event_set(&client->iev.ev, client->fd, EV_READ, gotd_request,
723 &client->iev);
724 gotd_imsg_event_add(&client->iev);
726 evtimer_set(&client->tmo, gotd_auth_timeout, client);
728 add_client(client);
729 log_debug("%s: new client uid %d connected on fd %d", __func__,
730 client->euid, client->fd);
731 done:
732 if (err) {
733 struct gotd_child_proc *listen_proc = gotd.listen_proc;
734 struct gotd_imsg_disconnect idisconnect;
736 idisconnect.client_id = client->id;
737 if (gotd_imsg_compose_event(&listen_proc->iev,
738 GOTD_IMSG_DISCONNECT, PROC_GOTD, -1,
739 &idisconnect, sizeof(idisconnect)) == -1)
740 log_warn("imsg compose DISCONNECT");
742 if (s != -1)
743 close(s);
746 return err;
749 static const char *gotd_proc_names[PROC_MAX] = {
750 "parent",
751 "listen",
752 "auth",
753 "session_read",
754 "session_write",
755 "repo_read",
756 "repo_write",
757 "gitwrapper",
758 "notify"
759 };
761 static void
762 kill_proc(struct gotd_child_proc *proc, int fatal)
764 struct timeval tv = { 5, 0 };
766 log_debug("kill -%d %d", fatal ? SIGKILL : SIGTERM, proc->pid);
768 if (proc->iev.ibuf.fd != -1) {
769 event_del(&proc->iev.ev);
770 msgbuf_clear(&proc->iev.ibuf.w);
771 close(proc->iev.ibuf.fd);
772 proc->iev.ibuf.fd = -1;
775 if (!evtimer_pending(&proc->tmo, NULL) && !fatal)
776 evtimer_add(&proc->tmo, &tv);
778 if (fatal) {
779 log_warnx("sending SIGKILL to PID %d", proc->pid);
780 kill(proc->pid, SIGKILL);
781 } else
782 kill(proc->pid, SIGTERM);
785 static void
786 kill_proc_timeout(int fd, short ev, void *d)
788 struct gotd_child_proc *proc = d;
790 log_warnx("timeout waiting for PID %d to terminate;"
791 " retrying with force", proc->pid);
792 kill_proc(proc, 1);
795 static void
796 gotd_shutdown(void)
798 uint64_t slot;
800 log_debug("shutting down");
801 for (slot = 0; slot < nitems(gotd_clients); slot++) {
802 struct gotd_client *c, *tmp;
804 STAILQ_FOREACH_SAFE(c, &gotd_clients[slot], entry, tmp)
805 disconnect(c);
808 kill_proc(gotd.listen_proc, 0);
810 log_info("terminating");
811 exit(0);
814 static struct gotd_child_proc *
815 find_proc_by_pid(pid_t pid)
817 struct gotd_child_proc *proc = NULL;
819 TAILQ_FOREACH(proc, &procs, entry)
820 if (proc->pid == pid)
821 break;
823 return proc;
826 void
827 gotd_sighdlr(int sig, short event, void *arg)
829 struct gotd_child_proc *proc;
830 pid_t pid;
831 int status;
833 /*
834 * Normal signal handler rules don't apply because libevent
835 * decouples for us.
836 */
838 switch (sig) {
839 case SIGHUP:
840 log_info("%s: ignoring SIGHUP", __func__);
841 break;
842 case SIGUSR1:
843 log_info("%s: ignoring SIGUSR1", __func__);
844 break;
845 case SIGTERM:
846 case SIGINT:
847 gotd_shutdown();
848 break;
849 case SIGCHLD:
850 for (;;) {
851 pid = waitpid(WAIT_ANY, &status, WNOHANG);
852 if (pid == -1) {
853 if (errno == EINTR)
854 continue;
855 if (errno == ECHILD)
856 break;
857 fatal("waitpid");
859 if (pid == 0)
860 break;
862 log_debug("reaped pid %d", pid);
863 proc = find_proc_by_pid(pid);
864 if (proc == NULL) {
865 log_info("caught exit of unknown child %d",
866 pid);
867 continue;
870 if (WIFSIGNALED(status)) {
871 log_warnx("child PID %d terminated with"
872 " signal %d", pid, WTERMSIG(status));
875 proc_done(proc);
877 break;
878 default:
879 fatalx("unexpected signal");
883 static const struct got_error *
884 ensure_proc_is_reading(struct gotd_client *client,
885 struct gotd_child_proc *proc)
887 if (!client_is_reading(client)) {
888 kill_proc(proc, 1);
889 return got_error_fmt(GOT_ERR_BAD_PACKET,
890 "PID %d handled a read-request for uid %d but this "
891 "user is not reading from a repository", proc->pid,
892 client->euid);
895 return NULL;
898 static const struct got_error *
899 ensure_proc_is_writing(struct gotd_client *client,
900 struct gotd_child_proc *proc)
902 if (!client_is_writing(client)) {
903 kill_proc(proc, 1);
904 return got_error_fmt(GOT_ERR_BAD_PACKET,
905 "PID %d handled a write-request for uid %d but this "
906 "user is not writing to a repository", proc->pid,
907 client->euid);
910 return NULL;
913 static int
914 verify_imsg_src(struct gotd_client *client, struct gotd_child_proc *proc,
915 struct imsg *imsg)
917 const struct got_error *err;
918 int ret = 0;
920 if (proc->type == PROC_REPO_READ || proc->type == PROC_REPO_WRITE) {
921 if (client->repo == NULL)
922 fatalx("no process found for uid %d", client->euid);
923 if (proc->pid != client->repo->pid) {
924 kill_proc(proc, 1);
925 log_warnx("received message from PID %d for uid %d, "
926 "while PID %d is the process serving this user",
927 proc->pid, client->euid, client->repo->pid);
928 return 0;
931 if (proc->type == PROC_SESSION_READ ||
932 proc->type == PROC_SESSION_WRITE) {
933 if (client->session == NULL) {
934 log_warnx("no session found for uid %d", client->euid);
935 return 0;
937 if (proc->pid != client->session->pid) {
938 kill_proc(proc, 1);
939 log_warnx("received message from PID %d for uid %d, "
940 "while PID %d is the process serving this user",
941 proc->pid, client->euid, client->session->pid);
942 return 0;
946 switch (imsg->hdr.type) {
947 case GOTD_IMSG_ERROR:
948 ret = 1;
949 break;
950 case GOTD_IMSG_CONNECT:
951 if (proc->type != PROC_LISTEN) {
952 err = got_error_fmt(GOT_ERR_BAD_PACKET,
953 "new connection for uid %d from PID %d "
954 "which is not the listen process",
955 client->euid, proc->pid);
956 } else
957 ret = 1;
958 break;
959 case GOTD_IMSG_ACCESS_GRANTED:
960 if (proc->type != PROC_AUTH) {
961 err = got_error_fmt(GOT_ERR_BAD_PACKET,
962 "authentication of uid %d from PID %d "
963 "which is not the auth process",
964 client->euid, proc->pid);
965 } else
966 ret = 1;
967 break;
968 case GOTD_IMSG_CLIENT_SESSION_READY:
969 if (proc->type != PROC_SESSION_READ &&
970 proc->type != PROC_SESSION_WRITE) {
971 err = got_error_fmt(GOT_ERR_BAD_PACKET,
972 "unexpected \"ready\" signal from PID %d",
973 proc->pid);
974 } else
975 ret = 1;
976 break;
977 case GOTD_IMSG_REPO_CHILD_READY:
978 if (proc->type != PROC_REPO_READ &&
979 proc->type != PROC_REPO_WRITE) {
980 err = got_error_fmt(GOT_ERR_BAD_PACKET,
981 "unexpected \"ready\" signal from PID %d",
982 proc->pid);
983 } else
984 ret = 1;
985 break;
986 case GOTD_IMSG_PACKFILE_DONE:
987 err = ensure_proc_is_reading(client, proc);
988 if (err)
989 log_warnx("uid %d: %s", client->euid, err->msg);
990 else
991 ret = 1;
992 break;
993 case GOTD_IMSG_PACKFILE_INSTALL:
994 case GOTD_IMSG_REF_UPDATES_START:
995 case GOTD_IMSG_REF_UPDATE:
996 err = ensure_proc_is_writing(client, proc);
997 if (err)
998 log_warnx("uid %d: %s", client->euid, err->msg);
999 else
1000 ret = 1;
1001 break;
1002 default:
1003 log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type);
1004 break;
1007 return ret;
1010 static const struct got_error *
1011 connect_repo_child(struct gotd_client *client,
1012 struct gotd_child_proc *repo_proc)
1014 static const struct got_error *err;
1015 struct gotd_imsgev *session_iev = &client->session->iev;
1016 struct gotd_imsg_connect_repo_child ireq;
1017 int pipe[2];
1018 int sock_flags = SOCK_STREAM | SOCK_NONBLOCK;
1020 #ifdef SOCK_CLOEXEC
1021 sock_flags |= SOCK_CLOEXEC;
1022 #endif
1024 if (client->state != GOTD_CLIENT_STATE_ACCESS_GRANTED)
1025 return got_error_msg(GOT_ERR_BAD_REQUEST,
1026 "unexpected repo child ready signal received");
1028 if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, pipe) == -1)
1029 fatal("socketpair");
1031 memset(&ireq, 0, sizeof(ireq));
1032 ireq.proc_id = repo_proc->type;
1034 /* Pass repo child pipe to session child process. */
1035 if (gotd_imsg_compose_event(session_iev, GOTD_IMSG_CONNECT_REPO_CHILD,
1036 PROC_GOTD, pipe[0], &ireq, sizeof(ireq)) == -1) {
1037 err = got_error_from_errno("imsg compose CONNECT_REPO_CHILD");
1038 close(pipe[0]);
1039 close(pipe[1]);
1040 return err;
1043 /* Pass session child pipe to repo child process. */
1044 if (gotd_imsg_compose_event(&repo_proc->iev,
1045 GOTD_IMSG_CONNECT_REPO_CHILD, PROC_GOTD, pipe[1], NULL, 0) == -1) {
1046 err = got_error_from_errno("imsg compose CONNECT_REPO_CHILD");
1047 close(pipe[1]);
1048 return err;
1051 return NULL;
1054 static void
1055 gotd_dispatch_listener(int fd, short event, void *arg)
1057 struct gotd_imsgev *iev = arg;
1058 struct imsgbuf *ibuf = &iev->ibuf;
1059 struct gotd_child_proc *proc = gotd.listen_proc;
1060 ssize_t n;
1061 int shut = 0;
1062 struct imsg imsg;
1064 if (proc->iev.ibuf.fd != fd)
1065 fatalx("%s: unexpected fd %d", __func__, fd);
1067 if (event & EV_READ) {
1068 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
1069 fatal("imsg_read error");
1070 if (n == 0) {
1071 /* Connection closed. */
1072 shut = 1;
1073 goto done;
1077 if (event & EV_WRITE) {
1078 n = msgbuf_write(&ibuf->w);
1079 if (n == -1 && errno != EAGAIN)
1080 fatal("msgbuf_write");
1081 if (n == 0) {
1082 /* Connection closed. */
1083 shut = 1;
1084 goto done;
1088 for (;;) {
1089 const struct got_error *err = NULL;
1090 struct gotd_client *client = NULL;
1091 uint32_t client_id = 0;
1092 int do_disconnect = 0;
1094 if ((n = imsg_get(ibuf, &imsg)) == -1)
1095 fatal("%s: imsg_get error", __func__);
1096 if (n == 0) /* No more messages. */
1097 break;
1099 switch (imsg.hdr.type) {
1100 case GOTD_IMSG_ERROR:
1101 do_disconnect = 1;
1102 err = gotd_imsg_recv_error(&client_id, &imsg);
1103 break;
1104 case GOTD_IMSG_CONNECT:
1105 err = recv_connect(&client_id, &imsg);
1106 break;
1107 default:
1108 log_debug("unexpected imsg %d", imsg.hdr.type);
1109 break;
1112 client = find_client(client_id);
1113 if (client == NULL) {
1114 log_warnx("%s: client not found", __func__);
1115 imsg_free(&imsg);
1116 continue;
1119 if (err)
1120 log_warnx("uid %d: %s", client->euid, err->msg);
1122 if (do_disconnect) {
1123 if (err)
1124 disconnect_on_error(client, err);
1125 else
1126 disconnect(client);
1129 imsg_free(&imsg);
1131 done:
1132 if (!shut) {
1133 gotd_imsg_event_add(iev);
1134 } else {
1135 /* This pipe is dead. Remove its event handler */
1136 event_del(&iev->ev);
1137 event_loopexit(NULL);
1141 static void
1142 gotd_dispatch_notifier(int fd, short event, void *arg)
1144 struct gotd_imsgev *iev = arg;
1145 struct imsgbuf *ibuf = &iev->ibuf;
1146 struct gotd_child_proc *proc = gotd.notify_proc;
1147 ssize_t n;
1148 int shut = 0;
1149 struct imsg imsg;
1151 if (proc->iev.ibuf.fd != fd)
1152 fatalx("%s: unexpected fd %d", __func__, fd);
1154 if (event & EV_READ) {
1155 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
1156 fatal("imsg_read error");
1157 if (n == 0) {
1158 /* Connection closed. */
1159 shut = 1;
1160 goto done;
1164 if (event & EV_WRITE) {
1165 n = msgbuf_write(&ibuf->w);
1166 if (n == -1 && errno != EAGAIN)
1167 fatal("msgbuf_write");
1168 if (n == 0) {
1169 /* Connection closed. */
1170 shut = 1;
1171 goto done;
1175 for (;;) {
1176 if ((n = imsg_get(ibuf, &imsg)) == -1)
1177 fatal("%s: imsg_get error", __func__);
1178 if (n == 0) /* No more messages. */
1179 break;
1181 switch (imsg.hdr.type) {
1182 default:
1183 log_debug("unexpected imsg %d", imsg.hdr.type);
1184 break;
1187 imsg_free(&imsg);
1189 done:
1190 if (!shut) {
1191 gotd_imsg_event_add(iev);
1192 } else {
1193 /* This pipe is dead. Remove its event handler */
1194 event_del(&iev->ev);
1197 * Do not exit all of gotd if the notification handler dies.
1198 * We can continue operating without notifications until an
1199 * operator intervenes.
1201 log_warnx("notify child process (pid %d) closed its imsg pipe "
1202 "unexpectedly", proc->pid);
1203 proc_done(proc);
1207 static void
1208 gotd_dispatch_auth_child(int fd, short event, void *arg)
1210 const struct got_error *err = NULL;
1211 struct gotd_imsgev *iev = arg;
1212 struct imsgbuf *ibuf = &iev->ibuf;
1213 struct gotd_client *client;
1214 struct gotd_repo *repo = NULL;
1215 ssize_t n;
1216 int shut = 0;
1217 struct imsg imsg;
1218 uint32_t client_id = 0;
1219 int do_disconnect = 0;
1220 size_t datalen;
1222 client = find_client_by_proc_fd(fd);
1223 if (client == NULL) {
1224 /* Can happen during process teardown. */
1225 warnx("cannot find client for fd %d", fd);
1226 shut = 1;
1227 goto done;
1230 if (client->auth == NULL)
1231 fatalx("cannot find auth child process for fd %d", fd);
1233 if (event & EV_READ) {
1234 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
1235 fatal("imsg_read error");
1236 if (n == 0) {
1237 /* Connection closed. */
1238 shut = 1;
1239 goto done;
1243 if (event & EV_WRITE) {
1244 n = msgbuf_write(&ibuf->w);
1245 if (n == -1 && errno != EAGAIN)
1246 fatal("msgbuf_write");
1247 if (n == 0) {
1248 /* Connection closed. */
1249 shut = 1;
1251 goto done;
1254 if (client->auth->iev.ibuf.fd != fd)
1255 fatalx("%s: unexpected fd %d", __func__, fd);
1257 if ((n = imsg_get(ibuf, &imsg)) == -1)
1258 fatal("%s: imsg_get error", __func__);
1259 if (n == 0) /* No more messages. */
1260 return;
1262 evtimer_del(&client->tmo);
1264 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1266 switch (imsg.hdr.type) {
1267 case GOTD_IMSG_ERROR:
1268 do_disconnect = 1;
1269 err = gotd_imsg_recv_error(&client_id, &imsg);
1270 break;
1271 case GOTD_IMSG_ACCESS_GRANTED:
1272 if (client->state != GOTD_CLIENT_STATE_NEW) {
1273 do_disconnect = 1;
1274 err = got_error(GOT_ERR_PRIVSEP_MSG);
1276 break;
1277 default:
1278 do_disconnect = 1;
1279 log_debug("unexpected imsg %d", imsg.hdr.type);
1280 break;
1283 if (!verify_imsg_src(client, client->auth, &imsg)) {
1284 do_disconnect = 1;
1285 log_debug("dropping imsg type %d from PID %d",
1286 imsg.hdr.type, client->auth->pid);
1289 if (do_disconnect) {
1290 if (err)
1291 disconnect_on_error(client, err);
1292 else
1293 disconnect(client);
1294 imsg_free(&imsg);
1295 return;
1298 client->state = GOTD_CLIENT_STATE_ACCESS_GRANTED;
1299 if (datalen > 0)
1300 client->username = strndup(imsg.data, datalen);
1301 imsg_free(&imsg);
1302 if (client->username == NULL &&
1303 asprintf(&client->username, "uid %d", client->euid) == -1) {
1304 err = got_error_from_errno("asprintf");
1305 goto done;
1308 repo = gotd_find_repo_by_name(client->auth->repo_name, &gotd.repos);
1309 if (repo == NULL) {
1310 err = got_error(GOT_ERR_NOT_GIT_REPO);
1311 goto done;
1313 kill_auth_proc(client);
1315 log_info("authenticated %s for repository %s",
1316 client->username, repo->name);
1318 err = start_session_child(client, repo, gotd.argv0,
1319 gotd.confpath, gotd.daemonize, gotd.verbosity);
1320 if (err)
1321 goto done;
1322 done:
1323 if (err)
1324 log_warnx("uid %d: %s", client->euid, err->msg);
1326 /* We might have killed the auth process by now. */
1327 if (client->auth != NULL) {
1328 if (!shut) {
1329 gotd_imsg_event_add(iev);
1330 } else {
1331 /* This pipe is dead. Remove its event handler */
1332 event_del(&iev->ev);
1337 static const struct got_error *
1338 connect_session(struct gotd_client *client)
1340 const struct got_error *err = NULL;
1341 struct gotd_imsg_connect iconnect;
1342 int s;
1343 struct ibuf *wbuf;
1345 memset(&iconnect, 0, sizeof(iconnect));
1347 s = dup(client->fd);
1348 if (s == -1)
1349 return got_error_from_errno("dup");
1351 iconnect.client_id = client->id;
1352 iconnect.euid = client->euid;
1353 iconnect.egid = client->egid;
1354 iconnect.username_len = strlen(client->username);
1356 wbuf = imsg_create(&client->session->iev.ibuf, GOTD_IMSG_CONNECT,
1357 PROC_GOTD, gotd.pid, sizeof(iconnect) + iconnect.username_len);
1358 if (wbuf == NULL) {
1359 err = got_error_from_errno("imsg compose CONNECT");
1360 close(s);
1361 return err;
1363 if (imsg_add(wbuf, &iconnect, sizeof(iconnect)) == -1) {
1364 close(s);
1365 return got_error_from_errno("imsg_add CONNECT");
1367 if (imsg_add(wbuf, client->username, iconnect.username_len) == -1) {
1368 close(s);
1369 return got_error_from_errno("imsg_add CONNECT");
1372 ibuf_fd_set(wbuf, s);
1373 imsg_close(&client->session->iev.ibuf, wbuf);
1374 gotd_imsg_event_add(&client->session->iev);
1377 * We are no longer interested in messages from this client.
1378 * Further client requests will be handled by the session process.
1380 msgbuf_clear(&client->iev.ibuf.w);
1381 imsg_clear(&client->iev.ibuf);
1382 event_del(&client->iev.ev);
1383 client->fd = -1; /* will be closed via copy in client->iev.ibuf.fd */
1385 return NULL;
1388 static void
1389 gotd_dispatch_client_session(int fd, short event, void *arg)
1391 struct gotd_imsgev *iev = arg;
1392 struct imsgbuf *ibuf = &iev->ibuf;
1393 struct gotd_child_proc *proc = NULL;
1394 struct gotd_client *client = NULL;
1395 ssize_t n;
1396 int shut = 0;
1397 struct imsg imsg;
1399 client = find_client_by_proc_fd(fd);
1400 if (client == NULL) {
1401 /* Can happen during process teardown. */
1402 warnx("cannot find client for fd %d", fd);
1403 shut = 1;
1404 goto done;
1407 if (event & EV_READ) {
1408 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
1409 fatal("imsg_read error");
1410 if (n == 0) {
1411 /* Connection closed. */
1412 shut = 1;
1413 goto done;
1417 if (event & EV_WRITE) {
1418 n = msgbuf_write(&ibuf->w);
1419 if (n == -1 && errno != EAGAIN)
1420 fatal("msgbuf_write");
1421 if (n == 0) {
1422 /* Connection closed. */
1423 shut = 1;
1424 goto done;
1428 proc = client->session;
1429 if (proc == NULL)
1430 fatalx("cannot find session child process for fd %d", fd);
1432 for (;;) {
1433 const struct got_error *err = NULL;
1434 uint32_t client_id = 0;
1435 int do_disconnect = 0, do_start_repo_child = 0;
1437 if ((n = imsg_get(ibuf, &imsg)) == -1)
1438 fatal("%s: imsg_get error", __func__);
1439 if (n == 0) /* No more messages. */
1440 break;
1442 switch (imsg.hdr.type) {
1443 case GOTD_IMSG_ERROR:
1444 do_disconnect = 1;
1445 err = gotd_imsg_recv_error(&client_id, &imsg);
1446 break;
1447 case GOTD_IMSG_CLIENT_SESSION_READY:
1448 if (client->state != GOTD_CLIENT_STATE_ACCESS_GRANTED) {
1449 err = got_error(GOT_ERR_PRIVSEP_MSG);
1450 break;
1452 do_start_repo_child = 1;
1453 break;
1454 case GOTD_IMSG_DISCONNECT:
1455 do_disconnect = 1;
1456 break;
1457 default:
1458 log_debug("unexpected imsg %d", imsg.hdr.type);
1459 break;
1462 if (!verify_imsg_src(client, proc, &imsg)) {
1463 log_debug("dropping imsg type %d from PID %d",
1464 imsg.hdr.type, proc->pid);
1465 imsg_free(&imsg);
1466 continue;
1468 if (err)
1469 log_warnx("uid %d: %s", client->euid, err->msg);
1471 if (do_start_repo_child) {
1472 struct gotd_repo *repo;
1473 const char *name = client->session->repo_name;
1475 repo = gotd_find_repo_by_name(name, &gotd.repos);
1476 if (repo != NULL) {
1477 enum gotd_procid proc_type;
1479 if (client->required_auth & GOTD_AUTH_WRITE)
1480 proc_type = PROC_REPO_WRITE;
1481 else
1482 proc_type = PROC_REPO_READ;
1484 err = start_repo_child(client, proc_type, repo,
1485 gotd.argv0, gotd.confpath, gotd.daemonize,
1486 gotd.verbosity);
1487 } else
1488 err = got_error(GOT_ERR_NOT_GIT_REPO);
1490 if (err) {
1491 log_warnx("uid %d: %s", client->euid, err->msg);
1492 do_disconnect = 1;
1496 if (do_disconnect) {
1497 if (err)
1498 disconnect_on_error(client, err);
1499 else
1500 disconnect(client);
1503 imsg_free(&imsg);
1505 done:
1506 if (!shut) {
1507 gotd_imsg_event_add(iev);
1508 } else {
1509 /* This pipe is dead. Remove its event handler */
1510 event_del(&iev->ev);
1511 disconnect(client);
1515 static const struct got_error *
1516 connect_notifier_and_session(struct gotd_client *client)
1518 const struct got_error *err = NULL;
1519 struct gotd_imsgev *session_iev = &client->session->iev;
1520 int pipe[2];
1521 int sock_flags = SOCK_STREAM|SOCK_NONBLOCK;
1523 if (gotd.notify_proc == NULL)
1524 return NULL;
1526 #ifdef SOCK_CLOEXEC
1527 sock_flags |= SOCK_CLOEXEC;
1528 #endif
1529 if (socketpair(AF_UNIX, sock_flags,
1530 PF_UNSPEC, pipe) == -1)
1531 return got_error_from_errno("socketpair");
1533 /* Pass notifier pipe to session . */
1534 if (gotd_imsg_compose_event(session_iev, GOTD_IMSG_CONNECT_NOTIFIER,
1535 PROC_GOTD, pipe[0], NULL, 0) == -1) {
1536 err = got_error_from_errno("imsg compose CONNECT_NOTIFIER");
1537 close(pipe[0]);
1538 close(pipe[1]);
1539 return err;
1542 /* Pass session pipe to notifier. */
1543 if (gotd_imsg_compose_event(&gotd.notify_proc->iev,
1544 GOTD_IMSG_CONNECT_SESSION, PROC_GOTD, pipe[1], NULL, 0) == -1) {
1545 err = got_error_from_errno("imsg compose CONNECT_SESSION");
1546 close(pipe[1]);
1547 return err;
1550 return NULL;
1553 static void
1554 gotd_dispatch_repo_child(int fd, short event, void *arg)
1556 struct gotd_imsgev *iev = arg;
1557 struct imsgbuf *ibuf = &iev->ibuf;
1558 struct gotd_child_proc *proc = NULL;
1559 struct gotd_client *client;
1560 ssize_t n;
1561 int shut = 0;
1562 struct imsg imsg;
1564 client = find_client_by_proc_fd(fd);
1565 if (client == NULL) {
1566 /* Can happen during process teardown. */
1567 warnx("cannot find client for fd %d", fd);
1568 shut = 1;
1569 goto done;
1572 if (event & EV_READ) {
1573 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
1574 fatal("imsg_read error");
1575 if (n == 0) {
1576 /* Connection closed. */
1577 shut = 1;
1578 goto done;
1582 if (event & EV_WRITE) {
1583 n = msgbuf_write(&ibuf->w);
1584 if (n == -1 && errno != EAGAIN)
1585 fatal("msgbuf_write");
1586 if (n == 0) {
1587 /* Connection closed. */
1588 shut = 1;
1589 goto done;
1593 proc = client->repo;
1594 if (proc == NULL)
1595 fatalx("cannot find child process for fd %d", fd);
1597 for (;;) {
1598 const struct got_error *err = NULL;
1599 uint32_t client_id = 0;
1600 int do_disconnect = 0;
1602 if ((n = imsg_get(ibuf, &imsg)) == -1)
1603 fatal("%s: imsg_get error", __func__);
1604 if (n == 0) /* No more messages. */
1605 break;
1607 switch (imsg.hdr.type) {
1608 case GOTD_IMSG_ERROR:
1609 do_disconnect = 1;
1610 err = gotd_imsg_recv_error(&client_id, &imsg);
1611 break;
1612 case GOTD_IMSG_REPO_CHILD_READY:
1613 err = connect_session(client);
1614 if (err)
1615 break;
1616 err = connect_notifier_and_session(client);
1617 if (err)
1618 break;
1619 err = connect_repo_child(client, proc);
1620 break;
1621 default:
1622 log_debug("unexpected imsg %d", imsg.hdr.type);
1623 break;
1626 if (!verify_imsg_src(client, proc, &imsg)) {
1627 log_debug("dropping imsg type %d from PID %d",
1628 imsg.hdr.type, proc->pid);
1629 imsg_free(&imsg);
1630 continue;
1632 if (err)
1633 log_warnx("uid %d: %s", client->euid, err->msg);
1635 if (do_disconnect) {
1636 if (err)
1637 disconnect_on_error(client, err);
1638 else
1639 disconnect(client);
1642 imsg_free(&imsg);
1644 done:
1645 if (!shut) {
1646 gotd_imsg_event_add(iev);
1647 } else {
1648 /* This pipe is dead. Remove its event handler */
1649 event_del(&iev->ev);
1650 disconnect(client);
1654 static pid_t
1655 start_child(enum gotd_procid proc_id, const char *repo_path,
1656 char *argv0, const char *confpath, int fd, int daemonize, int verbosity)
1658 char *argv[11];
1659 int argc = 0;
1660 pid_t pid;
1662 switch (pid = fork()) {
1663 case -1:
1664 fatal("cannot fork");
1665 case 0:
1666 break;
1667 default:
1668 close(fd);
1669 return pid;
1672 if (fd != GOTD_FILENO_MSG_PIPE) {
1673 if (dup2(fd, GOTD_FILENO_MSG_PIPE) == -1)
1674 fatal("cannot setup imsg fd");
1675 } else if (fcntl(fd, F_SETFD, 0) == -1)
1676 fatal("cannot setup imsg fd");
1678 argv[argc++] = argv0;
1679 switch (proc_id) {
1680 case PROC_LISTEN:
1681 argv[argc++] = (char *)"-L";
1682 break;
1683 case PROC_AUTH:
1684 argv[argc++] = (char *)"-A";
1685 break;
1686 case PROC_SESSION_READ:
1687 argv[argc++] = (char *)"-s";
1688 break;
1689 case PROC_SESSION_WRITE:
1690 argv[argc++] = (char *)"-S";
1691 break;
1692 case PROC_REPO_READ:
1693 argv[argc++] = (char *)"-R";
1694 break;
1695 case PROC_REPO_WRITE:
1696 argv[argc++] = (char *)"-W";
1697 break;
1698 case PROC_NOTIFY:
1699 argv[argc++] = (char *)"-N";
1700 break;
1701 default:
1702 fatalx("invalid process id %d", proc_id);
1705 argv[argc++] = (char *)"-f";
1706 argv[argc++] = (char *)confpath;
1708 if (repo_path) {
1709 argv[argc++] = (char *)"-P";
1710 argv[argc++] = (char *)repo_path;
1713 if (!daemonize)
1714 argv[argc++] = (char *)"-d";
1715 if (verbosity > 0)
1716 argv[argc++] = (char *)"-v";
1717 if (verbosity > 1)
1718 argv[argc++] = (char *)"-v";
1719 argv[argc++] = NULL;
1721 execvp(argv0, argv);
1722 fatal("execvp");
1725 static void
1726 start_listener(char *argv0, const char *confpath, int daemonize, int verbosity)
1728 struct gotd_child_proc *proc;
1729 int sock_flags = SOCK_STREAM|SOCK_NONBLOCK;
1731 #ifdef SOCK_CLOEXEC
1732 sock_flags |= SOCK_CLOEXEC;
1733 #endif
1735 proc = calloc(1, sizeof(*proc));
1736 if (proc == NULL)
1737 fatal("calloc");
1739 TAILQ_INSERT_HEAD(&procs, proc, entry);
1741 /* proc->tmo is initialized in main() after event_init() */
1743 proc->type = PROC_LISTEN;
1745 if (socketpair(AF_UNIX, sock_flags,
1746 PF_UNSPEC, proc->pipe) == -1)
1747 fatal("socketpair");
1749 proc->pid = start_child(proc->type, NULL, argv0, confpath,
1750 proc->pipe[1], daemonize, verbosity);
1751 imsg_init(&proc->iev.ibuf, proc->pipe[0]);
1752 proc->iev.handler = gotd_dispatch_listener;
1753 proc->iev.events = EV_READ;
1754 proc->iev.handler_arg = NULL;
1756 gotd.listen_proc = proc;
1759 static void
1760 start_notifier(char *argv0, const char *confpath, int daemonize, int verbosity)
1762 struct gotd_child_proc *proc;
1763 int sock_flags = SOCK_STREAM | SOCK_NONBLOCK;
1766 proc = calloc(1, sizeof(*proc));
1767 if (proc == NULL)
1768 fatal("calloc");
1770 TAILQ_INSERT_HEAD(&procs, proc, entry);
1772 /* proc->tmo is initialized in main() after event_init() */
1774 proc->type = PROC_NOTIFY;
1776 #ifdef SOCK_CLOEXEC
1777 sock_flags |= SOCK_CLOEXEC;
1778 #endif
1779 if (socketpair(AF_UNIX, sock_flags,
1780 PF_UNSPEC, proc->pipe) == -1)
1781 fatal("socketpair");
1783 proc->pid = start_child(proc->type, NULL, argv0, confpath,
1784 proc->pipe[1], daemonize, verbosity);
1785 imsg_init(&proc->iev.ibuf, proc->pipe[0]);
1786 proc->iev.handler = gotd_dispatch_notifier;
1787 proc->iev.events = EV_READ;
1788 proc->iev.handler_arg = NULL;
1789 event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ,
1790 gotd_dispatch_notifier, &proc->iev);
1792 gotd.notify_proc = proc;
1795 static const struct got_error *
1796 start_session_child(struct gotd_client *client, struct gotd_repo *repo,
1797 char *argv0, const char *confpath, int daemonize, int verbosity)
1799 struct gotd_child_proc *proc;
1800 int sock_flags = SOCK_STREAM | SOCK_NONBLOCK;
1802 #ifdef SOCK_CLOEXEC
1803 sock_flags |= SOCK_CLOEXEC;
1804 #endif
1806 proc = calloc(1, sizeof(*proc));
1807 if (proc == NULL)
1808 return got_error_from_errno("calloc");
1810 TAILQ_INSERT_HEAD(&procs, proc, entry);
1811 evtimer_set(&proc->tmo, kill_proc_timeout, proc);
1813 if (client_is_reading(client))
1814 proc->type = PROC_SESSION_READ;
1815 else
1816 proc->type = PROC_SESSION_WRITE;
1817 if (strlcpy(proc->repo_name, repo->name,
1818 sizeof(proc->repo_name)) >= sizeof(proc->repo_name))
1819 fatalx("repository name too long: %s", repo->name);
1820 log_debug("starting client uid %d session for repository %s",
1821 client->euid, repo->name);
1822 if (strlcpy(proc->repo_path, repo->path, sizeof(proc->repo_path)) >=
1823 sizeof(proc->repo_path))
1824 fatalx("repository path too long: %s", repo->path);
1825 if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, proc->pipe) == -1)
1826 fatal("socketpair");
1827 proc->pid = start_child(proc->type, proc->repo_path, argv0,
1828 confpath, proc->pipe[1], daemonize, verbosity);
1829 imsg_init(&proc->iev.ibuf, proc->pipe[0]);
1830 log_debug("proc %s %s is on fd %d",
1831 gotd_proc_names[proc->type], proc->repo_path,
1832 proc->pipe[0]);
1833 proc->iev.handler = gotd_dispatch_client_session;
1834 proc->iev.events = EV_READ;
1835 proc->iev.handler_arg = NULL;
1836 event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ,
1837 gotd_dispatch_client_session, &proc->iev);
1838 gotd_imsg_event_add(&proc->iev);
1840 client->session = proc;
1841 return NULL;
1844 static const struct got_error *
1845 start_repo_child(struct gotd_client *client, enum gotd_procid proc_type,
1846 struct gotd_repo *repo, char *argv0, const char *confpath,
1847 int daemonize, int verbosity)
1849 struct gotd_child_proc *proc;
1850 int sock_flags = SOCK_STREAM|SOCK_NONBLOCK;
1852 #ifdef SOCK_CLOEXEC
1853 sock_flags |= SOCK_CLOEXEC;
1854 #endif
1856 if (proc_type != PROC_REPO_READ && proc_type != PROC_REPO_WRITE)
1857 return got_error_msg(GOT_ERR_NOT_IMPL, "bad process type");
1859 proc = calloc(1, sizeof(*proc));
1860 if (proc == NULL)
1861 return got_error_from_errno("calloc");
1863 TAILQ_INSERT_HEAD(&procs, proc, entry);
1864 evtimer_set(&proc->tmo, kill_proc_timeout, proc);
1866 proc->type = proc_type;
1867 if (strlcpy(proc->repo_name, repo->name,
1868 sizeof(proc->repo_name)) >= sizeof(proc->repo_name))
1869 fatalx("repository name too long: %s", repo->name);
1870 log_debug("starting %s for repository %s",
1871 proc->type == PROC_REPO_READ ? "reader" : "writer", repo->name);
1873 if (strlcpy(proc->repo_path, repo->path, sizeof(proc->repo_path)) >=
1874 sizeof(proc->repo_path))
1875 fatalx("repository path too long: %s", repo->path);
1876 if (realpath(repo->path, proc->repo_path) == NULL)
1877 fatal("%s", repo->path);
1878 if (socketpair(AF_UNIX, sock_flags,
1879 PF_UNSPEC, proc->pipe) == -1)
1880 fatal("socketpair");
1881 proc->pid = start_child(proc->type, proc->repo_path, argv0,
1882 confpath, proc->pipe[1], daemonize, verbosity);
1883 imsg_init(&proc->iev.ibuf, proc->pipe[0]);
1884 log_debug("proc %s %s is on fd %d",
1885 gotd_proc_names[proc->type], proc->repo_path,
1886 proc->pipe[0]);
1887 proc->iev.handler = gotd_dispatch_repo_child;
1888 proc->iev.events = EV_READ;
1889 proc->iev.handler_arg = NULL;
1890 event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ,
1891 gotd_dispatch_repo_child, &proc->iev);
1892 gotd_imsg_event_add(&proc->iev);
1894 client->repo = proc;
1895 return NULL;
1898 static const struct got_error *
1899 start_auth_child(struct gotd_client *client, int required_auth,
1900 struct gotd_repo *repo, char *argv0, const char *confpath,
1901 int daemonize, int verbosity)
1903 const struct got_error *err = NULL;
1904 struct gotd_child_proc *proc;
1905 struct gotd_imsg_auth iauth;
1906 int fd;
1907 int sock_flags = SOCK_STREAM|SOCK_NONBLOCK;
1909 #ifdef SOCK_CLOEXEC
1910 sock_flags |= SOCK_CLOEXEC;
1911 #endif
1913 memset(&iauth, 0, sizeof(iauth));
1915 fd = dup(client->fd);
1916 if (fd == -1)
1917 return got_error_from_errno("dup");
1919 proc = calloc(1, sizeof(*proc));
1920 if (proc == NULL) {
1921 err = got_error_from_errno("calloc");
1922 close(fd);
1923 return err;
1926 TAILQ_INSERT_HEAD(&procs, proc, entry);
1927 evtimer_set(&proc->tmo, kill_proc_timeout, proc);
1929 proc->type = PROC_AUTH;
1930 if (strlcpy(proc->repo_name, repo->name,
1931 sizeof(proc->repo_name)) >= sizeof(proc->repo_name))
1932 fatalx("repository name too long: %s", repo->name);
1933 log_debug("starting auth for uid %d repository %s",
1934 client->euid, repo->name);
1935 if (strlcpy(proc->repo_path, repo->path, sizeof(proc->repo_path)) >=
1936 sizeof(proc->repo_path))
1937 fatalx("repository path too long: %s", repo->path);
1938 if (realpath(repo->path, proc->repo_path) == NULL)
1939 fatal("%s", repo->path);
1940 if (socketpair(AF_UNIX, sock_flags,
1941 PF_UNSPEC, proc->pipe) == -1)
1942 fatal("socketpair");
1943 proc->pid = start_child(proc->type, proc->repo_path, argv0,
1944 confpath, proc->pipe[1], daemonize, verbosity);
1945 imsg_init(&proc->iev.ibuf, proc->pipe[0]);
1946 log_debug("proc %s %s is on fd %d",
1947 gotd_proc_names[proc->type], proc->repo_path,
1948 proc->pipe[0]);
1949 proc->iev.handler = gotd_dispatch_auth_child;
1950 proc->iev.events = EV_READ;
1951 proc->iev.handler_arg = NULL;
1952 event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ,
1953 gotd_dispatch_auth_child, &proc->iev);
1954 gotd_imsg_event_add(&proc->iev);
1956 iauth.euid = client->euid;
1957 iauth.egid = client->egid;
1958 iauth.required_auth = required_auth;
1959 iauth.client_id = client->id;
1960 if (gotd_imsg_compose_event(&proc->iev, GOTD_IMSG_AUTHENTICATE,
1961 PROC_GOTD, fd, &iauth, sizeof(iauth)) == -1) {
1962 log_warn("imsg compose AUTHENTICATE");
1963 close(fd);
1964 /* Let the auth_timeout handler tidy up. */
1967 client->auth = proc;
1968 client->required_auth = required_auth;
1969 return NULL;
1972 static void
1973 apply_unveil_repo_readonly(const char *repo_path, int need_tmpdir)
1975 if (need_tmpdir) {
1976 if (unveil(GOT_TMPDIR_STR, "rwc") == -1)
1977 fatal("unveil %s", GOT_TMPDIR_STR);
1980 if (unveil(repo_path, "r") == -1)
1981 fatal("unveil %s", repo_path);
1983 if (unveil(NULL, NULL) == -1)
1984 fatal("unveil");
1987 static void
1988 apply_unveil_repo_readwrite(const char *repo_path)
1990 if (unveil(repo_path, "rwc") == -1)
1991 fatal("unveil %s", repo_path);
1993 if (unveil(GOT_TMPDIR_STR, "rwc") == -1)
1994 fatal("unveil %s", GOT_TMPDIR_STR);
1996 if (unveil(NULL, NULL) == -1)
1997 fatal("unveil");
2000 static void
2001 apply_unveil_none(void)
2003 if (unveil("/", "") == -1)
2004 fatal("unveil");
2006 if (unveil(NULL, NULL) == -1)
2007 fatal("unveil");
2010 static void
2011 apply_unveil_selfexec(void)
2013 if (unveil(gotd.argv0, "x") == -1)
2014 fatal("unveil %s", gotd.argv0);
2016 if (unveil(NULL, NULL) == -1)
2017 fatal("unveil");
2020 static void
2021 set_max_datasize(void)
2023 struct rlimit rl;
2025 if (getrlimit(RLIMIT_DATA, &rl) != 0)
2026 return;
2028 rl.rlim_cur = rl.rlim_max;
2029 setrlimit(RLIMIT_DATA, &rl);
2032 static void
2033 unveil_notification_helpers(void)
2035 const char *helpers[] = {
2036 GOTD_PATH_PROG_NOTIFY_EMAIL,
2037 GOTD_PATH_PROG_NOTIFY_HTTP,
2039 size_t i;
2041 for (i = 0; i < nitems(helpers); i++) {
2042 if (unveil(helpers[i], "x") == 0)
2043 continue;
2044 fatal("unveil %s", helpers[i]);
2047 if (unveil(NULL, NULL) == -1)
2048 fatal("unveil");
2051 int
2052 main(int argc, char **argv)
2054 const struct got_error *error = NULL;
2055 int ch, fd = -1, daemonize = 1, verbosity = 0, noaction = 0;
2056 const char *confpath = GOTD_CONF_PATH;
2057 char *argv0 = argv[0];
2058 char title[2048];
2059 struct passwd *pw = NULL;
2060 char *repo_path = NULL;
2061 enum gotd_procid proc_id = PROC_GOTD;
2062 struct event evsigint, evsigterm, evsighup, evsigusr1, evsigchld;
2063 int *pack_fds = NULL, *temp_fds = NULL;
2064 struct gotd_repo *repo = NULL;
2065 char *default_sender = NULL;
2066 char hostname[_POSIX_HOST_NAME_MAX + 1];
2067 FILE *diff_f1 = NULL, *diff_f2 = NULL;
2068 int diff_fd1 = -1, diff_fd2 = -1;
2070 TAILQ_INIT(&procs);
2072 log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */
2074 while ((ch = getopt(argc, argv, "Adf:LnNP:RsSvW")) != -1) {
2075 switch (ch) {
2076 case 'A':
2077 proc_id = PROC_AUTH;
2078 break;
2079 case 'd':
2080 daemonize = 0;
2081 break;
2082 case 'f':
2083 confpath = optarg;
2084 break;
2085 case 'L':
2086 proc_id = PROC_LISTEN;
2087 break;
2088 case 'n':
2089 noaction = 1;
2090 break;
2091 case 'N':
2092 proc_id = PROC_NOTIFY;
2093 break;
2094 case 'P':
2095 repo_path = realpath(optarg, NULL);
2096 if (repo_path == NULL)
2097 fatal("realpath '%s'", optarg);
2098 break;
2099 case 'R':
2100 proc_id = PROC_REPO_READ;
2101 break;
2102 case 's':
2103 proc_id = PROC_SESSION_READ;
2104 break;
2105 case 'S':
2106 proc_id = PROC_SESSION_WRITE;
2107 break;
2108 case 'v':
2109 if (verbosity < 3)
2110 verbosity++;
2111 break;
2112 case 'W':
2113 proc_id = PROC_REPO_WRITE;
2114 break;
2115 default:
2116 usage();
2120 argc -= optind;
2121 argv += optind;
2123 if (argc != 0)
2124 usage();
2126 if (geteuid() && (proc_id == PROC_GOTD || proc_id == PROC_LISTEN))
2127 fatalx("need root privileges");
2129 if (parse_config(confpath, proc_id, &gotd) != 0)
2130 return 1;
2132 pw = getpwnam(gotd.user_name);
2133 if (pw == NULL)
2134 fatalx("user %s not found", gotd.user_name);
2136 if (pw->pw_uid == 0)
2137 fatalx("cannot run %s as the superuser", getprogname());
2139 if (noaction) {
2140 fprintf(stderr, "configuration OK\n");
2141 return 0;
2144 gotd.argv0 = argv0;
2145 gotd.daemonize = daemonize;
2146 gotd.verbosity = verbosity;
2147 gotd.confpath = confpath;
2149 /* Require an absolute path in argv[0] for reliable re-exec. */
2150 if (!got_path_is_absolute(argv0))
2151 fatalx("bad path \"%s\": must be an absolute path", argv0);
2153 log_init(daemonize ? 0 : 1, LOG_DAEMON);
2154 log_setverbose(verbosity);
2156 if (proc_id == PROC_GOTD) {
2157 snprintf(title, sizeof(title), "%s", gotd_proc_names[proc_id]);
2158 arc4random_buf(&clients_hash_key, sizeof(clients_hash_key));
2159 if (daemonize && daemon(1, 0) == -1)
2160 fatal("daemon");
2161 gotd.pid = getpid();
2162 start_listener(argv0, confpath, daemonize, verbosity);
2163 start_notifier(argv0, confpath, daemonize, verbosity);
2164 } else if (proc_id == PROC_LISTEN) {
2165 snprintf(title, sizeof(title), "%s", gotd_proc_names[proc_id]);
2166 if (verbosity) {
2167 log_info("socket: %s", gotd.unix_socket_path);
2168 log_info("user: %s", pw->pw_name);
2171 fd = unix_socket_listen(gotd.unix_socket_path, pw->pw_uid,
2172 pw->pw_gid);
2173 if (fd == -1) {
2174 fatal("cannot listen on unix socket %s",
2175 gotd.unix_socket_path);
2177 } else if (proc_id == PROC_AUTH) {
2178 snprintf(title, sizeof(title), "%s %s",
2179 gotd_proc_names[proc_id], repo_path);
2180 } else if (proc_id == PROC_REPO_READ || proc_id == PROC_REPO_WRITE ||
2181 proc_id == PROC_SESSION_READ || proc_id == PROC_SESSION_WRITE) {
2182 error = got_repo_pack_fds_open(&pack_fds);
2183 if (error != NULL)
2184 fatalx("cannot open pack tempfiles: %s", error->msg);
2185 error = got_repo_temp_fds_open(&temp_fds);
2186 if (error != NULL)
2187 fatalx("cannot open pack tempfiles: %s", error->msg);
2188 if (repo_path == NULL)
2189 fatalx("repository path not specified");
2190 snprintf(title, sizeof(title), "%s %s",
2191 gotd_proc_names[proc_id], repo_path);
2192 } else if (proc_id == PROC_NOTIFY) {
2193 snprintf(title, sizeof(title), "%s", gotd_proc_names[proc_id]);
2194 if (gethostname(hostname, sizeof(hostname)) == -1)
2195 fatal("gethostname");
2196 if (asprintf(&default_sender, "%s@%s",
2197 pw->pw_name, hostname) == -1)
2198 fatal("asprintf");
2199 } else
2200 fatal("invalid process id %d", proc_id);
2202 setproctitle("%s", title);
2203 log_procinit(title);
2205 if (proc_id != PROC_GOTD && proc_id != PROC_LISTEN &&
2206 proc_id != PROC_REPO_READ && proc_id != PROC_REPO_WRITE) {
2207 /* Drop root privileges. */
2208 if (setgid(pw->pw_gid) == -1)
2209 fatal("setgid %d failed", pw->pw_gid);
2210 if (setuid(pw->pw_uid) == -1)
2211 fatal("setuid %d failed", pw->pw_uid);
2214 event_init();
2216 switch (proc_id) {
2217 case PROC_GOTD:
2218 #ifndef PROFILE
2219 /* "exec" promise will be limited to argv[0] via unveil(2). */
2220 if (pledge("stdio proc exec sendfd recvfd unveil", NULL) == -1)
2221 err(1, "pledge");
2222 #endif
2223 break;
2224 case PROC_LISTEN:
2225 #ifndef PROFILE
2226 if (pledge("stdio sendfd unix unveil", NULL) == -1)
2227 err(1, "pledge");
2228 #endif
2230 * Ensure that AF_UNIX bind(2) cannot be used with any other
2231 * sockets by revoking all filesystem access via unveil(2).
2233 apply_unveil_none();
2235 enter_chroot(GOTD_EMPTY_PATH);
2236 drop_privs(pw);
2238 listen_main(title, fd, gotd.connection_limits,
2239 gotd.nconnection_limits);
2240 /* NOTREACHED */
2241 break;
2242 case PROC_AUTH:
2243 #ifndef PROFILE
2244 if (pledge("stdio getpw recvfd unix unveil", NULL) == -1)
2245 err(1, "pledge");
2246 #endif
2248 * We need the "unix" pledge promise for getpeername(2) only.
2249 * Ensure that AF_UNIX bind(2) cannot be used by revoking all
2250 * filesystem access via unveil(2). Access to password database
2251 * files will still work since "getpw" bypasses unveil(2).
2253 apply_unveil_none();
2255 auth_main(title, &gotd.repos, repo_path);
2256 /* NOTREACHED */
2257 break;
2258 case PROC_SESSION_READ:
2259 case PROC_SESSION_WRITE:
2260 #ifndef PROFILE
2262 * The "recvfd" promise is only needed during setup and
2263 * will be removed in a later pledge(2) call.
2265 if (pledge("stdio rpath wpath cpath recvfd sendfd fattr flock "
2266 "unveil", NULL) == -1)
2267 err(1, "pledge");
2268 #endif
2269 if (proc_id == PROC_SESSION_READ)
2270 apply_unveil_repo_readonly(repo_path, 1);
2271 else {
2272 apply_unveil_repo_readwrite(repo_path);
2273 repo = gotd_find_repo_by_path(repo_path, &gotd);
2274 if (repo == NULL)
2275 fatalx("no repository for path %s", repo_path);
2277 session_main(title, repo_path, pack_fds, temp_fds,
2278 &gotd.request_timeout, repo, proc_id);
2279 /* NOTREACHED */
2280 break;
2281 case PROC_REPO_READ:
2282 set_max_datasize();
2283 #ifndef PROFILE
2284 if (pledge("stdio rpath recvfd unveil", NULL) == -1)
2285 err(1, "pledge");
2286 #endif
2287 apply_unveil_repo_readonly(repo_path, 0);
2289 if (enter_chroot(repo_path)) {
2290 log_info("change repo path %s", repo_path);
2291 free(repo_path);
2292 repo_path = strdup("/");
2293 if (repo_path == NULL)
2294 fatal("strdup");
2295 log_info("repo path is now %s", repo_path);
2297 drop_privs(pw);
2299 repo_read_main(title, repo_path, pack_fds, temp_fds);
2300 /* NOTREACHED */
2301 exit(0);
2302 case PROC_REPO_WRITE:
2303 set_max_datasize();
2305 diff_f1 = got_opentemp();
2306 if (diff_f1 == NULL)
2307 fatal("got_opentemp");
2308 diff_f2 = got_opentemp();
2309 if (diff_f2 == NULL)
2310 fatal("got_opentemp");
2311 diff_fd1 = got_opentempfd();
2312 if (diff_fd1 == -1)
2313 fatal("got_opentempfd");
2314 diff_fd2 = got_opentempfd();
2315 if (diff_fd2 == -1)
2316 fatal("got_opentempfd");
2317 #ifndef PROFILE
2318 if (pledge("stdio rpath recvfd unveil", NULL) == -1)
2319 err(1, "pledge");
2320 #endif
2321 apply_unveil_repo_readonly(repo_path, 0);
2322 repo = gotd_find_repo_by_path(repo_path, &gotd);
2323 if (repo == NULL)
2324 fatalx("no repository for path %s", repo_path);
2326 if (enter_chroot(repo_path)) {
2327 free(repo_path);
2328 repo_path = strdup("/");
2329 if (repo_path == NULL)
2330 fatal("strdup");
2332 drop_privs(pw);
2334 repo_write_main(title, repo_path, pack_fds, temp_fds,
2335 diff_f1, diff_f2, diff_fd1, diff_fd2,
2336 &repo->protected_tag_namespaces,
2337 &repo->protected_branch_namespaces,
2338 &repo->protected_branches);
2339 /* NOTREACHED */
2340 exit(0);
2341 case PROC_NOTIFY:
2342 #ifndef PROFILE
2343 if (pledge("stdio proc exec recvfd unveil", NULL) == -1)
2344 err(1, "pledge");
2345 #endif
2347 * Limit "exec" promise to notification helpers via unveil(2).
2349 unveil_notification_helpers();
2351 notify_main(title, &gotd.repos, default_sender);
2352 /* NOTREACHED */
2353 exit(0);
2354 default:
2355 fatal("invalid process id %d", proc_id);
2358 if (proc_id != PROC_GOTD)
2359 fatal("invalid process id %d", proc_id);
2361 evtimer_set(&gotd.listen_proc->tmo, kill_proc_timeout,
2362 gotd.listen_proc);
2363 if (gotd.notify_proc) {
2364 evtimer_set(&gotd.notify_proc->tmo, kill_proc_timeout,
2365 gotd.notify_proc);
2368 apply_unveil_selfexec();
2370 signal_set(&evsigint, SIGINT, gotd_sighdlr, NULL);
2371 signal_set(&evsigterm, SIGTERM, gotd_sighdlr, NULL);
2372 signal_set(&evsighup, SIGHUP, gotd_sighdlr, NULL);
2373 signal_set(&evsigusr1, SIGUSR1, gotd_sighdlr, NULL);
2374 signal_set(&evsigchld, SIGCHLD, gotd_sighdlr, NULL);
2375 signal(SIGPIPE, SIG_IGN);
2377 signal_add(&evsigint, NULL);
2378 signal_add(&evsigterm, NULL);
2379 signal_add(&evsighup, NULL);
2380 signal_add(&evsigusr1, NULL);
2381 signal_add(&evsigchld, NULL);
2383 gotd_imsg_event_add(&gotd.listen_proc->iev);
2384 if (gotd.notify_proc)
2385 gotd_imsg_event_add(&gotd.notify_proc->iev);
2387 event_dispatch();
2389 free(repo_path);
2390 free(default_sender);
2391 gotd_shutdown();
2393 return 0;