sudo.c

来源:互联网 发布:特大网络传销案判决书 编辑:程序博客网 时间:2024/06/05 21:09
/*
**   sudo - run a command as root
*/

#include <stdio.h>
#include <strings.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <pwd.h>

#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif MAXHOSTNAMELEN

/* terryh */
/*#define ALERTMAIL    "root"*/
#define ALERTMAIL    "terryh"
/* terryh */
/* #define LOGFILE      "/usr/local/adm/logs/sudo.log"*/
#define LOGFILE      "/nfs/juno/u5/etc/bfdo/logs/bfdo.log"

extern char          *ctime();
extern long          time();

/* terryh */
/*char               *userfile = "/usr/local/adm/sudoers";*/
char                 *userfile = "/nfs/juno/u5/etc/bfdo/bfdoers";
char                 *progname;
long                 now;

void                 log(), errexit(), firsthostname();
int                  checkdoer();
char                 *isadoer();

main(argc, argv)

int                  argc;
char                 *argv[];

{
     char             doerline[512];
     char             cmd[512];
     char             *dp;
     struct passwd    *pw;
     int              uid, pid;

     progname = argv[0];

     if(argc < 2)
     {
         fprintf(stderr, "usage: %s cmd\n", progname);
         exit(1);
     }

     /* remember who this user really is */

     uid = getuid();

     /* Set userid to be root and group id to be daemon */
    
/* terryh     if((setuid(0)) < 0)
     {
         eperror("setuid");
     }*/

/* terryh    if((setgid(3)) < 0)
     {
         eperror("setgid");
     }*/

     dp = &doerline[0];
     pw = getpwuid(uid);
     now = time((long*) 0);

     if ((dp = isadoer(pw->pw_name,pw->pw_passwd)) == NULL)
     {
         log(pw->pw_name,"FAIL",argc,argv);

         fprintf(stderr,"%s:I don't know you, and I'm telling!\n",*argv);

         if ((pid = fork()) == 0)
             mailmsg(pw->pw_name,argv,argc);
         if (pid == -1)
             eperror("fork");
            
         exit(1);
     }

     argv++, argc--;

     checkdoer(dp,*argv,cmd);

     if (strcmp(cmd,"all") == 0)
     {
         log(pw->pw_name,"",argc, argv);
         execvp(*argv, argv);     /* then do it   */
         eperror(*argv);
     }
    
     if (cmd[0] == '\0')
     {
         log(pw->pw_name,"FAIL",argc,argv);
         fprintf(stderr,
         "%s: I know you, but I can't let you: %s\n",progname,*argv);
         exit(1);
     }

     /* do a specific command with hard-coded path from doer file */
    
     log(pw->pw_name,"",argc,argv);
     execv(cmd, argv);    /* then do it   */
     eperror(*argv);
}

/*
**   isadoer(name, encrypted password) - look for a user in USERFILE 
**       return doer entry on success, else NULL.
*/

char *isadoer(name,password)

char             *name;
char             *password;

{
     register FILE *fp;
     char buf[BUFSIZ];
     struct stat statb;

     if (stat(userfile, &statb))
         eperror(userfile);

     /* terryh
     if (statb.st_uid != 0)
         errexit("%s must be owned by root\n", userfile);*/
    
     /* terryh
     if (statb.st_mode & 022)*/     /* should be og-w */
         /*errexit("bad modes on %s\n", userfile);*/
    
     if ((fp = fopen(userfile,"r")) == 0 )
         errexit("Couldn't open %s\n",userfile);

     while ((fgets(buf,BUFSIZ,fp)) != NULL)
     {
         if(buf[0] == '#')    /* munch comments */
         {
             continue;
         }

         if((strncmp(buf,name,strlen(name))) == 0) 
         {
         /* terryh */
             /* if (not_timed_out(name,password)) */
             {
                 return(buf);
             }
             return(NULL);
         }
     }
    
     return(NULL);
}

/*
**   log this command in the log file
*/

void
log(username, info, argc, argv)

char             *username;
char             *info;
int              argc;
char             **argv;

{
     register FILE *fp;
     fp = fopen(LOGFILE,"a");

     if (fp == NULL)
     {
         errexit("can't open %s.\n", LOGFILE);
     }
    
     fprintf (fp, "%20.20s :", ctime(&now));
     fprintf (fp,"%s",info);
     fprintf (fp,"%7.7s :",username);

     while (argc--) 
     {
         fprintf (fp,"%s ",*argv++);
     }

     fprintf (fp,"\n");
     (void) fclose (fp);
     return;
}

/*
**   eperror - print system error message and exit
**      string s is printed too.
*/

eperror(s)

register char        *s;

{
     fprintf(stderr,"%s: ",progname);
     perror(s);
     exit(1);
}

