2 56324ebe 2022-07-14 thomas * Copyright (c) 2016, 2019, 2020-2021 Tracey Emery <tracey@traceyemery.net>
3 56324ebe 2022-07-14 thomas * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
5 56324ebe 2022-07-14 thomas * Permission to use, copy, modify, and distribute this software for any
6 56324ebe 2022-07-14 thomas * purpose with or without fee is hereby granted, provided that the above
7 56324ebe 2022-07-14 thomas * copyright notice and this permission notice appear in all copies.
9 56324ebe 2022-07-14 thomas * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 56324ebe 2022-07-14 thomas * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 56324ebe 2022-07-14 thomas * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 56324ebe 2022-07-14 thomas * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 56324ebe 2022-07-14 thomas * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 56324ebe 2022-07-14 thomas * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 56324ebe 2022-07-14 thomas * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 56324ebe 2022-07-14 thomas #include <sys/param.h>
19 56324ebe 2022-07-14 thomas #include <sys/socket.h>
20 56324ebe 2022-07-14 thomas #include <sys/wait.h>
21 56324ebe 2022-07-14 thomas #include <sys/cdefs.h>
23 56324ebe 2022-07-14 thomas #include <net/if.h>
24 56324ebe 2022-07-14 thomas #include <netinet/in.h>
26 56324ebe 2022-07-14 thomas #include <stdio.h>
27 56324ebe 2022-07-14 thomas #include <stdlib.h>
28 56324ebe 2022-07-14 thomas #include <string.h>
29 56324ebe 2022-07-14 thomas #include <termios.h>
30 56324ebe 2022-07-14 thomas #include <err.h>
31 56324ebe 2022-07-14 thomas #include <errno.h>
32 56324ebe 2022-07-14 thomas #include <event.h>
33 56324ebe 2022-07-14 thomas #include <fcntl.h>
34 56324ebe 2022-07-14 thomas #include <pwd.h>
35 56324ebe 2022-07-14 thomas #include <signal.h>
36 56324ebe 2022-07-14 thomas #include <syslog.h>
37 56324ebe 2022-07-14 thomas #include <unistd.h>
38 56324ebe 2022-07-14 thomas #include <ctype.h>
40 56324ebe 2022-07-14 thomas #include "got_opentemp.h"
42 56324ebe 2022-07-14 thomas #include "proc.h"
43 56324ebe 2022-07-14 thomas #include "gotwebd.h"
45 d7cad54e 2022-07-14 thomas #include "got_compat.h"
47 56324ebe 2022-07-14 thomas __dead void usage(void);
49 56324ebe 2022-07-14 thomas int main(int, char **);
50 56324ebe 2022-07-14 thomas int gotwebd_configure(struct gotwebd *);
51 56324ebe 2022-07-14 thomas void gotwebd_configure_done(struct gotwebd *);
52 56324ebe 2022-07-14 thomas void gotwebd_sighdlr(int sig, short event, void *arg);
53 56324ebe 2022-07-14 thomas void gotwebd_shutdown(void);
54 56324ebe 2022-07-14 thomas int gotwebd_dispatch_sockets(int, struct privsep_proc *, struct imsg *);
56 56324ebe 2022-07-14 thomas struct gotwebd *gotwebd_env;
58 56324ebe 2022-07-14 thomas static struct privsep_proc procs[] = {
59 56324ebe 2022-07-14 thomas { "sockets", PROC_SOCKS, gotwebd_dispatch_sockets, sockets,
60 56324ebe 2022-07-14 thomas sockets_shutdown },
64 56324ebe 2022-07-14 thomas gotwebd_dispatch_sockets(int fd, struct privsep_proc *p, struct imsg *imsg)
66 56324ebe 2022-07-14 thomas struct privsep *ps = p->p_ps;
67 56324ebe 2022-07-14 thomas struct gotwebd *env = ps->ps_env;
69 56324ebe 2022-07-14 thomas switch (imsg->hdr.type) {
70 56324ebe 2022-07-14 thomas case IMSG_CFG_DONE:
71 56324ebe 2022-07-14 thomas gotwebd_configure_done(env);
74 56324ebe 2022-07-14 thomas return (-1);
77 56324ebe 2022-07-14 thomas return (0);
81 56324ebe 2022-07-14 thomas gotwebd_sighdlr(int sig, short event, void *arg)
83 56324ebe 2022-07-14 thomas /* struct privsep *ps = arg; */
85 56324ebe 2022-07-14 thomas if (privsep_process != PROC_GOTWEBD)
88 56324ebe 2022-07-14 thomas switch (sig) {
89 56324ebe 2022-07-14 thomas case SIGHUP:
90 56324ebe 2022-07-14 thomas log_info("%s: ignoring SIGHUP", __func__);
92 56324ebe 2022-07-14 thomas case SIGPIPE:
93 56324ebe 2022-07-14 thomas log_info("%s: ignoring SIGPIPE", __func__);
95 56324ebe 2022-07-14 thomas case SIGUSR1:
96 56324ebe 2022-07-14 thomas log_info("%s: ignoring SIGUSR1", __func__);
98 56324ebe 2022-07-14 thomas case SIGTERM:
99 56324ebe 2022-07-14 thomas case SIGINT:
100 56324ebe 2022-07-14 thomas gotwebd_shutdown();
103 56324ebe 2022-07-14 thomas fatalx("unexpected signal");
107 56324ebe 2022-07-14 thomas __dead void
108 56324ebe 2022-07-14 thomas usage(void)
110 56324ebe 2022-07-14 thomas fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n",
111 56324ebe 2022-07-14 thomas getprogname());
116 56324ebe 2022-07-14 thomas main(int argc, char **argv)
118 56324ebe 2022-07-14 thomas struct gotwebd *env;
119 56324ebe 2022-07-14 thomas struct privsep *ps;
120 56324ebe 2022-07-14 thomas unsigned int proc;
122 56324ebe 2022-07-14 thomas const char *conffile = GOTWEBD_CONF;
123 56324ebe 2022-07-14 thomas enum privsep_procid proc_id = PROC_GOTWEBD;
124 56324ebe 2022-07-14 thomas int proc_instance = 0;
125 56324ebe 2022-07-14 thomas const char *errp, *title = NULL;
126 56324ebe 2022-07-14 thomas int argc0 = argc;
128 56324ebe 2022-07-14 thomas env = calloc(1, sizeof(*env));
129 56324ebe 2022-07-14 thomas if (env == NULL)
130 56324ebe 2022-07-14 thomas fatal("%s: calloc", __func__);
132 56324ebe 2022-07-14 thomas /* XXX: add s and S for both sockets */
133 56324ebe 2022-07-14 thomas while ((ch = getopt(argc, argv, "D:P:I:df:vn")) != -1) {
134 56324ebe 2022-07-14 thomas switch (ch) {
135 56324ebe 2022-07-14 thomas case 'D':
136 56324ebe 2022-07-14 thomas if (cmdline_symset(optarg) < 0)
137 56324ebe 2022-07-14 thomas log_warnx("could not parse macro definition %s",
140 56324ebe 2022-07-14 thomas case 'd':
141 56324ebe 2022-07-14 thomas env->gotwebd_debug = 2;
143 56324ebe 2022-07-14 thomas case 'f':
144 56324ebe 2022-07-14 thomas conffile = optarg;
146 56324ebe 2022-07-14 thomas case 'v':
147 56324ebe 2022-07-14 thomas env->gotwebd_verbose++;
149 56324ebe 2022-07-14 thomas case 'n':
150 56324ebe 2022-07-14 thomas env->gotwebd_debug = 2;
151 56324ebe 2022-07-14 thomas env->gotwebd_noaction = 1;
153 56324ebe 2022-07-14 thomas case 'P':
154 56324ebe 2022-07-14 thomas title = optarg;
155 56324ebe 2022-07-14 thomas proc_id = proc_getid(procs, nitems(procs), title);
156 56324ebe 2022-07-14 thomas if (proc_id == PROC_MAX)
157 56324ebe 2022-07-14 thomas fatalx("invalid process name");
159 56324ebe 2022-07-14 thomas case 'I':
160 56324ebe 2022-07-14 thomas proc_instance = strtonum(optarg, 0,
161 56324ebe 2022-07-14 thomas PROC_MAX_INSTANCES, &errp);
162 56324ebe 2022-07-14 thomas if (errp)
163 56324ebe 2022-07-14 thomas fatalx("invalid process instance");
170 56324ebe 2022-07-14 thomas /* log to stderr until daemonized */
171 56324ebe 2022-07-14 thomas log_init(env->gotwebd_debug ? env->gotwebd_debug : 1, LOG_DAEMON);
173 56324ebe 2022-07-14 thomas argc -= optind;
174 56324ebe 2022-07-14 thomas if (argc > 0)
177 56324ebe 2022-07-14 thomas ps = calloc(1, sizeof(*ps));
178 56324ebe 2022-07-14 thomas if (ps == NULL)
179 56324ebe 2022-07-14 thomas fatal("%s: calloc:", __func__);
181 56324ebe 2022-07-14 thomas gotwebd_env = env;
182 56324ebe 2022-07-14 thomas env->gotwebd_ps = ps;
183 56324ebe 2022-07-14 thomas ps->ps_env = env;
184 56324ebe 2022-07-14 thomas env->gotwebd_conffile = conffile;
186 56324ebe 2022-07-14 thomas if (parse_config(env->gotwebd_conffile, env) == -1)
189 56324ebe 2022-07-14 thomas if (env->gotwebd_noaction && !env->gotwebd_debug)
190 56324ebe 2022-07-14 thomas env->gotwebd_debug = 1;
192 56324ebe 2022-07-14 thomas /* check for root privileges */
193 56324ebe 2022-07-14 thomas if (env->gotwebd_noaction == 0) {
194 56324ebe 2022-07-14 thomas if (geteuid())
195 56324ebe 2022-07-14 thomas fatalx("need root privileges");
198 56324ebe 2022-07-14 thomas ps->ps_pw = getpwnam(GOTWEBD_USER);
199 56324ebe 2022-07-14 thomas if (ps->ps_pw == NULL)
200 56324ebe 2022-07-14 thomas fatalx("unknown user %s", GOTWEBD_USER);
202 56324ebe 2022-07-14 thomas log_init(env->gotwebd_debug, LOG_DAEMON);
203 56324ebe 2022-07-14 thomas log_setverbose(env->gotwebd_verbose);
205 56324ebe 2022-07-14 thomas if (env->gotwebd_noaction)
206 56324ebe 2022-07-14 thomas ps->ps_noaction = 1;
208 56324ebe 2022-07-14 thomas ps->ps_instances[PROC_SOCKS] = env->prefork_gotwebd;
209 56324ebe 2022-07-14 thomas ps->ps_instance = proc_instance;
210 56324ebe 2022-07-14 thomas if (title != NULL)
211 56324ebe 2022-07-14 thomas ps->ps_title[proc_id] = title;
213 56324ebe 2022-07-14 thomas for (proc = 0; proc < nitems(procs); proc++)
214 56324ebe 2022-07-14 thomas procs[proc].p_chroot = strlen(env->httpd_chroot) ?
215 56324ebe 2022-07-14 thomas env->httpd_chroot : D_HTTPD_CHROOT;
217 56324ebe 2022-07-14 thomas /* only the gotwebd returns */
218 56324ebe 2022-07-14 thomas proc_init(ps, procs, nitems(procs), argc0, argv, proc_id);
220 56324ebe 2022-07-14 thomas log_procinit("gotwebd");
221 56324ebe 2022-07-14 thomas if (!env->gotwebd_debug && daemon(0, 0) == -1)
222 56324ebe 2022-07-14 thomas fatal("can't daemonize");
224 56324ebe 2022-07-14 thomas if (ps->ps_noaction == 0)
225 56324ebe 2022-07-14 thomas log_info("%s startup", getprogname());
227 56324ebe 2022-07-14 thomas event_init();
229 56324ebe 2022-07-14 thomas signal_set(&ps->ps_evsigint, SIGINT, gotwebd_sighdlr, ps);
230 56324ebe 2022-07-14 thomas signal_set(&ps->ps_evsigterm, SIGTERM, gotwebd_sighdlr, ps);
231 56324ebe 2022-07-14 thomas signal_set(&ps->ps_evsighup, SIGHUP, gotwebd_sighdlr, ps);
232 56324ebe 2022-07-14 thomas signal_set(&ps->ps_evsigpipe, SIGPIPE, gotwebd_sighdlr, ps);
233 56324ebe 2022-07-14 thomas signal_set(&ps->ps_evsigusr1, SIGUSR1, gotwebd_sighdlr, ps);
235 56324ebe 2022-07-14 thomas signal_add(&ps->ps_evsigint, NULL);
236 56324ebe 2022-07-14 thomas signal_add(&ps->ps_evsigterm, NULL);
237 56324ebe 2022-07-14 thomas signal_add(&ps->ps_evsighup, NULL);
238 56324ebe 2022-07-14 thomas signal_add(&ps->ps_evsigpipe, NULL);
239 56324ebe 2022-07-14 thomas signal_add(&ps->ps_evsigusr1, NULL);
241 56324ebe 2022-07-14 thomas if (!env->gotwebd_noaction)
242 56324ebe 2022-07-14 thomas proc_connect(ps);
244 56324ebe 2022-07-14 thomas if (gotwebd_configure(env) == -1)
245 56324ebe 2022-07-14 thomas fatalx("configuration failed");
247 56324ebe 2022-07-14 thomas #ifdef PROFILE
248 56324ebe 2022-07-14 thomas if (unveil("gmon.out", "rwc") != 0)
249 56324ebe 2022-07-14 thomas err(1, "gmon.out");
252 56324ebe 2022-07-14 thomas if (unveil(strlen(env->httpd_chroot) > 0 ? env->httpd_chroot :
253 56324ebe 2022-07-14 thomas D_HTTPD_CHROOT, "rwc") == -1)
254 56324ebe 2022-07-14 thomas err(1, "unveil");
256 56324ebe 2022-07-14 thomas if (unveil(GOT_TMPDIR_STR, "rw") == -1)
257 56324ebe 2022-07-14 thomas err(1, "unveil");
259 56324ebe 2022-07-14 thomas if (unveil(GOTWEBD_CONF, "r") == -1)
260 56324ebe 2022-07-14 thomas err(1, "unveil");
262 56324ebe 2022-07-14 thomas if (unveil(NULL, NULL) != 0)
263 56324ebe 2022-07-14 thomas err(1, "unveil");
265 56324ebe 2022-07-14 thomas #ifndef PROFILE
266 56324ebe 2022-07-14 thomas if (pledge("stdio rpath wpath cpath inet unix", NULL) == -1)
267 56324ebe 2022-07-14 thomas err(1, "pledge");
270 56324ebe 2022-07-14 thomas event_dispatch();
272 56324ebe 2022-07-14 thomas log_debug("%s gotwebd exiting", getprogname());
274 56324ebe 2022-07-14 thomas return (0);
278 56324ebe 2022-07-14 thomas gotwebd_configure(struct gotwebd *env)
280 56324ebe 2022-07-14 thomas struct server *srv;
281 56324ebe 2022-07-14 thomas struct socket *sock;
284 56324ebe 2022-07-14 thomas if (env->gotwebd_noaction) {
285 56324ebe 2022-07-14 thomas fprintf(stderr, "configuration OK\n");
286 56324ebe 2022-07-14 thomas proc_kill(env->gotwebd_ps);
290 56324ebe 2022-07-14 thomas /* gotweb need to reload its config. */
291 56324ebe 2022-07-14 thomas env->gotwebd_reload = env->prefork_gotwebd;
293 56324ebe 2022-07-14 thomas /* send our gotweb servers */
294 56324ebe 2022-07-14 thomas TAILQ_FOREACH(srv, env->servers, entry) {
295 56324ebe 2022-07-14 thomas if (config_setserver(env, srv) == -1)
296 56324ebe 2022-07-14 thomas fatalx("%s: send server error", __func__);
299 56324ebe 2022-07-14 thomas /* send our sockets */
300 56324ebe 2022-07-14 thomas TAILQ_FOREACH(sock, env->sockets, entry) {
301 56324ebe 2022-07-14 thomas if (config_setsock(env, sock) == -1)
302 56324ebe 2022-07-14 thomas fatalx("%s: send socket error", __func__);
303 56324ebe 2022-07-14 thomas if (config_setfd(env, sock) == -1)
304 56324ebe 2022-07-14 thomas fatalx("%s: send priv_fd error", __func__);
307 56324ebe 2022-07-14 thomas for (id = 0; id < PROC_MAX; id++) {
308 56324ebe 2022-07-14 thomas if (id == privsep_process)
309 56324ebe 2022-07-14 thomas continue;
310 56324ebe 2022-07-14 thomas proc_compose(env->gotwebd_ps, id, IMSG_CFG_DONE, NULL, 0);
313 56324ebe 2022-07-14 thomas return (0);
317 56324ebe 2022-07-14 thomas gotwebd_configure_done(struct gotwebd *env)
321 56324ebe 2022-07-14 thomas if (env->gotwebd_reload == 0) {
322 56324ebe 2022-07-14 thomas log_warnx("%s: configuration already finished", __func__);
326 56324ebe 2022-07-14 thomas env->gotwebd_reload--;
327 56324ebe 2022-07-14 thomas if (env->gotwebd_reload == 0) {
328 56324ebe 2022-07-14 thomas for (id = 0; id < PROC_MAX; id++) {
329 56324ebe 2022-07-14 thomas if (id == privsep_process)
330 56324ebe 2022-07-14 thomas continue;
331 56324ebe 2022-07-14 thomas proc_compose(env->gotwebd_ps, id, IMSG_CTL_START,
332 56324ebe 2022-07-14 thomas NULL, 0);
338 56324ebe 2022-07-14 thomas gotwebd_shutdown(void)
340 56324ebe 2022-07-14 thomas proc_kill(gotwebd_env->gotwebd_ps);
342 56324ebe 2022-07-14 thomas /* unlink(gotwebd_env->gotweb->gotweb_conf.gotweb_unix_socket_name); */
343 56324ebe 2022-07-14 thomas /* free(gotwebd_env->gotweb); */
344 56324ebe 2022-07-14 thomas free(gotwebd_env);
346 56324ebe 2022-07-14 thomas log_warnx("gotwebd terminating");