Blob


1 /*
2 * Copyright (c) 2016, 2019, 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/param.h>
19 #include <sys/queue.h>
20 #include <sys/socket.h>
21 #include <sys/wait.h>
22 #include <sys/cdefs.h>
24 #include <net/if.h>
25 #include <netinet/in.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <termios.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <event.h>
34 #include <fcntl.h>
35 #include <imsg.h>
36 #include <pwd.h>
37 #include <signal.h>
38 #include <syslog.h>
39 #include <unistd.h>
40 #include <ctype.h>
41 #include <util.h>
43 #include "got_opentemp.h"
44 #include "got_reference.h"
46 #include "proc.h"
47 #include "gotwebd.h"
49 __dead void usage(void);
51 int main(int, char **);
52 int gotwebd_configure(struct gotwebd *);
53 void gotwebd_configure_done(struct gotwebd *);
54 void gotwebd_sighdlr(int sig, short event, void *arg);
55 void gotwebd_shutdown(void);
56 int gotwebd_dispatch_sockets(int, struct privsep_proc *, struct imsg *);
58 struct gotwebd *gotwebd_env;
60 static struct privsep_proc procs[] = {
61 { "sockets", PROC_SOCKS, gotwebd_dispatch_sockets, sockets,
62 sockets_shutdown },
63 };
65 int
66 gotwebd_dispatch_sockets(int fd, struct privsep_proc *p, struct imsg *imsg)
67 {
68 struct privsep *ps = p->p_ps;
69 struct gotwebd *env = ps->ps_env;
71 switch (imsg->hdr.type) {
72 case IMSG_CFG_DONE:
73 gotwebd_configure_done(env);
74 break;
75 default:
76 return (-1);
77 }
79 return (0);
80 }
82 void
83 gotwebd_sighdlr(int sig, short event, void *arg)
84 {
85 /* struct privsep *ps = arg; */
87 if (privsep_process != PROC_GOTWEBD)
88 return;
90 switch (sig) {
91 case SIGHUP:
92 log_info("%s: ignoring SIGHUP", __func__);
93 break;
94 case SIGPIPE:
95 log_info("%s: ignoring SIGPIPE", __func__);
96 break;
97 case SIGUSR1:
98 log_info("%s: ignoring SIGUSR1", __func__);
99 break;
100 case SIGTERM:
101 case SIGINT:
102 gotwebd_shutdown();
103 break;
104 default:
105 fatalx("unexpected signal");
109 __dead void
110 usage(void)
112 fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n",
113 getprogname());
114 exit(1);
117 int
118 main(int argc, char **argv)
120 struct gotwebd *env;
121 struct privsep *ps;
122 unsigned int proc;
123 int ch;
124 const char *conffile = GOTWEBD_CONF;
125 enum privsep_procid proc_id = PROC_GOTWEBD;
126 int proc_instance = 0;
127 const char *errp, *title = NULL;
128 int argc0 = argc;
130 env = calloc(1, sizeof(*env));
131 if (env == NULL)
132 fatal("%s: calloc", __func__);
134 /* XXX: add s and S for both sockets */
135 while ((ch = getopt(argc, argv, "D:df:I:nP:v")) != -1) {
136 switch (ch) {
137 case 'D':
138 if (cmdline_symset(optarg) < 0)
139 log_warnx("could not parse macro definition %s",
140 optarg);
141 break;
142 case 'd':
143 env->gotwebd_debug = 2;
144 break;
145 case 'f':
146 conffile = optarg;
147 break;
148 case 'I':
149 proc_instance = strtonum(optarg, 0,
150 PROC_MAX_INSTANCES, &errp);
151 if (errp)
152 fatalx("invalid process instance");
153 break;
154 case 'n':
155 env->gotwebd_debug = 2;
156 env->gotwebd_noaction = 1;
157 break;
158 case 'P':
159 title = optarg;
160 proc_id = proc_getid(procs, nitems(procs), title);
161 if (proc_id == PROC_MAX)
162 fatalx("invalid process name");
163 break;
164 case 'v':
165 env->gotwebd_verbose++;
166 break;
167 default:
168 usage();
172 /* log to stderr until daemonized */
173 log_init(env->gotwebd_debug ? env->gotwebd_debug : 1, LOG_DAEMON);
175 argc -= optind;
176 if (argc > 0)
177 usage();
179 ps = calloc(1, sizeof(*ps));
180 if (ps == NULL)
181 fatal("%s: calloc:", __func__);
183 gotwebd_env = env;
184 env->gotwebd_ps = ps;
185 ps->ps_env = env;
186 env->gotwebd_conffile = conffile;
188 if (parse_config(env->gotwebd_conffile, env) == -1)
189 exit(1);
191 if (env->gotwebd_noaction && !env->gotwebd_debug)
192 env->gotwebd_debug = 1;
194 /* check for root privileges */
195 if (env->gotwebd_noaction == 0) {
196 if (geteuid())
197 fatalx("need root privileges");
200 ps->ps_pw = getpwnam(GOTWEBD_USER);
201 if (ps->ps_pw == NULL)
202 fatalx("unknown user %s", GOTWEBD_USER);
204 log_init(env->gotwebd_debug, LOG_DAEMON);
205 log_setverbose(env->gotwebd_verbose);
207 if (env->gotwebd_noaction)
208 ps->ps_noaction = 1;
210 ps->ps_instances[PROC_SOCKS] = env->prefork_gotwebd;
211 ps->ps_instance = proc_instance;
212 if (title != NULL)
213 ps->ps_title[proc_id] = title;
215 for (proc = 0; proc < nitems(procs); proc++)
216 procs[proc].p_chroot = strlen(env->httpd_chroot) ?
217 env->httpd_chroot : D_HTTPD_CHROOT;
219 /* only the gotwebd returns */
220 proc_init(ps, procs, nitems(procs), argc0, argv, proc_id);
222 log_procinit("gotwebd");
223 if (!env->gotwebd_debug && daemon(0, 0) == -1)
224 fatal("can't daemonize");
226 if (ps->ps_noaction == 0)
227 log_info("%s startup", getprogname());
229 event_init();
231 signal_set(&ps->ps_evsigint, SIGINT, gotwebd_sighdlr, ps);
232 signal_set(&ps->ps_evsigterm, SIGTERM, gotwebd_sighdlr, ps);
233 signal_set(&ps->ps_evsighup, SIGHUP, gotwebd_sighdlr, ps);
234 signal_set(&ps->ps_evsigpipe, SIGPIPE, gotwebd_sighdlr, ps);
235 signal_set(&ps->ps_evsigusr1, SIGUSR1, gotwebd_sighdlr, ps);
237 signal_add(&ps->ps_evsigint, NULL);
238 signal_add(&ps->ps_evsigterm, NULL);
239 signal_add(&ps->ps_evsighup, NULL);
240 signal_add(&ps->ps_evsigpipe, NULL);
241 signal_add(&ps->ps_evsigusr1, NULL);
243 if (!env->gotwebd_noaction)
244 proc_connect(ps);
246 if (gotwebd_configure(env) == -1)
247 fatalx("configuration failed");
249 #ifdef PROFILE
250 if (unveil("gmon.out", "rwc") != 0)
251 err(1, "gmon.out");
252 #endif
254 if (unveil(strlen(env->httpd_chroot) > 0 ? env->httpd_chroot :
255 D_HTTPD_CHROOT, "rwc") == -1)
256 err(1, "unveil");
258 if (unveil(GOT_TMPDIR_STR, "rw") == -1)
259 err(1, "unveil");
261 if (unveil(GOTWEBD_CONF, "r") == -1)
262 err(1, "unveil");
264 if (unveil(NULL, NULL) != 0)
265 err(1, "unveil");
267 #ifndef PROFILE
268 if (pledge("stdio rpath wpath cpath inet unix", NULL) == -1)
269 err(1, "pledge");
270 #endif
272 event_dispatch();
274 log_debug("%s gotwebd exiting", getprogname());
276 return (0);
279 int
280 gotwebd_configure(struct gotwebd *env)
282 struct server *srv;
283 struct socket *sock;
284 int id;
286 if (env->gotwebd_noaction) {
287 fprintf(stderr, "configuration OK\n");
288 proc_kill(env->gotwebd_ps);
289 exit(0);
292 /* gotweb need to reload its config. */
293 env->gotwebd_reload = env->prefork_gotwebd;
295 /* send our gotweb servers */
296 TAILQ_FOREACH(srv, &env->servers, entry) {
297 if (config_setserver(env, srv) == -1)
298 fatalx("%s: send server error", __func__);
301 /* send our sockets */
302 TAILQ_FOREACH(sock, &env->sockets, entry) {
303 if (config_setsock(env, sock) == -1)
304 fatalx("%s: send socket error", __func__);
305 if (config_setfd(env, sock) == -1)
306 fatalx("%s: send priv_fd error", __func__);
309 for (id = 0; id < PROC_MAX; id++) {
310 if (id == privsep_process)
311 continue;
312 proc_compose(env->gotwebd_ps, id, IMSG_CFG_DONE, NULL, 0);
315 return (0);
318 void
319 gotwebd_configure_done(struct gotwebd *env)
321 int id;
323 if (env->gotwebd_reload == 0) {
324 log_warnx("%s: configuration already finished", __func__);
325 return;
328 env->gotwebd_reload--;
329 if (env->gotwebd_reload == 0) {
330 for (id = 0; id < PROC_MAX; id++) {
331 if (id == privsep_process)
332 continue;
333 proc_compose(env->gotwebd_ps, id, IMSG_CTL_START,
334 NULL, 0);
339 void
340 gotwebd_shutdown(void)
342 proc_kill(gotwebd_env->gotwebd_ps);
344 /* unlink(gotwebd_env->gotweb->gotweb_conf.gotweb_unix_socket_name); */
345 /* free(gotwebd_env->gotweb); */
346 free(gotwebd_env);
348 log_warnx("gotwebd terminating");
349 exit(0);