check_script.c revision 1.3
1/*	$OpenBSD: check_script.c,v 1.3 2007/10/13 17:50:05 deraadt Exp $	*/
2
3/*
4 * Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/queue.h>
21#include <sys/socket.h>
22#include <sys/param.h>
23#include <sys/types.h>
24#include <sys/wait.h>
25
26#include <net/if.h>
27
28#include <limits.h>
29#include <event.h>
30#include <errno.h>
31#include <unistd.h>
32#include <string.h>
33#include <stdlib.h>
34#include <signal.h>
35#include <pwd.h>
36#include <err.h>
37
38#include <openssl/ssl.h>
39
40#include "hoststated.h"
41
42void	 script_sig_alarm(int);
43
44extern struct imsgbuf		*ibuf_main;
45pid_t				 child = -1;
46
47void
48check_script(struct host *host)
49{
50	struct ctl_script	 scr;
51
52	host->last_up = host->up;
53	host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE);
54
55	scr.host = host->conf.id;
56	imsg_compose(ibuf_main, IMSG_SCRIPT, 0, 0, -1, &scr, sizeof(scr));
57}
58
59void
60script_done(struct hoststated *env, struct ctl_script *scr)
61{
62	struct host		*host;
63
64	if ((host = host_find(env, scr->host)) == NULL)
65		fatalx("hce_dispatch_parent: invalid host id");
66
67	if (scr->retval < 0)
68		host->up = HOST_UNKNOWN;
69	else if (scr->retval == 0)
70		host->up = HOST_DOWN;
71	else
72		host->up = HOST_UP;
73	host->flags |= F_CHECK_DONE;
74
75	hce_notify_done(host, host->up == HOST_UP ?
76	    "script: done" : "script: failed");
77}
78
79void
80script_sig_alarm(int sig)
81{
82	int save_errno = errno;
83
84	if (child != -1)
85		kill(child, SIGKILL);
86	errno = save_errno;
87}
88
89int
90script_exec(struct hoststated *env, struct ctl_script *scr)
91{
92	int			 status = 0, ret = 0;
93	sig_t			 save_quit, save_int, save_chld;
94	struct itimerval	 it;
95	struct timeval		*tv;
96	const char		*file, *arg;
97	struct host		*host;
98	struct table		*table;
99	struct passwd		*pw;
100
101	if ((host = host_find(env, scr->host)) == NULL)
102		fatalx("script_exec: invalid host id");
103	if ((table = table_find(env, host->conf.tableid)) == NULL)
104		fatalx("script_exec: invalid table id");
105
106	arg = host->conf.name;
107	file = table->conf.path;
108	tv = &table->conf.timeout;
109
110	save_quit = signal(SIGQUIT, SIG_IGN);
111	save_int = signal(SIGINT, SIG_IGN);
112	save_chld = signal(SIGCHLD, SIG_DFL);
113
114	switch (child = fork()) {
115	case -1:
116		ret = -1;
117		goto done;
118	case 0:
119		signal(SIGQUIT, SIG_DFL);
120		signal(SIGINT, SIG_DFL);
121		signal(SIGCHLD, SIG_DFL);
122
123		if ((pw = getpwnam(HOSTSTATED_USER)) == NULL)
124			fatal("script_exec: getpwnam");
125		if (chdir("/") == -1)
126			fatal("script_exec: chdir(\"/\")");
127		if (setgroups(1, &pw->pw_gid) ||
128		    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
129		    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
130			fatal("script_exec: can't drop privileges");
131
132		execlp(file, file, arg, (char *)NULL);
133		_exit(0);
134		break;
135	default:
136		/* Kill the process after a timeout */
137		signal(SIGALRM, script_sig_alarm);
138		bzero(&it, sizeof(it));
139		bcopy(tv, &it.it_value, sizeof(it.it_value));
140		setitimer(ITIMER_REAL, &it, NULL);
141
142		waitpid(child, &status, 0);
143		break;
144	}
145
146	switch (ret) {
147	case -1:
148		ret = -1;
149		break;
150	default:
151		if (WIFEXITED(status))
152			ret = WEXITSTATUS(status);
153		else
154			ret = -1;
155	}
156
157 done:
158	/* Disable the process timeout timer */
159	bzero(&it, sizeof(it));
160	setitimer(ITIMER_REAL, &it, NULL);
161	child = -1;
162
163	signal(SIGQUIT, save_quit);
164	signal(SIGINT, save_int);
165	signal(SIGCHLD, save_chld);
166	signal(SIGALRM, SIG_DFL);
167
168	return (ret);
169}
170