Blob


1 /*
2 * Copyright (c) 2020-2021 Tracey Emery <tracey@traceyemery.net>
3 * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
4 *
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.
8 *
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.
16 */
18 #include <sys/types.h>
19 #include <sys/queue.h>
20 #include <sys/time.h>
21 #include <sys/uio.h>
22 #include <sys/socket.h>
24 #include <net/if.h>
25 #include <netinet/in.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <termios.h>
30 #include <unistd.h>
31 #include <limits.h>
32 #include <string.h>
33 #include <event.h>
34 #include <fcntl.h>
35 #include <util.h>
36 #include <errno.h>
37 #include <imsg.h>
39 #include "got_opentemp.h"
40 #include "got_reference.h"
42 #include "proc.h"
43 #include "gotwebd.h"
45 int
46 config_init(struct gotwebd *env)
47 {
48 struct privsep *ps = env->gotwebd_ps;
49 unsigned int what;
51 /* Global configuration. */
52 if (privsep_process == PROC_GOTWEBD)
53 env->prefork_gotwebd = GOTWEBD_NUMPROC;
55 ps->ps_what[PROC_GOTWEBD] = CONFIG_ALL;
56 ps->ps_what[PROC_SOCKS] = CONFIG_SOCKS;
58 /* Other configuration. */
59 what = ps->ps_what[privsep_process];
60 if (what & CONFIG_SOCKS) {
61 env->server_cnt = 0;
62 TAILQ_INIT(&env->servers);
63 TAILQ_INIT(&env->sockets);
64 }
65 return 0;
66 }
68 int
69 config_getcfg(struct gotwebd *env, struct imsg *imsg)
70 {
71 /* nothing to do but tell gotwebd configuration is done */
72 if (privsep_process != PROC_GOTWEBD)
73 proc_compose(env->gotwebd_ps, PROC_GOTWEBD,
74 IMSG_CFG_DONE, NULL, 0);
76 return 0;
77 }
79 int
80 config_setserver(struct gotwebd *env, struct server *srv)
81 {
82 struct server ssrv;
83 struct privsep *ps = env->gotwebd_ps;
85 memcpy(&ssrv, srv, sizeof(ssrv));
86 if (proc_compose(ps, PROC_SOCKS, IMSG_CFG_SRV, &ssrv, sizeof(ssrv))
87 == -1)
88 fatal("proc_compose");
89 return 0;
90 }
92 int
93 config_getserver(struct gotwebd *env, struct imsg *imsg)
94 {
95 struct server *srv;
96 uint8_t *p = imsg->data;
98 IMSG_SIZE_CHECK(imsg, &srv);
100 srv = calloc(1, sizeof(*srv));
101 if (srv == NULL)
102 fatalx("%s: calloc", __func__);
104 if (IMSG_DATA_SIZE(imsg) != sizeof(*srv)) {
105 log_debug("%s: imsg size error", __func__);
106 free(srv);
107 return 1;
110 memcpy(srv, p, sizeof(*srv));
111 srv->cached_repos = calloc(GOTWEBD_REPO_CACHESIZE,
112 sizeof(*srv->cached_repos));
113 if (srv->cached_repos == NULL)
114 fatal("%s: calloc", __func__);
115 srv->ncached_repos = 0;
117 /* log server info */
118 log_debug("%s: server=%s fcgi_socket=%s unix_socket=%s", __func__,
119 srv->name, srv->fcgi_socket ? "yes" : "no", srv->unix_socket ?
120 "yes" : "no");
122 TAILQ_INSERT_TAIL(&env->servers, srv, entry);
124 return 0;
127 int
128 config_setsock(struct gotwebd *env, struct socket *sock)
130 struct privsep *ps = env->gotwebd_ps;
131 struct socket_conf s;
132 int id;
133 int fd = -1, n, m;
134 struct iovec iov[6];
135 size_t c;
136 unsigned int what;
138 /* open listening sockets */
139 if (sockets_privinit(env, sock) == -1)
140 return -1;
142 for (id = 0; id < PROC_MAX; id++) {
143 what = ps->ps_what[id];
145 if ((what & CONFIG_SOCKS) == 0 || id == privsep_process)
146 continue;
148 memcpy(&s, &sock->conf, sizeof(s));
150 c = 0;
151 iov[c].iov_base = &s;
152 iov[c++].iov_len = sizeof(s);
154 if (id == PROC_SOCKS) {
155 /* XXX imsg code will close the fd after 1st call */
156 n = -1;
157 proc_range(ps, id, &n, &m);
158 for (n = 0; n < m; n++) {
159 if (sock->fd == -1)
160 fd = -1;
161 else if ((fd = dup(sock->fd)) == -1)
162 return 1;
163 if (proc_composev_imsg(ps, id, n, IMSG_CFG_SOCK,
164 -1, fd, iov, c) != 0) {
165 log_warn("%s: failed to compose "
166 "IMSG_CFG_SOCK imsg",
167 __func__);
168 return 1;
170 if (proc_flush_imsg(ps, id, n) == -1) {
171 log_warn("%s: failed to flush "
172 "IMSG_CFG_SOCK imsg",
173 __func__);
174 return 1;
180 /* Close socket early to prevent fd exhaustion in gotwebd. */
181 if (sock->fd != -1) {
182 close(sock->fd);
183 sock->fd = -1;
186 return 0;
189 int
190 config_getsock(struct gotwebd *env, struct imsg *imsg)
192 struct socket *sock = NULL;
193 struct socket_conf sock_conf;
194 uint8_t *p = imsg->data;
195 int i;
197 IMSG_SIZE_CHECK(imsg, &sock_conf);
198 memcpy(&sock_conf, p, sizeof(sock_conf));
200 if (IMSG_DATA_SIZE(imsg) != sizeof(sock_conf)) {
201 log_debug("%s: imsg size error", __func__);
202 return 1;
205 /* create a new socket */
206 if ((sock = calloc(1, sizeof(*sock))) == NULL) {
207 if (imsg->fd != -1)
208 close(imsg->fd);
209 return 1;
212 memcpy(&sock->conf, &sock_conf, sizeof(sock->conf));
213 sock->fd = imsg->fd;
215 TAILQ_INSERT_TAIL(&env->sockets, sock, entry);
217 for (i = 0; i < PRIV_FDS__MAX; i++)
218 sock->priv_fd[i] = -1;
220 for (i = 0; i < GOTWEB_PACK_NUM_TEMPFILES; i++)
221 sock->pack_fds[i] = -1;
223 /* log new socket info */
224 log_debug("%s: name=%s id=%d server=%s af_type=%s socket_path=%s",
225 __func__, sock->conf.name, sock->conf.id, sock->conf.srv_name,
226 sock->conf.af_type == AF_UNIX ? "unix" :
227 (sock->conf.af_type == AF_INET ? "inet" :
228 (sock->conf.af_type == AF_INET6 ? "inet6" : "unknown")),
229 strlen(sock->conf.unix_socket_name) ?
230 sock->conf.unix_socket_name : "none");
232 return 0;
235 int
236 config_setfd(struct gotwebd *env, struct socket *sock)
238 struct privsep *ps = env->gotwebd_ps;
239 int id, s;
240 int fd = -1, n, m, j;
241 struct iovec iov[6];
242 size_t c;
243 unsigned int what;
245 log_debug("%s: Allocating %d file descriptors",
246 __func__, PRIV_FDS__MAX + GOTWEB_PACK_NUM_TEMPFILES);
248 for (j = 0; j < PRIV_FDS__MAX + GOTWEB_PACK_NUM_TEMPFILES; j++) {
249 for (id = 0; id < PROC_MAX; id++) {
250 what = ps->ps_what[id];
252 if ((what & CONFIG_SOCKS) == 0 || id == privsep_process)
253 continue;
255 s = sock->conf.id;
256 c = 0;
257 iov[c].iov_base = &s;
258 iov[c++].iov_len = sizeof(s);
260 if (id == PROC_SOCKS) {
261 /*
262 * XXX imsg code will close the fd
263 * after 1st call
264 */
265 n = -1;
266 proc_range(ps, id, &n, &m);
267 for (n = 0; n < m; n++) {
268 fd = got_opentempfd();
269 if (fd == -1)
270 return 1;
271 if (proc_composev_imsg(ps, id, n,
272 IMSG_CFG_FD, -1, fd, iov, c) != 0) {
273 log_warn("%s: failed to compose "
274 "IMSG_CFG_FD imsg",
275 __func__);
276 return 1;
278 if (proc_flush_imsg(ps, id, n) == -1) {
279 log_warn("%s: failed to flush "
280 "IMSG_CFG_FD imsg",
281 __func__);
282 return 1;
288 /* Close fd early to prevent fd exhaustion in gotwebd. */
289 if (fd != -1)
290 close(fd);
292 return 0;
295 int
296 config_getfd(struct gotwebd *env, struct imsg *imsg)
298 struct socket *sock;
299 uint8_t *p = imsg->data;
300 int sock_id, match = 0, i;
302 IMSG_SIZE_CHECK(imsg, &sock_id);
303 memcpy(&sock_id, p, sizeof(sock_id));
305 TAILQ_FOREACH(sock, &env->sockets, entry) {
306 const int nfds = (GOTWEB_PACK_NUM_TEMPFILES + PRIV_FDS__MAX);
307 for (i = 0; i < nfds; i++) {
308 if (i < PRIV_FDS__MAX && sock->priv_fd[i] == -1) {
309 log_debug("%s: assigning socket %d priv_fd %d",
310 __func__, sock_id, imsg->fd);
311 sock->priv_fd[i] = imsg->fd;
312 match = 1;
313 break;
315 if (sock->pack_fds[i - PRIV_FDS__MAX] == -1) {
316 log_debug("%s: assigning socket %d pack_fd %d",
317 __func__, sock_id, imsg->fd);
318 sock->pack_fds[i - PRIV_FDS__MAX] = imsg->fd;
319 match = 1;
320 break;
325 if (match)
326 return 0;
327 else
328 return 1;