1*19a6b45eSjmatthew /* $OpenBSD: check_script.c,v 1.22 2021/02/22 01:24:59 jmatthew Exp $ */
24156152fSreyk
34156152fSreyk /*
4d535e21cSreyk * Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
54156152fSreyk *
64156152fSreyk * Permission to use, copy, modify, and distribute this software for any
74156152fSreyk * purpose with or without fee is hereby granted, provided that the above
84156152fSreyk * copyright notice and this permission notice appear in all copies.
94156152fSreyk *
104156152fSreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
114156152fSreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
124156152fSreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
134156152fSreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
144156152fSreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
154156152fSreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
164156152fSreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
174156152fSreyk */
184156152fSreyk
194156152fSreyk #include <sys/wait.h>
20f04ff968Sreyk #include <sys/time.h>
214156152fSreyk
224156152fSreyk #include <errno.h>
234156152fSreyk #include <unistd.h>
244156152fSreyk #include <string.h>
254156152fSreyk #include <stdlib.h>
264156152fSreyk #include <signal.h>
274156152fSreyk #include <pwd.h>
284156152fSreyk
29748ceb64Sreyk #include "relayd.h"
304156152fSreyk
314156152fSreyk void script_sig_alarm(int);
324156152fSreyk
334156152fSreyk pid_t child = -1;
344156152fSreyk
354156152fSreyk void
check_script(struct relayd * env,struct host * host)360325c666Sreyk check_script(struct relayd *env, struct host *host)
374156152fSreyk {
384156152fSreyk struct ctl_script scr;
3982b2e7ebSreyk struct table *table;
4082b2e7ebSreyk
41*19a6b45eSjmatthew if ((host->flags & (F_CHECK_SENT|F_CHECK_DONE)) == F_CHECK_SENT)
42*19a6b45eSjmatthew return;
43*19a6b45eSjmatthew
4482b2e7ebSreyk if ((table = table_find(env, host->conf.tableid)) == NULL)
45efc39811Sbenno fatalx("%s: invalid table id", __func__);
464156152fSreyk
474156152fSreyk host->last_up = host->up;
484156152fSreyk host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE);
494156152fSreyk
504156152fSreyk scr.host = host->conf.id;
519888254dSreyk if ((strlcpy(scr.name, host->conf.name,sizeof(scr.name)) >=
529888254dSreyk sizeof(scr.name)) ||
539888254dSreyk (strlcpy(scr.path, table->conf.path, sizeof(scr.path)) >=
549888254dSreyk sizeof(scr.path)))
559888254dSreyk fatalx("invalid script path");
5682b2e7ebSreyk memcpy(&scr.timeout, &table->conf.timeout, sizeof(scr.timeout));
5782b2e7ebSreyk
58*19a6b45eSjmatthew if (proc_compose(env->sc_ps, PROC_PARENT, IMSG_SCRIPT, &scr,
59*19a6b45eSjmatthew sizeof(scr)) == 0)
60*19a6b45eSjmatthew host->flags |= F_CHECK_SENT;
614156152fSreyk }
624156152fSreyk
634156152fSreyk void
script_done(struct relayd * env,struct ctl_script * scr)64748ceb64Sreyk script_done(struct relayd *env, struct ctl_script *scr)
654156152fSreyk {
664156152fSreyk struct host *host;
674156152fSreyk
684156152fSreyk if ((host = host_find(env, scr->host)) == NULL)
69efc39811Sbenno fatalx("%s: invalid host id", __func__);
704156152fSreyk
714156152fSreyk if (scr->retval < 0)
724156152fSreyk host->up = HOST_UNKNOWN;
734156152fSreyk else if (scr->retval == 0)
744156152fSreyk host->up = HOST_DOWN;
754156152fSreyk else
764156152fSreyk host->up = HOST_UP;
774156152fSreyk host->flags |= F_CHECK_DONE;
784156152fSreyk
794156152fSreyk hce_notify_done(host, host->up == HOST_UP ?
80c0dc99f6Sreyk HCE_SCRIPT_OK : HCE_SCRIPT_FAIL);
814156152fSreyk }
824156152fSreyk
834156152fSreyk void
script_sig_alarm(int sig)844156152fSreyk script_sig_alarm(int sig)
854156152fSreyk {
8615b1562dSderaadt int save_errno = errno;
8715b1562dSderaadt
884156152fSreyk if (child != -1)
894156152fSreyk kill(child, SIGKILL);
9015b1562dSderaadt errno = save_errno;
914156152fSreyk }
924156152fSreyk
934156152fSreyk int
script_exec(struct relayd * env,struct ctl_script * scr)94748ceb64Sreyk script_exec(struct relayd *env, struct ctl_script *scr)
954156152fSreyk {
964156152fSreyk int status = 0, ret = 0;
974156152fSreyk sig_t save_quit, save_int, save_chld;
984156152fSreyk struct itimerval it;
994156152fSreyk struct timeval *tv;
1004156152fSreyk const char *file, *arg;
1014156152fSreyk struct passwd *pw;
1024156152fSreyk
103586b5f8aSreyk if ((env->sc_conf.flags & F_SCRIPT) == 0) {
1046e8056acSreyk log_warnx("%s: script disabled", __func__);
1056e8056acSreyk return (-1);
1066e8056acSreyk }
1076e8056acSreyk
10882b2e7ebSreyk DPRINTF("%s: running script %s, host %s",
10982b2e7ebSreyk __func__, scr->path, scr->name);
1104156152fSreyk
11182b2e7ebSreyk arg = scr->name;
11282b2e7ebSreyk file = scr->path;
11382b2e7ebSreyk tv = &scr->timeout;
1144156152fSreyk
1154156152fSreyk save_quit = signal(SIGQUIT, SIG_IGN);
1164156152fSreyk save_int = signal(SIGINT, SIG_IGN);
1174156152fSreyk save_chld = signal(SIGCHLD, SIG_DFL);
1184156152fSreyk
1194156152fSreyk switch (child = fork()) {
1204156152fSreyk case -1:
1214156152fSreyk ret = -1;
1224156152fSreyk goto done;
1234156152fSreyk case 0:
1244156152fSreyk signal(SIGQUIT, SIG_DFL);
1254156152fSreyk signal(SIGINT, SIG_DFL);
1264156152fSreyk signal(SIGCHLD, SIG_DFL);
1274156152fSreyk
128748ceb64Sreyk if ((pw = getpwnam(RELAYD_USER)) == NULL)
129efc39811Sbenno fatal("%s: getpwnam", __func__);
1304156152fSreyk if (chdir("/") == -1)
131efc39811Sbenno fatal("%s: chdir(\"/\")", __func__);
1324156152fSreyk if (setgroups(1, &pw->pw_gid) ||
1334156152fSreyk setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
1344156152fSreyk setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
135efc39811Sbenno fatal("%s: can't drop privileges", __func__);
1364156152fSreyk
137b5d6a36dSreyk /*
138b5d6a36dSreyk * close fds before executing an external program, to
139b5d6a36dSreyk * prevent access to internal fds, eg. IMSG connections
140b5d6a36dSreyk * of internal processes.
141b5d6a36dSreyk */
142b5d6a36dSreyk closefrom(STDERR_FILENO + 1);
143b5d6a36dSreyk
1444156152fSreyk execlp(file, file, arg, (char *)NULL);
1454156152fSreyk _exit(0);
1464156152fSreyk break;
1474156152fSreyk default:
1484156152fSreyk /* Kill the process after a timeout */
1494156152fSreyk signal(SIGALRM, script_sig_alarm);
1504156152fSreyk bzero(&it, sizeof(it));
1514156152fSreyk bcopy(tv, &it.it_value, sizeof(it.it_value));
1524156152fSreyk setitimer(ITIMER_REAL, &it, NULL);
1534156152fSreyk
1544156152fSreyk waitpid(child, &status, 0);
1554156152fSreyk break;
1564156152fSreyk }
1574156152fSreyk
1584156152fSreyk switch (ret) {
1594156152fSreyk case -1:
1604156152fSreyk ret = -1;
1614156152fSreyk break;
1624156152fSreyk default:
1634156152fSreyk if (WIFEXITED(status))
1644156152fSreyk ret = WEXITSTATUS(status);
1654156152fSreyk else
16609c845d4Ssthen ret = 0;
1674156152fSreyk }
1684156152fSreyk
1694156152fSreyk done:
1704156152fSreyk /* Disable the process timeout timer */
1714156152fSreyk bzero(&it, sizeof(it));
1724156152fSreyk setitimer(ITIMER_REAL, &it, NULL);
1734156152fSreyk child = -1;
1744156152fSreyk
1754156152fSreyk signal(SIGQUIT, save_quit);
1764156152fSreyk signal(SIGINT, save_int);
1774156152fSreyk signal(SIGCHLD, save_chld);
1784156152fSreyk signal(SIGALRM, SIG_DFL);
1794156152fSreyk
1804156152fSreyk return (ret);
1814156152fSreyk }
182