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