version 1.1, 2010/10/16 03:30:51
|
version 1.2, 2011/06/08 12:45:41
|
Line 0
|
Line 1
|
|
/************************************************************************* |
|
* (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com> |
|
* by Michael Pounov <misho@aitbg.com> |
|
* |
|
* $Author$ |
|
* $Id$ |
|
* |
|
*************************************************************************/ |
|
#include "global.h" |
|
|
|
|
|
int Verbose, Kill, Log; |
|
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 <dir>\tBefore execute chroot to dir [default=/]\n" |
|
"\t-u <user>\tBefore execute change user\n" |
|
"\t-P\t\tInfinit loop, bypass penalty timeout\n" |
|
"\t-S\t\tDisable send log events to syslog\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; |
|
} |
|
} |
|
|
|
static void |
|
logmsg(int prio, const char *fmt, ...) |
|
{ |
|
va_list lst; |
|
|
|
va_start(lst, fmt); |
|
if (!Log) |
|
vsyslog(prio, fmt, lst); |
|
else |
|
vprintf(fmt, lst); |
|
va_end(lst); |
|
} |
|
|
|
|
|
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, "vhSPc:u:")) != -1) |
|
switch (ch) { |
|
case 'v': |
|
Verbose++; |
|
break; |
|
case 'P': |
|
bypass = 1; |
|
break; |
|
case 'S': |
|
Log = 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; |
|
} |
|
|
|
if (!Log) |
|
openlog("wdog", LOG_PID, LOG_USER); |
|
|
|
VERB(2) logmsg(LOG_NOTICE, "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) logmsg(LOG_NOTICE, "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) logmsg(LOG_NOTICE, "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) logmsg(LOG_NOTICE, "Info:: setuid to %u\n", uid); |
|
|
|
status ^= status; |
|
while (!Kill && penalty) { |
|
switch ((ret = fork())) { |
|
case -1: |
|
logmsg(LOG_ERR, "Error:: error in fork #%d - %s\n", errno, strerror(errno)); |
|
ret = 5; |
|
goto end; |
|
case 0: |
|
VERB(3) logmsg(LOG_NOTICE, "Info:: I`m child of shadows ...\n"); |
|
if (execvp(*argv, argv) == -1) { |
|
logmsg(LOG_ERR, "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) logmsg(LOG_NOTICE, "Info:: penalty timeout %u microseconds\n", penalty); |
|
} |
|
} |
|
if (!penalty) |
|
ret = 9; |
|
end: |
|
if (!Log) |
|
closelog(); |
|
return ret; |
|
} |