/*************************************************************************
* (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com>
* by Michael Pounov <misho@aitbg.com>
*
* $Author: misho $
* $Id: wdog.c,v 1.1.2.8 2010/10/18 15:06:10 misho Exp $
*
*************************************************************************/
#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;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>