GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/relayd/check_script.c Lines: 0 67 0.0 %
Date: 2017-11-13 Branches: 0 31 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: check_script.c,v 1.21 2017/05/28 10:39:15 benno Exp $	*/
2
3
/*
4
 * Copyright (c) 2007 - 2014 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/wait.h>
20
#include <sys/time.h>
21
22
#include <errno.h>
23
#include <unistd.h>
24
#include <string.h>
25
#include <stdlib.h>
26
#include <signal.h>
27
#include <pwd.h>
28
29
#include "relayd.h"
30
31
void	 script_sig_alarm(int);
32
33
pid_t			 child = -1;
34
35
void
36
check_script(struct relayd *env, struct host *host)
37
{
38
	struct ctl_script	 scr;
39
	struct table		*table;
40
41
	if ((table = table_find(env, host->conf.tableid)) == NULL)
42
		fatalx("%s: invalid table id", __func__);
43
44
	host->last_up = host->up;
45
	host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE);
46
47
	scr.host = host->conf.id;
48
	if ((strlcpy(scr.name, host->conf.name,sizeof(scr.name)) >=
49
	    sizeof(scr.name)) ||
50
	    (strlcpy(scr.path, table->conf.path, sizeof(scr.path)) >=
51
	    sizeof(scr.path)))
52
		fatalx("invalid script path");
53
	memcpy(&scr.timeout, &table->conf.timeout, sizeof(scr.timeout));
54
55
	proc_compose(env->sc_ps, PROC_PARENT, IMSG_SCRIPT, &scr, sizeof(scr));
56
}
57
58
void
59
script_done(struct relayd *env, struct ctl_script *scr)
60
{
61
	struct host		*host;
62
63
	if ((host = host_find(env, scr->host)) == NULL)
64
		fatalx("%s: invalid host id", __func__);
65
66
	if (scr->retval < 0)
67
		host->up = HOST_UNKNOWN;
68
	else if (scr->retval == 0)
69
		host->up = HOST_DOWN;
70
	else
71
		host->up = HOST_UP;
72
	host->flags |= F_CHECK_DONE;
73
74
	hce_notify_done(host, host->up == HOST_UP ?
75
	    HCE_SCRIPT_OK : HCE_SCRIPT_FAIL);
76
}
77
78
void
79
script_sig_alarm(int sig)
80
{
81
	int save_errno = errno;
82
83
	if (child != -1)
84
		kill(child, SIGKILL);
85
	errno = save_errno;
86
}
87
88
int
89
script_exec(struct relayd *env, struct ctl_script *scr)
90
{
91
	int			 status = 0, ret = 0;
92
	sig_t			 save_quit, save_int, save_chld;
93
	struct itimerval	 it;
94
	struct timeval		*tv;
95
	const char		*file, *arg;
96
	struct passwd		*pw;
97
98
	if ((env->sc_conf.flags & F_SCRIPT) == 0) {
99
		log_warnx("%s: script disabled", __func__);
100
		return (-1);
101
	}
102
103
	DPRINTF("%s: running script %s, host %s",
104
	    __func__, scr->path, scr->name);
105
106
	arg = scr->name;
107
	file = scr->path;
108
	tv = &scr->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(RELAYD_USER)) == NULL)
124
			fatal("%s: getpwnam", __func__);
125
		if (chdir("/") == -1)
126
			fatal("%s: chdir(\"/\")", __func__);
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("%s: can't drop privileges", __func__);
131
132
		/*
133
		 * close fds before executing an external program, to
134
		 * prevent access to internal fds, eg. IMSG connections
135
		 * of internal processes.
136
		 */
137
		closefrom(STDERR_FILENO + 1);
138
139
		execlp(file, file, arg, (char *)NULL);
140
		_exit(0);
141
		break;
142
	default:
143
		/* Kill the process after a timeout */
144
		signal(SIGALRM, script_sig_alarm);
145
		bzero(&it, sizeof(it));
146
		bcopy(tv, &it.it_value, sizeof(it.it_value));
147
		setitimer(ITIMER_REAL, &it, NULL);
148
149
		waitpid(child, &status, 0);
150
		break;
151
	}
152
153
	switch (ret) {
154
	case -1:
155
		ret = -1;
156
		break;
157
	default:
158
		if (WIFEXITED(status))
159
			ret = WEXITSTATUS(status);
160
		else
161
			ret = 0;
162
	}
163
164
 done:
165
	/* Disable the process timeout timer */
166
	bzero(&it, sizeof(it));
167
	setitimer(ITIMER_REAL, &it, NULL);
168
	child = -1;
169
170
	signal(SIGQUIT, save_quit);
171
	signal(SIGINT, save_int);
172
	signal(SIGCHLD, save_chld);
173
	signal(SIGALRM, SIG_DFL);
174
175
	return (ret);
176
}