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 <sys/queue.h>
18 #include <sys/tree.h>
19 #include <sys/time.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <sys/wait.h>
26 #include <fcntl.h>
27 #include <err.h>
28 #include <errno.h>
29 #include <event.h>
30 #include <limits.h>
31 #include <pwd.h>
32 #include <imsg.h>
33 #include <signal.h>
34 #include <siphash.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <syslog.h>
40 #include <unistd.h>
42 #include "got_error.h"
43 #include "got_opentemp.h"
44 #include "got_path.h"
45 #include "got_repository.h"
46 #include "got_object.h"
47 #include "got_reference.h"
49 #include "got_lib_delta.h"
50 #include "got_lib_object.h"
51 #include "got_lib_object_cache.h"
52 #include "got_lib_hash.h"
53 #include "got_lib_gitproto.h"
54 #include "got_lib_pack.h"
55 #include "got_lib_repository.h"
57 #include "gotd.h"
58 #include "log.h"
59 #include "listen.h"
60 #include "auth.h"
61 #include "session.h"
62 #include "repo_read.h"
63 #include "repo_write.h"
65 #ifndef nitems
66 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
67 #endif
69 enum gotd_client_state {
70 GOTD_CLIENT_STATE_NEW,
71 GOTD_CLIENT_STATE_ACCESS_GRANTED,
72 };
74 struct gotd_client {
75 STAILQ_ENTRY(gotd_client) entry;
76 enum gotd_client_state state;
77 uint32_t id;
78 int fd;
79 struct gotd_imsgev iev;
80 struct event tmo;
81 uid_t euid;
82 gid_t egid;
83 struct gotd_child_proc *repo;
84 struct gotd_child_proc *auth;
85 struct gotd_child_proc *session;
86 int required_auth;
87 };
88 STAILQ_HEAD(gotd_clients, gotd_client);
90 static struct gotd_clients gotd_clients[GOTD_CLIENT_TABLE_SIZE];
91 static SIPHASH_KEY clients_hash_key;
92 volatile int client_cnt;
93 static struct timeval auth_timeout = { 5, 0 };
94 static struct gotd gotd;
96 void gotd_sighdlr(int sig, short event, void *arg);
97 static void gotd_shutdown(void);
98 static const struct got_error *start_session_child(struct gotd_client *,
99 struct gotd_repo *, char *, const char *, int, int);
100 static const struct got_error *start_repo_child(struct gotd_client *,
101 enum gotd_procid, struct gotd_repo *, char *, const char *, int, int);
102 static const struct got_error *start_auth_child(struct gotd_client *, int,
103 struct gotd_repo *, char *, const char *, int, int);
104 static void kill_proc(struct gotd_child_proc *, int);
106 __dead static void
107 usage(void)
109 fprintf(stderr, "usage: %s [-dnv] [-f config-file]\n", getprogname());
110 exit(1);
113 static int
114 unix_socket_listen(const char *unix_socket_path, uid_t uid, gid_t gid)
116 struct sockaddr_un sun;
117 int fd = -1;
118 mode_t old_umask, mode;
120 fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK| SOCK_CLOEXEC, 0);
121 if (fd == -1) {
122 log_warn("socket");
123 return -1;
126 sun.sun_family = AF_UNIX;
127 if (strlcpy(sun.sun_path, unix_socket_path,
128 sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) {
129 log_warnx("%s: name too long", unix_socket_path);
130 close(fd);
131 return -1;
134 if (unlink(unix_socket_path) == -1) {
135 if (errno != ENOENT) {
136 log_warn("unlink %s", unix_socket_path);
137 close(fd);
138 return -1;
142 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
143 mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
145 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
146 log_warn("bind: %s", unix_socket_path);
147 close(fd);
148 umask(old_umask);
149 return -1;
152 umask(old_umask);
154 if (chmod(unix_socket_path, mode) == -1) {
155 log_warn("chmod %o %s", mode, unix_socket_path);
156 close(fd);
157 unlink(unix_socket_path);
158 return -1;
161 if (chown(unix_socket_path, uid, gid) == -1) {
162 log_warn("chown %s uid=%d gid=%d", unix_socket_path, uid, gid);
163 close(fd);
164 unlink(unix_socket_path);
165 return -1;
168 if (listen(fd, GOTD_UNIX_SOCKET_BACKLOG) == -1) {
169 log_warn("listen");
170 close(fd);
171 unlink(unix_socket_path);
172 return -1;
175 return fd;
178 static uint64_t
179 client_hash(uint32_t client_id)
181 return SipHash24(&clients_hash_key, &client_id, sizeof(client_id));
184 static void
185 add_client(struct gotd_client *client)
187 uint64_t slot = client_hash(client->id) % nitems(gotd_clients);
188 STAILQ_INSERT_HEAD(&gotd_clients[slot], client, entry);
189 client_cnt++;
192 static struct gotd_client *
193 find_client(uint32_t client_id)
195 uint64_t slot;
196 struct gotd_client *c;
198 slot = client_hash(client_id) % nitems(gotd_clients);
199 STAILQ_FOREACH(c, &gotd_clients[slot], entry) {
200 if (c->id == client_id)
201 return c;
204 return NULL;
207 static struct gotd_client *
208 find_client_by_proc_fd(int fd)
210 uint64_t slot;
212 for (slot = 0; slot < nitems(gotd_clients); slot++) {
213 struct gotd_client *c;
215 STAILQ_FOREACH(c, &gotd_clients[slot], entry) {
216 if (c->repo && c->repo->iev.ibuf.fd == fd)
217 return c;
218 if (c->auth && c->auth->iev.ibuf.fd == fd)
219 return c;
220 if (c->session && c->session->iev.ibuf.fd == fd)
221 return c;
225 return NULL;
228 static int
229 client_is_reading(struct gotd_client *client)
231 return (client->required_auth &
232 (GOTD_AUTH_READ | GOTD_AUTH_WRITE)) == GOTD_AUTH_READ;
235 static int
236 client_is_writing(struct gotd_client *client)
238 return (client->required_auth &
239 (GOTD_AUTH_READ | GOTD_AUTH_WRITE)) ==
240 (GOTD_AUTH_READ | GOTD_AUTH_WRITE);
243 static const struct got_error *
244 ensure_client_is_not_writing(struct gotd_client *client)
246 if (client_is_writing(client)) {
247 return got_error_fmt(GOT_ERR_BAD_PACKET,
248 "uid %d made a read-request but is writing to "
249 "a repository", client->euid);
252 return NULL;
255 static const struct got_error *
256 ensure_client_is_not_reading(struct gotd_client *client)
258 if (client_is_reading(client)) {
259 return got_error_fmt(GOT_ERR_BAD_PACKET,
260 "uid %d made a write-request but is reading from "
261 "a repository", client->euid);
264 return NULL;
267 static void
268 wait_for_child(pid_t child_pid)
270 pid_t pid;
271 int status;
273 log_debug("waiting for child PID %ld to terminate",
274 (long)child_pid);
276 do {
277 pid = waitpid(child_pid, &status, WNOHANG);
278 if (pid == -1) {
279 if (errno != EINTR && errno != ECHILD)
280 fatal("wait");
281 } else if (WIFSIGNALED(status)) {
282 log_warnx("child PID %ld terminated; signal %d",
283 (long)pid, WTERMSIG(status));
285 } while (pid != -1 || (pid == -1 && errno == EINTR));
288 static void
289 proc_done(struct gotd_child_proc *proc)
291 event_del(&proc->iev.ev);
292 msgbuf_clear(&proc->iev.ibuf.w);
293 close(proc->iev.ibuf.fd);
294 kill_proc(proc, 0);
295 wait_for_child(proc->pid);
296 free(proc);
299 static void
300 kill_auth_proc(struct gotd_client *client)
302 struct gotd_child_proc *proc;
304 if (client->auth == NULL)
305 return;
307 proc = client->auth;
308 client->auth = NULL;
310 proc_done(proc);
313 static void
314 kill_session_proc(struct gotd_client *client)
316 struct gotd_child_proc *proc;
318 if (client->session == NULL)
319 return;
321 proc = client->session;
322 client->session = NULL;
324 proc_done(proc);
327 static void
328 disconnect(struct gotd_client *client)
330 struct gotd_imsg_disconnect idisconnect;
331 struct gotd_child_proc *proc = client->repo;
332 struct gotd_child_proc *listen_proc = &gotd.listen_proc;
333 uint64_t slot;
335 log_debug("uid %d: disconnecting", client->euid);
337 kill_auth_proc(client);
338 kill_session_proc(client);
340 if (proc) {
341 event_del(&proc->iev.ev);
342 msgbuf_clear(&proc->iev.ibuf.w);
343 close(proc->iev.ibuf.fd);
344 kill_proc(proc, 0);
345 wait_for_child(proc->pid);
346 free(proc);
347 proc = NULL;
350 idisconnect.client_id = client->id;
351 if (gotd_imsg_compose_event(&listen_proc->iev,
352 GOTD_IMSG_DISCONNECT, PROC_GOTD, -1,
353 &idisconnect, sizeof(idisconnect)) == -1)
354 log_warn("imsg compose DISCONNECT");
356 slot = client_hash(client->id) % nitems(gotd_clients);
357 STAILQ_REMOVE(&gotd_clients[slot], client, gotd_client, entry);
358 imsg_clear(&client->iev.ibuf);
359 event_del(&client->iev.ev);
360 evtimer_del(&client->tmo);
361 if (client->fd != -1)
362 close(client->fd);
363 else if (client->iev.ibuf.fd != -1)
364 close(client->iev.ibuf.fd);
365 free(client);
366 client_cnt--;
369 static void
370 disconnect_on_error(struct gotd_client *client, const struct got_error *err)
372 struct imsgbuf ibuf;
374 log_warnx("uid %d: %s", client->euid, err->msg);
375 if (err->code != GOT_ERR_EOF && client->fd != -1) {
376 imsg_init(&ibuf, client->fd);
377 gotd_imsg_send_error(&ibuf, 0, PROC_GOTD, err);
378 imsg_clear(&ibuf);
380 disconnect(client);
383 static const struct got_error *
384 send_repo_info(struct gotd_imsgev *iev, struct gotd_repo *repo)
386 const struct got_error *err = NULL;
387 struct gotd_imsg_info_repo irepo;
389 memset(&irepo, 0, sizeof(irepo));
391 if (strlcpy(irepo.repo_name, repo->name, sizeof(irepo.repo_name))
392 >= sizeof(irepo.repo_name))
393 return got_error_msg(GOT_ERR_NO_SPACE, "repo name too long");
394 if (strlcpy(irepo.repo_path, repo->path, sizeof(irepo.repo_path))
395 >= sizeof(irepo.repo_path))
396 return got_error_msg(GOT_ERR_NO_SPACE, "repo path too long");
398 if (gotd_imsg_compose_event(iev, GOTD_IMSG_INFO_REPO, PROC_GOTD, -1,
399 &irepo, sizeof(irepo)) == -1) {
400 err = got_error_from_errno("imsg compose INFO_REPO");
401 if (err)
402 return err;
405 return NULL;
408 static const struct got_error *
409 send_client_info(struct gotd_imsgev *iev, struct gotd_client *client)
411 const struct got_error *err = NULL;
412 struct gotd_imsg_info_client iclient;
413 struct gotd_child_proc *proc;
415 memset(&iclient, 0, sizeof(iclient));
416 iclient.euid = client->euid;
417 iclient.egid = client->egid;
419 proc = client->repo;
420 if (proc) {
421 if (strlcpy(iclient.repo_name, proc->repo_path,
422 sizeof(iclient.repo_name)) >= sizeof(iclient.repo_name)) {
423 return got_error_msg(GOT_ERR_NO_SPACE,
424 "repo name too long");
426 if (client_is_writing(client))
427 iclient.is_writing = 1;
429 iclient.repo_child_pid = proc->pid;
432 if (client->session)
433 iclient.session_child_pid = client->session->pid;
435 if (gotd_imsg_compose_event(iev, GOTD_IMSG_INFO_CLIENT, PROC_GOTD, -1,
436 &iclient, sizeof(iclient)) == -1) {
437 err = got_error_from_errno("imsg compose INFO_CLIENT");
438 if (err)
439 return err;
442 return NULL;
445 static const struct got_error *
446 send_info(struct gotd_client *client)
448 const struct got_error *err = NULL;
449 struct gotd_imsg_info info;
450 uint64_t slot;
451 struct gotd_repo *repo;
453 if (client->euid != 0)
454 return got_error_set_errno(EPERM, "info");
456 info.pid = gotd.pid;
457 info.verbosity = gotd.verbosity;
458 info.nrepos = gotd.nrepos;
459 info.nclients = client_cnt - 1;
461 if (gotd_imsg_compose_event(&client->iev, GOTD_IMSG_INFO, PROC_GOTD, -1,
462 &info, sizeof(info)) == -1) {
463 err = got_error_from_errno("imsg compose INFO");
464 if (err)
465 return err;
468 TAILQ_FOREACH(repo, &gotd.repos, entry) {
469 err = send_repo_info(&client->iev, repo);
470 if (err)
471 return err;
474 for (slot = 0; slot < nitems(gotd_clients); slot++) {
475 struct gotd_client *c;
476 STAILQ_FOREACH(c, &gotd_clients[slot], entry) {
477 if (c->id == client->id)
478 continue;
479 err = send_client_info(&client->iev, c);
480 if (err)
481 return err;
485 return NULL;
488 static const struct got_error *
489 stop_gotd(struct gotd_client *client)
492 if (client->euid != 0)
493 return got_error_set_errno(EPERM, "stop");
495 gotd_shutdown();
496 /* NOTREACHED */
497 return NULL;
500 static struct gotd_repo *
501 find_repo_by_name(const char *repo_name)
503 struct gotd_repo *repo;
504 size_t namelen;
506 TAILQ_FOREACH(repo, &gotd.repos, entry) {
507 namelen = strlen(repo->name);
508 if (strncmp(repo->name, repo_name, namelen) != 0)
509 continue;
510 if (repo_name[namelen] == '\0' ||
511 strcmp(&repo_name[namelen], ".git") == 0)
512 return repo;
515 return NULL;
518 static const struct got_error *
519 start_client_authentication(struct gotd_client *client, struct imsg *imsg)
521 const struct got_error *err;
522 struct gotd_imsg_list_refs ireq;
523 struct gotd_repo *repo = NULL;
524 size_t datalen;
526 log_debug("list-refs request from uid %d", client->euid);
528 if (client->state != GOTD_CLIENT_STATE_NEW)
529 return got_error_msg(GOT_ERR_BAD_REQUEST,
530 "unexpected list-refs request received");
532 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
533 if (datalen != sizeof(ireq))
534 return got_error(GOT_ERR_PRIVSEP_LEN);
536 memcpy(&ireq, imsg->data, datalen);
538 if (ireq.client_is_reading) {
539 err = ensure_client_is_not_writing(client);
540 if (err)
541 return err;
542 repo = find_repo_by_name(ireq.repo_name);
543 if (repo == NULL)
544 return got_error(GOT_ERR_NOT_GIT_REPO);
545 err = start_auth_child(client, GOTD_AUTH_READ, repo,
546 gotd.argv0, gotd.confpath, gotd.daemonize,
547 gotd.verbosity);
548 if (err)
549 return err;
550 } else {
551 err = ensure_client_is_not_reading(client);
552 if (err)
553 return err;
554 repo = find_repo_by_name(ireq.repo_name);
555 if (repo == NULL)
556 return got_error(GOT_ERR_NOT_GIT_REPO);
557 err = start_auth_child(client,
558 GOTD_AUTH_READ | GOTD_AUTH_WRITE,
559 repo, gotd.argv0, gotd.confpath, gotd.daemonize,
560 gotd.verbosity);
561 if (err)
562 return err;
565 evtimer_add(&client->tmo, &auth_timeout);
567 /* Flow continues upon authentication successs/failure or timeout. */
568 return NULL;
571 static void
572 gotd_request(int fd, short events, void *arg)
574 struct gotd_imsgev *iev = arg;
575 struct imsgbuf *ibuf = &iev->ibuf;
576 struct gotd_client *client = iev->handler_arg;
577 const struct got_error *err = NULL;
578 struct imsg imsg;
579 ssize_t n;
581 if (events & EV_WRITE) {
582 while (ibuf->w.queued) {
583 n = msgbuf_write(&ibuf->w);
584 if (n == -1 && errno == EPIPE) {
585 /*
586 * The client has closed its socket.
587 * This can happen when Git clients are
588 * done sending pack file data.
589 */
590 msgbuf_clear(&ibuf->w);
591 continue;
592 } else if (n == -1 && errno != EAGAIN) {
593 err = got_error_from_errno("imsg_flush");
594 disconnect_on_error(client, err);
595 return;
597 if (n == 0) {
598 /* Connection closed. */
599 err = got_error(GOT_ERR_EOF);
600 disconnect_on_error(client, err);
601 return;
605 /* Disconnect gotctl(8) now that messages have been sent. */
606 if (!client_is_reading(client) && !client_is_writing(client)) {
607 disconnect(client);
608 return;
612 if ((events & EV_READ) == 0)
613 return;
615 memset(&imsg, 0, sizeof(imsg));
617 while (err == NULL) {
618 err = gotd_imsg_recv(&imsg, ibuf, 0);
619 if (err) {
620 if (err->code == GOT_ERR_PRIVSEP_READ)
621 err = NULL;
622 break;
625 evtimer_del(&client->tmo);
627 switch (imsg.hdr.type) {
628 case GOTD_IMSG_INFO:
629 err = send_info(client);
630 break;
631 case GOTD_IMSG_STOP:
632 err = stop_gotd(client);
633 break;
634 case GOTD_IMSG_LIST_REFS:
635 err = start_client_authentication(client, &imsg);
636 break;
637 default:
638 log_debug("unexpected imsg %d", imsg.hdr.type);
639 err = got_error(GOT_ERR_PRIVSEP_MSG);
640 break;
643 imsg_free(&imsg);
646 if (err) {
647 disconnect_on_error(client, err);
648 } else {
649 gotd_imsg_event_add(&client->iev);
653 static void
654 gotd_auth_timeout(int fd, short events, void *arg)
656 struct gotd_client *client = arg;
658 log_debug("disconnecting uid %d due to authentication timeout",
659 client->euid);
660 disconnect(client);
663 static const struct got_error *
664 recv_connect(uint32_t *client_id, struct imsg *imsg)
666 const struct got_error *err = NULL;
667 struct gotd_imsg_connect iconnect;
668 size_t datalen;
669 int s = -1;
670 struct gotd_client *client = NULL;
672 *client_id = 0;
674 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
675 if (datalen != sizeof(iconnect))
676 return got_error(GOT_ERR_PRIVSEP_LEN);
677 memcpy(&iconnect, imsg->data, sizeof(iconnect));
679 s = imsg->fd;
680 if (s == -1) {
681 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
682 goto done;
685 if (find_client(iconnect.client_id)) {
686 err = got_error_msg(GOT_ERR_CLIENT_ID, "duplicate client ID");
687 goto done;
690 client = calloc(1, sizeof(*client));
691 if (client == NULL) {
692 err = got_error_from_errno("calloc");
693 goto done;
696 *client_id = iconnect.client_id;
698 client->state = GOTD_CLIENT_STATE_NEW;
699 client->id = iconnect.client_id;
700 client->fd = s;
701 s = -1;
702 /* The auth process will verify UID/GID for us. */
703 client->euid = iconnect.euid;
704 client->egid = iconnect.egid;
706 imsg_init(&client->iev.ibuf, client->fd);
707 client->iev.handler = gotd_request;
708 client->iev.events = EV_READ;
709 client->iev.handler_arg = client;
711 event_set(&client->iev.ev, client->fd, EV_READ, gotd_request,
712 &client->iev);
713 gotd_imsg_event_add(&client->iev);
715 evtimer_set(&client->tmo, gotd_auth_timeout, client);
717 add_client(client);
718 log_debug("%s: new client uid %d connected on fd %d", __func__,
719 client->euid, client->fd);
720 done:
721 if (err) {
722 struct gotd_child_proc *listen_proc = &gotd.listen_proc;
723 struct gotd_imsg_disconnect idisconnect;
725 idisconnect.client_id = client->id;
726 if (gotd_imsg_compose_event(&listen_proc->iev,
727 GOTD_IMSG_DISCONNECT, PROC_GOTD, -1,
728 &idisconnect, sizeof(idisconnect)) == -1)
729 log_warn("imsg compose DISCONNECT");
731 if (s != -1)
732 close(s);
735 return err;
738 static const char *gotd_proc_names[PROC_MAX] = {
739 "parent",
740 "listen",
741 "auth",
742 "session",
743 "repo_read",
744 "repo_write"
745 };
747 static void
748 kill_proc(struct gotd_child_proc *proc, int fatal)
750 if (fatal) {
751 log_warnx("sending SIGKILL to PID %d", proc->pid);
752 kill(proc->pid, SIGKILL);
753 } else
754 kill(proc->pid, SIGTERM);
757 static void
758 gotd_shutdown(void)
760 struct gotd_child_proc *proc;
761 uint64_t slot;
763 log_debug("shutting down");
764 for (slot = 0; slot < nitems(gotd_clients); slot++) {
765 struct gotd_client *c, *tmp;
767 STAILQ_FOREACH_SAFE(c, &gotd_clients[slot], entry, tmp)
768 disconnect(c);
771 proc = &gotd.listen_proc;
772 msgbuf_clear(&proc->iev.ibuf.w);
773 close(proc->iev.ibuf.fd);
774 kill_proc(proc, 0);
775 wait_for_child(proc->pid);
777 log_info("terminating");
778 exit(0);
781 void
782 gotd_sighdlr(int sig, short event, void *arg)
784 /*
785 * Normal signal handler rules don't apply because libevent
786 * decouples for us.
787 */
789 switch (sig) {
790 case SIGHUP:
791 log_info("%s: ignoring SIGHUP", __func__);
792 break;
793 case SIGUSR1:
794 log_info("%s: ignoring SIGUSR1", __func__);
795 break;
796 case SIGTERM:
797 case SIGINT:
798 gotd_shutdown();
799 break;
800 default:
801 fatalx("unexpected signal");
805 static const struct got_error *
806 ensure_proc_is_reading(struct gotd_client *client,
807 struct gotd_child_proc *proc)
809 if (!client_is_reading(client)) {
810 kill_proc(proc, 1);
811 return got_error_fmt(GOT_ERR_BAD_PACKET,
812 "PID %d handled a read-request for uid %d but this "
813 "user is not reading from a repository", proc->pid,
814 client->euid);
817 return NULL;
820 static const struct got_error *
821 ensure_proc_is_writing(struct gotd_client *client,
822 struct gotd_child_proc *proc)
824 if (!client_is_writing(client)) {
825 kill_proc(proc, 1);
826 return got_error_fmt(GOT_ERR_BAD_PACKET,
827 "PID %d handled a write-request for uid %d but this "
828 "user is not writing to a repository", proc->pid,
829 client->euid);
832 return NULL;
835 static int
836 verify_imsg_src(struct gotd_client *client, struct gotd_child_proc *proc,
837 struct imsg *imsg)
839 const struct got_error *err;
840 int ret = 0;
842 if (proc->type == PROC_REPO_READ || proc->type == PROC_REPO_WRITE) {
843 if (client->repo == NULL)
844 fatalx("no process found for uid %d", client->euid);
845 if (proc->pid != client->repo->pid) {
846 kill_proc(proc, 1);
847 log_warnx("received message from PID %d for uid %d, "
848 "while PID %d is the process serving this user",
849 proc->pid, client->euid, client->repo->pid);
850 return 0;
853 if (proc->type == PROC_SESSION) {
854 if (client->session == NULL) {
855 log_warnx("no session found for uid %d", client->euid);
856 return 0;
858 if (proc->pid != client->session->pid) {
859 kill_proc(proc, 1);
860 log_warnx("received message from PID %d for uid %d, "
861 "while PID %d is the process serving this user",
862 proc->pid, client->euid, client->session->pid);
863 return 0;
867 switch (imsg->hdr.type) {
868 case GOTD_IMSG_ERROR:
869 ret = 1;
870 break;
871 case GOTD_IMSG_CONNECT:
872 if (proc->type != PROC_LISTEN) {
873 err = got_error_fmt(GOT_ERR_BAD_PACKET,
874 "new connection for uid %d from PID %d "
875 "which is not the listen process",
876 proc->pid, client->euid);
877 } else
878 ret = 1;
879 break;
880 case GOTD_IMSG_ACCESS_GRANTED:
881 if (proc->type != PROC_AUTH) {
882 err = got_error_fmt(GOT_ERR_BAD_PACKET,
883 "authentication of uid %d from PID %d "
884 "which is not the auth process",
885 proc->pid, client->euid);
886 } else
887 ret = 1;
888 break;
889 case GOTD_IMSG_CLIENT_SESSION_READY:
890 if (proc->type != PROC_SESSION) {
891 err = got_error_fmt(GOT_ERR_BAD_PACKET,
892 "unexpected \"ready\" signal from PID %d",
893 proc->pid);
894 } else
895 ret = 1;
896 break;
897 case GOTD_IMSG_REPO_CHILD_READY:
898 if (proc->type != PROC_REPO_READ &&
899 proc->type != PROC_REPO_WRITE) {
900 err = got_error_fmt(GOT_ERR_BAD_PACKET,
901 "unexpected \"ready\" signal from PID %d",
902 proc->pid);
903 } else
904 ret = 1;
905 break;
906 case GOTD_IMSG_PACKFILE_DONE:
907 err = ensure_proc_is_reading(client, proc);
908 if (err)
909 log_warnx("uid %d: %s", client->euid, err->msg);
910 else
911 ret = 1;
912 break;
913 case GOTD_IMSG_PACKFILE_INSTALL:
914 case GOTD_IMSG_REF_UPDATES_START:
915 case GOTD_IMSG_REF_UPDATE:
916 err = ensure_proc_is_writing(client, proc);
917 if (err)
918 log_warnx("uid %d: %s", client->euid, err->msg);
919 else
920 ret = 1;
921 break;
922 default:
923 log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type);
924 break;
927 return ret;
930 static const struct got_error *
931 connect_repo_child(struct gotd_client *client,
932 struct gotd_child_proc *repo_proc)
934 static const struct got_error *err;
935 struct gotd_imsgev *session_iev = &client->session->iev;
936 struct gotd_imsg_connect_repo_child ireq;
937 int pipe[2];
939 if (client->state != GOTD_CLIENT_STATE_ACCESS_GRANTED)
940 return got_error_msg(GOT_ERR_BAD_REQUEST,
941 "unexpected repo child ready signal received");
943 if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK,
944 PF_UNSPEC, pipe) == -1)
945 fatal("socketpair");
947 memset(&ireq, 0, sizeof(ireq));
948 ireq.client_id = client->id;
949 ireq.proc_id = repo_proc->type;
951 /* Pass repo child pipe to session child process. */
952 if (gotd_imsg_compose_event(session_iev, GOTD_IMSG_CONNECT_REPO_CHILD,
953 PROC_GOTD, pipe[0], &ireq, sizeof(ireq)) == -1) {
954 err = got_error_from_errno("imsg compose CONNECT_REPO_CHILD");
955 close(pipe[0]);
956 close(pipe[1]);
957 return err;
960 /* Pass session child pipe to repo child process. */
961 if (gotd_imsg_compose_event(&repo_proc->iev,
962 GOTD_IMSG_CONNECT_REPO_CHILD, PROC_GOTD, pipe[1], NULL, 0) == -1) {
963 err = got_error_from_errno("imsg compose CONNECT_REPO_CHILD");
964 close(pipe[1]);
965 return err;
968 return NULL;
971 static void
972 gotd_dispatch_listener(int fd, short event, void *arg)
974 struct gotd_imsgev *iev = arg;
975 struct imsgbuf *ibuf = &iev->ibuf;
976 struct gotd_child_proc *proc = &gotd.listen_proc;
977 ssize_t n;
978 int shut = 0;
979 struct imsg imsg;
981 if (proc->iev.ibuf.fd != fd)
982 fatalx("%s: unexpected fd %d", __func__, fd);
984 if (event & EV_READ) {
985 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
986 fatal("imsg_read error");
987 if (n == 0) {
988 /* Connection closed. */
989 shut = 1;
990 goto done;
994 if (event & EV_WRITE) {
995 n = msgbuf_write(&ibuf->w);
996 if (n == -1 && errno != EAGAIN)
997 fatal("msgbuf_write");
998 if (n == 0) {
999 /* Connection closed. */
1000 shut = 1;
1001 goto done;
1005 for (;;) {
1006 const struct got_error *err = NULL;
1007 struct gotd_client *client = NULL;
1008 uint32_t client_id = 0;
1009 int do_disconnect = 0;
1011 if ((n = imsg_get(ibuf, &imsg)) == -1)
1012 fatal("%s: imsg_get error", __func__);
1013 if (n == 0) /* No more messages. */
1014 break;
1016 switch (imsg.hdr.type) {
1017 case GOTD_IMSG_ERROR:
1018 do_disconnect = 1;
1019 err = gotd_imsg_recv_error(&client_id, &imsg);
1020 break;
1021 case GOTD_IMSG_CONNECT:
1022 err = recv_connect(&client_id, &imsg);
1023 break;
1024 default:
1025 log_debug("unexpected imsg %d", imsg.hdr.type);
1026 break;
1029 client = find_client(client_id);
1030 if (client == NULL) {
1031 log_warnx("%s: client not found", __func__);
1032 imsg_free(&imsg);
1033 continue;
1036 if (err)
1037 log_warnx("uid %d: %s", client->euid, err->msg);
1039 if (do_disconnect) {
1040 if (err)
1041 disconnect_on_error(client, err);
1042 else
1043 disconnect(client);
1046 imsg_free(&imsg);
1048 done:
1049 if (!shut) {
1050 gotd_imsg_event_add(iev);
1051 } else {
1052 /* This pipe is dead. Remove its event handler */
1053 event_del(&iev->ev);
1054 event_loopexit(NULL);
1058 static void
1059 gotd_dispatch_auth_child(int fd, short event, void *arg)
1061 const struct got_error *err = NULL;
1062 struct gotd_imsgev *iev = arg;
1063 struct imsgbuf *ibuf = &iev->ibuf;
1064 struct gotd_client *client;
1065 struct gotd_repo *repo = NULL;
1066 ssize_t n;
1067 int shut = 0;
1068 struct imsg imsg;
1069 uint32_t client_id = 0;
1070 int do_disconnect = 0;
1072 client = find_client_by_proc_fd(fd);
1073 if (client == NULL) {
1074 /* Can happen during process teardown. */
1075 warnx("cannot find client for fd %d", fd);
1076 shut = 1;
1077 goto done;
1080 if (client->auth == NULL)
1081 fatalx("cannot find auth child process for fd %d", fd);
1083 if (event & EV_READ) {
1084 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
1085 fatal("imsg_read error");
1086 if (n == 0) {
1087 /* Connection closed. */
1088 shut = 1;
1089 goto done;
1093 if (event & EV_WRITE) {
1094 n = msgbuf_write(&ibuf->w);
1095 if (n == -1 && errno != EAGAIN)
1096 fatal("msgbuf_write");
1097 if (n == 0) {
1098 /* Connection closed. */
1099 shut = 1;
1101 goto done;
1104 if (client->auth->iev.ibuf.fd != fd)
1105 fatalx("%s: unexpected fd %d", __func__, fd);
1107 if ((n = imsg_get(ibuf, &imsg)) == -1)
1108 fatal("%s: imsg_get error", __func__);
1109 if (n == 0) /* No more messages. */
1110 return;
1112 evtimer_del(&client->tmo);
1114 switch (imsg.hdr.type) {
1115 case GOTD_IMSG_ERROR:
1116 do_disconnect = 1;
1117 err = gotd_imsg_recv_error(&client_id, &imsg);
1118 break;
1119 case GOTD_IMSG_ACCESS_GRANTED:
1120 client->state = GOTD_CLIENT_STATE_ACCESS_GRANTED;
1121 break;
1122 default:
1123 do_disconnect = 1;
1124 log_debug("unexpected imsg %d", imsg.hdr.type);
1125 break;
1128 if (!verify_imsg_src(client, client->auth, &imsg)) {
1129 do_disconnect = 1;
1130 log_debug("dropping imsg type %d from PID %d",
1131 imsg.hdr.type, client->auth->pid);
1133 imsg_free(&imsg);
1135 if (do_disconnect) {
1136 if (err)
1137 disconnect_on_error(client, err);
1138 else
1139 disconnect(client);
1140 goto done;
1143 repo = find_repo_by_name(client->auth->repo_name);
1144 if (repo == NULL) {
1145 err = got_error(GOT_ERR_NOT_GIT_REPO);
1146 goto done;
1148 kill_auth_proc(client);
1150 log_info("authenticated uid %d for repository %s",
1151 client->euid, repo->name);
1153 err = start_session_child(client, repo, gotd.argv0,
1154 gotd.confpath, gotd.daemonize, gotd.verbosity);
1155 if (err)
1156 goto done;
1157 done:
1158 if (err)
1159 log_warnx("uid %d: %s", client->euid, err->msg);
1161 /* We might have killed the auth process by now. */
1162 if (client->auth != NULL) {
1163 if (!shut) {
1164 gotd_imsg_event_add(iev);
1165 } else {
1166 /* This pipe is dead. Remove its event handler */
1167 event_del(&iev->ev);
1172 static const struct got_error *
1173 connect_session(struct gotd_client *client)
1175 const struct got_error *err = NULL;
1176 struct gotd_imsg_connect iconnect;
1177 int s;
1179 memset(&iconnect, 0, sizeof(iconnect));
1181 s = dup(client->fd);
1182 if (s == -1)
1183 return got_error_from_errno("dup");
1185 iconnect.client_id = client->id;
1186 iconnect.euid = client->euid;
1187 iconnect.egid = client->egid;
1189 if (gotd_imsg_compose_event(&client->session->iev, GOTD_IMSG_CONNECT,
1190 PROC_GOTD, s, &iconnect, sizeof(iconnect)) == -1) {
1191 err = got_error_from_errno("imsg compose CONNECT");
1192 close(s);
1193 return err;
1197 * We are no longer interested in messages from this client.
1198 * Further client requests will be handled by the session process.
1200 msgbuf_clear(&client->iev.ibuf.w);
1201 imsg_clear(&client->iev.ibuf);
1202 event_del(&client->iev.ev);
1203 client->fd = -1; /* will be closed via copy in client->iev.ibuf.fd */
1205 return NULL;
1208 static void
1209 gotd_dispatch_client_session(int fd, short event, void *arg)
1211 struct gotd_imsgev *iev = arg;
1212 struct imsgbuf *ibuf = &iev->ibuf;
1213 struct gotd_child_proc *proc = NULL;
1214 struct gotd_client *client = NULL;
1215 ssize_t n;
1216 int shut = 0;
1217 struct imsg imsg;
1219 client = find_client_by_proc_fd(fd);
1220 if (client == NULL) {
1221 /* Can happen during process teardown. */
1222 warnx("cannot find client for fd %d", fd);
1223 shut = 1;
1224 goto done;
1227 if (event & EV_READ) {
1228 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
1229 fatal("imsg_read error");
1230 if (n == 0) {
1231 /* Connection closed. */
1232 shut = 1;
1233 goto done;
1237 if (event & EV_WRITE) {
1238 n = msgbuf_write(&ibuf->w);
1239 if (n == -1 && errno != EAGAIN)
1240 fatal("msgbuf_write");
1241 if (n == 0) {
1242 /* Connection closed. */
1243 shut = 1;
1244 goto done;
1248 proc = client->session;
1249 if (proc == NULL)
1250 fatalx("cannot find session child process for fd %d", fd);
1252 for (;;) {
1253 const struct got_error *err = NULL;
1254 uint32_t client_id = 0;
1255 int do_disconnect = 0, do_start_repo_child = 0;
1257 if ((n = imsg_get(ibuf, &imsg)) == -1)
1258 fatal("%s: imsg_get error", __func__);
1259 if (n == 0) /* No more messages. */
1260 break;
1262 switch (imsg.hdr.type) {
1263 case GOTD_IMSG_ERROR:
1264 do_disconnect = 1;
1265 err = gotd_imsg_recv_error(&client_id, &imsg);
1266 break;
1267 case GOTD_IMSG_CLIENT_SESSION_READY:
1268 if (client->state != GOTD_CLIENT_STATE_ACCESS_GRANTED) {
1269 err = got_error(GOT_ERR_PRIVSEP_MSG);
1270 break;
1272 do_start_repo_child = 1;
1273 break;
1274 case GOTD_IMSG_DISCONNECT:
1275 do_disconnect = 1;
1276 break;
1277 default:
1278 log_debug("unexpected imsg %d", imsg.hdr.type);
1279 break;
1282 if (!verify_imsg_src(client, proc, &imsg)) {
1283 log_debug("dropping imsg type %d from PID %d",
1284 imsg.hdr.type, proc->pid);
1285 imsg_free(&imsg);
1286 continue;
1288 if (err)
1289 log_warnx("uid %d: %s", client->euid, err->msg);
1291 if (do_start_repo_child) {
1292 struct gotd_repo *repo;
1294 repo = find_repo_by_name(client->session->repo_name);
1295 if (repo != NULL) {
1296 enum gotd_procid proc_type;
1298 if (client->required_auth & GOTD_AUTH_WRITE)
1299 proc_type = PROC_REPO_WRITE;
1300 else
1301 proc_type = PROC_REPO_READ;
1303 err = start_repo_child(client, proc_type, repo,
1304 gotd.argv0, gotd.confpath, gotd.daemonize,
1305 gotd.verbosity);
1306 } else
1307 err = got_error(GOT_ERR_NOT_GIT_REPO);
1309 if (err) {
1310 log_warnx("uid %d: %s", client->euid, err->msg);
1311 do_disconnect = 1;
1315 if (do_disconnect) {
1316 if (err)
1317 disconnect_on_error(client, err);
1318 else
1319 disconnect(client);
1322 imsg_free(&imsg);
1324 done:
1325 if (!shut) {
1326 gotd_imsg_event_add(iev);
1327 } else {
1328 /* This pipe is dead. Remove its event handler */
1329 event_del(&iev->ev);
1330 disconnect(client);
1334 static void
1335 gotd_dispatch_repo_child(int fd, short event, void *arg)
1337 struct gotd_imsgev *iev = arg;
1338 struct imsgbuf *ibuf = &iev->ibuf;
1339 struct gotd_child_proc *proc = NULL;
1340 struct gotd_client *client;
1341 ssize_t n;
1342 int shut = 0;
1343 struct imsg imsg;
1345 client = find_client_by_proc_fd(fd);
1346 if (client == NULL) {
1347 /* Can happen during process teardown. */
1348 warnx("cannot find client for fd %d", fd);
1349 shut = 1;
1350 goto done;
1353 if (event & EV_READ) {
1354 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
1355 fatal("imsg_read error");
1356 if (n == 0) {
1357 /* Connection closed. */
1358 shut = 1;
1359 goto done;
1363 if (event & EV_WRITE) {
1364 n = msgbuf_write(&ibuf->w);
1365 if (n == -1 && errno != EAGAIN)
1366 fatal("msgbuf_write");
1367 if (n == 0) {
1368 /* Connection closed. */
1369 shut = 1;
1370 goto done;
1374 proc = client->repo;
1375 if (proc == NULL)
1376 fatalx("cannot find child process for fd %d", fd);
1378 for (;;) {
1379 const struct got_error *err = NULL;
1380 uint32_t client_id = 0;
1381 int do_disconnect = 0;
1383 if ((n = imsg_get(ibuf, &imsg)) == -1)
1384 fatal("%s: imsg_get error", __func__);
1385 if (n == 0) /* No more messages. */
1386 break;
1388 switch (imsg.hdr.type) {
1389 case GOTD_IMSG_ERROR:
1390 do_disconnect = 1;
1391 err = gotd_imsg_recv_error(&client_id, &imsg);
1392 break;
1393 case GOTD_IMSG_REPO_CHILD_READY:
1394 err = connect_session(client);
1395 if (err)
1396 break;
1397 err = connect_repo_child(client, proc);
1398 break;
1399 default:
1400 log_debug("unexpected imsg %d", imsg.hdr.type);
1401 break;
1404 if (!verify_imsg_src(client, proc, &imsg)) {
1405 log_debug("dropping imsg type %d from PID %d",
1406 imsg.hdr.type, proc->pid);
1407 imsg_free(&imsg);
1408 continue;
1410 if (err)
1411 log_warnx("uid %d: %s", client->euid, err->msg);
1413 if (do_disconnect) {
1414 if (err)
1415 disconnect_on_error(client, err);
1416 else
1417 disconnect(client);
1420 imsg_free(&imsg);
1422 done:
1423 if (!shut) {
1424 gotd_imsg_event_add(iev);
1425 } else {
1426 /* This pipe is dead. Remove its event handler */
1427 event_del(&iev->ev);
1428 disconnect(client);
1432 static pid_t
1433 start_child(enum gotd_procid proc_id, const char *repo_path,
1434 char *argv0, const char *confpath, int fd, int daemonize, int verbosity)
1436 char *argv[11];
1437 int argc = 0;
1438 pid_t pid;
1440 switch (pid = fork()) {
1441 case -1:
1442 fatal("cannot fork");
1443 case 0:
1444 break;
1445 default:
1446 close(fd);
1447 return pid;
1450 if (fd != GOTD_FILENO_MSG_PIPE) {
1451 if (dup2(fd, GOTD_FILENO_MSG_PIPE) == -1)
1452 fatal("cannot setup imsg fd");
1453 } else if (fcntl(fd, F_SETFD, 0) == -1)
1454 fatal("cannot setup imsg fd");
1456 argv[argc++] = argv0;
1457 switch (proc_id) {
1458 case PROC_LISTEN:
1459 argv[argc++] = (char *)"-L";
1460 break;
1461 case PROC_AUTH:
1462 argv[argc++] = (char *)"-A";
1463 break;
1464 case PROC_SESSION:
1465 argv[argc++] = (char *)"-S";
1466 break;
1467 case PROC_REPO_READ:
1468 argv[argc++] = (char *)"-R";
1469 break;
1470 case PROC_REPO_WRITE:
1471 argv[argc++] = (char *)"-W";
1472 break;
1473 default:
1474 fatalx("invalid process id %d", proc_id);
1477 argv[argc++] = (char *)"-f";
1478 argv[argc++] = (char *)confpath;
1480 if (repo_path) {
1481 argv[argc++] = (char *)"-P";
1482 argv[argc++] = (char *)repo_path;
1485 if (!daemonize)
1486 argv[argc++] = (char *)"-d";
1487 if (verbosity > 0)
1488 argv[argc++] = (char *)"-v";
1489 if (verbosity > 1)
1490 argv[argc++] = (char *)"-v";
1491 argv[argc++] = NULL;
1493 execvp(argv0, argv);
1494 fatal("execvp");
1497 static void
1498 start_listener(char *argv0, const char *confpath, int daemonize, int verbosity)
1500 struct gotd_child_proc *proc = &gotd.listen_proc;
1502 proc->type = PROC_LISTEN;
1504 if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK,
1505 PF_UNSPEC, proc->pipe) == -1)
1506 fatal("socketpair");
1508 proc->pid = start_child(proc->type, NULL, argv0, confpath,
1509 proc->pipe[1], daemonize, verbosity);
1510 imsg_init(&proc->iev.ibuf, proc->pipe[0]);
1511 proc->iev.handler = gotd_dispatch_listener;
1512 proc->iev.events = EV_READ;
1513 proc->iev.handler_arg = NULL;
1516 static const struct got_error *
1517 start_session_child(struct gotd_client *client, struct gotd_repo *repo,
1518 char *argv0, const char *confpath, int daemonize, int verbosity)
1520 struct gotd_child_proc *proc;
1522 proc = calloc(1, sizeof(*proc));
1523 if (proc == NULL)
1524 return got_error_from_errno("calloc");
1526 proc->type = PROC_SESSION;
1527 if (strlcpy(proc->repo_name, repo->name,
1528 sizeof(proc->repo_name)) >= sizeof(proc->repo_name))
1529 fatalx("repository name too long: %s", repo->name);
1530 log_debug("starting client uid %d session for repository %s",
1531 client->euid, repo->name);
1532 if (strlcpy(proc->repo_path, repo->path, sizeof(proc->repo_path)) >=
1533 sizeof(proc->repo_path))
1534 fatalx("repository path too long: %s", repo->path);
1535 if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK,
1536 PF_UNSPEC, proc->pipe) == -1)
1537 fatal("socketpair");
1538 proc->pid = start_child(proc->type, proc->repo_path, argv0,
1539 confpath, proc->pipe[1], daemonize, verbosity);
1540 imsg_init(&proc->iev.ibuf, proc->pipe[0]);
1541 log_debug("proc %s %s is on fd %d",
1542 gotd_proc_names[proc->type], proc->repo_path,
1543 proc->pipe[0]);
1544 proc->iev.handler = gotd_dispatch_client_session;
1545 proc->iev.events = EV_READ;
1546 proc->iev.handler_arg = NULL;
1547 event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ,
1548 gotd_dispatch_client_session, &proc->iev);
1549 gotd_imsg_event_add(&proc->iev);
1551 client->session = proc;
1552 return NULL;
1555 static const struct got_error *
1556 start_repo_child(struct gotd_client *client, enum gotd_procid proc_type,
1557 struct gotd_repo *repo, char *argv0, const char *confpath,
1558 int daemonize, int verbosity)
1560 struct gotd_child_proc *proc;
1562 if (proc_type != PROC_REPO_READ && proc_type != PROC_REPO_WRITE)
1563 return got_error_msg(GOT_ERR_NOT_IMPL, "bad process type");
1565 proc = calloc(1, sizeof(*proc));
1566 if (proc == NULL)
1567 return got_error_from_errno("calloc");
1569 proc->type = proc_type;
1570 if (strlcpy(proc->repo_name, repo->name,
1571 sizeof(proc->repo_name)) >= sizeof(proc->repo_name))
1572 fatalx("repository name too long: %s", repo->name);
1573 log_debug("starting %s for repository %s",
1574 proc->type == PROC_REPO_READ ? "reader" : "writer", repo->name);
1575 if (strlcpy(proc->repo_path, repo->path, sizeof(proc->repo_path)) >=
1576 sizeof(proc->repo_path))
1577 fatalx("repository path too long: %s", repo->path);
1578 if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK,
1579 PF_UNSPEC, proc->pipe) == -1)
1580 fatal("socketpair");
1581 proc->pid = start_child(proc->type, proc->repo_path, argv0,
1582 confpath, proc->pipe[1], daemonize, verbosity);
1583 imsg_init(&proc->iev.ibuf, proc->pipe[0]);
1584 log_debug("proc %s %s is on fd %d",
1585 gotd_proc_names[proc->type], proc->repo_path,
1586 proc->pipe[0]);
1587 proc->iev.handler = gotd_dispatch_repo_child;
1588 proc->iev.events = EV_READ;
1589 proc->iev.handler_arg = NULL;
1590 event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ,
1591 gotd_dispatch_repo_child, &proc->iev);
1592 gotd_imsg_event_add(&proc->iev);
1594 client->repo = proc;
1595 return NULL;
1598 static const struct got_error *
1599 start_auth_child(struct gotd_client *client, int required_auth,
1600 struct gotd_repo *repo, char *argv0, const char *confpath,
1601 int daemonize, int verbosity)
1603 const struct got_error *err = NULL;
1604 struct gotd_child_proc *proc;
1605 struct gotd_imsg_auth iauth;
1606 int fd;
1608 memset(&iauth, 0, sizeof(iauth));
1610 fd = dup(client->fd);
1611 if (fd == -1)
1612 return got_error_from_errno("dup");
1614 proc = calloc(1, sizeof(*proc));
1615 if (proc == NULL) {
1616 err = got_error_from_errno("calloc");
1617 close(fd);
1618 return err;
1621 proc->type = PROC_AUTH;
1622 if (strlcpy(proc->repo_name, repo->name,
1623 sizeof(proc->repo_name)) >= sizeof(proc->repo_name))
1624 fatalx("repository name too long: %s", repo->name);
1625 log_debug("starting auth for uid %d repository %s",
1626 client->euid, repo->name);
1627 if (strlcpy(proc->repo_path, repo->path, sizeof(proc->repo_path)) >=
1628 sizeof(proc->repo_path))
1629 fatalx("repository path too long: %s", repo->path);
1630 if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK,
1631 PF_UNSPEC, proc->pipe) == -1)
1632 fatal("socketpair");
1633 proc->pid = start_child(proc->type, proc->repo_path, argv0,
1634 confpath, proc->pipe[1], daemonize, verbosity);
1635 imsg_init(&proc->iev.ibuf, proc->pipe[0]);
1636 log_debug("proc %s %s is on fd %d",
1637 gotd_proc_names[proc->type], proc->repo_path,
1638 proc->pipe[0]);
1639 proc->iev.handler = gotd_dispatch_auth_child;
1640 proc->iev.events = EV_READ;
1641 proc->iev.handler_arg = NULL;
1642 event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ,
1643 gotd_dispatch_auth_child, &proc->iev);
1644 gotd_imsg_event_add(&proc->iev);
1646 iauth.euid = client->euid;
1647 iauth.egid = client->egid;
1648 iauth.required_auth = required_auth;
1649 iauth.client_id = client->id;
1650 if (gotd_imsg_compose_event(&proc->iev, GOTD_IMSG_AUTHENTICATE,
1651 PROC_GOTD, fd, &iauth, sizeof(iauth)) == -1) {
1652 log_warn("imsg compose AUTHENTICATE");
1653 close(fd);
1654 /* Let the auth_timeout handler tidy up. */
1657 client->auth = proc;
1658 client->required_auth = required_auth;
1659 return NULL;
1662 static void
1663 apply_unveil_repo_readonly(const char *repo_path)
1665 if (unveil(repo_path, "r") == -1)
1666 fatal("unveil %s", repo_path);
1668 if (unveil(NULL, NULL) == -1)
1669 fatal("unveil");
1672 static void
1673 apply_unveil_repo_readwrite(const char *repo_path)
1675 if (unveil(repo_path, "rwc") == -1)
1676 fatal("unveil %s", repo_path);
1678 if (unveil(GOT_TMPDIR_STR, "rwc") == -1)
1679 fatal("unveil %s", GOT_TMPDIR_STR);
1681 if (unveil(NULL, NULL) == -1)
1682 fatal("unveil");
1685 static void
1686 apply_unveil_none(void)
1688 if (unveil("/", "") == -1)
1689 fatal("unveil");
1691 if (unveil(NULL, NULL) == -1)
1692 fatal("unveil");
1695 static void
1696 apply_unveil_selfexec(void)
1698 if (unveil(gotd.argv0, "x") == -1)
1699 fatal("unveil %s", gotd.argv0);
1701 if (unveil(NULL, NULL) == -1)
1702 fatal("unveil");
1705 int
1706 main(int argc, char **argv)
1708 const struct got_error *error = NULL;
1709 int ch, fd = -1, daemonize = 1, verbosity = 0, noaction = 0;
1710 const char *confpath = GOTD_CONF_PATH;
1711 char *argv0 = argv[0];
1712 char title[2048];
1713 struct passwd *pw = NULL;
1714 char *repo_path = NULL;
1715 enum gotd_procid proc_id = PROC_GOTD;
1716 struct event evsigint, evsigterm, evsighup, evsigusr1;
1717 int *pack_fds = NULL, *temp_fds = NULL;
1719 log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */
1721 while ((ch = getopt(argc, argv, "Adf:LnP:RSvW")) != -1) {
1722 switch (ch) {
1723 case 'A':
1724 proc_id = PROC_AUTH;
1725 break;
1726 case 'd':
1727 daemonize = 0;
1728 break;
1729 case 'f':
1730 confpath = optarg;
1731 break;
1732 case 'L':
1733 proc_id = PROC_LISTEN;
1734 break;
1735 case 'n':
1736 noaction = 1;
1737 break;
1738 case 'P':
1739 repo_path = realpath(optarg, NULL);
1740 if (repo_path == NULL)
1741 fatal("realpath '%s'", optarg);
1742 break;
1743 case 'R':
1744 proc_id = PROC_REPO_READ;
1745 break;
1746 case 'S':
1747 proc_id = PROC_SESSION;
1748 break;
1749 case 'v':
1750 if (verbosity < 3)
1751 verbosity++;
1752 break;
1753 case 'W':
1754 proc_id = PROC_REPO_WRITE;
1755 break;
1756 default:
1757 usage();
1761 argc -= optind;
1762 argv += optind;
1764 if (argc != 0)
1765 usage();
1767 if (geteuid() && (proc_id == PROC_GOTD || proc_id == PROC_LISTEN))
1768 fatalx("need root privileges");
1770 if (parse_config(confpath, proc_id, &gotd) != 0)
1771 return 1;
1773 pw = getpwnam(gotd.user_name);
1774 if (pw == NULL)
1775 fatalx("user %s not found", gotd.user_name);
1777 if (pw->pw_uid == 0)
1778 fatalx("cannot run %s as the superuser", getprogname());
1780 if (noaction) {
1781 fprintf(stderr, "configuration OK\n");
1782 return 0;
1785 gotd.argv0 = argv0;
1786 gotd.daemonize = daemonize;
1787 gotd.verbosity = verbosity;
1788 gotd.confpath = confpath;
1790 /* Require an absolute path in argv[0] for reliable re-exec. */
1791 if (!got_path_is_absolute(argv0))
1792 fatalx("bad path \"%s\": must be an absolute path", argv0);
1794 log_init(daemonize ? 0 : 1, LOG_DAEMON);
1795 log_setverbose(verbosity);
1797 if (proc_id == PROC_GOTD) {
1798 snprintf(title, sizeof(title), "%s", gotd_proc_names[proc_id]);
1799 arc4random_buf(&clients_hash_key, sizeof(clients_hash_key));
1800 if (daemonize && daemon(1, 0) == -1)
1801 fatal("daemon");
1802 gotd.pid = getpid();
1803 start_listener(argv0, confpath, daemonize, verbosity);
1804 } else if (proc_id == PROC_LISTEN) {
1805 snprintf(title, sizeof(title), "%s", gotd_proc_names[proc_id]);
1806 if (verbosity) {
1807 log_info("socket: %s", gotd.unix_socket_path);
1808 log_info("user: %s", pw->pw_name);
1811 fd = unix_socket_listen(gotd.unix_socket_path, pw->pw_uid,
1812 pw->pw_gid);
1813 if (fd == -1) {
1814 fatal("cannot listen on unix socket %s",
1815 gotd.unix_socket_path);
1817 } else if (proc_id == PROC_AUTH) {
1818 snprintf(title, sizeof(title), "%s %s",
1819 gotd_proc_names[proc_id], repo_path);
1820 } else if (proc_id == PROC_REPO_READ || proc_id == PROC_REPO_WRITE ||
1821 proc_id == PROC_SESSION) {
1822 error = got_repo_pack_fds_open(&pack_fds);
1823 if (error != NULL)
1824 fatalx("cannot open pack tempfiles: %s", error->msg);
1825 error = got_repo_temp_fds_open(&temp_fds);
1826 if (error != NULL)
1827 fatalx("cannot open pack tempfiles: %s", error->msg);
1828 if (repo_path == NULL)
1829 fatalx("repository path not specified");
1830 snprintf(title, sizeof(title), "%s %s",
1831 gotd_proc_names[proc_id], repo_path);
1832 } else
1833 fatal("invalid process id %d", proc_id);
1835 setproctitle("%s", title);
1836 log_procinit(title);
1838 /* Drop root privileges. */
1839 if (setgid(pw->pw_gid) == -1)
1840 fatal("setgid %d failed", pw->pw_gid);
1841 if (setuid(pw->pw_uid) == -1)
1842 fatal("setuid %d failed", pw->pw_uid);
1844 event_init();
1846 switch (proc_id) {
1847 case PROC_GOTD:
1848 #ifndef PROFILE
1849 /* "exec" promise will be limited to argv[0] via unveil(2). */
1850 if (pledge("stdio proc exec sendfd recvfd unveil", NULL) == -1)
1851 err(1, "pledge");
1852 #endif
1853 break;
1854 case PROC_LISTEN:
1855 #ifndef PROFILE
1856 if (pledge("stdio sendfd unix unveil", NULL) == -1)
1857 err(1, "pledge");
1858 #endif
1860 * Ensure that AF_UNIX bind(2) cannot be used with any other
1861 * sockets by revoking all filesystem access via unveil(2).
1863 apply_unveil_none();
1865 listen_main(title, fd, gotd.connection_limits,
1866 gotd.nconnection_limits);
1867 /* NOTREACHED */
1868 break;
1869 case PROC_AUTH:
1870 #ifndef PROFILE
1871 if (pledge("stdio getpw recvfd unix unveil", NULL) == -1)
1872 err(1, "pledge");
1873 #endif
1875 * We need the "unix" pledge promise for getpeername(2) only.
1876 * Ensure that AF_UNIX bind(2) cannot be used by revoking all
1877 * filesystem access via unveil(2). Access to password database
1878 * files will still work since "getpw" bypasses unveil(2).
1880 apply_unveil_none();
1882 auth_main(title, &gotd.repos, repo_path);
1883 /* NOTREACHED */
1884 break;
1885 case PROC_SESSION:
1886 #ifndef PROFILE
1888 * The "recvfd" promise is only needed during setup and
1889 * will be removed in a later pledge(2) call.
1891 if (pledge("stdio rpath wpath cpath recvfd sendfd fattr flock "
1892 "unveil", NULL) == -1)
1893 err(1, "pledge");
1894 #endif
1895 apply_unveil_repo_readwrite(repo_path);
1896 session_main(title, repo_path, pack_fds, temp_fds,
1897 &gotd.request_timeout);
1898 /* NOTREACHED */
1899 break;
1900 case PROC_REPO_READ:
1901 #ifndef PROFILE
1902 if (pledge("stdio rpath recvfd unveil", NULL) == -1)
1903 err(1, "pledge");
1904 #endif
1905 apply_unveil_repo_readonly(repo_path);
1906 repo_read_main(title, repo_path, pack_fds, temp_fds);
1907 /* NOTREACHED */
1908 exit(0);
1909 case PROC_REPO_WRITE:
1910 #ifndef PROFILE
1911 if (pledge("stdio rpath recvfd unveil", NULL) == -1)
1912 err(1, "pledge");
1913 #endif
1914 apply_unveil_repo_readonly(repo_path);
1915 repo_write_main(title, repo_path, pack_fds, temp_fds);
1916 /* NOTREACHED */
1917 exit(0);
1918 default:
1919 fatal("invalid process id %d", proc_id);
1922 if (proc_id != PROC_GOTD)
1923 fatal("invalid process id %d", proc_id);
1925 apply_unveil_selfexec();
1927 signal_set(&evsigint, SIGINT, gotd_sighdlr, NULL);
1928 signal_set(&evsigterm, SIGTERM, gotd_sighdlr, NULL);
1929 signal_set(&evsighup, SIGHUP, gotd_sighdlr, NULL);
1930 signal_set(&evsigusr1, SIGUSR1, gotd_sighdlr, NULL);
1931 signal(SIGPIPE, SIG_IGN);
1933 signal_add(&evsigint, NULL);
1934 signal_add(&evsigterm, NULL);
1935 signal_add(&evsighup, NULL);
1936 signal_add(&evsigusr1, NULL);
1938 gotd_imsg_event_add(&gotd.listen_proc.iev);
1940 event_dispatch();
1942 free(repo_path);
1943 gotd_shutdown();
1945 return 0;