Cover V02, I06
Article
Listing 1

nov93.tar


Listing 1: 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);
}
}

/* End of File */