1 /* $OpenBSD: check_script.c,v 1.10 2009/06/05 23:39:51 pyr 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 40 void script_sig_alarm(int); 41 42 extern struct imsgev *iev_main; 43 pid_t child = -1; 44 45 void 46 check_script(struct host *host) 47 { 48 struct ctl_script scr; 49 50 host->last_up = host->up; 51 host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE); 52 53 scr.host = host->conf.id; 54 imsg_compose_event(iev_main, IMSG_SCRIPT, 0, 0, -1, &scr, sizeof(scr)); 55 } 56 57 void 58 script_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 77 void 78 script_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 87 int 88 script_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 = -1; 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