/************************************************************************* * (C) 2010 AITNET - Sofia/Bulgaria - * by Michael Pounov * * $Author: misho $ * $Id: wdog.c,v 1.1.2.7 2010/10/18 12:18:21 misho Exp $ * *************************************************************************/ #include "global.h" int Verbose, Kill; extern char compiled[], compiledby[], compilehost[]; static void Usage() { printf( "WatchDog tool for risk process managment\n" "=== %s === %s@%s ===\n\n" " Syntax: wdog [options] [exec_file]\n\n" "\t-v\t\tVerbose ...\n" "\t-c \tBefore execute chroot to dir [default=/]\n" "\t-u \tBefore execute change user\n" "\t-P\t\tInfinit loop, bypass penalty timeout\n" "\n", compiled, compiledby, compilehost); } static void sigHand(int sig) { int stat; switch (sig) { case SIGTERM: Kill++; break; case SIGCHLD: while (waitpid(-1, &stat, WNOHANG) > 0); break; } } int main(int argc, char **argv) { char ch, bypass = 0, szChroot[MAXPATHLEN] = DEFAULT_CHROOT; int status = 0, ret = 1; struct sigaction sa; struct passwd *pass = NULL; u_int penalty = 1; uid_t uid = getuid(); while ((ch = getopt(argc, argv, "vhPc:u:")) != -1) switch (ch) { case 'v': Verbose++; break; case 'P': bypass = 1; break; case 'c': if (uid) { printf("Error:: can`t chroot, please run as root!\n"); goto end; } if (access(optarg, R_OK)) { printf("Error:: can`t chroot to %s #%d - %s\n", optarg, errno, strerror(errno)); goto end; } else strlcpy(szChroot, optarg, MAXPATHLEN); status |= 1; break; case 'u': if (uid) { printf("Error:: can`t setuid, please run as root!\n"); goto end; } pass = getpwnam(optarg); if (!pass) { printf("Error:: can`t find user %s\n", optarg); goto end; } else uid = pass->pw_uid; endpwent(); status |= 2; break; case 'h': default: Usage(); goto end; } argc -= optind; argv += optind; if (!argc || !argv || !*argv) { Usage(); goto end; } else VERB(2) printf("Info:: Chroot=%s Run=%s\n", szChroot, *argv); memset(&sa, 0, sizeof sa); sa.sa_handler = sigHand; sigemptyset(&sa.sa_mask); sigaction(SIGTERM, &sa, NULL); sigaction(SIGCHLD, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction(SIGHUP, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); sigaction(SIGTSTP, &sa, NULL); sigaction(SIGSTOP, &sa, NULL); VERB(5) printf("Info:: Catched signals ...\n"); if (status & 1 && (ret = chroot(szChroot)) == -1) { printf("Error:: error in chroot to %s #%d - %s\n", szChroot, errno, strerror(errno)); ret = 3; goto end; } else VERB(1) printf("Info:: chrooted to %s\n", szChroot); if (status & 2 && setuid(uid) == -1) { printf("Error:: error in setuid to %u #%d - %s\n", uid, errno, strerror(errno)); ret = 4; goto end; } else VERB(1) printf("Info:: setuid to %u\n", uid); status ^= status; while (!Kill && penalty) { switch ((ret = fork())) { case -1: printf("Error:: error in fork #%d - %s\n", errno, strerror(errno)); ret = 5; goto end; case 0: VERB(3) printf("Info:: I`m child of shadows ...\n"); if (execvp(*argv, argv) == -1) { printf("Error:: error in exec %s #%d - %s\n", *argv, errno, strerror(errno)); ret = 6; goto end; } /* never reached !!! */ break; default: wait(&status); kill(ret, SIGTERM); ret = status; } /* penalty timeout retry */ usleep(penalty); if (!bypass) { penalty <<= 1; VERB(2) printf("Info:: penalty timeout %u microseconds\n", penalty); } } if (!penalty) ret = 9; end: return ret; }