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