2 * Copyright (c) 2022 Stefan Sperling <stsp@openbsd.org>
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.
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.
17 #include "got_compat.h"
19 #include <sys/queue.h>
21 #include <sys/types.h>
23 #include <sys/socket.h>
26 #include <sys/resource.h>
43 #include "got_error.h"
44 #include "got_opentemp.h"
46 #include "got_repository.h"
47 #include "got_object.h"
48 #include "got_reference.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"
63 #include "session_read.h"
64 #include "session_write.h"
65 #include "repo_read.h"
66 #include "repo_write.h"
70 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
73 enum gotd_client_state
{
74 GOTD_CLIENT_STATE_NEW
,
75 GOTD_CLIENT_STATE_ACCESS_GRANTED
,
78 struct gotd_child_proc
{
80 enum gotd_procid type
;
81 char repo_name
[NAME_MAX
];
82 char repo_path
[PATH_MAX
];
84 struct gotd_imsgev iev
;
87 TAILQ_ENTRY(gotd_child_proc
) entry
;
89 TAILQ_HEAD(gotd_procs
, gotd_child_proc
) procs
;
92 STAILQ_ENTRY(gotd_client
) entry
;
93 enum gotd_client_state state
;
96 struct gotd_imsgev iev
;
101 struct gotd_child_proc
*repo
;
102 struct gotd_child_proc
*auth
;
103 struct gotd_child_proc
*session
;
106 STAILQ_HEAD(gotd_clients
, gotd_client
);
108 static struct gotd_clients gotd_clients
[GOTD_CLIENT_TABLE_SIZE
];
109 static SIPHASH_KEY clients_hash_key
;
110 volatile int client_cnt
;
111 static struct timeval auth_timeout
= { 5, 0 };
112 static struct gotd gotd
;
114 void gotd_sighdlr(int sig
, short event
, void *arg
);
115 static void gotd_shutdown(void);
116 static const struct got_error
*start_session_child(struct gotd_client
*,
117 struct gotd_repo
*, char *, const char *, int, int);
118 static const struct got_error
*start_repo_child(struct gotd_client
*,
119 enum gotd_procid
, struct gotd_repo
*, char *, const char *, int, int);
120 static const struct got_error
*start_auth_child(struct gotd_client
*, int,
121 struct gotd_repo
*, char *, const char *, int, int);
122 static void kill_proc(struct gotd_child_proc
*, int);
123 static void disconnect(struct gotd_client
*);
124 static void drop_privs(struct passwd
*);
129 fprintf(stderr
, "usage: %s [-dnv] [-f config-file]\n", getprogname());
134 drop_privs(struct passwd
*pw
)
136 /* Drop root privileges. */
137 if (setgid(pw
->pw_gid
) == -1)
138 fatal("setgid %d failed", pw
->pw_gid
);
139 if (setuid(pw
->pw_uid
) == -1)
140 fatal("setuid %d failed", pw
->pw_uid
);
144 unix_socket_listen(const char *unix_socket_path
, uid_t uid
, gid_t gid
)
146 struct sockaddr_un sun
;
148 mode_t old_umask
, mode
;
149 int sock_flags
= SOCK_STREAM
| SOCK_NONBLOCK
;
152 sock_flags
|= SOCK_CLOEXEC
;
155 fd
= socket(AF_UNIX
, sock_flags
, 0);
161 sun
.sun_family
= AF_UNIX
;
162 if (strlcpy(sun
.sun_path
, unix_socket_path
,
163 sizeof(sun
.sun_path
)) >= sizeof(sun
.sun_path
)) {
164 log_warnx("%s: name too long", unix_socket_path
);
169 if (unlink(unix_socket_path
) == -1) {
170 if (errno
!= ENOENT
) {
171 log_warn("unlink %s", unix_socket_path
);
177 old_umask
= umask(S_IXUSR
|S_IXGRP
|S_IWOTH
|S_IROTH
|S_IXOTH
);
178 mode
= S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
;
180 if (bind(fd
, (struct sockaddr
*)&sun
, sizeof(sun
)) == -1) {
181 log_warn("bind: %s", unix_socket_path
);
189 if (chmod(unix_socket_path
, mode
) == -1) {
190 log_warn("chmod %o %s", mode
, unix_socket_path
);
192 unlink(unix_socket_path
);
196 if (chown(unix_socket_path
, uid
, gid
) == -1) {
197 log_warn("chown %s uid=%d gid=%d", unix_socket_path
, uid
, gid
);
199 unlink(unix_socket_path
);
203 if (listen(fd
, GOTD_UNIX_SOCKET_BACKLOG
) == -1) {
206 unlink(unix_socket_path
);
214 client_hash(uint32_t client_id
)
216 return SipHash24(&clients_hash_key
, &client_id
, sizeof(client_id
));
220 add_client(struct gotd_client
*client
)
222 uint64_t slot
= client_hash(client
->id
) % nitems(gotd_clients
);
223 STAILQ_INSERT_HEAD(&gotd_clients
[slot
], client
, entry
);
227 static struct gotd_client
*
228 find_client(uint32_t client_id
)
231 struct gotd_client
*c
;
233 slot
= client_hash(client_id
) % nitems(gotd_clients
);
234 STAILQ_FOREACH(c
, &gotd_clients
[slot
], entry
) {
235 if (c
->id
== client_id
)
242 static struct gotd_client
*
243 find_client_by_proc_fd(int fd
)
247 for (slot
= 0; slot
< nitems(gotd_clients
); slot
++) {
248 struct gotd_client
*c
;
250 STAILQ_FOREACH(c
, &gotd_clients
[slot
], entry
) {
251 if (c
->repo
&& c
->repo
->iev
.ibuf
.fd
== fd
)
253 if (c
->auth
&& c
->auth
->iev
.ibuf
.fd
== fd
)
255 if (c
->session
&& c
->session
->iev
.ibuf
.fd
== fd
)
264 client_is_reading(struct gotd_client
*client
)
266 return (client
->required_auth
&
267 (GOTD_AUTH_READ
| GOTD_AUTH_WRITE
)) == GOTD_AUTH_READ
;
271 client_is_writing(struct gotd_client
*client
)
273 return (client
->required_auth
&
274 (GOTD_AUTH_READ
| GOTD_AUTH_WRITE
)) ==
275 (GOTD_AUTH_READ
| GOTD_AUTH_WRITE
);
278 static const struct got_error
*
279 ensure_client_is_not_writing(struct gotd_client
*client
)
281 if (client_is_writing(client
)) {
282 return got_error_fmt(GOT_ERR_BAD_PACKET
,
283 "uid %d made a read-request but is writing to "
284 "a repository", client
->euid
);
290 static const struct got_error
*
291 ensure_client_is_not_reading(struct gotd_client
*client
)
293 if (client_is_reading(client
)) {
294 return got_error_fmt(GOT_ERR_BAD_PACKET
,
295 "uid %d made a write-request but is reading from "
296 "a repository", client
->euid
);
303 proc_done(struct gotd_child_proc
*proc
)
305 struct gotd_client
*client
;
307 TAILQ_REMOVE(&procs
, proc
, entry
);
309 client
= find_client_by_proc_fd(proc
->iev
.ibuf
.fd
);
310 if (client
!= NULL
) {
311 if (proc
== client
->repo
)
313 if (proc
== client
->auth
)
315 if (proc
== client
->session
)
316 client
->session
= NULL
;
320 if (proc
== gotd
.notify_proc
)
321 gotd
.notify_proc
= NULL
;
323 evtimer_del(&proc
->tmo
);
325 if (proc
->iev
.ibuf
.fd
!= -1) {
326 event_del(&proc
->iev
.ev
);
327 msgbuf_clear(&proc
->iev
.ibuf
.w
);
328 close(proc
->iev
.ibuf
.fd
);
335 kill_repo_proc(struct gotd_client
*client
)
337 if (client
->repo
== NULL
)
340 kill_proc(client
->repo
, 0);
345 kill_auth_proc(struct gotd_client
*client
)
347 if (client
->auth
== NULL
)
350 kill_proc(client
->auth
, 0);
355 kill_session_proc(struct gotd_client
*client
)
357 if (client
->session
== NULL
)
360 kill_proc(client
->session
, 0);
361 client
->session
= NULL
;
365 disconnect(struct gotd_client
*client
)
367 struct gotd_imsg_disconnect idisconnect
;
368 struct gotd_child_proc
*listen_proc
= gotd
.listen_proc
;
371 log_debug("uid %d: disconnecting", client
->euid
);
373 kill_auth_proc(client
);
374 kill_session_proc(client
);
375 kill_repo_proc(client
);
377 idisconnect
.client_id
= client
->id
;
378 if (gotd_imsg_compose_event(&listen_proc
->iev
,
379 GOTD_IMSG_DISCONNECT
, PROC_GOTD
, -1,
380 &idisconnect
, sizeof(idisconnect
)) == -1)
381 log_warn("imsg compose DISCONNECT");
383 slot
= client_hash(client
->id
) % nitems(gotd_clients
);
384 STAILQ_REMOVE(&gotd_clients
[slot
], client
, gotd_client
, entry
);
385 imsg_clear(&client
->iev
.ibuf
);
386 event_del(&client
->iev
.ev
);
387 evtimer_del(&client
->tmo
);
388 if (client
->fd
!= -1)
390 else if (client
->iev
.ibuf
.fd
!= -1)
391 close(client
->iev
.ibuf
.fd
);
392 free(client
->username
);
398 disconnect_on_error(struct gotd_client
*client
, const struct got_error
*err
)
402 if (err
->code
!= GOT_ERR_EOF
) {
403 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
404 if (client
->fd
!= -1) {
405 imsg_init(&ibuf
, client
->fd
);
406 gotd_imsg_send_error(&ibuf
, 0, PROC_GOTD
, err
);
413 static const struct got_error
*
414 send_repo_info(struct gotd_imsgev
*iev
, struct gotd_repo
*repo
)
416 const struct got_error
*err
= NULL
;
417 struct gotd_imsg_info_repo irepo
;
419 memset(&irepo
, 0, sizeof(irepo
));
421 if (strlcpy(irepo
.repo_name
, repo
->name
, sizeof(irepo
.repo_name
))
422 >= sizeof(irepo
.repo_name
))
423 return got_error_msg(GOT_ERR_NO_SPACE
, "repo name too long");
424 if (strlcpy(irepo
.repo_path
, repo
->path
, sizeof(irepo
.repo_path
))
425 >= sizeof(irepo
.repo_path
))
426 return got_error_msg(GOT_ERR_NO_SPACE
, "repo path too long");
428 if (gotd_imsg_compose_event(iev
, GOTD_IMSG_INFO_REPO
, PROC_GOTD
, -1,
429 &irepo
, sizeof(irepo
)) == -1) {
430 err
= got_error_from_errno("imsg compose INFO_REPO");
438 static const struct got_error
*
439 send_client_info(struct gotd_imsgev
*iev
, struct gotd_client
*client
)
441 const struct got_error
*err
= NULL
;
442 struct gotd_imsg_info_client iclient
;
443 struct gotd_child_proc
*proc
;
445 memset(&iclient
, 0, sizeof(iclient
));
446 iclient
.euid
= client
->euid
;
447 iclient
.egid
= client
->egid
;
451 if (strlcpy(iclient
.repo_name
, proc
->repo_path
,
452 sizeof(iclient
.repo_name
)) >= sizeof(iclient
.repo_name
)) {
453 return got_error_msg(GOT_ERR_NO_SPACE
,
454 "repo name too long");
456 if (client_is_writing(client
))
457 iclient
.is_writing
= 1;
459 iclient
.repo_child_pid
= proc
->pid
;
463 iclient
.session_child_pid
= client
->session
->pid
;
465 if (gotd_imsg_compose_event(iev
, GOTD_IMSG_INFO_CLIENT
, PROC_GOTD
, -1,
466 &iclient
, sizeof(iclient
)) == -1) {
467 err
= got_error_from_errno("imsg compose INFO_CLIENT");
475 static const struct got_error
*
476 send_info(struct gotd_client
*client
)
478 const struct got_error
*err
= NULL
;
479 struct gotd_imsg_info info
;
481 struct gotd_repo
*repo
;
483 if (client
->euid
!= 0)
484 return got_error_set_errno(EPERM
, "info");
487 info
.verbosity
= gotd
.verbosity
;
488 info
.nrepos
= gotd
.nrepos
;
489 info
.nclients
= client_cnt
- 1;
491 if (gotd_imsg_compose_event(&client
->iev
, GOTD_IMSG_INFO
, PROC_GOTD
, -1,
492 &info
, sizeof(info
)) == -1) {
493 err
= got_error_from_errno("imsg compose INFO");
498 TAILQ_FOREACH(repo
, &gotd
.repos
, entry
) {
499 err
= send_repo_info(&client
->iev
, repo
);
504 for (slot
= 0; slot
< nitems(gotd_clients
); slot
++) {
505 struct gotd_client
*c
;
506 STAILQ_FOREACH(c
, &gotd_clients
[slot
], entry
) {
507 if (c
->id
== client
->id
)
509 err
= send_client_info(&client
->iev
, c
);
518 static const struct got_error
*
519 stop_gotd(struct gotd_client
*client
)
522 if (client
->euid
!= 0)
523 return got_error_set_errno(EPERM
, "stop");
530 static const struct got_error
*
531 start_client_authentication(struct gotd_client
*client
, struct imsg
*imsg
)
533 const struct got_error
*err
;
534 struct gotd_imsg_list_refs ireq
;
535 struct gotd_repo
*repo
= NULL
;
538 log_debug("list-refs request from uid %d", client
->euid
);
540 if (client
->state
!= GOTD_CLIENT_STATE_NEW
)
541 return got_error_msg(GOT_ERR_BAD_REQUEST
,
542 "unexpected list-refs request received");
544 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
545 if (datalen
!= sizeof(ireq
))
546 return got_error(GOT_ERR_PRIVSEP_LEN
);
548 memcpy(&ireq
, imsg
->data
, datalen
);
550 if (ireq
.client_is_reading
) {
551 err
= ensure_client_is_not_writing(client
);
554 repo
= gotd_find_repo_by_name(ireq
.repo_name
, &gotd
.repos
);
556 return got_error(GOT_ERR_NOT_GIT_REPO
);
557 err
= start_auth_child(client
, GOTD_AUTH_READ
, repo
,
558 gotd
.argv0
, gotd
.confpath
, gotd
.daemonize
,
563 err
= ensure_client_is_not_reading(client
);
566 repo
= gotd_find_repo_by_name(ireq
.repo_name
, &gotd
.repos
);
568 return got_error(GOT_ERR_NOT_GIT_REPO
);
569 err
= start_auth_child(client
,
570 GOTD_AUTH_READ
| GOTD_AUTH_WRITE
,
571 repo
, gotd
.argv0
, gotd
.confpath
, gotd
.daemonize
,
577 evtimer_add(&client
->tmo
, &auth_timeout
);
579 /* Flow continues upon authentication success/failure or timeout. */
584 gotd_request(int fd
, short events
, void *arg
)
586 struct gotd_imsgev
*iev
= arg
;
587 struct imsgbuf
*ibuf
= &iev
->ibuf
;
588 struct gotd_client
*client
= iev
->handler_arg
;
589 const struct got_error
*err
= NULL
;
593 if (events
& EV_WRITE
) {
594 while (ibuf
->w
.queued
) {
595 n
= msgbuf_write(&ibuf
->w
);
596 if (n
== -1 && errno
== EPIPE
) {
598 * The client has closed its socket.
599 * This can happen when Git clients are
600 * done sending pack file data.
602 msgbuf_clear(&ibuf
->w
);
604 } else if (n
== -1 && errno
!= EAGAIN
) {
605 err
= got_error_from_errno("imsg_flush");
606 disconnect_on_error(client
, err
);
610 /* Connection closed. */
611 err
= got_error(GOT_ERR_EOF
);
612 disconnect_on_error(client
, err
);
617 /* Disconnect gotctl(8) now that messages have been sent. */
618 if (!client_is_reading(client
) && !client_is_writing(client
)) {
624 if ((events
& EV_READ
) == 0)
627 memset(&imsg
, 0, sizeof(imsg
));
629 while (err
== NULL
) {
630 err
= gotd_imsg_recv(&imsg
, ibuf
, 0);
632 if (err
->code
== GOT_ERR_PRIVSEP_READ
)
637 evtimer_del(&client
->tmo
);
639 switch (imsg
.hdr
.type
) {
641 err
= send_info(client
);
644 err
= stop_gotd(client
);
646 case GOTD_IMSG_LIST_REFS
:
647 err
= start_client_authentication(client
, &imsg
);
650 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
651 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
659 disconnect_on_error(client
, err
);
661 gotd_imsg_event_add(&client
->iev
);
666 gotd_auth_timeout(int fd
, short events
, void *arg
)
668 struct gotd_client
*client
= arg
;
670 log_debug("disconnecting uid %d due to authentication timeout",
675 static const struct got_error
*
676 recv_connect(uint32_t *client_id
, struct imsg
*imsg
)
678 const struct got_error
*err
= NULL
;
679 struct gotd_imsg_connect iconnect
;
682 struct gotd_client
*client
= NULL
;
686 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
687 if (datalen
!= sizeof(iconnect
))
688 return got_error(GOT_ERR_PRIVSEP_LEN
);
689 memcpy(&iconnect
, imsg
->data
, sizeof(iconnect
));
691 s
= imsg_get_fd(imsg
);
693 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
697 if (find_client(iconnect
.client_id
)) {
698 err
= got_error_msg(GOT_ERR_CLIENT_ID
, "duplicate client ID");
702 client
= calloc(1, sizeof(*client
));
703 if (client
== NULL
) {
704 err
= got_error_from_errno("calloc");
708 *client_id
= iconnect
.client_id
;
710 client
->state
= GOTD_CLIENT_STATE_NEW
;
711 client
->id
= iconnect
.client_id
;
714 /* The auth process will verify UID/GID for us. */
715 client
->euid
= iconnect
.euid
;
716 client
->egid
= iconnect
.egid
;
718 imsg_init(&client
->iev
.ibuf
, client
->fd
);
719 client
->iev
.handler
= gotd_request
;
720 client
->iev
.events
= EV_READ
;
721 client
->iev
.handler_arg
= client
;
723 event_set(&client
->iev
.ev
, client
->fd
, EV_READ
, gotd_request
,
725 gotd_imsg_event_add(&client
->iev
);
727 evtimer_set(&client
->tmo
, gotd_auth_timeout
, client
);
730 log_debug("%s: new client uid %d connected on fd %d", __func__
,
731 client
->euid
, client
->fd
);
734 struct gotd_child_proc
*listen_proc
= gotd
.listen_proc
;
735 struct gotd_imsg_disconnect idisconnect
;
737 idisconnect
.client_id
= client
->id
;
738 if (gotd_imsg_compose_event(&listen_proc
->iev
,
739 GOTD_IMSG_DISCONNECT
, PROC_GOTD
, -1,
740 &idisconnect
, sizeof(idisconnect
)) == -1)
741 log_warn("imsg compose DISCONNECT");
750 static const char *gotd_proc_names
[PROC_MAX
] = {
763 kill_proc(struct gotd_child_proc
*proc
, int fatal
)
765 struct timeval tv
= { 5, 0 };
767 log_debug("kill -%d %d", fatal
? SIGKILL
: SIGTERM
, proc
->pid
);
769 if (proc
->iev
.ibuf
.fd
!= -1) {
770 event_del(&proc
->iev
.ev
);
771 msgbuf_clear(&proc
->iev
.ibuf
.w
);
772 close(proc
->iev
.ibuf
.fd
);
773 proc
->iev
.ibuf
.fd
= -1;
776 if (!evtimer_pending(&proc
->tmo
, NULL
) && !fatal
)
777 evtimer_add(&proc
->tmo
, &tv
);
780 log_warnx("sending SIGKILL to PID %d", proc
->pid
);
781 kill(proc
->pid
, SIGKILL
);
783 kill(proc
->pid
, SIGTERM
);
787 kill_proc_timeout(int fd
, short ev
, void *d
)
789 struct gotd_child_proc
*proc
= d
;
791 log_warnx("timeout waiting for PID %d to terminate;"
792 " retrying with force", proc
->pid
);
801 log_debug("shutting down");
802 for (slot
= 0; slot
< nitems(gotd_clients
); slot
++) {
803 struct gotd_client
*c
, *tmp
;
805 STAILQ_FOREACH_SAFE(c
, &gotd_clients
[slot
], entry
, tmp
)
809 kill_proc(gotd
.listen_proc
, 0);
811 log_info("terminating");
815 static struct gotd_child_proc
*
816 find_proc_by_pid(pid_t pid
)
818 struct gotd_child_proc
*proc
= NULL
;
820 TAILQ_FOREACH(proc
, &procs
, entry
)
821 if (proc
->pid
== pid
)
828 gotd_sighdlr(int sig
, short event
, void *arg
)
830 struct gotd_child_proc
*proc
;
835 * Normal signal handler rules don't apply because libevent
841 log_info("%s: ignoring SIGHUP", __func__
);
844 log_info("%s: ignoring SIGUSR1", __func__
);
852 pid
= waitpid(WAIT_ANY
, &status
, WNOHANG
);
863 log_debug("reaped pid %d", pid
);
864 proc
= find_proc_by_pid(pid
);
866 log_info("caught exit of unknown child %d",
871 if (WIFSIGNALED(status
)) {
872 log_warnx("child PID %d terminated with"
873 " signal %d", pid
, WTERMSIG(status
));
880 fatalx("unexpected signal");
884 static const struct got_error
*
885 ensure_proc_is_reading(struct gotd_client
*client
,
886 struct gotd_child_proc
*proc
)
888 if (!client_is_reading(client
)) {
890 return got_error_fmt(GOT_ERR_BAD_PACKET
,
891 "PID %d handled a read-request for uid %d but this "
892 "user is not reading from a repository", proc
->pid
,
899 static const struct got_error
*
900 ensure_proc_is_writing(struct gotd_client
*client
,
901 struct gotd_child_proc
*proc
)
903 if (!client_is_writing(client
)) {
905 return got_error_fmt(GOT_ERR_BAD_PACKET
,
906 "PID %d handled a write-request for uid %d but this "
907 "user is not writing to a repository", proc
->pid
,
915 verify_imsg_src(struct gotd_client
*client
, struct gotd_child_proc
*proc
,
918 const struct got_error
*err
;
921 if (proc
->type
== PROC_REPO_READ
|| proc
->type
== PROC_REPO_WRITE
) {
922 if (client
->repo
== NULL
)
923 fatalx("no process found for uid %d", client
->euid
);
924 if (proc
->pid
!= client
->repo
->pid
) {
926 log_warnx("received message from PID %d for uid %d, "
927 "while PID %d is the process serving this user",
928 proc
->pid
, client
->euid
, client
->repo
->pid
);
932 if (proc
->type
== PROC_SESSION_READ
||
933 proc
->type
== PROC_SESSION_WRITE
) {
934 if (client
->session
== NULL
) {
935 log_warnx("no session found for uid %d", client
->euid
);
938 if (proc
->pid
!= client
->session
->pid
) {
940 log_warnx("received message from PID %d for uid %d, "
941 "while PID %d is the process serving this user",
942 proc
->pid
, client
->euid
, client
->session
->pid
);
947 switch (imsg
->hdr
.type
) {
948 case GOTD_IMSG_ERROR
:
951 case GOTD_IMSG_CONNECT
:
952 if (proc
->type
!= PROC_LISTEN
) {
953 err
= got_error_fmt(GOT_ERR_BAD_PACKET
,
954 "new connection for uid %d from PID %d "
955 "which is not the listen process",
956 client
->euid
, proc
->pid
);
960 case GOTD_IMSG_ACCESS_GRANTED
:
961 if (proc
->type
!= PROC_AUTH
) {
962 err
= got_error_fmt(GOT_ERR_BAD_PACKET
,
963 "authentication of uid %d from PID %d "
964 "which is not the auth process",
965 client
->euid
, proc
->pid
);
969 case GOTD_IMSG_CLIENT_SESSION_READY
:
970 if (proc
->type
!= PROC_SESSION_READ
&&
971 proc
->type
!= PROC_SESSION_WRITE
) {
972 err
= got_error_fmt(GOT_ERR_BAD_PACKET
,
973 "unexpected \"ready\" signal from PID %d",
978 case GOTD_IMSG_REPO_CHILD_READY
:
979 if (proc
->type
!= PROC_REPO_READ
&&
980 proc
->type
!= PROC_REPO_WRITE
) {
981 err
= got_error_fmt(GOT_ERR_BAD_PACKET
,
982 "unexpected \"ready\" signal from PID %d",
987 case GOTD_IMSG_PACKFILE_DONE
:
988 err
= ensure_proc_is_reading(client
, proc
);
990 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
994 case GOTD_IMSG_PACKFILE_INSTALL
:
995 case GOTD_IMSG_REF_UPDATES_START
:
996 case GOTD_IMSG_REF_UPDATE
:
997 err
= ensure_proc_is_writing(client
, proc
);
999 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
1004 log_debug("%s: unexpected imsg %d", __func__
, imsg
->hdr
.type
);
1011 static const struct got_error
*
1012 connect_repo_child(struct gotd_client
*client
,
1013 struct gotd_child_proc
*repo_proc
)
1015 static const struct got_error
*err
;
1016 struct gotd_imsgev
*session_iev
= &client
->session
->iev
;
1017 struct gotd_imsg_connect_repo_child ireq
;
1019 int sock_flags
= SOCK_STREAM
| SOCK_NONBLOCK
;
1022 sock_flags
|= SOCK_CLOEXEC
;
1025 if (client
->state
!= GOTD_CLIENT_STATE_ACCESS_GRANTED
)
1026 return got_error_msg(GOT_ERR_BAD_REQUEST
,
1027 "unexpected repo child ready signal received");
1029 if (socketpair(AF_UNIX
, sock_flags
, PF_UNSPEC
, pipe
) == -1)
1030 fatal("socketpair");
1032 memset(&ireq
, 0, sizeof(ireq
));
1033 ireq
.proc_id
= repo_proc
->type
;
1035 /* Pass repo child pipe to session child process. */
1036 if (gotd_imsg_compose_event(session_iev
, GOTD_IMSG_CONNECT_REPO_CHILD
,
1037 PROC_GOTD
, pipe
[0], &ireq
, sizeof(ireq
)) == -1) {
1038 err
= got_error_from_errno("imsg compose CONNECT_REPO_CHILD");
1044 /* Pass session child pipe to repo child process. */
1045 if (gotd_imsg_compose_event(&repo_proc
->iev
,
1046 GOTD_IMSG_CONNECT_REPO_CHILD
, PROC_GOTD
, pipe
[1], NULL
, 0) == -1) {
1047 err
= got_error_from_errno("imsg compose CONNECT_REPO_CHILD");
1056 gotd_dispatch_listener(int fd
, short event
, void *arg
)
1058 struct gotd_imsgev
*iev
= arg
;
1059 struct imsgbuf
*ibuf
= &iev
->ibuf
;
1060 struct gotd_child_proc
*proc
= gotd
.listen_proc
;
1065 if (proc
->iev
.ibuf
.fd
!= fd
)
1066 fatalx("%s: unexpected fd %d", __func__
, fd
);
1068 if (event
& EV_READ
) {
1069 if ((n
= imsg_read(ibuf
)) == -1 && errno
!= EAGAIN
)
1070 fatal("imsg_read error");
1072 /* Connection closed. */
1078 if (event
& EV_WRITE
) {
1079 n
= msgbuf_write(&ibuf
->w
);
1080 if (n
== -1 && errno
!= EAGAIN
)
1081 fatal("msgbuf_write");
1083 /* Connection closed. */
1090 const struct got_error
*err
= NULL
;
1091 struct gotd_client
*client
= NULL
;
1092 uint32_t client_id
= 0;
1093 int do_disconnect
= 0;
1095 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
1096 fatal("%s: imsg_get error", __func__
);
1097 if (n
== 0) /* No more messages. */
1100 switch (imsg
.hdr
.type
) {
1101 case GOTD_IMSG_ERROR
:
1103 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
1105 case GOTD_IMSG_CONNECT
:
1106 err
= recv_connect(&client_id
, &imsg
);
1109 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
1113 client
= find_client(client_id
);
1114 if (client
== NULL
) {
1115 log_warnx("%s: client not found", __func__
);
1121 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
1123 if (do_disconnect
) {
1125 disconnect_on_error(client
, err
);
1134 gotd_imsg_event_add(iev
);
1136 /* This pipe is dead. Remove its event handler */
1137 event_del(&iev
->ev
);
1138 event_loopexit(NULL
);
1143 gotd_dispatch_notifier(int fd
, short event
, void *arg
)
1145 struct gotd_imsgev
*iev
= arg
;
1146 struct imsgbuf
*ibuf
= &iev
->ibuf
;
1147 struct gotd_child_proc
*proc
= gotd
.notify_proc
;
1152 if (proc
->iev
.ibuf
.fd
!= fd
)
1153 fatalx("%s: unexpected fd %d", __func__
, fd
);
1155 if (event
& EV_READ
) {
1156 if ((n
= imsg_read(ibuf
)) == -1 && errno
!= EAGAIN
)
1157 fatal("imsg_read error");
1159 /* Connection closed. */
1165 if (event
& EV_WRITE
) {
1166 n
= msgbuf_write(&ibuf
->w
);
1167 if (n
== -1 && errno
!= EAGAIN
)
1168 fatal("msgbuf_write");
1170 /* Connection closed. */
1177 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
1178 fatal("%s: imsg_get error", __func__
);
1179 if (n
== 0) /* No more messages. */
1182 switch (imsg
.hdr
.type
) {
1184 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
1192 gotd_imsg_event_add(iev
);
1194 /* This pipe is dead. Remove its event handler */
1195 event_del(&iev
->ev
);
1198 * Do not exit all of gotd if the notification handler dies.
1199 * We can continue operating without notifications until an
1200 * operator intervenes.
1202 log_warnx("notify child process (pid %d) closed its imsg pipe "
1203 "unexpectedly", proc
->pid
);
1209 gotd_dispatch_auth_child(int fd
, short event
, void *arg
)
1211 const struct got_error
*err
= NULL
;
1212 struct gotd_imsgev
*iev
= arg
;
1213 struct imsgbuf
*ibuf
= &iev
->ibuf
;
1214 struct gotd_client
*client
;
1215 struct gotd_repo
*repo
= NULL
;
1219 uint32_t client_id
= 0;
1220 int do_disconnect
= 0;
1223 client
= find_client_by_proc_fd(fd
);
1224 if (client
== NULL
) {
1225 /* Can happen during process teardown. */
1226 warnx("cannot find client for fd %d", fd
);
1231 if (client
->auth
== NULL
)
1232 fatalx("cannot find auth child process for fd %d", fd
);
1234 if (event
& EV_READ
) {
1235 if ((n
= imsg_read(ibuf
)) == -1 && errno
!= EAGAIN
)
1236 fatal("imsg_read error");
1238 /* Connection closed. */
1244 if (event
& EV_WRITE
) {
1245 n
= msgbuf_write(&ibuf
->w
);
1246 if (n
== -1 && errno
!= EAGAIN
)
1247 fatal("msgbuf_write");
1249 /* Connection closed. */
1255 if (client
->auth
->iev
.ibuf
.fd
!= fd
)
1256 fatalx("%s: unexpected fd %d", __func__
, fd
);
1258 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
1259 fatal("%s: imsg_get error", __func__
);
1260 if (n
== 0) /* No more messages. */
1263 evtimer_del(&client
->tmo
);
1265 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
1267 switch (imsg
.hdr
.type
) {
1268 case GOTD_IMSG_ERROR
:
1270 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
1272 case GOTD_IMSG_ACCESS_GRANTED
:
1273 if (client
->state
!= GOTD_CLIENT_STATE_NEW
) {
1275 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1280 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
1284 if (!verify_imsg_src(client
, client
->auth
, &imsg
)) {
1286 log_debug("dropping imsg type %d from PID %d",
1287 imsg
.hdr
.type
, client
->auth
->pid
);
1290 if (do_disconnect
) {
1292 disconnect_on_error(client
, err
);
1299 client
->state
= GOTD_CLIENT_STATE_ACCESS_GRANTED
;
1301 client
->username
= strndup(imsg
.data
, datalen
);
1303 if (client
->username
== NULL
&&
1304 asprintf(&client
->username
, "uid %d", client
->euid
) == -1) {
1305 err
= got_error_from_errno("asprintf");
1309 repo
= gotd_find_repo_by_name(client
->auth
->repo_name
, &gotd
.repos
);
1311 err
= got_error(GOT_ERR_NOT_GIT_REPO
);
1314 kill_auth_proc(client
);
1316 log_info("authenticated %s for repository %s",
1317 client
->username
, repo
->name
);
1319 err
= start_session_child(client
, repo
, gotd
.argv0
,
1320 gotd
.confpath
, gotd
.daemonize
, gotd
.verbosity
);
1325 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
1327 /* We might have killed the auth process by now. */
1328 if (client
->auth
!= NULL
) {
1330 gotd_imsg_event_add(iev
);
1332 /* This pipe is dead. Remove its event handler */
1333 event_del(&iev
->ev
);
1338 static const struct got_error
*
1339 connect_session(struct gotd_client
*client
)
1341 const struct got_error
*err
= NULL
;
1342 struct gotd_imsg_connect iconnect
;
1346 memset(&iconnect
, 0, sizeof(iconnect
));
1348 s
= dup(client
->fd
);
1350 return got_error_from_errno("dup");
1352 iconnect
.client_id
= client
->id
;
1353 iconnect
.euid
= client
->euid
;
1354 iconnect
.egid
= client
->egid
;
1355 iconnect
.username_len
= strlen(client
->username
);
1357 wbuf
= imsg_create(&client
->session
->iev
.ibuf
, GOTD_IMSG_CONNECT
,
1358 PROC_GOTD
, gotd
.pid
, sizeof(iconnect
) + iconnect
.username_len
);
1360 err
= got_error_from_errno("imsg compose CONNECT");
1364 if (imsg_add(wbuf
, &iconnect
, sizeof(iconnect
)) == -1) {
1366 return got_error_from_errno("imsg_add CONNECT");
1368 if (imsg_add(wbuf
, client
->username
, iconnect
.username_len
) == -1) {
1370 return got_error_from_errno("imsg_add CONNECT");
1373 ibuf_fd_set(wbuf
, s
);
1374 imsg_close(&client
->session
->iev
.ibuf
, wbuf
);
1375 gotd_imsg_event_add(&client
->session
->iev
);
1378 * We are no longer interested in messages from this client.
1379 * Further client requests will be handled by the session process.
1381 msgbuf_clear(&client
->iev
.ibuf
.w
);
1382 imsg_clear(&client
->iev
.ibuf
);
1383 event_del(&client
->iev
.ev
);
1384 client
->fd
= -1; /* will be closed via copy in client->iev.ibuf.fd */
1390 gotd_dispatch_client_session(int fd
, short event
, void *arg
)
1392 struct gotd_imsgev
*iev
= arg
;
1393 struct imsgbuf
*ibuf
= &iev
->ibuf
;
1394 struct gotd_child_proc
*proc
= NULL
;
1395 struct gotd_client
*client
= NULL
;
1400 client
= find_client_by_proc_fd(fd
);
1401 if (client
== NULL
) {
1402 /* Can happen during process teardown. */
1403 warnx("cannot find client for fd %d", fd
);
1408 if (event
& EV_READ
) {
1409 if ((n
= imsg_read(ibuf
)) == -1 && errno
!= EAGAIN
)
1410 fatal("imsg_read error");
1412 /* Connection closed. */
1418 if (event
& EV_WRITE
) {
1419 n
= msgbuf_write(&ibuf
->w
);
1420 if (n
== -1 && errno
!= EAGAIN
)
1421 fatal("msgbuf_write");
1423 /* Connection closed. */
1429 proc
= client
->session
;
1431 fatalx("cannot find session child process for fd %d", fd
);
1434 const struct got_error
*err
= NULL
;
1435 uint32_t client_id
= 0;
1436 int do_disconnect
= 0, do_start_repo_child
= 0;
1438 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
1439 fatal("%s: imsg_get error", __func__
);
1440 if (n
== 0) /* No more messages. */
1443 switch (imsg
.hdr
.type
) {
1444 case GOTD_IMSG_ERROR
:
1446 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
1448 case GOTD_IMSG_CLIENT_SESSION_READY
:
1449 if (client
->state
!= GOTD_CLIENT_STATE_ACCESS_GRANTED
) {
1450 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1453 do_start_repo_child
= 1;
1455 case GOTD_IMSG_DISCONNECT
:
1459 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
1463 if (!verify_imsg_src(client
, proc
, &imsg
)) {
1464 log_debug("dropping imsg type %d from PID %d",
1465 imsg
.hdr
.type
, proc
->pid
);
1470 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
1472 if (do_start_repo_child
) {
1473 struct gotd_repo
*repo
;
1474 const char *name
= client
->session
->repo_name
;
1476 repo
= gotd_find_repo_by_name(name
, &gotd
.repos
);
1478 enum gotd_procid proc_type
;
1480 if (client
->required_auth
& GOTD_AUTH_WRITE
)
1481 proc_type
= PROC_REPO_WRITE
;
1483 proc_type
= PROC_REPO_READ
;
1485 err
= start_repo_child(client
, proc_type
, repo
,
1486 gotd
.argv0
, gotd
.confpath
, gotd
.daemonize
,
1489 err
= got_error(GOT_ERR_NOT_GIT_REPO
);
1492 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
1497 if (do_disconnect
) {
1499 disconnect_on_error(client
, err
);
1508 gotd_imsg_event_add(iev
);
1510 /* This pipe is dead. Remove its event handler */
1511 event_del(&iev
->ev
);
1516 static const struct got_error
*
1517 connect_notifier_and_session(struct gotd_client
*client
)
1519 const struct got_error
*err
= NULL
;
1520 struct gotd_imsgev
*session_iev
= &client
->session
->iev
;
1522 int sock_flags
= SOCK_STREAM
|SOCK_NONBLOCK
;
1524 if (gotd
.notify_proc
== NULL
)
1528 sock_flags
|= SOCK_CLOEXEC
;
1530 if (socketpair(AF_UNIX
, sock_flags
,
1531 PF_UNSPEC
, pipe
) == -1)
1532 return got_error_from_errno("socketpair");
1534 /* Pass notifier pipe to session . */
1535 if (gotd_imsg_compose_event(session_iev
, GOTD_IMSG_CONNECT_NOTIFIER
,
1536 PROC_GOTD
, pipe
[0], NULL
, 0) == -1) {
1537 err
= got_error_from_errno("imsg compose CONNECT_NOTIFIER");
1543 /* Pass session pipe to notifier. */
1544 if (gotd_imsg_compose_event(&gotd
.notify_proc
->iev
,
1545 GOTD_IMSG_CONNECT_SESSION
, PROC_GOTD
, pipe
[1], NULL
, 0) == -1) {
1546 err
= got_error_from_errno("imsg compose CONNECT_SESSION");
1555 gotd_dispatch_repo_child(int fd
, short event
, void *arg
)
1557 struct gotd_imsgev
*iev
= arg
;
1558 struct imsgbuf
*ibuf
= &iev
->ibuf
;
1559 struct gotd_child_proc
*proc
= NULL
;
1560 struct gotd_client
*client
;
1565 client
= find_client_by_proc_fd(fd
);
1566 if (client
== NULL
) {
1567 /* Can happen during process teardown. */
1568 warnx("cannot find client for fd %d", fd
);
1573 if (event
& EV_READ
) {
1574 if ((n
= imsg_read(ibuf
)) == -1 && errno
!= EAGAIN
)
1575 fatal("imsg_read error");
1577 /* Connection closed. */
1583 if (event
& EV_WRITE
) {
1584 n
= msgbuf_write(&ibuf
->w
);
1585 if (n
== -1 && errno
!= EAGAIN
)
1586 fatal("msgbuf_write");
1588 /* Connection closed. */
1594 proc
= client
->repo
;
1596 fatalx("cannot find child process for fd %d", fd
);
1599 const struct got_error
*err
= NULL
;
1600 uint32_t client_id
= 0;
1601 int do_disconnect
= 0;
1603 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
1604 fatal("%s: imsg_get error", __func__
);
1605 if (n
== 0) /* No more messages. */
1608 switch (imsg
.hdr
.type
) {
1609 case GOTD_IMSG_ERROR
:
1611 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
1613 case GOTD_IMSG_REPO_CHILD_READY
:
1614 err
= connect_session(client
);
1617 err
= connect_notifier_and_session(client
);
1620 err
= connect_repo_child(client
, proc
);
1623 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
1627 if (!verify_imsg_src(client
, proc
, &imsg
)) {
1628 log_debug("dropping imsg type %d from PID %d",
1629 imsg
.hdr
.type
, proc
->pid
);
1634 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
1636 if (do_disconnect
) {
1638 disconnect_on_error(client
, err
);
1647 gotd_imsg_event_add(iev
);
1649 /* This pipe is dead. Remove its event handler */
1650 event_del(&iev
->ev
);
1656 start_child(enum gotd_procid proc_id
, const char *repo_path
,
1657 char *argv0
, const char *confpath
, int fd
, int daemonize
, int verbosity
)
1663 switch (pid
= fork()) {
1665 fatal("cannot fork");
1673 if (fd
!= GOTD_FILENO_MSG_PIPE
) {
1674 if (dup2(fd
, GOTD_FILENO_MSG_PIPE
) == -1)
1675 fatal("cannot setup imsg fd");
1676 } else if (fcntl(fd
, F_SETFD
, 0) == -1)
1677 fatal("cannot setup imsg fd");
1679 argv
[argc
++] = argv0
;
1682 argv
[argc
++] = (char *)"-L";
1685 argv
[argc
++] = (char *)"-A";
1687 case PROC_SESSION_READ
:
1688 argv
[argc
++] = (char *)"-s";
1690 case PROC_SESSION_WRITE
:
1691 argv
[argc
++] = (char *)"-S";
1693 case PROC_REPO_READ
:
1694 argv
[argc
++] = (char *)"-R";
1696 case PROC_REPO_WRITE
:
1697 argv
[argc
++] = (char *)"-W";
1700 argv
[argc
++] = (char *)"-N";
1703 fatalx("invalid process id %d", proc_id
);
1706 argv
[argc
++] = (char *)"-f";
1707 argv
[argc
++] = (char *)confpath
;
1710 argv
[argc
++] = (char *)"-P";
1711 argv
[argc
++] = (char *)repo_path
;
1715 argv
[argc
++] = (char *)"-d";
1717 argv
[argc
++] = (char *)"-v";
1719 argv
[argc
++] = (char *)"-v";
1720 argv
[argc
++] = NULL
;
1722 execvp(argv0
, argv
);
1727 start_listener(char *argv0
, const char *confpath
, int daemonize
, int verbosity
)
1729 struct gotd_child_proc
*proc
;
1730 int sock_flags
= SOCK_STREAM
|SOCK_NONBLOCK
;
1733 sock_flags
|= SOCK_CLOEXEC
;
1736 proc
= calloc(1, sizeof(*proc
));
1740 TAILQ_INSERT_HEAD(&procs
, proc
, entry
);
1742 /* proc->tmo is initialized in main() after event_init() */
1744 proc
->type
= PROC_LISTEN
;
1746 if (socketpair(AF_UNIX
, sock_flags
,
1747 PF_UNSPEC
, proc
->pipe
) == -1)
1748 fatal("socketpair");
1750 proc
->pid
= start_child(proc
->type
, NULL
, argv0
, confpath
,
1751 proc
->pipe
[1], daemonize
, verbosity
);
1752 imsg_init(&proc
->iev
.ibuf
, proc
->pipe
[0]);
1753 proc
->iev
.handler
= gotd_dispatch_listener
;
1754 proc
->iev
.events
= EV_READ
;
1755 proc
->iev
.handler_arg
= NULL
;
1757 gotd
.listen_proc
= proc
;
1761 start_notifier(char *argv0
, const char *confpath
, int daemonize
, int verbosity
)
1763 struct gotd_child_proc
*proc
;
1764 int sock_flags
= SOCK_STREAM
| SOCK_NONBLOCK
;
1767 proc
= calloc(1, sizeof(*proc
));
1771 TAILQ_INSERT_HEAD(&procs
, proc
, entry
);
1773 /* proc->tmo is initialized in main() after event_init() */
1775 proc
->type
= PROC_NOTIFY
;
1778 sock_flags
|= SOCK_CLOEXEC
;
1780 if (socketpair(AF_UNIX
, sock_flags
,
1781 PF_UNSPEC
, proc
->pipe
) == -1)
1782 fatal("socketpair");
1784 proc
->pid
= start_child(proc
->type
, NULL
, argv0
, confpath
,
1785 proc
->pipe
[1], daemonize
, verbosity
);
1786 imsg_init(&proc
->iev
.ibuf
, proc
->pipe
[0]);
1787 proc
->iev
.handler
= gotd_dispatch_notifier
;
1788 proc
->iev
.events
= EV_READ
;
1789 proc
->iev
.handler_arg
= NULL
;
1790 event_set(&proc
->iev
.ev
, proc
->iev
.ibuf
.fd
, EV_READ
,
1791 gotd_dispatch_notifier
, &proc
->iev
);
1793 gotd
.notify_proc
= proc
;
1796 static const struct got_error
*
1797 start_session_child(struct gotd_client
*client
, struct gotd_repo
*repo
,
1798 char *argv0
, const char *confpath
, int daemonize
, int verbosity
)
1800 struct gotd_child_proc
*proc
;
1801 int sock_flags
= SOCK_STREAM
| SOCK_NONBLOCK
;
1804 sock_flags
|= SOCK_CLOEXEC
;
1807 proc
= calloc(1, sizeof(*proc
));
1809 return got_error_from_errno("calloc");
1811 TAILQ_INSERT_HEAD(&procs
, proc
, entry
);
1812 evtimer_set(&proc
->tmo
, kill_proc_timeout
, proc
);
1814 if (client_is_reading(client
))
1815 proc
->type
= PROC_SESSION_READ
;
1817 proc
->type
= PROC_SESSION_WRITE
;
1818 if (strlcpy(proc
->repo_name
, repo
->name
,
1819 sizeof(proc
->repo_name
)) >= sizeof(proc
->repo_name
))
1820 fatalx("repository name too long: %s", repo
->name
);
1821 log_debug("starting client uid %d session for repository %s",
1822 client
->euid
, repo
->name
);
1823 if (strlcpy(proc
->repo_path
, repo
->path
, sizeof(proc
->repo_path
)) >=
1824 sizeof(proc
->repo_path
))
1825 fatalx("repository path too long: %s", repo
->path
);
1826 if (socketpair(AF_UNIX
, sock_flags
, PF_UNSPEC
, proc
->pipe
) == -1)
1827 fatal("socketpair");
1828 proc
->pid
= start_child(proc
->type
, proc
->repo_path
, argv0
,
1829 confpath
, proc
->pipe
[1], daemonize
, verbosity
);
1830 imsg_init(&proc
->iev
.ibuf
, proc
->pipe
[0]);
1831 log_debug("proc %s %s is on fd %d",
1832 gotd_proc_names
[proc
->type
], proc
->repo_path
,
1834 proc
->iev
.handler
= gotd_dispatch_client_session
;
1835 proc
->iev
.events
= EV_READ
;
1836 proc
->iev
.handler_arg
= NULL
;
1837 event_set(&proc
->iev
.ev
, proc
->iev
.ibuf
.fd
, EV_READ
,
1838 gotd_dispatch_client_session
, &proc
->iev
);
1839 gotd_imsg_event_add(&proc
->iev
);
1841 client
->session
= proc
;
1845 static const struct got_error
*
1846 start_repo_child(struct gotd_client
*client
, enum gotd_procid proc_type
,
1847 struct gotd_repo
*repo
, char *argv0
, const char *confpath
,
1848 int daemonize
, int verbosity
)
1850 struct gotd_child_proc
*proc
;
1851 int sock_flags
= SOCK_STREAM
|SOCK_NONBLOCK
;
1854 sock_flags
|= SOCK_CLOEXEC
;
1857 if (proc_type
!= PROC_REPO_READ
&& proc_type
!= PROC_REPO_WRITE
)
1858 return got_error_msg(GOT_ERR_NOT_IMPL
, "bad process type");
1860 proc
= calloc(1, sizeof(*proc
));
1862 return got_error_from_errno("calloc");
1864 TAILQ_INSERT_HEAD(&procs
, proc
, entry
);
1865 evtimer_set(&proc
->tmo
, kill_proc_timeout
, proc
);
1867 proc
->type
= proc_type
;
1868 if (strlcpy(proc
->repo_name
, repo
->name
,
1869 sizeof(proc
->repo_name
)) >= sizeof(proc
->repo_name
))
1870 fatalx("repository name too long: %s", repo
->name
);
1871 log_debug("starting %s for repository %s",
1872 proc
->type
== PROC_REPO_READ
? "reader" : "writer", repo
->name
);
1874 if (strlcpy(proc
->repo_path
, repo
->path
, sizeof(proc
->repo_path
)) >=
1875 sizeof(proc
->repo_path
))
1876 fatalx("repository path too long: %s", repo
->path
);
1877 if (realpath(repo
->path
, proc
->repo_path
) == NULL
)
1878 fatal("%s", repo
->path
);
1879 if (socketpair(AF_UNIX
, sock_flags
,
1880 PF_UNSPEC
, proc
->pipe
) == -1)
1881 fatal("socketpair");
1882 proc
->pid
= start_child(proc
->type
, proc
->repo_path
, argv0
,
1883 confpath
, proc
->pipe
[1], daemonize
, verbosity
);
1884 imsg_init(&proc
->iev
.ibuf
, proc
->pipe
[0]);
1885 log_debug("proc %s %s is on fd %d",
1886 gotd_proc_names
[proc
->type
], proc
->repo_path
,
1888 proc
->iev
.handler
= gotd_dispatch_repo_child
;
1889 proc
->iev
.events
= EV_READ
;
1890 proc
->iev
.handler_arg
= NULL
;
1891 event_set(&proc
->iev
.ev
, proc
->iev
.ibuf
.fd
, EV_READ
,
1892 gotd_dispatch_repo_child
, &proc
->iev
);
1893 gotd_imsg_event_add(&proc
->iev
);
1895 client
->repo
= proc
;
1899 static const struct got_error
*
1900 start_auth_child(struct gotd_client
*client
, int required_auth
,
1901 struct gotd_repo
*repo
, char *argv0
, const char *confpath
,
1902 int daemonize
, int verbosity
)
1904 const struct got_error
*err
= NULL
;
1905 struct gotd_child_proc
*proc
;
1906 struct gotd_imsg_auth iauth
;
1908 int sock_flags
= SOCK_STREAM
|SOCK_NONBLOCK
;
1911 sock_flags
|= SOCK_CLOEXEC
;
1914 memset(&iauth
, 0, sizeof(iauth
));
1916 fd
= dup(client
->fd
);
1918 return got_error_from_errno("dup");
1920 proc
= calloc(1, sizeof(*proc
));
1922 err
= got_error_from_errno("calloc");
1927 TAILQ_INSERT_HEAD(&procs
, proc
, entry
);
1928 evtimer_set(&proc
->tmo
, kill_proc_timeout
, proc
);
1930 proc
->type
= PROC_AUTH
;
1931 if (strlcpy(proc
->repo_name
, repo
->name
,
1932 sizeof(proc
->repo_name
)) >= sizeof(proc
->repo_name
))
1933 fatalx("repository name too long: %s", repo
->name
);
1934 log_debug("starting auth for uid %d repository %s",
1935 client
->euid
, repo
->name
);
1936 if (strlcpy(proc
->repo_path
, repo
->path
, sizeof(proc
->repo_path
)) >=
1937 sizeof(proc
->repo_path
))
1938 fatalx("repository path too long: %s", repo
->path
);
1939 if (realpath(repo
->path
, proc
->repo_path
) == NULL
)
1940 fatal("%s", repo
->path
);
1941 if (socketpair(AF_UNIX
, sock_flags
,
1942 PF_UNSPEC
, proc
->pipe
) == -1)
1943 fatal("socketpair");
1944 proc
->pid
= start_child(proc
->type
, proc
->repo_path
, argv0
,
1945 confpath
, proc
->pipe
[1], daemonize
, verbosity
);
1946 imsg_init(&proc
->iev
.ibuf
, proc
->pipe
[0]);
1947 log_debug("proc %s %s is on fd %d",
1948 gotd_proc_names
[proc
->type
], proc
->repo_path
,
1950 proc
->iev
.handler
= gotd_dispatch_auth_child
;
1951 proc
->iev
.events
= EV_READ
;
1952 proc
->iev
.handler_arg
= NULL
;
1953 event_set(&proc
->iev
.ev
, proc
->iev
.ibuf
.fd
, EV_READ
,
1954 gotd_dispatch_auth_child
, &proc
->iev
);
1955 gotd_imsg_event_add(&proc
->iev
);
1957 iauth
.euid
= client
->euid
;
1958 iauth
.egid
= client
->egid
;
1959 iauth
.required_auth
= required_auth
;
1960 iauth
.client_id
= client
->id
;
1961 if (gotd_imsg_compose_event(&proc
->iev
, GOTD_IMSG_AUTHENTICATE
,
1962 PROC_GOTD
, fd
, &iauth
, sizeof(iauth
)) == -1) {
1963 log_warn("imsg compose AUTHENTICATE");
1965 /* Let the auth_timeout handler tidy up. */
1968 client
->auth
= proc
;
1969 client
->required_auth
= required_auth
;
1974 apply_unveil_repo_readonly(const char *repo_path
, int need_tmpdir
)
1977 if (unveil(GOT_TMPDIR_STR
, "rwc") == -1)
1978 fatal("unveil %s", GOT_TMPDIR_STR
);
1981 if (unveil(repo_path
, "r") == -1)
1982 fatal("unveil %s", repo_path
);
1984 if (unveil(NULL
, NULL
) == -1)
1989 apply_unveil_repo_readwrite(const char *repo_path
)
1991 if (unveil(repo_path
, "rwc") == -1)
1992 fatal("unveil %s", repo_path
);
1994 if (unveil(GOT_TMPDIR_STR
, "rwc") == -1)
1995 fatal("unveil %s", GOT_TMPDIR_STR
);
1997 if (unveil(NULL
, NULL
) == -1)
2002 apply_unveil_none(void)
2004 if (unveil("/", "") == -1)
2007 if (unveil(NULL
, NULL
) == -1)
2012 apply_unveil_selfexec(void)
2014 if (unveil(gotd
.argv0
, "x") == -1)
2015 fatal("unveil %s", gotd
.argv0
);
2017 if (unveil(NULL
, NULL
) == -1)
2022 set_max_datasize(void)
2026 if (getrlimit(RLIMIT_DATA
, &rl
) != 0)
2029 rl
.rlim_cur
= rl
.rlim_max
;
2030 setrlimit(RLIMIT_DATA
, &rl
);
2034 unveil_notification_helpers(void)
2036 const char *helpers
[] = {
2037 GOTD_PATH_PROG_NOTIFY_EMAIL
,
2038 GOTD_PATH_PROG_NOTIFY_HTTP
,
2042 for (i
= 0; i
< nitems(helpers
); i
++) {
2043 if (unveil(helpers
[i
], "x") == 0)
2045 fatal("unveil %s", helpers
[i
]);
2048 if (unveil(NULL
, NULL
) == -1)
2053 main(int argc
, char **argv
)
2055 const struct got_error
*error
= NULL
;
2056 int ch
, fd
= -1, daemonize
= 1, verbosity
= 0, noaction
= 0;
2057 const char *confpath
= GOTD_CONF_PATH
;
2058 char *argv0
= argv
[0];
2060 struct passwd
*pw
= NULL
;
2061 char *repo_path
= NULL
;
2062 enum gotd_procid proc_id
= PROC_GOTD
;
2063 struct event evsigint
, evsigterm
, evsighup
, evsigusr1
, evsigchld
;
2064 int *pack_fds
= NULL
, *temp_fds
= NULL
;
2065 struct gotd_repo
*repo
= NULL
;
2066 char *default_sender
= NULL
;
2067 char hostname
[_POSIX_HOST_NAME_MAX
+ 1];
2068 FILE *diff_f1
= NULL
, *diff_f2
= NULL
;
2069 int diff_fd1
= -1, diff_fd2
= -1;
2073 log_init(1, LOG_DAEMON
); /* Log to stderr until daemonized. */
2075 while ((ch
= getopt(argc
, argv
, "Adf:LnNP:RsSvW")) != -1) {
2078 proc_id
= PROC_AUTH
;
2087 proc_id
= PROC_LISTEN
;
2093 proc_id
= PROC_NOTIFY
;
2096 repo_path
= realpath(optarg
, NULL
);
2097 if (repo_path
== NULL
)
2098 fatal("realpath '%s'", optarg
);
2101 proc_id
= PROC_REPO_READ
;
2104 proc_id
= PROC_SESSION_READ
;
2107 proc_id
= PROC_SESSION_WRITE
;
2114 proc_id
= PROC_REPO_WRITE
;
2127 if (geteuid() && (proc_id
== PROC_GOTD
|| proc_id
== PROC_LISTEN
))
2128 fatalx("need root privileges");
2130 if (parse_config(confpath
, proc_id
, &gotd
) != 0)
2133 pw
= getpwnam(gotd
.user_name
);
2135 fatalx("user %s not found", gotd
.user_name
);
2137 if (pw
->pw_uid
== 0)
2138 fatalx("cannot run %s as the superuser", getprogname());
2141 fprintf(stderr
, "configuration OK\n");
2146 gotd
.daemonize
= daemonize
;
2147 gotd
.verbosity
= verbosity
;
2148 gotd
.confpath
= confpath
;
2150 /* Require an absolute path in argv[0] for reliable re-exec. */
2151 if (!got_path_is_absolute(argv0
))
2152 fatalx("bad path \"%s\": must be an absolute path", argv0
);
2154 log_init(daemonize
? 0 : 1, LOG_DAEMON
);
2155 log_setverbose(verbosity
);
2157 if (proc_id
== PROC_GOTD
) {
2158 snprintf(title
, sizeof(title
), "%s", gotd_proc_names
[proc_id
]);
2159 arc4random_buf(&clients_hash_key
, sizeof(clients_hash_key
));
2160 if (daemonize
&& daemon(1, 0) == -1)
2162 gotd
.pid
= getpid();
2163 start_listener(argv0
, confpath
, daemonize
, verbosity
);
2164 start_notifier(argv0
, confpath
, daemonize
, verbosity
);
2165 } else if (proc_id
== PROC_LISTEN
) {
2166 snprintf(title
, sizeof(title
), "%s", gotd_proc_names
[proc_id
]);
2168 log_info("socket: %s", gotd
.unix_socket_path
);
2169 log_info("user: %s", pw
->pw_name
);
2172 fd
= unix_socket_listen(gotd
.unix_socket_path
, pw
->pw_uid
,
2175 fatal("cannot listen on unix socket %s",
2176 gotd
.unix_socket_path
);
2178 } else if (proc_id
== PROC_AUTH
) {
2179 snprintf(title
, sizeof(title
), "%s %s",
2180 gotd_proc_names
[proc_id
], repo_path
);
2181 } else if (proc_id
== PROC_REPO_READ
|| proc_id
== PROC_REPO_WRITE
||
2182 proc_id
== PROC_SESSION_READ
|| proc_id
== PROC_SESSION_WRITE
) {
2183 error
= got_repo_pack_fds_open(&pack_fds
);
2185 fatalx("cannot open pack tempfiles: %s", error
->msg
);
2186 error
= got_repo_temp_fds_open(&temp_fds
);
2188 fatalx("cannot open pack tempfiles: %s", error
->msg
);
2189 if (repo_path
== NULL
)
2190 fatalx("repository path not specified");
2191 snprintf(title
, sizeof(title
), "%s %s",
2192 gotd_proc_names
[proc_id
], repo_path
);
2193 } else if (proc_id
== PROC_NOTIFY
) {
2194 snprintf(title
, sizeof(title
), "%s", gotd_proc_names
[proc_id
]);
2195 if (gethostname(hostname
, sizeof(hostname
)) == -1)
2196 fatal("gethostname");
2197 if (asprintf(&default_sender
, "%s@%s",
2198 pw
->pw_name
, hostname
) == -1)
2201 fatal("invalid process id %d", proc_id
);
2203 setproctitle("%s", title
);
2204 log_procinit(title
);
2206 if (proc_id
!= PROC_GOTD
&& proc_id
!= PROC_LISTEN
&&
2207 proc_id
!= PROC_REPO_READ
&& proc_id
!= PROC_REPO_WRITE
) {
2208 /* Drop root privileges. */
2209 if (setgid(pw
->pw_gid
) == -1)
2210 fatal("setgid %d failed", pw
->pw_gid
);
2211 if (setuid(pw
->pw_uid
) == -1)
2212 fatal("setuid %d failed", pw
->pw_uid
);
2220 /* "exec" promise will be limited to argv[0] via unveil(2). */
2221 if (pledge("stdio proc exec sendfd recvfd unveil", NULL
) == -1)
2227 if (pledge("stdio sendfd unix unveil", NULL
) == -1)
2231 * Ensure that AF_UNIX bind(2) cannot be used with any other
2232 * sockets by revoking all filesystem access via unveil(2).
2234 apply_unveil_none();
2236 enter_chroot(GOTD_EMPTY_PATH
);
2239 listen_main(title
, fd
, gotd
.connection_limits
,
2240 gotd
.nconnection_limits
);
2245 if (pledge("stdio getpw recvfd unix unveil", NULL
) == -1)
2249 * We need the "unix" pledge promise for getpeername(2) only.
2250 * Ensure that AF_UNIX bind(2) cannot be used by revoking all
2251 * filesystem access via unveil(2). Access to password database
2252 * files will still work since "getpw" bypasses unveil(2).
2254 apply_unveil_none();
2256 auth_main(title
, &gotd
.repos
, repo_path
);
2259 case PROC_SESSION_READ
:
2260 case PROC_SESSION_WRITE
:
2263 * The "recvfd" promise is only needed during setup and
2264 * will be removed in a later pledge(2) call.
2266 if (pledge("stdio rpath wpath cpath recvfd sendfd fattr flock "
2267 "unveil", NULL
) == -1)
2270 if (proc_id
== PROC_SESSION_READ
)
2271 apply_unveil_repo_readonly(repo_path
, 1);
2273 apply_unveil_repo_readwrite(repo_path
);
2274 repo
= gotd_find_repo_by_path(repo_path
, &gotd
);
2276 fatalx("no repository for path %s", repo_path
);
2278 if (proc_id
== PROC_SESSION_READ
)
2279 session_read_main(title
, repo_path
, pack_fds
, temp_fds
,
2280 &gotd
.request_timeout
, repo
);
2282 session_write_main(title
, repo_path
, pack_fds
, temp_fds
,
2283 &gotd
.request_timeout
, repo
);
2286 case PROC_REPO_READ
:
2289 if (pledge("stdio rpath recvfd unveil", NULL
) == -1)
2292 apply_unveil_repo_readonly(repo_path
, 0);
2294 if (enter_chroot(repo_path
)) {
2295 log_info("change repo path %s", repo_path
);
2297 repo_path
= strdup("/");
2298 if (repo_path
== NULL
)
2300 log_info("repo path is now %s", repo_path
);
2304 repo_read_main(title
, repo_path
, pack_fds
, temp_fds
);
2307 case PROC_REPO_WRITE
:
2310 diff_f1
= got_opentemp();
2311 if (diff_f1
== NULL
)
2312 fatal("got_opentemp");
2313 diff_f2
= got_opentemp();
2314 if (diff_f2
== NULL
)
2315 fatal("got_opentemp");
2316 diff_fd1
= got_opentempfd();
2318 fatal("got_opentempfd");
2319 diff_fd2
= got_opentempfd();
2321 fatal("got_opentempfd");
2323 if (pledge("stdio rpath recvfd unveil", NULL
) == -1)
2326 apply_unveil_repo_readonly(repo_path
, 0);
2327 repo
= gotd_find_repo_by_path(repo_path
, &gotd
);
2329 fatalx("no repository for path %s", repo_path
);
2331 if (enter_chroot(repo_path
)) {
2333 repo_path
= strdup("/");
2334 if (repo_path
== NULL
)
2339 repo_write_main(title
, repo_path
, pack_fds
, temp_fds
,
2340 diff_f1
, diff_f2
, diff_fd1
, diff_fd2
,
2341 &repo
->protected_tag_namespaces
,
2342 &repo
->protected_branch_namespaces
,
2343 &repo
->protected_branches
);
2348 if (pledge("stdio proc exec recvfd unveil", NULL
) == -1)
2352 * Limit "exec" promise to notification helpers via unveil(2).
2354 unveil_notification_helpers();
2356 notify_main(title
, &gotd
.repos
, default_sender
);
2360 fatal("invalid process id %d", proc_id
);
2363 if (proc_id
!= PROC_GOTD
)
2364 fatal("invalid process id %d", proc_id
);
2366 evtimer_set(&gotd
.listen_proc
->tmo
, kill_proc_timeout
,
2368 if (gotd
.notify_proc
) {
2369 evtimer_set(&gotd
.notify_proc
->tmo
, kill_proc_timeout
,
2373 apply_unveil_selfexec();
2375 signal_set(&evsigint
, SIGINT
, gotd_sighdlr
, NULL
);
2376 signal_set(&evsigterm
, SIGTERM
, gotd_sighdlr
, NULL
);
2377 signal_set(&evsighup
, SIGHUP
, gotd_sighdlr
, NULL
);
2378 signal_set(&evsigusr1
, SIGUSR1
, gotd_sighdlr
, NULL
);
2379 signal_set(&evsigchld
, SIGCHLD
, gotd_sighdlr
, NULL
);
2380 signal(SIGPIPE
, SIG_IGN
);
2382 signal_add(&evsigint
, NULL
);
2383 signal_add(&evsigterm
, NULL
);
2384 signal_add(&evsighup
, NULL
);
2385 signal_add(&evsigusr1
, NULL
);
2386 signal_add(&evsigchld
, NULL
);
2388 gotd_imsg_event_add(&gotd
.listen_proc
->iev
);
2389 if (gotd
.notify_proc
)
2390 gotd_imsg_event_add(&gotd
.notify_proc
->iev
);
2395 free(default_sender
);