2 * Copyright (c) 2020-2021 Tracey Emery <tracey@traceyemery.net>
3 * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <sys/types.h>
19 #include <sys/queue.h>
22 #include <sys/socket.h>
25 #include <netinet/in.h>
37 #include "got_opentemp.h"
38 #include "got_reference.h"
40 #include "got_compat.h"
46 config_init(struct gotwebd *env)
48 struct privsep *ps = env->gotwebd_ps;
51 strlcpy(env->httpd_chroot, D_HTTPD_CHROOT, sizeof(env->httpd_chroot));
53 /* Global configuration. */
54 if (privsep_process == PROC_GOTWEBD)
55 env->prefork_gotwebd = GOTWEBD_NUMPROC;
57 ps->ps_what[PROC_GOTWEBD] = CONFIG_ALL;
58 ps->ps_what[PROC_SOCKS] = CONFIG_SOCKS;
60 /* Other configuration. */
61 what = ps->ps_what[privsep_process];
62 if (what & CONFIG_SOCKS) {
64 TAILQ_INIT(&env->servers);
65 TAILQ_INIT(&env->sockets);
71 config_getcfg(struct gotwebd *env, struct imsg *imsg)
73 /* nothing to do but tell gotwebd configuration is done */
74 if (privsep_process != PROC_GOTWEBD)
75 proc_compose(env->gotwebd_ps, PROC_GOTWEBD,
76 IMSG_CFG_DONE, NULL, 0);
82 config_setserver(struct gotwebd *env, struct server *srv)
85 struct privsep *ps = env->gotwebd_ps;
87 memcpy(&ssrv, srv, sizeof(ssrv));
88 if (proc_compose(ps, PROC_SOCKS, IMSG_CFG_SRV, &ssrv, sizeof(ssrv))
90 fatal("proc_compose");
95 config_getserver(struct gotwebd *env, struct imsg *imsg)
98 uint8_t *p = imsg->data;
100 IMSG_SIZE_CHECK(imsg, &srv);
102 srv = calloc(1, sizeof(*srv));
104 fatalx("%s: calloc", __func__);
106 if (IMSG_DATA_SIZE(imsg) != sizeof(*srv)) {
107 log_debug("%s: imsg size error", __func__);
112 memcpy(srv, p, sizeof(*srv));
113 srv->cached_repos = calloc(GOTWEBD_REPO_CACHESIZE,
114 sizeof(*srv->cached_repos));
115 if (srv->cached_repos == NULL)
116 fatal("%s: calloc", __func__);
117 srv->ncached_repos = 0;
119 /* log server info */
120 log_debug("%s: server=%s fcgi_socket=%s unix_socket=%s", __func__,
121 srv->name, srv->fcgi_socket ? "yes" : "no", srv->unix_socket ?
124 TAILQ_INSERT_TAIL(&env->servers, srv, entry);
130 config_setsock(struct gotwebd *env, struct socket *sock)
132 struct privsep *ps = env->gotwebd_ps;
133 struct socket_conf s;
140 /* open listening sockets */
141 if (sockets_privinit(env, sock) == -1)
144 for (id = 0; id < PROC_MAX; id++) {
145 what = ps->ps_what[id];
147 if ((what & CONFIG_SOCKS) == 0 || id == privsep_process)
150 memcpy(&s, &sock->conf, sizeof(s));
153 iov[c].iov_base = &s;
154 iov[c++].iov_len = sizeof(s);
156 if (id == PROC_SOCKS) {
157 /* XXX imsg code will close the fd after 1st call */
159 proc_range(ps, id, &n, &m);
160 for (n = 0; n < m; n++) {
163 else if ((fd = dup(sock->fd)) == -1)
165 if (proc_composev_imsg(ps, id, n, IMSG_CFG_SOCK,
166 -1, fd, iov, c) != 0) {
167 log_warn("%s: failed to compose "
168 "IMSG_CFG_SOCK imsg",
172 if (proc_flush_imsg(ps, id, n) == -1) {
173 log_warn("%s: failed to flush "
174 "IMSG_CFG_SOCK imsg",
182 /* Close socket early to prevent fd exhaustion in gotwebd. */
183 if (sock->fd != -1) {
192 config_getsock(struct gotwebd *env, struct imsg *imsg)
194 struct socket *sock = NULL;
195 struct socket_conf sock_conf;
196 uint8_t *p = imsg->data;
199 IMSG_SIZE_CHECK(imsg, &sock_conf);
200 memcpy(&sock_conf, p, sizeof(sock_conf));
202 if (IMSG_DATA_SIZE(imsg) != sizeof(sock_conf)) {
203 log_debug("%s: imsg size error", __func__);
207 /* create a new socket */
208 if ((sock = calloc(1, sizeof(*sock))) == NULL) {
214 memcpy(&sock->conf, &sock_conf, sizeof(sock->conf));
217 TAILQ_INSERT_TAIL(&env->sockets, sock, entry);
219 for (i = 0; i < PRIV_FDS__MAX; i++)
220 sock->priv_fd[i] = -1;
222 for (i = 0; i < GOTWEB_PACK_NUM_TEMPFILES; i++)
223 sock->pack_fds[i] = -1;
225 /* log new socket info */
226 log_debug("%s: name=%s id=%d server=%s af_type=%s socket_path=%s",
227 __func__, sock->conf.name, sock->conf.id, sock->conf.srv_name,
228 sock->conf.af_type == AF_UNIX ? "unix" :
229 (sock->conf.af_type == AF_INET ? "inet" :
230 (sock->conf.af_type == AF_INET6 ? "inet6" : "unknown")),
231 *sock->conf.unix_socket_name != '\0' ?
232 sock->conf.unix_socket_name : "none");
238 config_setfd(struct gotwebd *env, struct socket *sock)
240 struct privsep *ps = env->gotwebd_ps;
242 int fd = -1, n, m, j;
247 log_debug("%s: Allocating %d file descriptors",
248 __func__, PRIV_FDS__MAX + GOTWEB_PACK_NUM_TEMPFILES);
250 for (j = 0; j < PRIV_FDS__MAX + GOTWEB_PACK_NUM_TEMPFILES; j++) {
251 for (id = 0; id < PROC_MAX; id++) {
252 what = ps->ps_what[id];
254 if ((what & CONFIG_SOCKS) == 0 || id == privsep_process)
259 iov[c].iov_base = &s;
260 iov[c++].iov_len = sizeof(s);
262 if (id == PROC_SOCKS) {
264 * XXX imsg code will close the fd
268 proc_range(ps, id, &n, &m);
269 for (n = 0; n < m; n++) {
270 fd = got_opentempfd();
273 if (proc_composev_imsg(ps, id, n,
274 IMSG_CFG_FD, -1, fd, iov, c) != 0) {
275 log_warn("%s: failed to compose "
280 if (proc_flush_imsg(ps, id, n) == -1) {
281 log_warn("%s: failed to flush "
290 /* Close fd early to prevent fd exhaustion in gotwebd. */
298 config_getfd(struct gotwebd *env, struct imsg *imsg)
301 uint8_t *p = imsg->data;
302 int sock_id, match = 0, i;
304 IMSG_SIZE_CHECK(imsg, &sock_id);
305 memcpy(&sock_id, p, sizeof(sock_id));
307 TAILQ_FOREACH(sock, &env->sockets, entry) {
308 const int nfds = (GOTWEB_PACK_NUM_TEMPFILES + PRIV_FDS__MAX);
309 for (i = 0; i < nfds; i++) {
310 if (i < PRIV_FDS__MAX && sock->priv_fd[i] == -1) {
311 log_debug("%s: assigning socket %d priv_fd %d",
312 __func__, sock_id, imsg->fd);
313 sock->priv_fd[i] = imsg->fd;
317 if (sock->pack_fds[i - PRIV_FDS__MAX] == -1) {
318 log_debug("%s: assigning socket %d pack_fd %d",
319 __func__, sock_id, imsg->fd);
320 sock->pack_fds[i - PRIV_FDS__MAX] = imsg->fd;