/*
**   errexit(format, message) - print formatted error and exit
**      also send mail
*/

void
errexit(fmt, arg)

register char        *fmt, *arg;

{
     FILE             *popen();
     FILE             *fd;
     char             hostname[MAXHOSTNAMELEN];
     char             cmd[80];

     fprintf(stderr,"%s: ", progname);
     fprintf(stderr, fmt, arg);

     if ((fd = popen(cmd, "w")) == NULL) 
     {
         return;
     }

     firsthostname(hostname, MAXHOSTNAMELEN);

     (void) sprintf(cmd,
         "/usr/ucb/mail -s \"HELP! %s@%s has problems.\" %s ",
         progname,hostname,ALERTMAIL);

     if ((fd = popen(cmd, "w")) == NULL) 
     {
         return;
     }

     fprintf(fd,"%s: ", progname);
     fprintf(fd, fmt, arg);
     (void) pclose(fd);
     exit(1);
}

/*
**   checkdoer - check to see if user is permitted to do command requested.
**      dp points to a sudoer file entry of the form:
**      'user ['all,','/dir/dir/cmd1,/dir/dir/cmd2,/dir/dir/cmdN'] ie)
**      coggs      /bin/wall,/etc/vipassw,/etc/adduser
**      operator shutdown
**      If 'all' is found, then string "all" is returned in res.
**      If command passed in ap is found, then that command, along
**      with its full path are passed back in res. If nothing is 
**      found, then NULL is returned in res.
*/

checkdoer(dp,ap,res)

char             *dp;         /* doer file entry: 'user cmd1,cmd2,cmdN' */
char             *ap;
char             *res;
{
     char         *cp0, *cp1, *cp2;

     cp0 = dp;

     while(isalnum(*cp0))     /* skip past user field */
     {
         cp0++;
     }

     while(*cp0)      /* search until end of line */
     {
         while(isspace(*cp0))     /* skip to beg of cmd field */
         {
             cp0++;
         }

         if (strncmp(cp0,"all",3) == 0)   /* if cmd field is "all" */
         {
             (void) strcpy(res,"all");    /* then pass it back */
             return;
         }

         cp1 = cp0;

         /* find end of this entry */

         while (*cp1 != '\n' && !isspace(*cp1))
         {
             cp1++;
         }

         cp1--;   /* point to last character of cmd */
         cp2 = cp1;

         while (*cp2 != '/')      /* backup to head of command */
         {
             cp2--;
         }
        
         cp2++;

         cp1++; /* point cp1 to last character + 1 */

         /* if command issued is found then pass whole path back */

         if (strncmp(cp2,ap,strlen(ap)) == 0) 
         {
             (void) strncpy(res,cp0,cp1-cp0); /* copy command back */
         *(res+(cp1-cp0)) = '\0';   /* terryh */
             return;
         }
        
         /* 
          * if it got to here, then command not found *yet*
          * move pointer past next comma and keep looking
          */
        
         while (!isspace(*cp0) && *cp0 != '\n')
         {
             cp0++;
         }

         if (*cp0 == '\n')   /* if at endo of line then fail */
         {
             break;
         }
         else
         {
             continue;
         }
     }
    
     *res = NULL;
     return;
}

/*
**   mailmsg - Snitch on person
*/

mailmsg (user,argv,argc)

char             *user, **argv;
int              argc;

{
     FILE         *popen();
     FILE         *fd;
     char     *p;
     char         cmd[80];
     char         hostname[MAXHOSTNAMELEN];

     firsthostname(hostname, MAXHOSTNAMELEN);

     (void) sprintf(cmd,
         "/usr/ucb/mail -s \"*SECURITY* %s@%s tried to execute %s\" %s ",
         user,hostname,*argv,ALERTMAIL);

     if ((fd = popen(cmd, "w")) == NULL) 
     {
         return;
     }

     fprintf(fd,"%s\@%s tried to do a\n\n ",user,hostname);

     while(argc--)
     {
     for (p = *argv++; *p; p++)
     {
         *p &= 0177;
         (void) fputc(*p, fd);
         if (*p == '\n') (void) fputc('+', fd);
     }
         (void) fputc(' ', fd);
     }

     (void) fputs("\n\nThought you might want to know.",fd);

     (void) pclose(fd);
}

/*
**   firsthostname() - return hostname without domain stuff.
**      Parameters - pointer to char array for name, and length of array.
*/

void
firsthostname(n, l)

char             *n;
int              l;

{
     (void) gethostname(n, l);        /*   get full hostname   */
     n[l-1] = 0;                      /*   make sure null terminated   */
     if (n = index(n, '.')) *n = 0;   /*   blat null on top of '.' if any   */
}
0 0