
# ------------ sudo.c ---- #


/*
**   sudo.c
*/

/*
**   Configurable constants
*/

#define SECURE_PATH "/bin:/usr/bin:/etc"
#define USERFILE    "/usr/local/adm/sudoers"
#define LOGFILE     "/usr/local/adm/sudolog"
#define TIMEDIR     "/usr/local/adm/sudocheck/"
#define TIME         5 /* minutes */
#define SUDO_COP    "root@localhost"

/*
**   To install create the directories in the SECURE_PATH
**   and TIMEDIR and the files USERFILE and LOGFILE.
**   Set the owner of these files to root and the permissions
**   to og-rw.  Change the owner to root for the sudo program
**   and set the permissions to 4111 (--s--x--x).
*/




#define BUFSIZE  256
#define SUCCESS  1
#define FAILED  -1

#define CONFIG_ERR "Configuration error.  " \
                   "Contact your security manager."
#define CONFIG_SUB "Invalid sudo configuration!"
#define SUID_ERR   "Set UID bit not set."
#define STAT_ERR   "Couldn't stat user file"
#define OWNER_ERR  "User file not owned by root"
#define PERM_ERR   "Invalid permissions on user file"
#define OPEN_ERR   "Couldn't open user file"

#define USER_ERR   "You are not set up to execute " \
                   "sudo on this machine."
#define USER_SUB   "SECURITY**  Invalid sudo user!"

#include <ctype.h>
#include <fcntl.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/file.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>

char *getpass();
char *crypt();

FILE *check_config(user)
char *user;
{
   struct stat statb;
   FILE *fp;

   if ((setuid(0)) < 0) /* no setuid */
      mail(CONFIG_SUB,user,SUID_ERR,CONFIG_ERR);
   if (stat(USERFILE, &statb))	/* couldn't stat */
      mail(CONFIG_SUB,user,STAT_ERR,CONFIG_ERR);
   if (statb.st_uid != 0) /* must be owned by root */
      mail(CONFIG_SUB,user,OWNER_ERR,CONFIG_ERR);
   if (statb.st_mode & 044)   /* should be og-rw */
      mail(CONFIG_SUB,user,PERM_ERR,CONFIG_ERR);
   if ((fp = fopen(USERFILE, "r")) == 0) /* open err */
      mail(CONFIG_SUB,user,OPEN_ERR,CONFIG_ERR);
      
     return(fp);
}


char *get_command_list(fp, name, password)
FILE *fp;
char *name;
char *password;
{
  char buffer[BUFSIZ];

   while ((fgets(buffer,BUFSIZ,fp)) != NULL)
   {  
      if(buffer[0] == '#') continue; /* skip remarks */

      if((strncmp(buffer,name,strlen(name))) == 0)
         if (get_password(name,password))
            return(buffer); /* valid user */
         else 
            return(NULL); /* invalid password */
   }

   return(NULL); /* invalid user */
}


int get_password(name, password)
char *name;
char *password;
{
   char     fname[200];
   char     *paswd;
   char     *encrypted;
   struct   stat stab;

   sprintf (fname, "%s/%s",TIMEDIR,name);

   if (stat(fname, &stab) == 0)
   {
      if ((time(NULL) - stab.st_mtime) < (TIME * 60))
      {
         create_file(fname);
         return (SUCCESS);
      }
    }

    paswd = getpass("Password:");
    encrypted = crypt(paswd,password);

    if (strcmp(password, encrypted))
    {
      fprintf (stderr,"Password incorrect\n");
      return(FAILED);
    }

    fflush (stderr);
    fflush (stdout);

   create_file(fname);
   return (SUCCESS);
}


create_file(file)
char     *file;    /* filename to be created */
{
   int      descrip;
   long     timep[2];

   if ((descrip = open(file, O_TRUNC|O_CREAT|O_WRONLY,
        0700)) > 0)
   {
      close (descrip);
      timep[0] = timep[1] = time(0);
      utime (file, timep);
   }
}




int checkdoer (dp, ap)
char *dp;
char *ap;
{
   char 	*cp0, *cp1;
   int not_flag = 0;

   cp0 = dp;

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


   while (*cp0)     /* search until end of line */
   {
      while (isspace (*cp0)) cp0++;   /* skip to cmd */
      if (strncmp (cp0, "not",3) == 0)  not_flag = 1;
      if (strncmp (cp0, "all",3) == 0) return (success);
      cp1 = cp0;

      /* find end of this entry */

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

      if (strncmp (cp0,ap,strlen(ap)) == 0)
      {
         cp1 = '\0';
         if (not_flag) return(FAILED);
         else          return(SUCCESS);
      }

      /* move pointer past and keep looking */

      while (!isspace (*cp0) && *cp0 != '\n') cp0++;

      if (*cp0 == '\n') break;  /* if EOL then fail */
      else continue;
   }

   if (not_flag) return(SUCCESS);
   else          return(FAILED);
}




char *log(username, info, argc, argv)
char      *username;
char      *info;
int       argc;
char      **argv;
{
   FILE *fp;
   long now;
   char ret_st[BUFSIZ];

   if ((fp = fopen(LOGFILE,"a")) == NULL)
      mail("WARNING sudo can't open logfile.",username,
            LOGFILE,"");

   now = time((long*) 0);
   fprintf (fp, "%20.20s :", ctime(&now));
   fprintf (fp, "%10.10s", info);
   fprintf (fp, "%9.9s :",username);

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

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

mail(subject,user,text,err_msg)
char *subject;
char *user;
char *text;
char *err_msg;
{
   char hostname[MAXHOSTNAMELEN];
   FILE *fd;
   FILE *popen();
   char cmd[80];

   firsthostname (hostname, MAXHOSTNAMELEN);

   (void) sprintf (cmd,"/usr/bin/mailx  -s \"%s\" %s ",
                        subject,SUDO_COP);

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

   (void) fputs(text, fd);

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


   (void) pclose(fd);

   fprintf(stderr,"%s %s",err_msg,"\n");
   exit(1);
}



firsthostname(n,l) 
char *n;
int l;
{
   (void) gethostname(n,l); /* get full hostname */
   n[l-1] = 0;         /* make sure null terminated */
   if (n = strchr(n, '.')) *n = 0; /* put null on '.'*/
} 

main(argc,argv)
int argc;
char **argv;
{

   FILE *userfile;
   struct passwd *user;
   int uid;
   char *valid_cmds;
   char *progname;
   char *cmd_line;



   progname = argv[0];

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

   uid = getuid();
   user = getpwuid(uid);

   userfile = check_config(user);

   if ((valid_cmds = get_command_list(userfile,
        user->pw_name,user->pw_passwd)) != NULL)
   { 

      argv++, argc--;

      if (checkdoer(valid_cmds,*argv) != FAILED)
      {

         putenv("PATH=" SECURE_PATH);
         putenv("SHELL=/bin/false");

         (void) log(user->pw_name,"",argc,argv);
         execvp(*argv, argv);   /* then do it */
         perror(*argv);
      }
      else
      {
         (void) log(user->pw_name,"FAIL ",argc, argv);
         fprintf(stderr,"%s: You are not set up to "
           "execute %s with sudo on this machine.\n",
           progname,*argv);
         exit(1);
      }
   }
   else
   {
      cmd_line = log(user->pw_name,"FAIL ",argc, argv);
      mail(USER_SUB,user->pw_name,cmd_line,USER_ERR);
   }
}




# ---- EOF ---- #


