2 * Copyright (c) 2016, 2019, 2020-2021 Tracey Emery <tracey@traceyemery.net>
3 * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
4 * Copyright (c) 2013 David Gwynne <dlg@openbsd.org>
5 * Copyright (c) 2013 Florian Obser <florian@openbsd.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include "got_compat.h"
22 #include <sys/param.h>
23 #include <sys/ioctl.h>
24 #include <sys/queue.h>
27 #include <sys/resource.h>
28 #include <sys/socket.h>
31 #include <sys/types.h>
36 #include <netinet/in.h>
52 #include "got_error.h"
53 #include "got_opentemp.h"
54 #include "got_reference.h"
55 #include "got_repository.h"
56 #include "got_privsep.h"
62 #define SOCKS_BACKLOG 5
63 #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
65 volatile int client_cnt
;
67 static struct timeval timeout
= { TIMEOUT_DEFAULT
, 0 };
69 static void sockets_sighdlr(int, short, void *);
70 static void sockets_shutdown(void);
71 static void sockets_launch(void);
72 static void sockets_accept_paused(int, short, void *);
73 static void sockets_rlimit(int);
75 static void sockets_dispatch_main(int, short, void *);
76 static int sockets_unix_socket_listen(struct gotwebd
*, struct socket
*);
77 static int sockets_create_socket(struct address
*);
78 static int sockets_accept_reserve(int, struct sockaddr
*, socklen_t
*,
81 static struct socket
*sockets_conf_new_socket(struct gotwebd
*,
82 int, struct address
*);
87 sockets(struct gotwebd
*env
, int fd
)
89 struct event sighup
, sigint
, sigusr1
, sigchld
, sigterm
;
90 struct event_base
*evb
;
96 if ((env
->iev_parent
= malloc(sizeof(*env
->iev_parent
))) == NULL
)
98 if (imsgbuf_init(&env
->iev_parent
->ibuf
, fd
) == -1)
99 fatal("imsgbuf_init");
100 imsgbuf_allow_fdpass(&env
->iev_parent
->ibuf
);
101 env
->iev_parent
->handler
= sockets_dispatch_main
;
102 env
->iev_parent
->data
= env
->iev_parent
;
103 event_set(&env
->iev_parent
->ev
, fd
, EV_READ
, sockets_dispatch_main
,
105 event_add(&env
->iev_parent
->ev
, NULL
);
107 signal(SIGPIPE
, SIG_IGN
);
109 signal_set(&sighup
, SIGHUP
, sockets_sighdlr
, env
);
110 signal_add(&sighup
, NULL
);
111 signal_set(&sigint
, SIGINT
, sockets_sighdlr
, env
);
112 signal_add(&sigint
, NULL
);
113 signal_set(&sigusr1
, SIGUSR1
, sockets_sighdlr
, env
);
114 signal_add(&sigusr1
, NULL
);
115 signal_set(&sigchld
, SIGCHLD
, sockets_sighdlr
, env
);
116 signal_add(&sigchld
, NULL
);
117 signal_set(&sigterm
, SIGTERM
, sockets_sighdlr
, env
);
118 signal_add(&sigterm
, NULL
);
121 if (pledge("stdio rpath inet recvfd proc exec sendfd unveil",
127 event_base_free(evb
);
132 sockets_parse_sockets(struct gotwebd
*env
)
135 struct socket
*new_sock
= NULL
;
138 TAILQ_FOREACH(a
, &env
->addresses
, entry
) {
139 new_sock
= sockets_conf_new_socket(env
, sock_id
, a
);
142 TAILQ_INSERT_TAIL(&env
->sockets
,
148 static struct socket
*
149 sockets_conf_new_socket(struct gotwebd
*env
, int id
, struct address
*a
)
154 if ((sock
= calloc(1, sizeof(*sock
))) == NULL
)
155 fatalx("%s: calloc", __func__
);
159 sock
->conf
.af_type
= a
->ss
.ss_family
;
161 if (a
->ss
.ss_family
== AF_UNIX
) {
162 struct sockaddr_un
*sun
;
164 sun
= (struct sockaddr_un
*)&a
->ss
;
165 if (strlcpy(sock
->conf
.unix_socket_name
, sun
->sun_path
,
166 sizeof(sock
->conf
.unix_socket_name
)) >=
167 sizeof(sock
->conf
.unix_socket_name
))
168 fatalx("unix socket path too long: %s", sun
->sun_path
);
171 sock
->conf
.fcgi_socket_port
= a
->port
;
173 acp
= &sock
->conf
.addr
;
175 memcpy(&acp
->ss
, &a
->ss
, sizeof(acp
->ss
));
177 acp
->ai_family
= a
->ai_family
;
178 acp
->ai_socktype
= a
->ai_socktype
;
179 acp
->ai_protocol
= a
->ai_protocol
;
181 if (*a
->ifname
!= '\0') {
182 if (strlcpy(acp
->ifname
, a
->ifname
,
183 sizeof(acp
->ifname
)) >= sizeof(acp
->ifname
)) {
184 fatalx("%s: interface name truncated",
197 const struct got_error
*error
;
199 TAILQ_FOREACH(sock
, &gotwebd_env
->sockets
, entry
) {
200 log_info("%s: configuring socket %d (%d)", __func__
,
201 sock
->conf
.id
, sock
->fd
);
203 event_set(&sock
->ev
, sock
->fd
, EV_READ
| EV_PERSIST
,
204 sockets_socket_accept
, sock
);
206 if (event_add(&sock
->ev
, NULL
))
207 fatalx("event add sock");
209 evtimer_set(&sock
->pause
, sockets_accept_paused
, sock
);
211 log_info("%s: running socket listener %d", __func__
,
215 TAILQ_FOREACH(srv
, &gotwebd_env
->servers
, entry
) {
216 if (unveil(srv
->repos_path
, "r") == -1)
217 fatal("unveil %s", srv
->repos_path
);
220 error
= got_privsep_unveil_exec_helpers();
222 fatal("%s", error
->msg
);
224 if (unveil(NULL
, NULL
) == -1)
229 sockets_purge(struct gotwebd
*env
)
231 struct socket
*sock
, *tsock
;
233 /* shutdown and remove sockets */
234 TAILQ_FOREACH_SAFE(sock
, &env
->sockets
, entry
, tsock
) {
235 if (event_initialized(&sock
->ev
))
236 event_del(&sock
->ev
);
237 if (evtimer_initialized(&sock
->evt
))
238 evtimer_del(&sock
->evt
);
239 if (evtimer_initialized(&sock
->pause
))
240 evtimer_del(&sock
->pause
);
243 TAILQ_REMOVE(&env
->sockets
, sock
, entry
);
249 sockets_dispatch_main(int fd
, short event
, void *arg
)
251 struct imsgev
*iev
= arg
;
252 struct imsgbuf
*ibuf
;
254 struct gotwebd
*env
= gotwebd_env
;
260 if (event
& EV_READ
) {
261 if ((n
= imsgbuf_read(ibuf
)) == -1)
262 fatal("imsgbuf_read error");
263 if (n
== 0) /* Connection closed */
266 if (event
& EV_WRITE
) {
267 if (imsgbuf_write(ibuf
) == -1)
268 fatal("imsgbuf_write");
272 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
274 if (n
== 0) /* No more messages. */
277 switch (imsg
.hdr
.type
) {
279 config_getserver(env
, &imsg
);
282 config_getsock(env
, &imsg
);
285 config_getfd(env
, &imsg
);
288 config_getcfg(env
, &imsg
);
294 fatalx("%s: unknown imsg type %d", __func__
,
304 /* This pipe is dead. Remove its event handler */
306 event_loopexit(NULL
);
311 sockets_sighdlr(int sig
, short event
, void *arg
)
315 log_info("%s: ignoring SIGHUP", __func__
);
318 log_info("%s: ignoring SIGPIPE", __func__
);
321 log_info("%s: ignoring SIGUSR1", __func__
);
330 log_info("SIGNAL: %d", sig
);
331 fatalx("unexpected signal");
336 sockets_shutdown(void)
338 sockets_purge(gotwebd_env
);
341 while (!TAILQ_EMPTY(&gotwebd_env
->servers
)) {
344 srv
= TAILQ_FIRST(&gotwebd_env
->servers
);
345 TAILQ_REMOVE(&gotwebd_env
->servers
, srv
, entry
);
349 while (!TAILQ_EMPTY(&gotwebd_env
->addresses
)) {
352 h
= TAILQ_FIRST(&gotwebd_env
->addresses
);
353 TAILQ_REMOVE(&gotwebd_env
->addresses
, h
, entry
);
357 imsgbuf_clear(&gotwebd_env
->iev_parent
->ibuf
);
358 free(gotwebd_env
->iev_parent
);
365 sockets_privinit(struct gotwebd
*env
, struct socket
*sock
)
367 if (sock
->conf
.af_type
== AF_UNIX
) {
368 log_info("%s: initializing unix socket %s", __func__
,
369 sock
->conf
.unix_socket_name
);
370 sock
->fd
= sockets_unix_socket_listen(env
, sock
);
375 if (sock
->conf
.af_type
== AF_INET
|| sock
->conf
.af_type
== AF_INET6
) {
376 log_info("%s: initializing %s FCGI socket on port %d",
377 __func__
, sock
->conf
.af_type
== AF_INET
? "inet" : "inet6",
378 sock
->conf
.fcgi_socket_port
);
379 sock
->fd
= sockets_create_socket(&sock
->conf
.addr
);
388 sockets_unix_socket_listen(struct gotwebd
*env
, struct socket
*sock
)
391 mode_t old_umask
, mode
;
392 int flags
= SOCK_STREAM
| SOCK_NONBLOCK
;
395 flags
|= SOCK_CLOEXEC
;
398 u_fd
= socket(AF_UNIX
, flags
, 0);
400 log_warn("%s: socket", __func__
);
404 if (unlink(sock
->conf
.unix_socket_name
) == -1) {
405 if (errno
!= ENOENT
) {
406 log_warn("%s: unlink %s", __func__
,
407 sock
->conf
.unix_socket_name
);
413 old_umask
= umask(S_IXUSR
|S_IXGRP
|S_IWOTH
|S_IROTH
|S_IXOTH
);
414 mode
= S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
;
416 if (bind(u_fd
, (struct sockaddr
*)&sock
->conf
.addr
.ss
,
417 sock
->conf
.addr
.slen
) == -1) {
418 log_warn("%s: bind: %s", __func__
, sock
->conf
.unix_socket_name
);
420 (void)umask(old_umask
);
424 (void)umask(old_umask
);
426 if (chmod(sock
->conf
.unix_socket_name
, mode
) == -1) {
427 log_warn("%s: chmod", __func__
);
429 (void)unlink(sock
->conf
.unix_socket_name
);
433 if (chown(sock
->conf
.unix_socket_name
, env
->pw
->pw_uid
,
434 env
->pw
->pw_gid
) == -1) {
435 log_warn("%s: chown", __func__
);
437 (void)unlink(sock
->conf
.unix_socket_name
);
441 if (listen(u_fd
, SOCKS_BACKLOG
) == -1) {
442 log_warn("%s: listen", __func__
);
450 sockets_create_socket(struct address
*a
)
452 int fd
= -1, o_val
= 1, flags
;
454 fd
= socket(a
->ai_family
, a
->ai_socktype
, a
->ai_protocol
);
458 log_debug("%s: opened socket (%d) for %s", __func__
,
461 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &o_val
,
462 sizeof(int)) == -1) {
463 log_warn("%s: setsockopt error", __func__
);
469 flags
= fcntl(fd
, F_GETFL
);
471 if (fcntl(fd
, F_SETFL
, flags
) == -1) {
472 log_warn("%s: could not enable non-blocking I/O", __func__
);
477 if (bind(fd
, (struct sockaddr
*)&a
->ss
, a
->slen
) == -1) {
479 log_warn("%s: can't bind to port %d", __func__
, a
->port
);
483 if (listen(fd
, SOMAXCONN
) == -1) {
484 log_warn("%s, unable to listen on socket", __func__
);
493 sockets_accept_reserve(int sockfd
, struct sockaddr
*addr
, socklen_t
*addrlen
,
494 int reserve
, volatile int *counter
)
498 if (getdtablecount() + reserve
+
499 ((*counter
+ 1) * FD_NEEDED
) >= getdtablesize()) {
500 log_warnx("inflight fds exceeded");
504 /* TA: This needs fixing upstream. */
506 ret
= accept(sockfd
, addr
, addrlen
);
508 ret
= accept4(sockfd
, addr
, addrlen
, SOCK_NONBLOCK
| SOCK_CLOEXEC
);
513 log_debug("inflight incremented, now %d", *counter
);
520 sockets_accept_paused(int fd
, short events
, void *arg
)
522 struct socket
*sock
= (struct socket
*)arg
;
524 event_add(&sock
->ev
, NULL
);
528 sockets_socket_accept(int fd
, short event
, void *arg
)
530 struct socket
*sock
= (struct socket
*)arg
;
531 struct sockaddr_storage ss
;
532 struct timeval backoff
;
533 struct request
*c
= NULL
;
540 event_add(&sock
->ev
, NULL
);
541 if (event
& EV_TIMEOUT
)
546 s
= sockets_accept_reserve(fd
, (struct sockaddr
*)&ss
, &len
,
547 FD_RESERVE
, &cgi_inflight
);
557 event_del(&sock
->ev
);
558 evtimer_add(&sock
->pause
, &backoff
);
561 log_warn("%s: accept", __func__
);
565 if (client_cnt
> GOTWEBD_MAXCLIENTS
)
568 c
= calloc(1, sizeof(struct request
));
570 log_warn("%s", __func__
);
576 c
->tp
= template(c
, &fcgi_write
, c
->outbuf
, sizeof(c
->outbuf
));
578 log_warn("%s", __func__
);
587 memcpy(c
->priv_fd
, gotwebd_env
->priv_fd
, sizeof(c
->priv_fd
));
590 c
->request_started
= 0;
591 c
->sock
->client_status
= CLIENT_CONNECT
;
593 event_set(&c
->ev
, s
, EV_READ
|EV_PERSIST
, fcgi_request
, c
);
594 event_add(&c
->ev
, NULL
);
596 evtimer_set(&c
->tmo
, fcgi_timeout
, c
);
597 evtimer_add(&c
->tmo
, &timeout
);
610 sockets_rlimit(int maxfd
)
614 if (getrlimit(RLIMIT_NOFILE
, &rl
) == -1)
615 fatal("%s: failed to get resource limit", __func__
);
616 log_info("%s: max open files %llu", __func__
,
617 (unsigned long long)rl
.rlim_max
);
620 * Allow the maximum number of open file descriptors for this
621 * login class (which should be the class "daemon" by default).
624 rl
.rlim_cur
= rl
.rlim_max
;
626 rl
.rlim_cur
= MAXIMUM(rl
.rlim_max
, (rlim_t
)maxfd
);
627 if (setrlimit(RLIMIT_NOFILE
, &rl
) == -1)
628 fatal("%s: failed to set resource limit", __func__
);