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
;