/* ================================================= */ 
/*  
   sukill.c  
   Steve Isaacson 
 
   make it set-uid root
   chown root filename 
   chmod 4755 filename 
*/ 
/* ================================================= */ 
 
#include <stdio.h> 
#include <signal.h> 
#include <ctype.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <time.h> 
#include <fcntl.h> 
 
extern int errno; 
extern char *sys_errlist[]; 
void log_user_info(), log_date(), plog(); 
 
#define MAX_BUF  200 
#define MAX_LINE 100 
#define MAX_PID  100
   /* no pid less than MAX_PID may be killed */
 
char *fn_log   = "/usr/lib/sukill/sukill.log"; 
char *fn_deny  = "/usr/lib/sukill/sukill.deny"; 
char *fn_allow = "/usr/lib/sukill/sukill.allow"; 
 
main (argc, argv) 
int argc; 
char *argv[]; 
{ 
    FILE *fp_log; 
    int i, pid, uid, signal=SIGTERM, arg_start=1; 
    char buf[MAX_BUF], tempbuf[MAX_BUF]; 
    char *username, *getlogin(); 
 
    if ( argc == 1 ) { 
        fprintf ( stderr, 
        "usage: %s [ -signo ] pid ...\n", argv[0] ); 
        exit(1); 
    } 
 
    if ((username = getlogin()) == NULL) { 
        fprintf(stderr, "Who are you?\n"); 
        exit(1); 
    } 
 
    /* is the user denied? */ 
    if ( fexist(fn_deny) ) { 
        if ( in_file (username, fn_deny) ) { 
            fprintf(stderr, "permission denied\n"); 
            exit(1); 
        } 
    } 
 
    /* is the user allowed? */ 
    if ( fexist(fn_allow) ) { 
 
        if ( ! in_file(username, fn_allow) ) { 
            fprintf(stderr, "no permission\n"); 
            exit(1); 
        } 
    } 
 
    /* open the log file */ 
    if ( (fp_log=fopen( fn_log, "a")) == NULL ) { 
        fprintf ( stderr, 
            "Error reading file (%s)\n", fn_log ); 
        exit(1); 
    } 
 
    /* record user name and command-line arguments */
    fprintf(fp_log, "\n%s: ", username); 
    for ( i = 0; i < argc; i++ ) 
        fprintf(fp_log, "%s ", argv[i]); 
    fprintf(fp_log, "\n"); 
 
    log_date(fp_log); 
    log_user_info(fp_log); 
 
    /* was a kill signal specified? */ 
 
    if ( argv[1][0] == '-' ) { 
        arg_start=2; 
        signal=atoi(&argv[1][1]); 
    } 
 
    /* loop through the pids on the command-line */ 
    for ( i=arg_start; i < argc; i++ ) { 
 
        if ( (pid=atoi(argv[i])) < MAX_PID ) { 
            fprintf(stderr, 
                "bad PID number: %d\n", pid); 
            fprintf(fp_log, "bad PID number: %d\n", pid); 
            continue; 
        } 
 
        /* log the info before the fatal blow */ 
        plog(fp_log, pid);  
 
        if ( kill(pid, signal) != 0 ) { 
            perror ("kill"); 
            fprintf(fp_log, "errno %d: %s\n",  
                errno, sys_errlist[errno]); 
        } 
    } 
    fclose(fp_log); 
    exit(0); 
} 
 
/* ================================================= */ 

void log_date(fp) 
FILE *fp; 
{ 
    time_t now; 
 
    if (time(&now)==01) 
        fprintf(fp,"time not available\n"); 
    else 
        fprintf(fp,"%s", ctime(&now)); 
} 
 
/* ================================================= */ 

void log_user_info(fp) 
FILE *fp; 
{ 
    char *ph="HOME", *pn="NAME", *cwd; 
 
    fprintf(fp, "getlogin=%s uid=%d gid= gid=%d ", 
        getlogin(), getuid(), getgid()); 

    fprintf(fp, "euid=%d egid=%d cuserid=%s\n",  
        geteuid(), getegid(), cuserid(NULL)); 
 
    fprintf(fp,"cwd=%s\n", getcwd((char *)NULL, 64)); 
    fprintf(fp,"$%s=%s ", ph, getenv(ph)); 
    fprintf(fp,"$%s=%s\n", pn, getenv(pn)); 
} 
 
/* ================================================= */ 
/* write pid info to log file using a pipe. the ps   */ 
/* flags may need to be changed to suit the local    */
/* version of ps.  If working with many different    */
/* versions, this could also be moved to a           */
/* configuration file so that you're not forced to   */
/* use the compiler to change an argument.           */

void plog(fp, pid) 
FILE *fp; 
int pid; 
{ 
    char cmd[50], buf[MAX_BUF]; 
    FILE *ptr; 
 
    /* get verbose information about this pid */
    sprintf(cmd, "/bin/ps -lfp %d", pid); 
 
    if ((ptr=popen(cmd, "r")) != NULL) 
        while(fgets(buf, sizeof(buf), ptr) != NULL) 
            fprintf(fp, "%s ",buf); 
    pclose(ptr); 
} 
 
/* ================================================= */ 
/* return true if string is in file.  one logname    */
/* per line.                                         */ 
 
int in_file(pstr, pfname) 
char *pstr, *pfname; 
{ 
    int ret_status=0; 
    FILE *fp; 
    char line[MAX_LINE]; 
 
    if ( (fp=fopen(pfname, "r")) == NULL ) 
        return(ret_status); 
 
    while ( fgets(line, MAX_LINE, fp) != NULL ) { 
        if ( memcmp (line, pstr, strlen(pstr))==0 ) { 
            ret_status=1; 
            break; 
        } 
    } 
 
    fclose(fp); 
    return(ret_status); 
} 
 
/* ================================================= */ 
/* return true if file exists                        */ 
 
int fexist(pfname) 
char *pfname; 
{ 
    struct stat sbuf; 
    return ( stat(pfname, &sbuf) == 0 ); 
} 
 
/* ================================================= */ 
