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/time.h>
20 #include <sys/uio.h>
21 #include <sys/socket.h>
23 #include <net/if.h>
24 #include <netinet/in.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <termios.h>
29 #include <unistd.h>
30 #include <limits.h>
31 #include <string.h>
32 #include <event.h>
33 #include <fcntl.h>
34 #include <errno.h>
36 #include "got_opentemp.h"
38 #include "got_compat.h"
40 #include "proc.h"
41 #include "gotwebd.h"
43 int
44 config_init(struct gotwebd *env)
45 {
46 struct privsep *ps = env->gotwebd_ps;
47 unsigned int what;
49 /* Global configuration. */
50 if (privsep_process == PROC_GOTWEBD)
51 env->prefork_gotwebd = GOTWEBD_NUMPROC;
53 ps->ps_what[PROC_GOTWEBD] = CONFIG_ALL;
54 ps->ps_what[PROC_SOCKS] = CONFIG_SOCKS;
56 /* Other configuration. */
57 what = ps->ps_what[privsep_process];
58 if (what & CONFIG_SOCKS) {
59 env->server_cnt = 0;
60 env->servers = calloc(1, sizeof(*env->servers));
61 if (env->servers == NULL)
62 fatalx("%s: calloc", __func__);
63 env->sockets = calloc(1, sizeof(*env->sockets));
64 if (env->sockets == NULL)
65 fatalx("%s: calloc", __func__);
66 TAILQ_INIT(env->servers);
67 TAILQ_INIT(env->sockets);
68 }
69 return 0;
70 }
72 int
73 config_getcfg(struct gotwebd *env, struct imsg *imsg)
74 {
75 /* nothing to do but tell gotwebd configuration is done */
76 if (privsep_process != PROC_GOTWEBD)
77 proc_compose(env->gotwebd_ps, PROC_GOTWEBD,
78 IMSG_CFG_DONE, NULL, 0);
80 return 0;
81 }
83 int
84 config_setserver(struct gotwebd *env, struct server *srv)
85 {
86 struct server ssrv;
87 struct privsep *ps = env->gotwebd_ps;
89 memcpy(&ssrv, srv, sizeof(ssrv));
90 proc_compose(ps, PROC_SOCKS, IMSG_CFG_SRV, &ssrv, sizeof(ssrv));
91 return 0;
92 }
94 int
95 config_getserver(struct gotwebd *env, struct imsg *imsg)
96 {
97 struct server *srv;
98 uint8_t *p = imsg->data;
100 IMSG_SIZE_CHECK(imsg, &srv);
102 srv = calloc(1, sizeof(*srv));
103 if (srv == NULL)
104 fatalx("%s: calloc", __func__);
105 memcpy(srv, p, sizeof(*srv));
107 if (IMSG_DATA_SIZE(imsg) != sizeof(*srv)) {
108 log_debug("%s: imsg size error", __func__);
109 free(srv);
110 return 1;
113 /* log server info */
114 log_debug("%s: server=%s fcgi_socket=%s unix_socket=%s", __func__,
115 srv->name, srv->fcgi_socket ? "yes" : "no", srv->unix_socket ?
116 "yes" : "no");
118 TAILQ_INSERT_TAIL(env->servers, srv, entry);
120 return 0;
123 int
124 config_setsock(struct gotwebd *env, struct socket *sock)
126 struct privsep *ps = env->gotwebd_ps;
127 struct socket_conf s;
128 int id;
129 int fd = -1, n, m;
130 struct iovec iov[6];
131 size_t c;
132 unsigned int what;
134 /* open listening sockets */
135 if (sockets_privinit(env, sock) == -1)
136 return -1;
138 for (id = 0; id < PROC_MAX; id++) {
139 what = ps->ps_what[id];
141 if ((what & CONFIG_SOCKS) == 0 || id == privsep_process)
142 continue;
144 memcpy(&s, &sock->conf, sizeof(s));
146 c = 0;
147 iov[c].iov_base = &s;
148 iov[c++].iov_len = sizeof(s);
150 if (id == PROC_SOCKS) {
151 /* XXX imsg code will close the fd after 1st call */
152 n = -1;
153 proc_range(ps, id, &n, &m);
154 for (n = 0; n < m; n++) {
155 if (sock->fd == -1)
156 fd = -1;
157 else if ((fd = dup(sock->fd)) == -1)
158 return 1;
159 if (proc_composev_imsg(ps, id, n, IMSG_CFG_SOCK,
160 -1, fd, iov, c) != 0) {
161 log_warn("%s: failed to compose "
162 "IMSG_CFG_SOCK imsg",
163 __func__);
164 return 1;
166 if (proc_flush_imsg(ps, id, n) == -1) {
167 log_warn("%s: failed to flush "
168 "IMSG_CFG_SOCK imsg",
169 __func__);
170 return 1;
176 /* Close socket early to prevent fd exhaustion in gotwebd. */
177 if (sock->fd != -1) {
178 close(sock->fd);
179 sock->fd = -1;
182 return 0;
185 int
186 config_getsock(struct gotwebd *env, struct imsg *imsg)
188 struct socket *sock = NULL;
189 struct socket_conf sock_conf;
190 uint8_t *p = imsg->data;
191 int i;
193 IMSG_SIZE_CHECK(imsg, &sock_conf);
194 memcpy(&sock_conf, p, sizeof(sock_conf));
196 if (IMSG_DATA_SIZE(imsg) != sizeof(sock_conf)) {
197 log_debug("%s: imsg size error", __func__);
198 return 1;
201 /* create a new socket */
202 if ((sock = calloc(1, sizeof(*sock))) == NULL) {
203 if (imsg->fd != -1)
204 close(imsg->fd);
205 return 1;
208 memcpy(&sock->conf, &sock_conf, sizeof(sock->conf));
209 sock->fd = imsg->fd;
211 TAILQ_INSERT_TAIL(env->sockets, sock, entry);
213 for (i = 0; i < PRIV_FDS__MAX; i++)
214 sock->priv_fd[i] = -1;
216 for (i = 0; i < GOT_PACK_NUM_TEMPFILES; i++)
217 sock->pack_fds[i] = -1;
219 /* log new socket info */
220 log_debug("%s: name=%s id=%d server=%s child_id=%d parent_id=%d "
221 "type=%s ipv4=%d ipv6=%d socket_path=%s",
222 __func__, sock->conf.name, sock->conf.id, sock->conf.srv_name,
223 sock->conf.child_id, sock->conf.parent_id, sock->conf.type ?
224 "fcgi" : "unix", sock->conf.ipv4, sock->conf.ipv6,
225 strlen(sock->conf.unix_socket_name) ?
226 sock->conf.unix_socket_name : "none");
228 return 0;
231 int
232 config_setfd(struct gotwebd *env, struct socket *sock)
234 struct privsep *ps = env->gotwebd_ps;
235 int id, s;
236 int fd = -1, n, m, j;
237 struct iovec iov[6];
238 size_t c;
239 unsigned int what;
241 log_debug("%s: Allocating %d file descriptors",
242 __func__, PRIV_FDS__MAX + GOT_PACK_NUM_TEMPFILES);
244 for (j = 0; j < PRIV_FDS__MAX + GOT_PACK_NUM_TEMPFILES; j++) {
245 for (id = 0; id < PROC_MAX; id++) {
246 what = ps->ps_what[id];
248 if ((what & CONFIG_SOCKS) == 0 || id == privsep_process)
249 continue;
251 s = sock->conf.id;
252 c = 0;
253 iov[c].iov_base = &s;
254 iov[c++].iov_len = sizeof(s);
256 if (id == PROC_SOCKS) {
257 /*
258 * XXX imsg code will close the fd
259 * after 1st call
260 */
261 n = -1;
262 proc_range(ps, id, &n, &m);
263 for (n = 0; n < m; n++) {
264 fd = got_opentempfd();
265 if (fd == -1)
266 return 1;
267 if (proc_composev_imsg(ps, id, n,
268 IMSG_CFG_FD, -1, fd, iov, c) != 0) {
269 log_warn("%s: failed to compose "
270 "IMSG_CFG_FD imsg",
271 __func__);
272 return 1;
274 if (proc_flush_imsg(ps, id, n) == -1) {
275 log_warn("%s: failed to flush "
276 "IMSG_CFG_FD imsg",
277 __func__);
278 return 1;
284 /* Close fd early to prevent fd exhaustion in gotwebd. */
285 if (fd != -1)
286 close(fd);
288 return 0;
291 int
292 config_getfd(struct gotwebd *env, struct imsg *imsg)
294 struct socket *sock;
295 uint8_t *p = imsg->data;
296 int sock_id, match = 0, i;
298 IMSG_SIZE_CHECK(imsg, &sock_id);
299 memcpy(&sock_id, p, sizeof(sock_id));
301 TAILQ_FOREACH(sock, env->sockets, entry) {
302 for (i = 0; i < (GOT_PACK_NUM_TEMPFILES + PRIV_FDS__MAX); i++) {
303 if (i < PRIV_FDS__MAX && sock->priv_fd[i] == -1) {
304 log_debug("%s: assigning socket %d priv_fd %d",
305 __func__, sock_id, imsg->fd);
306 sock->priv_fd[i] = imsg->fd;
307 match = 1;
308 break;
310 if (sock->pack_fds[i - PRIV_FDS__MAX] == -1) {
311 log_debug("%s: assigning socket %d pack_fd %d",
312 __func__, sock_id, imsg->fd);
313 sock->pack_fds[i - PRIV_FDS__MAX] = imsg->fd;
314 match = 1;
315 break;
320 if (match)
321 return 0;
322 else
323 return 1;