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 <errno.h>
37 #include "got_opentemp.h"
39 #include "got_compat.h"
41 #include "proc.h"
42 #include "gotwebd.h"
44 int
45 config_init(struct gotwebd *env)
46 {
47 struct privsep *ps = env->gotwebd_ps;
48 unsigned int what;
50 /* Global configuration. */
51 if (privsep_process == PROC_GOTWEBD)
52 env->prefork_gotwebd = GOTWEBD_NUMPROC;
54 ps->ps_what[PROC_GOTWEBD] = CONFIG_ALL;
55 ps->ps_what[PROC_SOCKS] = CONFIG_SOCKS;
57 /* Other configuration. */
58 what = ps->ps_what[privsep_process];
59 if (what & CONFIG_SOCKS) {
60 env->server_cnt = 0;
61 env->servers = calloc(1, sizeof(*env->servers));
62 if (env->servers == NULL)
63 fatalx("%s: calloc", __func__);
64 env->sockets = calloc(1, sizeof(*env->sockets));
65 if (env->sockets == NULL)
66 fatalx("%s: calloc", __func__);
67 TAILQ_INIT(env->servers);
68 TAILQ_INIT(env->sockets);
69 }
70 return 0;
71 }
73 int
74 config_getcfg(struct gotwebd *env, struct imsg *imsg)
75 {
76 /* nothing to do but tell gotwebd configuration is done */
77 if (privsep_process != PROC_GOTWEBD)
78 proc_compose(env->gotwebd_ps, PROC_GOTWEBD,
79 IMSG_CFG_DONE, NULL, 0);
81 return 0;
82 }
84 int
85 config_setserver(struct gotwebd *env, struct server *srv)
86 {
87 struct server ssrv;
88 struct privsep *ps = env->gotwebd_ps;
90 memcpy(&ssrv, srv, sizeof(ssrv));
91 proc_compose(ps, PROC_SOCKS, IMSG_CFG_SRV, &ssrv, sizeof(ssrv));
92 return 0;
93 }
95 int
96 config_getserver(struct gotwebd *env, struct imsg *imsg)
97 {
98 struct server *srv;
99 uint8_t *p = imsg->data;
101 IMSG_SIZE_CHECK(imsg, &srv);
103 srv = calloc(1, sizeof(*srv));
104 if (srv == NULL)
105 fatalx("%s: calloc", __func__);
106 memcpy(srv, p, sizeof(*srv));
108 if (IMSG_DATA_SIZE(imsg) != sizeof(*srv)) {
109 log_debug("%s: imsg size error", __func__);
110 free(srv);
111 return 1;
114 /* log server info */
115 log_debug("%s: server=%s fcgi_socket=%s unix_socket=%s", __func__,
116 srv->name, srv->fcgi_socket ? "yes" : "no", srv->unix_socket ?
117 "yes" : "no");
119 TAILQ_INSERT_TAIL(env->servers, srv, entry);
121 return 0;
124 int
125 config_setsock(struct gotwebd *env, struct socket *sock)
127 struct privsep *ps = env->gotwebd_ps;
128 struct socket_conf s;
129 int id;
130 int fd = -1, n, m;
131 struct iovec iov[6];
132 size_t c;
133 unsigned int what;
135 /* open listening sockets */
136 if (sockets_privinit(env, sock) == -1)
137 return -1;
139 for (id = 0; id < PROC_MAX; id++) {
140 what = ps->ps_what[id];
142 if ((what & CONFIG_SOCKS) == 0 || id == privsep_process)
143 continue;
145 memcpy(&s, &sock->conf, sizeof(s));
147 c = 0;
148 iov[c].iov_base = &s;
149 iov[c++].iov_len = sizeof(s);
151 if (id == PROC_SOCKS) {
152 /* XXX imsg code will close the fd after 1st call */
153 n = -1;
154 proc_range(ps, id, &n, &m);
155 for (n = 0; n < m; n++) {
156 if (sock->fd == -1)
157 fd = -1;
158 else if ((fd = dup(sock->fd)) == -1)
159 return 1;
160 if (proc_composev_imsg(ps, id, n, IMSG_CFG_SOCK,
161 -1, fd, iov, c) != 0) {
162 log_warn("%s: failed to compose "
163 "IMSG_CFG_SOCK imsg",
164 __func__);
165 return 1;
167 if (proc_flush_imsg(ps, id, n) == -1) {
168 log_warn("%s: failed to flush "
169 "IMSG_CFG_SOCK imsg",
170 __func__);
171 return 1;
177 /* Close socket early to prevent fd exhaustion in gotwebd. */
178 if (sock->fd != -1) {
179 close(sock->fd);
180 sock->fd = -1;
183 return 0;
186 int
187 config_getsock(struct gotwebd *env, struct imsg *imsg)
189 struct socket *sock = NULL;
190 struct socket_conf sock_conf;
191 uint8_t *p = imsg->data;
192 int i;
194 IMSG_SIZE_CHECK(imsg, &sock_conf);
195 memcpy(&sock_conf, p, sizeof(sock_conf));
197 if (IMSG_DATA_SIZE(imsg) != sizeof(sock_conf)) {
198 log_debug("%s: imsg size error", __func__);
199 return 1;
202 /* create a new socket */
203 if ((sock = calloc(1, sizeof(*sock))) == NULL) {
204 if (imsg->fd != -1)
205 close(imsg->fd);
206 return 1;
209 memcpy(&sock->conf, &sock_conf, sizeof(sock->conf));
210 sock->fd = imsg->fd;
212 TAILQ_INSERT_TAIL(env->sockets, sock, entry);
214 for (i = 0; i < PRIV_FDS__MAX; i++)
215 sock->priv_fd[i] = -1;
217 for (i = 0; i < GOTWEB_PACK_NUM_TEMPFILES; i++)
218 sock->pack_fds[i] = -1;
220 /* log new socket info */
221 log_debug("%s: name=%s id=%d server=%s child_id=%d parent_id=%d "
222 "type=%s ipv4=%d ipv6=%d socket_path=%s",
223 __func__, sock->conf.name, sock->conf.id, sock->conf.srv_name,
224 sock->conf.child_id, sock->conf.parent_id, sock->conf.type ?
225 "fcgi" : "unix", sock->conf.ipv4, sock->conf.ipv6,
226 strlen(sock->conf.unix_socket_name) ?
227 sock->conf.unix_socket_name : "none");
229 return 0;
232 int
233 config_setfd(struct gotwebd *env, struct socket *sock)
235 struct privsep *ps = env->gotwebd_ps;
236 int id, s;
237 int fd = -1, n, m, j;
238 struct iovec iov[6];
239 size_t c;
240 unsigned int what;
242 log_debug("%s: Allocating %d file descriptors",
243 __func__, PRIV_FDS__MAX + GOTWEB_PACK_NUM_TEMPFILES);
245 for (j = 0; j < PRIV_FDS__MAX + GOTWEB_PACK_NUM_TEMPFILES; j++) {
246 for (id = 0; id < PROC_MAX; id++) {
247 what = ps->ps_what[id];
249 if ((what & CONFIG_SOCKS) == 0 || id == privsep_process)
250 continue;
252 s = sock->conf.id;
253 c = 0;
254 iov[c].iov_base = &s;
255 iov[c++].iov_len = sizeof(s);
257 if (id == PROC_SOCKS) {
258 /*
259 * XXX imsg code will close the fd
260 * after 1st call
261 */
262 n = -1;
263 proc_range(ps, id, &n, &m);
264 for (n = 0; n < m; n++) {
265 fd = got_opentempfd();
266 if (fd == -1)
267 return 1;
268 if (proc_composev_imsg(ps, id, n,
269 IMSG_CFG_FD, -1, fd, iov, c) != 0) {
270 log_warn("%s: failed to compose "
271 "IMSG_CFG_FD imsg",
272 __func__);
273 return 1;
275 if (proc_flush_imsg(ps, id, n) == -1) {
276 log_warn("%s: failed to flush "
277 "IMSG_CFG_FD imsg",
278 __func__);
279 return 1;
285 /* Close fd early to prevent fd exhaustion in gotwebd. */
286 if (fd != -1)
287 close(fd);
289 return 0;
292 int
293 config_getfd(struct gotwebd *env, struct imsg *imsg)
295 struct socket *sock;
296 uint8_t *p = imsg->data;
297 int sock_id, match = 0, i;
299 IMSG_SIZE_CHECK(imsg, &sock_id);
300 memcpy(&sock_id, p, sizeof(sock_id));
302 TAILQ_FOREACH(sock, env->sockets, entry) {
303 const int nfds = (GOTWEB_PACK_NUM_TEMPFILES + PRIV_FDS__MAX);
304 for (i = 0; i < nfds; i++) {
305 if (i < PRIV_FDS__MAX && sock->priv_fd[i] == -1) {
306 log_debug("%s: assigning socket %d priv_fd %d",
307 __func__, sock_id, imsg->fd);
308 sock->priv_fd[i] = imsg->fd;
309 match = 1;
310 break;
312 if (sock->pack_fds[i - PRIV_FDS__MAX] == -1) {
313 log_debug("%s: assigning socket %d pack_fd %d",
314 __func__, sock_id, imsg->fd);
315 sock->pack_fds[i - PRIV_FDS__MAX] = imsg->fd;
316 match = 1;
317 break;
322 if (match)
323 return 0;
324 else
325 return 1;