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"
71 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
74 enum gotd_client_state
{
75 GOTD_CLIENT_STATE_NEW
,
76 GOTD_CLIENT_STATE_ACCESS_GRANTED
,
79 struct gotd_child_proc
{
81 enum gotd_procid type
;
82 char repo_name
[NAME_MAX
];
83 char repo_path
[PATH_MAX
];
85 struct gotd_imsgev iev
;
88 TAILQ_ENTRY(gotd_child_proc
) entry
;
90 TAILQ_HEAD(gotd_procs
, gotd_child_proc
) procs
;
93 STAILQ_ENTRY(gotd_client
) entry
;
94 enum gotd_client_state state
;
97 struct gotd_imsgev iev
;
102 struct gotd_child_proc
*repo
;
103 struct gotd_child_proc
*auth
;
104 struct gotd_child_proc
*session
;
107 STAILQ_HEAD(gotd_clients
, gotd_client
);
109 static struct gotd_clients gotd_clients
[GOTD_CLIENT_TABLE_SIZE
];
110 static SIPHASH_KEY clients_hash_key
;
111 volatile int client_cnt
;
112 static struct timeval auth_timeout
= { 5, 0 };
113 static struct gotd gotd
;
115 void gotd_sighdlr(int sig
, short event
, void *arg
);
116 static void gotd_shutdown(void);
117 static const struct got_error
*start_session_child(struct gotd_client
*,
118 struct gotd_repo
*, char *, const char *, int, int);
119 static const struct got_error
*start_repo_child(struct gotd_client
*,
120 enum gotd_procid
, struct gotd_repo
*, char *, const char *, int, int);
121 static const struct got_error
*start_auth_child(struct gotd_client
*, int,
122 struct gotd_repo
*, char *, const char *, int, int);
123 static void kill_proc(struct gotd_child_proc
*, int);
124 static void disconnect(struct gotd_client
*);
125 static void drop_privs(struct passwd
*);
130 fprintf(stderr
, "usage: %s [-dnv] [-f config-file] [-s secrets]\n",
136 drop_privs(struct passwd
*pw
)
138 /* Drop root privileges. */
139 if (setgid(pw
->pw_gid
) == -1)
140 fatal("setgid %d failed", pw
->pw_gid
);
141 if (setuid(pw
->pw_uid
) == -1)
142 fatal("setuid %d failed", pw
->pw_uid
);
146 unix_socket_listen(const char *unix_socket_path
, uid_t uid
, gid_t gid
)
148 struct sockaddr_un sun
;
150 mode_t old_umask
, mode
;
151 int sock_flags
= SOCK_STREAM
| SOCK_NONBLOCK
;
154 sock_flags
|= SOCK_CLOEXEC
;
157 fd
= socket(AF_UNIX
, sock_flags
, 0);
163 sun
.sun_family
= AF_UNIX
;
164 if (strlcpy(sun
.sun_path
, unix_socket_path
,
165 sizeof(sun
.sun_path
)) >= sizeof(sun
.sun_path
)) {
166 log_warnx("%s: name too long", unix_socket_path
);
171 if (unlink(unix_socket_path
) == -1) {
172 if (errno
!= ENOENT
) {
173 log_warn("unlink %s", unix_socket_path
);
179 old_umask
= umask(S_IXUSR
|S_IXGRP
|S_IWOTH
|S_IROTH
|S_IXOTH
);
180 mode
= S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
;
182 if (bind(fd
, (struct sockaddr
*)&sun
, sizeof(sun
)) == -1) {
183 log_warn("bind: %s", unix_socket_path
);
191 if (chmod(unix_socket_path
, mode
) == -1) {
192 log_warn("chmod %o %s", mode
, unix_socket_path
);
194 unlink(unix_socket_path
);
198 if (chown(unix_socket_path
, uid
, gid
) == -1) {
199 log_warn("chown %s uid=%d gid=%d", unix_socket_path
, uid
, gid
);
201 unlink(unix_socket_path
);
205 if (listen(fd
, GOTD_UNIX_SOCKET_BACKLOG
) == -1) {
208 unlink(unix_socket_path
);
216 client_hash(uint32_t client_id
)
218 return SipHash24(&clients_hash_key
, &client_id
, sizeof(client_id
));
222 add_client(struct gotd_client
*client
)
224 uint64_t slot
= client_hash(client
->id
) % nitems(gotd_clients
);
225 STAILQ_INSERT_HEAD(&gotd_clients
[slot
], client
, entry
);
229 static struct gotd_client
*
230 find_client(uint32_t client_id
)
233 struct gotd_client
*c
;
235 slot
= client_hash(client_id
) % nitems(gotd_clients
);
236 STAILQ_FOREACH(c
, &gotd_clients
[slot
], entry
) {
237 if (c
->id
== client_id
)
244 static struct gotd_client
*
245 find_client_by_proc_fd(int fd
)
249 for (slot
= 0; slot
< nitems(gotd_clients
); slot
++) {
250 struct gotd_client
*c
;
252 STAILQ_FOREACH(c
, &gotd_clients
[slot
], entry
) {
253 if (c
->repo
&& c
->repo
->iev
.ibuf
.fd
== fd
)
255 if (c
->auth
&& c
->auth
->iev
.ibuf
.fd
== fd
)
257 if (c
->session
&& c
->session
->iev
.ibuf
.fd
== fd
)
266 client_is_reading(struct gotd_client
*client
)
268 return (client
->required_auth
&
269 (GOTD_AUTH_READ
| GOTD_AUTH_WRITE
)) == GOTD_AUTH_READ
;
273 client_is_writing(struct gotd_client
*client
)
275 return (client
->required_auth
&
276 (GOTD_AUTH_READ
| GOTD_AUTH_WRITE
)) ==
277 (GOTD_AUTH_READ
| GOTD_AUTH_WRITE
);
280 static const struct got_error
*
281 ensure_client_is_not_writing(struct gotd_client
*client
)
283 if (client_is_writing(client
)) {
284 return got_error_fmt(GOT_ERR_BAD_PACKET
,
285 "uid %d made a read-request but is writing to "
286 "a repository", client
->euid
);
292 static const struct got_error
*
293 ensure_client_is_not_reading(struct gotd_client
*client
)
295 if (client_is_reading(client
)) {
296 return got_error_fmt(GOT_ERR_BAD_PACKET
,
297 "uid %d made a write-request but is reading from "
298 "a repository", client
->euid
);
305 proc_done(struct gotd_child_proc
*proc
)
307 struct gotd_client
*client
;
309 TAILQ_REMOVE(&procs
, proc
, entry
);
311 client
= find_client_by_proc_fd(proc
->iev
.ibuf
.fd
);
312 if (client
!= NULL
) {
313 if (proc
== client
->repo
)
315 if (proc
== client
->auth
)
317 if (proc
== client
->session
)
318 client
->session
= NULL
;
322 if (proc
== gotd
.notify_proc
)
323 gotd
.notify_proc
= NULL
;
325 evtimer_del(&proc
->tmo
);
327 if (proc
->iev
.ibuf
.fd
!= -1) {
328 event_del(&proc
->iev
.ev
);
329 imsgbuf_clear(&proc
->iev
.ibuf
);
330 close(proc
->iev
.ibuf
.fd
);
337 kill_repo_proc(struct gotd_client
*client
)
339 if (client
->repo
== NULL
)
342 kill_proc(client
->repo
, 0);
347 kill_auth_proc(struct gotd_client
*client
)
349 if (client
->auth
== NULL
)
352 kill_proc(client
->auth
, 0);
357 kill_session_proc(struct gotd_client
*client
)
359 if (client
->session
== NULL
)
362 kill_proc(client
->session
, 0);
363 client
->session
= NULL
;
367 disconnect(struct gotd_client
*client
)
369 struct gotd_imsg_disconnect idisconnect
;
370 struct gotd_child_proc
*listen_proc
= gotd
.listen_proc
;
373 log_debug("uid %d: disconnecting", client
->euid
);
375 kill_auth_proc(client
);
376 kill_session_proc(client
);
377 kill_repo_proc(client
);
379 idisconnect
.client_id
= client
->id
;
380 if (gotd_imsg_compose_event(&listen_proc
->iev
,
381 GOTD_IMSG_DISCONNECT
, PROC_GOTD
, -1,
382 &idisconnect
, sizeof(idisconnect
)) == -1)
383 log_warn("imsg compose DISCONNECT");
385 slot
= client_hash(client
->id
) % nitems(gotd_clients
);
386 STAILQ_REMOVE(&gotd_clients
[slot
], client
, gotd_client
, entry
);
387 imsgbuf_clear(&client
->iev
.ibuf
);
388 event_del(&client
->iev
.ev
);
389 evtimer_del(&client
->tmo
);
390 if (client
->fd
!= -1)
392 else if (client
->iev
.ibuf
.fd
!= -1)
393 close(client
->iev
.ibuf
.fd
);
394 free(client
->username
);
400 disconnect_on_error(struct gotd_client
*client
, const struct got_error
*err
)
404 if (err
->code
!= GOT_ERR_EOF
) {
405 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
406 if (client
->fd
!= -1) {
407 if (imsgbuf_init(&ibuf
, client
->fd
) != -1) {
408 gotd_imsg_send_error(&ibuf
, 0, PROC_GOTD
,
410 imsgbuf_clear(&ibuf
);
412 log_warn("%s: imsgbuf_init failed", __func__
);
418 static const struct got_error
*
419 send_repo_info(struct gotd_imsgev
*iev
, struct gotd_repo
*repo
)
421 const struct got_error
*err
= NULL
;
422 struct gotd_imsg_info_repo irepo
;
424 memset(&irepo
, 0, sizeof(irepo
));
426 if (strlcpy(irepo
.repo_name
, repo
->name
, sizeof(irepo
.repo_name
))
427 >= sizeof(irepo
.repo_name
))
428 return got_error_msg(GOT_ERR_NO_SPACE
, "repo name too long");
429 if (strlcpy(irepo
.repo_path
, repo
->path
, sizeof(irepo
.repo_path
))
430 >= sizeof(irepo
.repo_path
))
431 return got_error_msg(GOT_ERR_NO_SPACE
, "repo path too long");
433 if (gotd_imsg_compose_event(iev
, GOTD_IMSG_INFO_REPO
, PROC_GOTD
, -1,
434 &irepo
, sizeof(irepo
)) == -1) {
435 err
= got_error_from_errno("imsg compose INFO_REPO");
443 static const struct got_error
*
444 send_client_info(struct gotd_imsgev
*iev
, struct gotd_client
*client
)
446 const struct got_error
*err
= NULL
;
447 struct gotd_imsg_info_client iclient
;
448 struct gotd_child_proc
*proc
;
450 memset(&iclient
, 0, sizeof(iclient
));
451 iclient
.euid
= client
->euid
;
452 iclient
.egid
= client
->egid
;
456 if (strlcpy(iclient
.repo_name
, proc
->repo_path
,
457 sizeof(iclient
.repo_name
)) >= sizeof(iclient
.repo_name
)) {
458 return got_error_msg(GOT_ERR_NO_SPACE
,
459 "repo name too long");
461 if (client_is_writing(client
))
462 iclient
.is_writing
= 1;
464 iclient
.repo_child_pid
= proc
->pid
;
468 iclient
.session_child_pid
= client
->session
->pid
;
470 if (gotd_imsg_compose_event(iev
, GOTD_IMSG_INFO_CLIENT
, PROC_GOTD
, -1,
471 &iclient
, sizeof(iclient
)) == -1) {
472 err
= got_error_from_errno("imsg compose INFO_CLIENT");
480 static const struct got_error
*
481 send_info(struct gotd_client
*client
)
483 const struct got_error
*err
= NULL
;
484 struct gotd_imsg_info info
;
486 struct gotd_repo
*repo
;
488 if (client
->euid
!= 0)
489 return got_error_set_errno(EPERM
, "info");
492 info
.verbosity
= gotd
.verbosity
;
493 info
.nrepos
= gotd
.nrepos
;
494 info
.nclients
= client_cnt
- 1;
496 if (gotd_imsg_compose_event(&client
->iev
, GOTD_IMSG_INFO
, PROC_GOTD
, -1,
497 &info
, sizeof(info
)) == -1) {
498 err
= got_error_from_errno("imsg compose INFO");
503 TAILQ_FOREACH(repo
, &gotd
.repos
, entry
) {
504 err
= send_repo_info(&client
->iev
, repo
);
509 for (slot
= 0; slot
< nitems(gotd_clients
); slot
++) {
510 struct gotd_client
*c
;
511 STAILQ_FOREACH(c
, &gotd_clients
[slot
], entry
) {
512 if (c
->id
== client
->id
)
514 err
= send_client_info(&client
->iev
, c
);
523 static const struct got_error
*
524 stop_gotd(struct gotd_client
*client
)
526 if (client
->euid
!= 0)
527 return got_error_set_errno(EPERM
, "stop");
534 static const struct got_error
*
535 start_client_authentication(struct gotd_client
*client
, struct imsg
*imsg
)
537 const struct got_error
*err
;
538 struct gotd_imsg_list_refs ireq
;
539 struct gotd_repo
*repo
= NULL
;
542 log_debug("list-refs request from uid %d", client
->euid
);
544 if (client
->state
!= GOTD_CLIENT_STATE_NEW
)
545 return got_error_msg(GOT_ERR_BAD_REQUEST
,
546 "unexpected list-refs request received");
548 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
549 if (datalen
!= sizeof(ireq
))
550 return got_error(GOT_ERR_PRIVSEP_LEN
);
552 memcpy(&ireq
, imsg
->data
, datalen
);
554 if (ireq
.client_is_reading
) {
555 err
= ensure_client_is_not_writing(client
);
558 repo
= gotd_find_repo_by_name(ireq
.repo_name
, &gotd
.repos
);
560 return got_error(GOT_ERR_NOT_GIT_REPO
);
561 err
= start_auth_child(client
, GOTD_AUTH_READ
, repo
,
562 gotd
.argv0
, gotd
.confpath
, gotd
.daemonize
,
567 err
= ensure_client_is_not_reading(client
);
570 repo
= gotd_find_repo_by_name(ireq
.repo_name
, &gotd
.repos
);
572 return got_error(GOT_ERR_NOT_GIT_REPO
);
573 err
= start_auth_child(client
,
574 GOTD_AUTH_READ
| GOTD_AUTH_WRITE
,
575 repo
, gotd
.argv0
, gotd
.confpath
, gotd
.daemonize
,
581 evtimer_add(&client
->tmo
, &auth_timeout
);
583 /* Flow continues upon authentication success/failure or timeout. */
588 gotd_request(int fd
, short events
, void *arg
)
590 struct gotd_imsgev
*iev
= arg
;
591 struct imsgbuf
*ibuf
= &iev
->ibuf
;
592 struct gotd_client
*client
= iev
->handler_arg
;
593 const struct got_error
*err
= NULL
;
597 if (events
& EV_WRITE
) {
598 err
= gotd_imsg_flush(ibuf
);
601 * The client has closed its socket. This can
602 * happen when Git clients are done sending
605 if (err
->code
== GOT_ERR_ERRNO
&& errno
== EPIPE
) {
609 disconnect_on_error(client
, err
);
613 /* Disconnect gotctl(8) if all messages have been sent. */
614 if (!client_is_reading(client
) && !client_is_writing(client
) &&
615 imsgbuf_queuelen(ibuf
) == 0) {
621 if (events
& EV_READ
) {
622 n
= imsgbuf_read(ibuf
);
624 err
= got_error_from_errno("imsgbuf_read");
625 disconnect_on_error(client
, err
);
629 err
= got_error(GOT_ERR_EOF
);
630 disconnect_on_error(client
, err
);
635 while (err
== NULL
) {
636 n
= imsg_get(ibuf
, &imsg
);
638 err
= got_error_from_errno("imsg_get");
644 evtimer_del(&client
->tmo
);
646 switch (imsg
.hdr
.type
) {
648 err
= send_info(client
);
651 err
= stop_gotd(client
);
653 case GOTD_IMSG_LIST_REFS
:
654 err
= start_client_authentication(client
, &imsg
);
657 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
658 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
666 disconnect_on_error(client
, err
);
668 gotd_imsg_event_add(&client
->iev
);
673 gotd_auth_timeout(int fd
, short events
, void *arg
)
675 struct gotd_client
*client
= arg
;
677 log_debug("disconnecting uid %d due to authentication timeout",
682 static const struct got_error
*
683 recv_connect(uint32_t *client_id
, struct imsg
*imsg
)
685 const struct got_error
*err
= NULL
;
686 struct gotd_imsg_connect iconnect
;
688 struct gotd_client
*client
= NULL
;
692 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
693 if (datalen
!= sizeof(iconnect
))
694 return got_error(GOT_ERR_PRIVSEP_LEN
);
695 memcpy(&iconnect
, imsg
->data
, sizeof(iconnect
));
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
;
712 /* The auth process will verify UID/GID for us. */
713 client
->euid
= iconnect
.euid
;
714 client
->egid
= iconnect
.egid
;
716 client
->fd
= imsg_get_fd(imsg
);
717 if (client
->fd
== -1) {
718 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
721 if (imsgbuf_init(&client
->iev
.ibuf
, client
->fd
) == -1) {
722 err
= got_error_from_errno("imsgbuf_init");
725 imsgbuf_allow_fdpass(&client
->iev
.ibuf
);
726 client
->iev
.handler
= gotd_request
;
727 client
->iev
.events
= EV_READ
;
728 client
->iev
.handler_arg
= client
;
730 event_set(&client
->iev
.ev
, client
->fd
, EV_READ
, gotd_request
,
732 gotd_imsg_event_add(&client
->iev
);
734 evtimer_set(&client
->tmo
, gotd_auth_timeout
, client
);
737 log_debug("%s: new client uid %d connected on fd %d", __func__
,
738 client
->euid
, client
->fd
);
741 struct gotd_child_proc
*listen_proc
= gotd
.listen_proc
;
742 struct gotd_imsg_disconnect idisconnect
;
744 idisconnect
.client_id
= client
->id
;
745 if (gotd_imsg_compose_event(&listen_proc
->iev
,
746 GOTD_IMSG_DISCONNECT
, PROC_GOTD
, -1,
747 &idisconnect
, sizeof(idisconnect
)) == -1)
748 log_warn("imsg compose DISCONNECT");
750 if (client
->fd
!= -1)
758 static const char *gotd_proc_names
[PROC_MAX
] = {
771 kill_proc(struct gotd_child_proc
*proc
, int fatal
)
773 struct timeval tv
= { 5, 0 };
775 log_debug("kill -%d %d", fatal
? SIGKILL
: SIGTERM
, proc
->pid
);
777 if (proc
->iev
.ibuf
.fd
!= -1) {
778 event_del(&proc
->iev
.ev
);
779 imsgbuf_clear(&proc
->iev
.ibuf
);
780 close(proc
->iev
.ibuf
.fd
);
781 proc
->iev
.ibuf
.fd
= -1;
784 if (!evtimer_pending(&proc
->tmo
, NULL
) && !fatal
)
785 evtimer_add(&proc
->tmo
, &tv
);
788 log_warnx("sending SIGKILL to PID %d", proc
->pid
);
789 kill(proc
->pid
, SIGKILL
);
791 kill(proc
->pid
, SIGTERM
);
795 kill_proc_timeout(int fd
, short ev
, void *d
)
797 struct gotd_child_proc
*proc
= d
;
799 log_warnx("timeout waiting for PID %d to terminate;"
800 " retrying with force", proc
->pid
);
809 log_debug("shutting down");
810 for (slot
= 0; slot
< nitems(gotd_clients
); slot
++) {
811 struct gotd_client
*c
, *tmp
;
813 STAILQ_FOREACH_SAFE(c
, &gotd_clients
[slot
], entry
, tmp
)
817 kill_proc(gotd
.listen_proc
, 0);
819 log_info("terminating");
823 static struct gotd_child_proc
*
824 find_proc_by_pid(pid_t pid
)
826 struct gotd_child_proc
*proc
= NULL
;
828 TAILQ_FOREACH(proc
, &procs
, entry
)
829 if (proc
->pid
== pid
)
836 gotd_sighdlr(int sig
, short event
, void *arg
)
838 struct gotd_child_proc
*proc
;
843 * Normal signal handler rules don't apply because libevent
849 log_info("%s: ignoring SIGHUP", __func__
);
852 log_info("%s: ignoring SIGUSR1", __func__
);
860 pid
= waitpid(WAIT_ANY
, &status
, WNOHANG
);
871 log_debug("reaped pid %d", pid
);
872 proc
= find_proc_by_pid(pid
);
874 log_info("caught exit of unknown child %d",
879 if (WIFSIGNALED(status
)) {
880 log_warnx("child PID %d terminated with"
881 " signal %d", pid
, WTERMSIG(status
));
888 fatalx("unexpected signal");
892 static const struct got_error
*
893 ensure_proc_is_reading(struct gotd_client
*client
,
894 struct gotd_child_proc
*proc
)
896 if (!client_is_reading(client
)) {
898 return got_error_fmt(GOT_ERR_BAD_PACKET
,
899 "PID %d handled a read-request for uid %d but this "
900 "user is not reading from a repository", proc
->pid
,
907 static const struct got_error
*
908 ensure_proc_is_writing(struct gotd_client
*client
,
909 struct gotd_child_proc
*proc
)
911 if (!client_is_writing(client
)) {
913 return got_error_fmt(GOT_ERR_BAD_PACKET
,
914 "PID %d handled a write-request for uid %d but this "
915 "user is not writing to a repository", proc
->pid
,
923 verify_imsg_src(struct gotd_client
*client
, struct gotd_child_proc
*proc
,
926 const struct got_error
*err
;
929 if (proc
->type
== PROC_REPO_READ
|| proc
->type
== PROC_REPO_WRITE
) {
930 if (client
->repo
== NULL
)
931 fatalx("no process found for uid %d", client
->euid
);
932 if (proc
->pid
!= client
->repo
->pid
) {
934 log_warnx("received message from PID %d for uid %d, "
935 "while PID %d is the process serving this user",
936 proc
->pid
, client
->euid
, client
->repo
->pid
);
940 if (proc
->type
== PROC_SESSION_READ
||
941 proc
->type
== PROC_SESSION_WRITE
) {
942 if (client
->session
== NULL
) {
943 log_warnx("no session found for uid %d", client
->euid
);
946 if (proc
->pid
!= client
->session
->pid
) {
948 log_warnx("received message from PID %d for uid %d, "
949 "while PID %d is the process serving this user",
950 proc
->pid
, client
->euid
, client
->session
->pid
);
955 switch (imsg
->hdr
.type
) {
956 case GOTD_IMSG_ERROR
:
959 case GOTD_IMSG_CONNECT
:
960 if (proc
->type
!= PROC_LISTEN
) {
961 err
= got_error_fmt(GOT_ERR_BAD_PACKET
,
962 "new connection for uid %d from PID %d "
963 "which is not the listen process",
964 client
->euid
, proc
->pid
);
968 case GOTD_IMSG_ACCESS_GRANTED
:
969 if (proc
->type
!= PROC_AUTH
) {
970 err
= got_error_fmt(GOT_ERR_BAD_PACKET
,
971 "authentication of uid %d from PID %d "
972 "which is not the auth process",
973 client
->euid
, proc
->pid
);
977 case GOTD_IMSG_CLIENT_SESSION_READY
:
978 if (proc
->type
!= PROC_SESSION_READ
&&
979 proc
->type
!= PROC_SESSION_WRITE
) {
980 err
= got_error_fmt(GOT_ERR_BAD_PACKET
,
981 "unexpected \"ready\" signal from PID %d",
986 case GOTD_IMSG_REPO_CHILD_READY
:
987 if (proc
->type
!= PROC_REPO_READ
&&
988 proc
->type
!= PROC_REPO_WRITE
) {
989 err
= got_error_fmt(GOT_ERR_BAD_PACKET
,
990 "unexpected \"ready\" signal from PID %d",
995 case GOTD_IMSG_PACKFILE_DONE
:
996 err
= ensure_proc_is_reading(client
, proc
);
998 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
1002 case GOTD_IMSG_PACKFILE_INSTALL
:
1003 case GOTD_IMSG_REF_UPDATES_START
:
1004 case GOTD_IMSG_REF_UPDATE
:
1005 err
= ensure_proc_is_writing(client
, proc
);
1007 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
1012 log_debug("%s: unexpected imsg %d", __func__
, imsg
->hdr
.type
);
1019 static const struct got_error
*
1020 connect_repo_child(struct gotd_client
*client
,
1021 struct gotd_child_proc
*repo_proc
)
1023 static const struct got_error
*err
;
1024 struct gotd_imsgev
*session_iev
= &client
->session
->iev
;
1025 struct gotd_imsg_connect_repo_child ireq
;
1027 int sock_flags
= SOCK_STREAM
| SOCK_NONBLOCK
;
1030 sock_flags
|= SOCK_CLOEXEC
;
1033 if (client
->state
!= GOTD_CLIENT_STATE_ACCESS_GRANTED
)
1034 return got_error_msg(GOT_ERR_BAD_REQUEST
,
1035 "unexpected repo child ready signal received");
1037 if (socketpair(AF_UNIX
, sock_flags
, PF_UNSPEC
, pipe
) == -1)
1038 fatal("socketpair");
1040 memset(&ireq
, 0, sizeof(ireq
));
1041 ireq
.proc_id
= repo_proc
->type
;
1043 /* Pass repo child pipe to session child process. */
1044 if (gotd_imsg_compose_event(session_iev
, GOTD_IMSG_CONNECT_REPO_CHILD
,
1045 PROC_GOTD
, pipe
[0], &ireq
, sizeof(ireq
)) == -1) {
1046 err
= got_error_from_errno("imsg compose CONNECT_REPO_CHILD");
1052 /* Pass session child pipe to repo child process. */
1053 if (gotd_imsg_compose_event(&repo_proc
->iev
,
1054 GOTD_IMSG_CONNECT_REPO_CHILD
, PROC_GOTD
, pipe
[1], NULL
, 0) == -1) {
1055 err
= got_error_from_errno("imsg compose CONNECT_REPO_CHILD");
1064 gotd_dispatch_listener(int fd
, short event
, void *arg
)
1066 const struct got_error
*err
= NULL
;
1067 struct gotd_imsgev
*iev
= arg
;
1068 struct imsgbuf
*ibuf
= &iev
->ibuf
;
1069 struct gotd_child_proc
*proc
= gotd
.listen_proc
;
1074 if (proc
->iev
.ibuf
.fd
!= fd
)
1075 fatalx("%s: unexpected fd %d", __func__
, fd
);
1077 if (event
& EV_READ
) {
1078 if ((n
= imsgbuf_read(ibuf
)) == -1)
1079 fatal("imsg_read error");
1081 /* Connection closed. */
1087 if (event
& EV_WRITE
) {
1088 err
= gotd_imsg_flush(ibuf
);
1090 fatalx("%s", err
->msg
);
1094 const struct got_error
*err
= NULL
;
1095 struct gotd_client
*client
= NULL
;
1096 uint32_t client_id
= 0;
1097 int do_disconnect
= 0;
1099 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
1100 fatal("%s: imsg_get error", __func__
);
1101 if (n
== 0) /* No more messages. */
1104 switch (imsg
.hdr
.type
) {
1105 case GOTD_IMSG_ERROR
:
1107 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
1109 case GOTD_IMSG_CONNECT
:
1110 err
= recv_connect(&client_id
, &imsg
);
1113 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
1117 client
= find_client(client_id
);
1118 if (client
== NULL
) {
1119 log_warnx("%s: client not found", __func__
);
1125 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
1127 if (do_disconnect
) {
1129 disconnect_on_error(client
, err
);
1138 gotd_imsg_event_add(iev
);
1140 /* This pipe is dead. Remove its event handler */
1141 event_del(&iev
->ev
);
1142 event_loopexit(NULL
);
1147 gotd_dispatch_notifier(int fd
, short event
, void *arg
)
1149 const struct got_error
*err
= NULL
;
1150 struct gotd_imsgev
*iev
= arg
;
1151 struct imsgbuf
*ibuf
= &iev
->ibuf
;
1152 struct gotd_child_proc
*proc
= gotd
.notify_proc
;
1157 if (proc
->iev
.ibuf
.fd
!= fd
)
1158 fatalx("%s: unexpected fd %d", __func__
, fd
);
1160 if (event
& EV_READ
) {
1161 if ((n
= imsgbuf_read(ibuf
)) == -1)
1162 fatal("imsg_read error");
1164 /* Connection closed. */
1170 if (event
& EV_WRITE
) {
1171 err
= gotd_imsg_flush(ibuf
);
1173 fatalx("%s", err
->msg
);
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
= imsgbuf_read(ibuf
)) == -1)
1236 fatal("imsg_read error");
1238 /* Connection closed. */
1244 if (event
& EV_WRITE
) {
1245 err
= gotd_imsg_flush(ibuf
);
1247 fatalx("%s", err
->msg
);
1251 if (client
->auth
->iev
.ibuf
.fd
!= fd
)
1252 fatalx("%s: unexpected fd %d", __func__
, fd
);
1254 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
1255 fatal("%s: imsg_get error", __func__
);
1256 if (n
== 0) /* No more messages. */
1259 evtimer_del(&client
->tmo
);
1261 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
1263 switch (imsg
.hdr
.type
) {
1264 case GOTD_IMSG_ERROR
:
1266 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
1268 case GOTD_IMSG_ACCESS_GRANTED
:
1269 if (client
->state
!= GOTD_CLIENT_STATE_NEW
) {
1271 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1276 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
1280 if (!verify_imsg_src(client
, client
->auth
, &imsg
)) {
1282 log_debug("dropping imsg type %d from PID %d",
1283 imsg
.hdr
.type
, client
->auth
->pid
);
1286 if (do_disconnect
) {
1288 disconnect_on_error(client
, err
);
1295 client
->state
= GOTD_CLIENT_STATE_ACCESS_GRANTED
;
1297 client
->username
= strndup(imsg
.data
, datalen
);
1299 if (client
->username
== NULL
&&
1300 asprintf(&client
->username
, "uid %d", client
->euid
) == -1) {
1301 err
= got_error_from_errno("asprintf");
1305 repo
= gotd_find_repo_by_name(client
->auth
->repo_name
, &gotd
.repos
);
1307 err
= got_error(GOT_ERR_NOT_GIT_REPO
);
1310 kill_auth_proc(client
);
1312 log_info("authenticated %s for repository %s",
1313 client
->username
, repo
->name
);
1315 err
= start_session_child(client
, repo
, gotd
.argv0
,
1316 gotd
.confpath
, gotd
.daemonize
, gotd
.verbosity
);
1321 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
1323 /* We might have killed the auth process by now. */
1324 if (client
->auth
!= NULL
) {
1326 gotd_imsg_event_add(iev
);
1328 /* This pipe is dead. Remove its event handler */
1329 event_del(&iev
->ev
);
1334 static const struct got_error
*
1335 connect_session(struct gotd_client
*client
)
1337 const struct got_error
*err
= NULL
;
1338 struct gotd_imsg_connect iconnect
;
1342 memset(&iconnect
, 0, sizeof(iconnect
));
1344 s
= dup(client
->fd
);
1346 return got_error_from_errno("dup");
1348 iconnect
.client_id
= client
->id
;
1349 iconnect
.euid
= client
->euid
;
1350 iconnect
.egid
= client
->egid
;
1351 iconnect
.username_len
= strlen(client
->username
);
1353 wbuf
= imsg_create(&client
->session
->iev
.ibuf
, GOTD_IMSG_CONNECT
,
1354 PROC_GOTD
, gotd
.pid
, sizeof(iconnect
) + iconnect
.username_len
);
1356 err
= got_error_from_errno("imsg compose CONNECT");
1360 if (imsg_add(wbuf
, &iconnect
, sizeof(iconnect
)) == -1) {
1362 return got_error_from_errno("imsg_add CONNECT");
1364 if (imsg_add(wbuf
, client
->username
, iconnect
.username_len
) == -1) {
1366 return got_error_from_errno("imsg_add CONNECT");
1369 ibuf_fd_set(wbuf
, s
);
1370 imsg_close(&client
->session
->iev
.ibuf
, wbuf
);
1371 gotd_imsg_event_add(&client
->session
->iev
);
1374 * We are no longer interested in messages from this client.
1375 * Further client requests will be handled by the session process.
1377 imsgbuf_clear(&client
->iev
.ibuf
);
1378 imsgbuf_clear(&client
->iev
.ibuf
);
1379 event_del(&client
->iev
.ev
);
1380 client
->fd
= -1; /* will be closed via copy in client->iev.ibuf.fd */
1386 gotd_dispatch_client_session(int fd
, short event
, void *arg
)
1388 const struct got_error
*err
= NULL
;
1389 struct gotd_imsgev
*iev
= arg
;
1390 struct imsgbuf
*ibuf
= &iev
->ibuf
;
1391 struct gotd_child_proc
*proc
= NULL
;
1392 struct gotd_client
*client
= NULL
;
1397 client
= find_client_by_proc_fd(fd
);
1398 if (client
== NULL
) {
1399 /* Can happen during process teardown. */
1400 warnx("cannot find client for fd %d", fd
);
1405 if (event
& EV_READ
) {
1406 if ((n
= imsgbuf_read(ibuf
)) == -1)
1407 fatal("imsg_read error");
1409 /* Connection closed. */
1415 if (event
& EV_WRITE
) {
1416 err
= gotd_imsg_flush(ibuf
);
1418 fatalx("%s", err
->msg
);
1421 proc
= client
->session
;
1423 fatalx("cannot find session child process for fd %d", fd
);
1426 const struct got_error
*err
= NULL
;
1427 uint32_t client_id
= 0;
1428 int do_disconnect
= 0, do_start_repo_child
= 0;
1430 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
1431 fatal("%s: imsg_get error", __func__
);
1432 if (n
== 0) /* No more messages. */
1435 switch (imsg
.hdr
.type
) {
1436 case GOTD_IMSG_ERROR
:
1438 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
1440 case GOTD_IMSG_CLIENT_SESSION_READY
:
1441 if (client
->state
!= GOTD_CLIENT_STATE_ACCESS_GRANTED
) {
1442 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1445 do_start_repo_child
= 1;
1447 case GOTD_IMSG_DISCONNECT
:
1451 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
1455 if (!verify_imsg_src(client
, proc
, &imsg
)) {
1456 log_debug("dropping imsg type %d from PID %d",
1457 imsg
.hdr
.type
, proc
->pid
);
1462 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
1464 if (do_start_repo_child
) {
1465 struct gotd_repo
*repo
;
1466 const char *name
= client
->session
->repo_name
;
1468 repo
= gotd_find_repo_by_name(name
, &gotd
.repos
);
1470 enum gotd_procid proc_type
;
1472 if (client
->required_auth
& GOTD_AUTH_WRITE
)
1473 proc_type
= PROC_REPO_WRITE
;
1475 proc_type
= PROC_REPO_READ
;
1477 err
= start_repo_child(client
, proc_type
, repo
,
1478 gotd
.argv0
, gotd
.confpath
, gotd
.daemonize
,
1481 err
= got_error(GOT_ERR_NOT_GIT_REPO
);
1484 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
1489 if (do_disconnect
) {
1491 disconnect_on_error(client
, err
);
1500 gotd_imsg_event_add(iev
);
1502 /* This pipe is dead. Remove its event handler */
1503 event_del(&iev
->ev
);
1508 static const struct got_error
*
1509 connect_notifier_and_session(struct gotd_client
*client
)
1511 const struct got_error
*err
= NULL
;
1512 struct gotd_imsgev
*session_iev
= &client
->session
->iev
;
1514 int sock_flags
= SOCK_STREAM
|SOCK_NONBLOCK
;
1516 if (gotd
.notify_proc
== NULL
)
1520 sock_flags
|= SOCK_CLOEXEC
;
1522 if (socketpair(AF_UNIX
, sock_flags
,
1523 PF_UNSPEC
, pipe
) == -1)
1524 return got_error_from_errno("socketpair");
1526 /* Pass notifier pipe to session . */
1527 if (gotd_imsg_compose_event(session_iev
, GOTD_IMSG_CONNECT_NOTIFIER
,
1528 PROC_GOTD
, pipe
[0], NULL
, 0) == -1) {
1529 err
= got_error_from_errno("imsg compose CONNECT_NOTIFIER");
1535 /* Pass session pipe to notifier. */
1536 if (gotd_imsg_compose_event(&gotd
.notify_proc
->iev
,
1537 GOTD_IMSG_CONNECT_SESSION
, PROC_GOTD
, pipe
[1], NULL
, 0) == -1) {
1538 err
= got_error_from_errno("imsg compose CONNECT_SESSION");
1547 gotd_dispatch_repo_child(int fd
, short event
, void *arg
)
1549 const struct got_error
*err
= NULL
;
1550 struct gotd_imsgev
*iev
= arg
;
1551 struct imsgbuf
*ibuf
= &iev
->ibuf
;
1552 struct gotd_child_proc
*proc
= NULL
;
1553 struct gotd_client
*client
;
1558 client
= find_client_by_proc_fd(fd
);
1559 if (client
== NULL
) {
1560 /* Can happen during process teardown. */
1561 warnx("cannot find client for fd %d", fd
);
1566 if (event
& EV_READ
) {
1567 if ((n
= imsgbuf_read(ibuf
)) == -1)
1568 fatal("imsg_read error");
1570 /* Connection closed. */
1576 if (event
& EV_WRITE
) {
1577 err
= gotd_imsg_flush(ibuf
);
1579 fatalx("%s", err
->msg
);
1582 proc
= client
->repo
;
1584 fatalx("cannot find child process for fd %d", fd
);
1587 uint32_t client_id
= 0;
1588 int do_disconnect
= 0;
1590 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
1591 fatal("%s: imsg_get error", __func__
);
1592 if (n
== 0) /* No more messages. */
1595 switch (imsg
.hdr
.type
) {
1596 case GOTD_IMSG_ERROR
:
1598 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
1600 case GOTD_IMSG_REPO_CHILD_READY
:
1601 err
= connect_session(client
);
1604 if (client_is_writing(client
)) {
1605 err
= connect_notifier_and_session(client
);
1609 err
= connect_repo_child(client
, proc
);
1612 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
1616 if (!verify_imsg_src(client
, proc
, &imsg
)) {
1617 log_debug("dropping imsg type %d from PID %d",
1618 imsg
.hdr
.type
, proc
->pid
);
1623 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
1625 if (do_disconnect
) {
1627 disconnect_on_error(client
, err
);
1636 gotd_imsg_event_add(iev
);
1638 /* This pipe is dead. Remove its event handler */
1639 event_del(&iev
->ev
);
1645 start_child(enum gotd_procid proc_id
, const char *repo_path
,
1646 char *argv0
, const char *confpath
, int fd
, int daemonize
, int verbosity
)
1648 const char *argv
[11];
1652 switch (pid
= fork()) {
1654 fatal("cannot fork");
1662 if (fd
!= GOTD_FILENO_MSG_PIPE
) {
1663 if (dup2(fd
, GOTD_FILENO_MSG_PIPE
) == -1)
1664 fatal("cannot setup imsg fd");
1665 } else if (fcntl(fd
, F_SETFD
, 0) == -1)
1666 fatal("cannot setup imsg fd");
1668 argv
[argc
++] = argv0
;
1671 argv
[argc
++] = "-TL";
1674 argv
[argc
++] = "-TA";
1676 case PROC_SESSION_READ
:
1677 argv
[argc
++] = "-Ts";
1679 case PROC_SESSION_WRITE
:
1680 argv
[argc
++] = "-TS";
1682 case PROC_REPO_READ
:
1683 argv
[argc
++] = "-TR";
1685 case PROC_REPO_WRITE
:
1686 argv
[argc
++] = "-TW";
1689 argv
[argc
++] = "-TN";
1692 fatalx("invalid process id %d", proc_id
);
1695 argv
[argc
++] = "-f";
1696 argv
[argc
++] = confpath
;
1699 argv
[argc
++] = "-P";
1700 argv
[argc
++] = repo_path
;
1704 argv
[argc
++] = "-d";
1706 argv
[argc
++] = "-v";
1708 argv
[argc
++] = "-v";
1709 argv
[argc
++] = NULL
;
1711 execvp(argv0
, (char * const *)argv
);
1716 start_listener(char *argv0
, const char *confpath
, int daemonize
, int verbosity
)
1718 struct gotd_child_proc
*proc
;
1719 int sock_flags
= SOCK_STREAM
|SOCK_NONBLOCK
;
1722 sock_flags
|= SOCK_CLOEXEC
;
1725 proc
= calloc(1, sizeof(*proc
));
1729 TAILQ_INSERT_HEAD(&procs
, proc
, entry
);
1731 /* proc->tmo is initialized in main() after event_init() */
1733 proc
->type
= PROC_LISTEN
;
1735 if (socketpair(AF_UNIX
, sock_flags
,
1736 PF_UNSPEC
, proc
->pipe
) == -1)
1737 fatal("socketpair");
1739 proc
->pid
= start_child(proc
->type
, NULL
, argv0
, confpath
,
1740 proc
->pipe
[1], daemonize
, verbosity
);
1741 if (imsgbuf_init(&proc
->iev
.ibuf
, proc
->pipe
[0]) == -1)
1742 fatal("imsgbuf_init");
1743 imsgbuf_allow_fdpass(&proc
->iev
.ibuf
);
1744 proc
->iev
.handler
= gotd_dispatch_listener
;
1745 proc
->iev
.events
= EV_READ
;
1746 proc
->iev
.handler_arg
= NULL
;
1748 gotd
.listen_proc
= proc
;
1752 start_notifier(char *argv0
, const char *confpath
, int daemonize
, int verbosity
)
1754 struct gotd_child_proc
*proc
;
1755 int sock_flags
= SOCK_STREAM
| SOCK_NONBLOCK
;
1758 proc
= calloc(1, sizeof(*proc
));
1762 TAILQ_INSERT_HEAD(&procs
, proc
, entry
);
1764 /* proc->tmo is initialized in main() after event_init() */
1766 proc
->type
= PROC_NOTIFY
;
1769 sock_flags
|= SOCK_CLOEXEC
;
1771 if (socketpair(AF_UNIX
, sock_flags
,
1772 PF_UNSPEC
, proc
->pipe
) == -1)
1773 fatal("socketpair");
1775 proc
->pid
= start_child(proc
->type
, NULL
, argv0
, confpath
,
1776 proc
->pipe
[1], daemonize
, verbosity
);
1777 if (imsgbuf_init(&proc
->iev
.ibuf
, proc
->pipe
[0]) == -1)
1778 fatal("imsgbuf_init");
1779 imsgbuf_allow_fdpass(&proc
->iev
.ibuf
);
1780 proc
->iev
.handler
= gotd_dispatch_notifier
;
1781 proc
->iev
.events
= EV_READ
;
1782 proc
->iev
.handler_arg
= NULL
;
1783 event_set(&proc
->iev
.ev
, proc
->iev
.ibuf
.fd
, EV_READ
,
1784 gotd_dispatch_notifier
, &proc
->iev
);
1786 gotd
.notify_proc
= proc
;
1789 static const struct got_error
*
1790 start_session_child(struct gotd_client
*client
, struct gotd_repo
*repo
,
1791 char *argv0
, const char *confpath
, int daemonize
, int verbosity
)
1793 struct gotd_child_proc
*proc
;
1794 int sock_flags
= SOCK_STREAM
| SOCK_NONBLOCK
;
1797 sock_flags
|= SOCK_CLOEXEC
;
1800 proc
= calloc(1, sizeof(*proc
));
1802 return got_error_from_errno("calloc");
1804 TAILQ_INSERT_HEAD(&procs
, proc
, entry
);
1805 evtimer_set(&proc
->tmo
, kill_proc_timeout
, proc
);
1807 if (client_is_reading(client
))
1808 proc
->type
= PROC_SESSION_READ
;
1810 proc
->type
= PROC_SESSION_WRITE
;
1811 if (strlcpy(proc
->repo_name
, repo
->name
,
1812 sizeof(proc
->repo_name
)) >= sizeof(proc
->repo_name
))
1813 fatalx("repository name too long: %s", repo
->name
);
1814 log_debug("starting client uid %d session for repository %s",
1815 client
->euid
, repo
->name
);
1816 if (strlcpy(proc
->repo_path
, repo
->path
, sizeof(proc
->repo_path
)) >=
1817 sizeof(proc
->repo_path
))
1818 fatalx("repository path too long: %s", repo
->path
);
1819 if (socketpair(AF_UNIX
, sock_flags
, PF_UNSPEC
, proc
->pipe
) == -1)
1820 fatal("socketpair");
1821 proc
->pid
= start_child(proc
->type
, proc
->repo_path
, argv0
,
1822 confpath
, proc
->pipe
[1], daemonize
, verbosity
);
1823 if (imsgbuf_init(&proc
->iev
.ibuf
, proc
->pipe
[0]) == -1)
1824 fatal("imsgbuf_init");
1825 imsgbuf_allow_fdpass(&proc
->iev
.ibuf
);
1826 log_debug("proc %s %s is on fd %d",
1827 gotd_proc_names
[proc
->type
], proc
->repo_path
,
1829 proc
->iev
.handler
= gotd_dispatch_client_session
;
1830 proc
->iev
.events
= EV_READ
;
1831 proc
->iev
.handler_arg
= NULL
;
1832 event_set(&proc
->iev
.ev
, proc
->iev
.ibuf
.fd
, EV_READ
,
1833 gotd_dispatch_client_session
, &proc
->iev
);
1834 gotd_imsg_event_add(&proc
->iev
);
1836 client
->session
= proc
;
1840 static const struct got_error
*
1841 start_repo_child(struct gotd_client
*client
, enum gotd_procid proc_type
,
1842 struct gotd_repo
*repo
, char *argv0
, const char *confpath
,
1843 int daemonize
, int verbosity
)
1845 struct gotd_child_proc
*proc
;
1846 int sock_flags
= SOCK_STREAM
|SOCK_NONBLOCK
;
1849 sock_flags
|= SOCK_CLOEXEC
;
1852 if (proc_type
!= PROC_REPO_READ
&& proc_type
!= PROC_REPO_WRITE
)
1853 return got_error_msg(GOT_ERR_NOT_IMPL
, "bad process type");
1855 proc
= calloc(1, sizeof(*proc
));
1857 return got_error_from_errno("calloc");
1859 TAILQ_INSERT_HEAD(&procs
, proc
, entry
);
1860 evtimer_set(&proc
->tmo
, kill_proc_timeout
, proc
);
1862 proc
->type
= proc_type
;
1863 if (strlcpy(proc
->repo_name
, repo
->name
,
1864 sizeof(proc
->repo_name
)) >= sizeof(proc
->repo_name
))
1865 fatalx("repository name too long: %s", repo
->name
);
1866 log_debug("starting %s for repository %s",
1867 proc
->type
== PROC_REPO_READ
? "reader" : "writer", repo
->name
);
1869 if (strlcpy(proc
->repo_path
, repo
->path
, sizeof(proc
->repo_path
)) >=
1870 sizeof(proc
->repo_path
))
1871 fatalx("repository path too long: %s", repo
->path
);
1872 if (realpath(repo
->path
, proc
->repo_path
) == NULL
)
1873 fatal("%s", repo
->path
);
1874 if (socketpair(AF_UNIX
, sock_flags
,
1875 PF_UNSPEC
, proc
->pipe
) == -1)
1876 fatal("socketpair");
1877 proc
->pid
= start_child(proc
->type
, proc
->repo_path
, argv0
,
1878 confpath
, proc
->pipe
[1], daemonize
, verbosity
);
1879 if (imsgbuf_init(&proc
->iev
.ibuf
, proc
->pipe
[0]) == -1)
1880 fatal("imsgbuf_init");
1881 imsgbuf_allow_fdpass(&proc
->iev
.ibuf
);
1882 log_debug("proc %s %s is on fd %d",
1883 gotd_proc_names
[proc
->type
], proc
->repo_path
,
1885 proc
->iev
.handler
= gotd_dispatch_repo_child
;
1886 proc
->iev
.events
= EV_READ
;
1887 proc
->iev
.handler_arg
= NULL
;
1888 event_set(&proc
->iev
.ev
, proc
->iev
.ibuf
.fd
, EV_READ
,
1889 gotd_dispatch_repo_child
, &proc
->iev
);
1890 gotd_imsg_event_add(&proc
->iev
);
1892 client
->repo
= proc
;
1896 static const struct got_error
*
1897 start_auth_child(struct gotd_client
*client
, int required_auth
,
1898 struct gotd_repo
*repo
, char *argv0
, const char *confpath
,
1899 int daemonize
, int verbosity
)
1901 const struct got_error
*err
= NULL
;
1902 struct gotd_child_proc
*proc
;
1903 struct gotd_imsg_auth iauth
;
1905 int sock_flags
= SOCK_STREAM
|SOCK_NONBLOCK
;
1908 sock_flags
|= SOCK_CLOEXEC
;
1911 memset(&iauth
, 0, sizeof(iauth
));
1913 fd
= dup(client
->fd
);
1915 return got_error_from_errno("dup");
1917 proc
= calloc(1, sizeof(*proc
));
1919 err
= got_error_from_errno("calloc");
1924 TAILQ_INSERT_HEAD(&procs
, proc
, entry
);
1925 evtimer_set(&proc
->tmo
, kill_proc_timeout
, proc
);
1927 proc
->type
= PROC_AUTH
;
1928 if (strlcpy(proc
->repo_name
, repo
->name
,
1929 sizeof(proc
->repo_name
)) >= sizeof(proc
->repo_name
))
1930 fatalx("repository name too long: %s", repo
->name
);
1931 log_debug("starting auth for uid %d repository %s",
1932 client
->euid
, repo
->name
);
1933 if (strlcpy(proc
->repo_path
, repo
->path
, sizeof(proc
->repo_path
)) >=
1934 sizeof(proc
->repo_path
))
1935 fatalx("repository path too long: %s", repo
->path
);
1936 if (realpath(repo
->path
, proc
->repo_path
) == NULL
)
1937 fatal("%s", repo
->path
);
1938 if (socketpair(AF_UNIX
, sock_flags
,
1939 PF_UNSPEC
, proc
->pipe
) == -1)
1940 fatal("socketpair");
1941 proc
->pid
= start_child(proc
->type
, proc
->repo_path
, argv0
,
1942 confpath
, proc
->pipe
[1], daemonize
, verbosity
);
1943 if (imsgbuf_init(&proc
->iev
.ibuf
, proc
->pipe
[0]) == -1)
1944 fatal("imsgbuf_init");
1945 imsgbuf_allow_fdpass(&proc
->iev
.ibuf
);
1946 log_debug("proc %s %s is on fd %d",
1947 gotd_proc_names
[proc
->type
], proc
->repo_path
,
1949 proc
->iev
.handler
= gotd_dispatch_auth_child
;
1950 proc
->iev
.events
= EV_READ
;
1951 proc
->iev
.handler_arg
= NULL
;
1952 event_set(&proc
->iev
.ev
, proc
->iev
.ibuf
.fd
, EV_READ
,
1953 gotd_dispatch_auth_child
, &proc
->iev
);
1954 gotd_imsg_event_add(&proc
->iev
);
1956 iauth
.euid
= client
->euid
;
1957 iauth
.egid
= client
->egid
;
1958 iauth
.required_auth
= required_auth
;
1959 iauth
.client_id
= client
->id
;
1960 if (gotd_imsg_compose_event(&proc
->iev
, GOTD_IMSG_AUTHENTICATE
,
1961 PROC_GOTD
, fd
, &iauth
, sizeof(iauth
)) == -1) {
1962 log_warn("imsg compose AUTHENTICATE");
1964 /* Let the auth_timeout handler tidy up. */
1967 client
->auth
= proc
;
1968 client
->required_auth
= required_auth
;
1973 apply_unveil_repo_readonly(const char *repo_path
, int need_tmpdir
)
1976 if (unveil(GOT_TMPDIR_STR
, "rwc") == -1)
1977 fatal("unveil %s", GOT_TMPDIR_STR
);
1980 if (unveil(repo_path
, "r") == -1)
1981 fatal("unveil %s", repo_path
);
1983 if (unveil(NULL
, NULL
) == -1)
1988 apply_unveil_repo_readwrite(const char *repo_path
)
1990 if (unveil(repo_path
, "rwc") == -1)
1991 fatal("unveil %s", repo_path
);
1993 if (unveil(GOT_TMPDIR_STR
, "rwc") == -1)
1994 fatal("unveil %s", GOT_TMPDIR_STR
);
1996 if (unveil(NULL
, NULL
) == -1)
2001 apply_unveil_none(void)
2003 if (unveil("/", "") == -1)
2006 if (unveil(NULL
, NULL
) == -1)
2011 apply_unveil_selfexec(void)
2013 if (unveil(gotd
.argv0
, "x") == -1)
2014 fatal("unveil %s", gotd
.argv0
);
2016 if (unveil(NULL
, NULL
) == -1)
2021 set_max_datasize(void)
2025 if (getrlimit(RLIMIT_DATA
, &rl
) != 0)
2028 rl
.rlim_cur
= rl
.rlim_max
;
2029 setrlimit(RLIMIT_DATA
, &rl
);
2033 unveil_notification_helpers(void)
2035 const char *helpers
[] = {
2036 GOTD_PATH_PROG_NOTIFY_EMAIL
,
2037 GOTD_PATH_PROG_NOTIFY_HTTP
,
2041 for (i
= 0; i
< nitems(helpers
); i
++) {
2042 if (unveil(helpers
[i
], "x") == 0)
2044 fatal("unveil %s", helpers
[i
]);
2047 if (unveil(NULL
, NULL
) == -1)
2052 check_file_secrecy(int fd
, const char *fname
)
2057 fatal("cannot stat %s", fname
);
2060 fatalx("secrets file %s must be owned by root", fname
);
2063 fatalx("secrets file %s must be owned by group wheel/root",
2066 if (st
.st_mode
& (S_IWGRP
| S_IXGRP
| S_IRWXO
))
2067 fatalx("secrets file %s must not be group writable or world "
2068 "readable/writable", fname
);
2072 main(int argc
, char **argv
)
2074 const struct got_error
*error
= NULL
;
2075 struct gotd_secrets
*secrets
= NULL
;
2076 int ch
, fd
= -1, daemonize
= 1, verbosity
= 0, noaction
= 0;
2077 const char *confpath
= GOTD_CONF_PATH
;
2078 char *secretspath
= NULL
;
2079 char *argv0
= argv
[0];
2081 struct passwd
*pw
= NULL
;
2083 char *repo_path
= NULL
;
2084 enum gotd_procid proc_id
= PROC_GOTD
;
2085 struct event evsigint
, evsigterm
, evsighup
, evsigusr1
, evsigchld
;
2086 int *pack_fds
= NULL
, *temp_fds
= NULL
;
2087 struct gotd_repo
*repo
= NULL
;
2088 char *default_sender
= NULL
;
2089 char hostname
[_POSIX_HOST_NAME_MAX
+ 1];
2091 FILE *diff_f1
= NULL
, *diff_f2
= NULL
;
2092 int diff_fd1
= -1, diff_fd2
= -1;
2097 log_init(1, LOG_DAEMON
); /* Log to stderr until daemonized. */
2099 while ((ch
= getopt(argc
, argv
, "df:nP:s:T:v")) != -1) {
2111 repo_path
= realpath(optarg
, NULL
);
2112 if (repo_path
== NULL
)
2113 fatal("realpath '%s'", optarg
);
2116 secretspath
= realpath(optarg
, NULL
);
2117 if (secretspath
== NULL
)
2118 fatal("realpath '%s'", optarg
);
2123 proc_id
= PROC_AUTH
;
2126 proc_id
= PROC_LISTEN
;
2129 proc_id
= PROC_NOTIFY
;
2132 proc_id
= PROC_REPO_READ
;
2135 proc_id
= PROC_SESSION_READ
;
2138 proc_id
= PROC_SESSION_WRITE
;
2141 proc_id
= PROC_REPO_WRITE
;
2144 errx(1, "unknown proc type %s", optarg
);
2162 if (geteuid() && (proc_id
== PROC_GOTD
|| proc_id
== PROC_LISTEN
))
2163 fatalx("need root privileges");
2165 if (proc_id
== PROC_GOTD
) {
2166 const char *p
= secretspath
? secretspath
: GOTD_SECRETS_PATH
;
2169 if (fp
== NULL
&& (secretspath
!= NULL
|| errno
!= ENOENT
))
2170 fatal("can't open secrets file %s", p
);
2173 check_file_secrecy(fileno(fp
), p
);
2174 error
= gotd_secrets_parse(p
, fp
, &secrets
);
2177 fatalx("failed to parse secrets file %s: %s",
2182 if (parse_config(confpath
, proc_id
, secrets
, &gotd
) != 0)
2185 pw
= getpwnam(gotd
.user_name
);
2187 uid
= strtonum(gotd
.user_name
, 0, UID_MAX
- 1, &errstr
);
2192 fatalx("user %s not found", gotd
.user_name
);
2194 if (pw
->pw_uid
== 0)
2195 fatalx("cannot run %s as the superuser", getprogname());
2198 * SHA2 repositories cannot be used with gotd until Git protocol v2
2199 * support is added. Reject them at startup for now.
2201 TAILQ_FOREACH(repo
, &gotd
.repos
, entry
) {
2202 struct got_repository
*r
;
2204 error
= got_repo_open(&r
, repo
->path
, NULL
, NULL
);
2206 if (error
->code
== GOT_ERR_ERRNO
&& errno
== ENOENT
)
2208 fatalx("%s: %s", repo
->path
, error
->msg
);
2211 if (got_repo_get_object_format(r
) != GOT_HASH_SHA1
) {
2212 error
= got_error_msg(GOT_ERR_NOT_IMPL
,
2213 "sha256 object IDs unsupported in network "
2215 fatalx("%s: %s", repo
->path
, error
->msg
);
2222 fprintf(stderr
, "configuration OK\n");
2227 gotd
.daemonize
= daemonize
;
2228 gotd
.verbosity
= verbosity
;
2229 gotd
.confpath
= confpath
;
2231 /* Require an absolute path in argv[0] for reliable re-exec. */
2232 if (!got_path_is_absolute(argv0
))
2233 fatalx("bad path \"%s\": must be an absolute path", argv0
);
2235 log_init(daemonize
? 0 : 1, LOG_DAEMON
);
2236 log_setverbose(verbosity
);
2238 if (proc_id
== PROC_GOTD
) {
2239 snprintf(title
, sizeof(title
), "%s", gotd_proc_names
[proc_id
]);
2240 arc4random_buf(&clients_hash_key
, sizeof(clients_hash_key
));
2241 if (daemonize
&& daemon(1, 0) == -1)
2243 gotd
.pid
= getpid();
2244 start_listener(argv0
, confpath
, daemonize
, verbosity
);
2245 start_notifier(argv0
, confpath
, daemonize
, verbosity
);
2246 } else if (proc_id
== PROC_LISTEN
) {
2247 snprintf(title
, sizeof(title
), "%s", gotd_proc_names
[proc_id
]);
2249 log_info("socket: %s", gotd
.unix_socket_path
);
2250 log_info("user: %s", pw
->pw_name
);
2253 fd
= unix_socket_listen(gotd
.unix_socket_path
, pw
->pw_uid
,
2256 fatal("cannot listen on unix socket %s",
2257 gotd
.unix_socket_path
);
2259 } else if (proc_id
== PROC_AUTH
) {
2260 snprintf(title
, sizeof(title
), "%s %s",
2261 gotd_proc_names
[proc_id
], repo_path
);
2262 } else if (proc_id
== PROC_REPO_READ
|| proc_id
== PROC_REPO_WRITE
||
2263 proc_id
== PROC_SESSION_READ
|| proc_id
== PROC_SESSION_WRITE
) {
2264 error
= got_repo_pack_fds_open(&pack_fds
);
2266 fatalx("cannot open pack tempfiles: %s", error
->msg
);
2267 error
= got_repo_temp_fds_open(&temp_fds
);
2269 fatalx("cannot open pack tempfiles: %s", error
->msg
);
2270 if (repo_path
== NULL
)
2271 fatalx("repository path not specified");
2272 snprintf(title
, sizeof(title
), "%s %s",
2273 gotd_proc_names
[proc_id
], repo_path
);
2274 } else if (proc_id
== PROC_NOTIFY
) {
2275 snprintf(title
, sizeof(title
), "%s", gotd_proc_names
[proc_id
]);
2276 if (gethostname(hostname
, sizeof(hostname
)) == -1)
2277 fatal("gethostname");
2278 if (asprintf(&default_sender
, "%s@%s",
2279 pw
->pw_name
, hostname
) == -1)
2282 fatal("invalid process id %d", proc_id
);
2284 setproctitle("%s", title
);
2285 log_procinit(title
);
2287 if (proc_id
!= PROC_GOTD
&& proc_id
!= PROC_LISTEN
&&
2288 proc_id
!= PROC_REPO_READ
&& proc_id
!= PROC_REPO_WRITE
) {
2289 /* Drop root privileges. */
2290 if (setgid(pw
->pw_gid
) == -1)
2291 fatal("setgid %d failed", pw
->pw_gid
);
2292 if (setuid(pw
->pw_uid
) == -1)
2293 fatal("setuid %d failed", pw
->pw_uid
);
2301 /* "exec" promise will be limited to argv[0] via unveil(2). */
2302 if (pledge("stdio proc exec sendfd recvfd unveil", NULL
) == -1)
2308 if (pledge("stdio sendfd unix unveil", NULL
) == -1)
2312 * Ensure that AF_UNIX bind(2) cannot be used with any other
2313 * sockets by revoking all filesystem access via unveil(2).
2315 apply_unveil_none();
2317 enter_chroot(GOTD_EMPTY_PATH
);
2320 listen_main(title
, fd
, gotd
.connection_limits
,
2321 gotd
.nconnection_limits
);
2326 if (pledge("stdio getpw recvfd unix unveil", NULL
) == -1)
2330 * We need the "unix" pledge promise for getpeername(2) only.
2331 * Ensure that AF_UNIX bind(2) cannot be used by revoking all
2332 * filesystem access via unveil(2). Access to password database
2333 * files will still work since "getpw" bypasses unveil(2).
2335 apply_unveil_none();
2339 auth_main(title
, &gotd
.repos
, repo_path
);
2342 case PROC_SESSION_READ
:
2343 case PROC_SESSION_WRITE
:
2346 * The "recvfd" promise is only needed during setup and
2347 * will be removed in a later pledge(2) call.
2349 if (pledge("stdio rpath wpath cpath recvfd sendfd fattr flock "
2350 "unveil", NULL
) == -1)
2353 if (proc_id
== PROC_SESSION_READ
)
2354 apply_unveil_repo_readonly(repo_path
, 1);
2356 apply_unveil_repo_readwrite(repo_path
);
2357 repo
= gotd_find_repo_by_path(repo_path
, &gotd
);
2359 fatalx("no repository for path %s", repo_path
);
2364 if (proc_id
== PROC_SESSION_READ
)
2365 session_read_main(title
, repo_path
, pack_fds
, temp_fds
,
2366 &gotd
.request_timeout
, repo
);
2368 session_write_main(title
, repo_path
, pack_fds
, temp_fds
,
2369 &gotd
.request_timeout
, repo
);
2372 case PROC_REPO_READ
:
2375 if (pledge("stdio rpath recvfd unveil", NULL
) == -1)
2378 apply_unveil_repo_readonly(repo_path
, 0);
2380 if (enter_chroot(repo_path
)) {
2381 log_info("change repo path %s", repo_path
);
2383 repo_path
= strdup("/");
2384 if (repo_path
== NULL
)
2386 log_info("repo path is now %s", repo_path
);
2390 repo_read_main(title
, repo_path
, pack_fds
, temp_fds
);
2393 case PROC_REPO_WRITE
:
2396 diff_f1
= got_opentemp();
2397 if (diff_f1
== NULL
)
2398 fatal("got_opentemp");
2399 diff_f2
= got_opentemp();
2400 if (diff_f2
== NULL
)
2401 fatal("got_opentemp");
2402 diff_fd1
= got_opentempfd();
2404 fatal("got_opentempfd");
2405 diff_fd2
= got_opentempfd();
2407 fatal("got_opentempfd");
2409 if (pledge("stdio rpath recvfd unveil", NULL
) == -1)
2412 apply_unveil_repo_readonly(repo_path
, 0);
2413 repo
= gotd_find_repo_by_path(repo_path
, &gotd
);
2415 fatalx("no repository for path %s", repo_path
);
2417 if (enter_chroot(repo_path
)) {
2419 repo_path
= strdup("/");
2420 if (repo_path
== NULL
)
2425 repo_write_main(title
, repo_path
, pack_fds
, temp_fds
,
2426 diff_f1
, diff_f2
, diff_fd1
, diff_fd2
,
2427 &repo
->protected_tag_namespaces
,
2428 &repo
->protected_branch_namespaces
,
2429 &repo
->protected_branches
);
2434 if (pledge("stdio proc exec recvfd unveil", NULL
) == -1)
2438 * Limit "exec" promise to notification helpers via unveil(2).
2440 unveil_notification_helpers();
2444 notify_main(title
, &gotd
.repos
, default_sender
);
2448 fatal("invalid process id %d", proc_id
);
2451 if (proc_id
!= PROC_GOTD
)
2452 fatal("invalid process id %d", proc_id
);
2454 evtimer_set(&gotd
.listen_proc
->tmo
, kill_proc_timeout
,
2456 if (gotd
.notify_proc
) {
2457 evtimer_set(&gotd
.notify_proc
->tmo
, kill_proc_timeout
,
2461 apply_unveil_selfexec();
2463 signal_set(&evsigint
, SIGINT
, gotd_sighdlr
, NULL
);
2464 signal_set(&evsigterm
, SIGTERM
, gotd_sighdlr
, NULL
);
2465 signal_set(&evsighup
, SIGHUP
, gotd_sighdlr
, NULL
);
2466 signal_set(&evsigusr1
, SIGUSR1
, gotd_sighdlr
, NULL
);
2467 signal_set(&evsigchld
, SIGCHLD
, gotd_sighdlr
, NULL
);
2468 signal(SIGPIPE
, SIG_IGN
);
2470 signal_add(&evsigint
, NULL
);
2471 signal_add(&evsigterm
, NULL
);
2472 signal_add(&evsighup
, NULL
);
2473 signal_add(&evsigusr1
, NULL
);
2474 signal_add(&evsigchld
, NULL
);
2476 gotd_imsg_event_add(&gotd
.listen_proc
->iev
);
2477 if (gotd
.notify_proc
) {
2478 struct imsgbuf
*imsgbuf
= &gotd
.notify_proc
->iev
.ibuf
;
2479 struct gotd_secret
*s
;
2482 gotd_imsg_event_add(&gotd
.notify_proc
->iev
);
2485 n
= gotd
.secrets
->len
;
2487 if (imsg_compose(imsgbuf
, GOTD_IMSG_SECRETS
, 0, 0, -1,
2488 &n
, sizeof(n
)) == -1)
2489 fatal("imsg_compose GOTD_IMSG_SECRETS");
2490 error
= gotd_imsg_flush(imsgbuf
);
2492 fatalx("%s", error
->msg
);
2494 for (i
= 0; i
< n
; ++i
) {
2495 struct iovec iov
[5];
2497 s
= &gotd
.secrets
->secrets
[i
];
2499 iov
[0].iov_base
= &s
->type
;
2500 iov
[0].iov_len
= sizeof(s
->type
);
2502 iov
[1].iov_base
= s
->label
;
2503 iov
[1].iov_len
= strlen(s
->label
) + 1;
2505 iov
[2].iov_base
= s
->user
;
2506 iov
[2].iov_len
= s
->user
? strlen(s
->user
) + 1 : 0 ;
2508 iov
[3].iov_base
= s
->pass
;
2509 iov
[3].iov_len
= s
->pass
? strlen(s
->pass
) + 1 : 0 ;
2511 iov
[4].iov_base
= s
->hmac
;
2512 iov
[4].iov_len
= s
->hmac
? strlen(s
->hmac
) + 1 : 0 ;
2514 if (imsg_composev(imsgbuf
, GOTD_IMSG_SECRET
,
2515 0, 0, -1, iov
, 5) == -1)
2516 fatal("imsg_composev GOTD_IMSG_SECRET");
2517 error
= gotd_imsg_flush(imsgbuf
);
2519 fatalx("%s", error
->msg
);
2522 gotd_secrets_free(gotd
.secrets
);
2523 gotd
.secrets
= NULL
;
2530 free(default_sender
);