used indent to "fix" coding style

This commit is contained in:
Todd C. Miller
1993-10-04 19:10:33 +00:00
parent 847ce91e0f
commit e75a6d3b54
7 changed files with 1030 additions and 979 deletions

235
check.c
View File

@@ -20,7 +20,7 @@
* them to include in future releases. Feel free to send them to:
* Jeff Nieusma nieusma@rootgroup.com
* 3959 Arbol CT (303) 447-8093
* Boulder, CO 80301-1752
* Boulder, CO 80301-1752
*
*******************************************************************
*
@@ -46,13 +46,13 @@
char *getpass();
static int check_timestamp();
static int check_timestamp();
static void check_passwd();
static void update_timestamp();
static void reminder();
static char *timestampfile_p;
static int timedir_is_good;
static int timedir_is_good;
/********************************************************************
@@ -65,38 +65,38 @@ static int timedir_is_good;
void check_user()
{
register int rtn;
register int rtn;
umask ( 077 ); /* make sure the timestamp files are private */
umask(077); /* make sure the timestamp files are private */
if ( setuid (0) ) { /* have to be root to see timestamps */
perror("setuid(0)");
exit(1);
if (setuid(0)) { /* have to be root to see timestamps */
perror("setuid(0)");
exit(1);
}
rtn = check_timestamp();
if ( setruid (uid) ) { /* don't want to be root longer than necessary */
rtn = check_timestamp();
if (setruid(uid)) { /* don't want to be root longer than
* necessary */
#ifndef _AIX
perror("setruid(uid)");
exit(1);
perror("setruid(uid)");
exit(1);
#endif
}
if (rtn && uid) /* if timestamp is not current... */
check_passwd();
if ( rtn && uid ) /* if timestamp is not current... */
check_passwd();
if ( setuid (0) ) { /* have to be root to play with timestamps */
perror("setuid(0)");
exit(1);
if (setuid(0)) { /* have to be root to play with timestamps */
perror("setuid(0)");
exit(1);
}
update_timestamp();
if ( setruid (uid) ) { /* don't want to be root longer than necessary */
update_timestamp();
if (setruid(uid)) { /* don't want to be root longer than
* necessary */
#ifndef _AIX
perror("setruid(uid)");
exit(1);
perror("setruid(uid)");
exit(1);
#endif
}
umask ( 022 ); /* want a real umask to exec() the command */
umask(022); /* want a real umask to exec() the command */
}
@@ -113,69 +113,67 @@ umask ( 022 ); /* want a real umask to exec() the command */
static int check_timestamp()
{
static char timestampfile[MAXPATHLEN+1];
register char *p;
struct stat statbuf;
register int timestamp_is_old = -1;
time_t now;
static char timestampfile[MAXPATHLEN + 1];
register char *p;
struct stat statbuf;
register int timestamp_is_old = -1;
time_t now;
(void) sprintf(timestampfile, "%s/%s", TIMEDIR, user);
timestampfile_p = timestampfile;
timedir_is_good = 1; /* now there's an assumption for ya... */
sprintf ( timestampfile, "%s/%s", TIMEDIR, user );
timestampfile_p = timestampfile;
timedir_is_good = 1; /* now there's an assumption for ya... */
/* walk through the path one directory at a time */
for ( p=timestampfile+1; p=index(p,'/'); *p++='/' ) {
*p='\0';
if ( stat(timestampfile,&statbuf) < 0) {
if ( strcmp ( timestampfile, TIMEDIR ))
fprintf ( stderr, "Cannot stat() %s\n", timestampfile );
timedir_is_good = 0;
*p='/';
break;
/*
* walk through the path one directory at a time
*/
for (p = timestampfile + 1; p = index(p, '/'); *p++ = '/') {
*p = '\0';
if (stat(timestampfile, &statbuf) < 0) {
if (strcmp(timestampfile, TIMEDIR))
(void) fprintf(stderr, "Cannot stat() %s\n", timestampfile);
timedir_is_good = 0;
*p = '/';
break;
}
}
if ( timedir_is_good ) { /* if all the directories are stat()able */
if ( stat(timestampfile, &statbuf) ) { /* does the file exist? */
if ( uid ) reminder(); /* if not, do the reminder */
timestamp_is_old=1; /* and return (1) */
}
else { /* otherwise, check the time */
now = time ( (time_t *) NULL );
if ( now - statbuf.st_mtime < 60 * TIMEOUT )
timestamp_is_old = 0; /* if file is recent, return(0) */
else
timestamp_is_old = 1; /* else make 'em enter password */
/*
* if all the directories are stat()able
*/
if (timedir_is_good) {
if (stat(timestampfile, &statbuf)) { /* does the file exist? */
if (uid)
reminder(); /* if not, do the reminder */
timestamp_is_old = 1; /* and return (1) */
} else { /* otherwise, check the time */
now = time((time_t *) NULL);
if (now - statbuf.st_mtime < 60 * TIMEOUT)
timestamp_is_old = 0; /* if file is recent, return(0) */
else
timestamp_is_old = 1; /* else make 'em enter password */
}
}
/* there was a problem stat()ing a directory */
else {
timestamp_is_old = 1; /* user has to enter password */
if ( mkdir (TIMEDIR, 0700 ) ) { /* make the TIMEDIR directory */
perror("check_timestamp: mkdir");
timedir_is_good = 0;
}
/*
* there was a problem stat()ing a directory
*/
else {
timedir_is_good = 1; /* TIMEDIR now exists */
reminder();
timestamp_is_old = 1; /* user has to enter password */
if (mkdir(TIMEDIR, 0700)) { /* make the TIMEDIR directory */
perror("check_timestamp: mkdir");
timedir_is_good = 0;
} else {
timedir_is_good = 1;/* TIMEDIR now exists */
reminder();
}
}
return (timestamp_is_old);
return (timestamp_is_old);
}
/********************************************************************
*
* update_timestamp()
@@ -185,20 +183,18 @@ return (timestamp_is_old);
static void update_timestamp()
{
register int fd;
register int fd;
if ( timedir_is_good ) {
unlink ( timestampfile_p );
if (( fd = open (timestampfile_p, O_WRONLY|O_CREAT|O_TRUNC, 0600 )) < 0 )
perror( "update_timestamp: open" );
close (fd);
if (timedir_is_good) {
unlink(timestampfile_p);
if ((fd = open(timestampfile_p, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
perror("update_timestamp: open");
close(fd);
}
}
/********************************************************************
*
* check_passwd()
@@ -209,44 +205,41 @@ if ( timedir_is_good ) {
static void check_passwd()
{
char *crypt();
struct passwd *pw_ent;
char *encrypted; /* this comes from /etc/passwd */
char *pass; /* this is what gets entered */
register int counter=TRIES_FOR_PASSWORD;
char *crypt();
struct passwd *pw_ent;
char *encrypted; /* this comes from /etc/passwd */
char *pass; /* this is what gets entered */
register int counter = TRIES_FOR_PASSWORD;
if ((pw_ent = getpwuid(uid)) == NULL) {
(void) sprintf(user, "%u", uid);
log_error(GLOBAL_NO_PW_ENT);
inform_user(GLOBAL_NO_PW_ENT);
exit(1);
}
encrypted = pw_ent -> pw_passwd;
if ( (pw_ent = getpwuid( uid )) == NULL ) {
sprintf ( user, "%u", uid );
log_error( GLOBAL_NO_PW_ENT );
inform_user ( GLOBAL_NO_PW_ENT );
exit (1);
/*
* you get TRIES_FOR_PASSWORD times to guess your password
*/
while (counter > 0) {
pass = getpass("Password:");
if (*pass == (char) NULL)
exit(0);
if (!strcmp(encrypted, crypt(pass, encrypted)))
return; /* if the passwd is correct return() */
--counter; /* otherwise, try again */
(void) fprintf(stderr, "%s\n", INCORRECT_PASSWORD);
}
encrypted = pw_ent -> pw_passwd;
/* you get TRIES_FOR_PASSWORD times to guess your password */
while ( counter > 0 ) {
pass = getpass ( "Password:" );
if ( *pass == (char)NULL ) exit(0);
if ( !strcmp(encrypted, crypt(pass,encrypted)))
return; /* if the passwd is correct return() */
-- counter; /* otherwise, try again */
fprintf ( stderr, "%s\n", INCORRECT_PASSWORD );
}
log_error( PASSWORD_NOT_CORRECT );
inform_user ( PASSWORD_NOT_CORRECT );
exit (1);
log_error(PASSWORD_NOT_CORRECT);
inform_user(PASSWORD_NOT_CORRECT);
exit(1);
}
/********************************************************************
*
* reminder()
@@ -256,21 +249,17 @@ exit (1);
static void reminder()
{
#ifdef SHORT_MESSAGE
fprintf(stderr,"\n%s\n%s\n\n%s\n%s\n\n",
(void) fprintf(stderr, "\n%s\n%s\n\n%s\n%s\n\n",
#else
fprintf(stderr,"\n%s\n%s\n%s\n\n%s\n%s\n\n%s\n%s\n\n",
" sudo version 1.1, Copyright (C) 1991 The Root Group, Inc.",
" sudo comes with ABSOLUTELY NO WARRANTY. This is free software,",
" and you are welcome to redistribute it under certain conditions.",
(void) fprintf(stderr, "\n%s\n%s\n%s\n\n%s\n%s\n\n%s\n%s\n\n",
" sudo version 1.1, Copyright (C) 1991 The Root Group, Inc.",
" sudo comes with ABSOLUTELY NO WARRANTY. This is free software,",
" and you are welcome to redistribute it under certain conditions.",
#endif
"We trust you have received the usual lecture from the local Systems",
"Administrator. It usually boils down to these two things:",
" #1) Respect the privacy of others.",
" #2) Think before you type."
);
"We trust you have received the usual lecture from the local Systems",
"Administrator. It usually boils down to these two things:",
" #1) Respect the privacy of others.",
" #2) Think before you type."
);
}

View File

@@ -20,7 +20,7 @@
* them to include in future releases. Feel free to send them to:
* Jeff Nieusma nieusma@rootgroup.com
* 3959 Arbol CT (303) 447-8093
* Boulder, CO 80301-1752
* Boulder, CO 80301-1752
*
*******************************************************************
*
@@ -36,8 +36,7 @@
/*
* Most of this code has been rewritten to fix bugs and bears little
* resemblence to the original. As such, this file conforms to my
* personal coding style.
* resemblence to the original.
*
* Todd C. Miller (millert@colorado.edu) Sat Sep 4 12:22:04 MDT 1993
*/
@@ -74,25 +73,29 @@ extern char *getwd();
char *find_path(file)
char *file;
{
register char *n; /* for traversing path */
char *path = NULL; /* contents of PATH env var */
char fn[MAXPATHLEN+1]; /* filename (path + file) */
struct stat statbuf; /* for stat(2) */
int statfailed; /* stat(2) return value */
int checkdot = 0; /* check current dir? */
register char *n; /* for traversing path */
char *path = NULL; /* contents of PATH env var */
char fn[MAXPATHLEN + 1]; /* filename (path + file) */
struct stat statbuf; /* for stat(2) */
int statfailed; /* stat(2) return value */
int checkdot = 0; /* check current dir? */
char *qualify();
if (strlen(file) > MAXPATHLEN) {
fprintf(stderr, "%s: path too long: %s\n", Argv[0], file);
(void) fprintf(stderr, "%s: path too long: %s\n", Argv[0], file);
exit(1);
}
/* do we need to search the path? */
/*
* do we need to search the path?
*/
if (index(file, '/'))
return (qualify(file));
/* grab PATH out of environment and make a local copy */
if ((path = getenv("PATH") ) == NULL)
/*
* grab PATH out of environment and make a local copy
*/
if ((path = getenv("PATH")) == NULL)
return (NULL);
if ((path = strdup(path)) == NULL) {
@@ -101,27 +104,27 @@ char *find_path(file)
}
do {
/* cheap strtok() */
if ((n = index(path, ':')))
*n = '\0';
/*
* search current dir last if it is in PATH
* This will miss sneaky things like using './' or './/'
* search current dir last if it is in PATH This will miss sneaky
* things like using './' or './/'
*/
if (*path == NULL || (*path == '.' && *(path+1) == NULL)) {
if (*path == NULL || (*path == '.' && *(path + 1) == NULL)) {
checkdot = 1;
path = n + 1;
continue;
}
/* filename to try */
(void)sprintf(fn, "%s/%s", path, file);
(void) sprintf(fn, "%s/%s", path, file);
/* stat the file to make sure it exists and is executable */
/*
* stat the file to make sure it exists and is executable
*/
statfailed = stat(fn, &statbuf);
if (!statfailed && (statbuf.st_mode & 0000111))
return(qualify(fn));
return (qualify(fn));
else if (statfailed && errno != ENOENT && errno != ENOTDIR) {
perror("find_path: stat");
exit(1);
@@ -130,20 +133,24 @@ char *find_path(file)
} while (n);
/* check current dir if dot was in the PATH */
/*
* check current dir if dot was in the PATH
*/
if (checkdot) {
(void)sprintf(fn, "./%s", file);
(void) sprintf(fn, "./%s", file);
/* stat the file to make sure it exists and is executable */
/*
* stat the file to make sure it exists and is executable
*/
statfailed = stat(fn, &statbuf);
if (!statfailed && (statbuf.st_mode & 0000111))
return(qualify(fn));
return (qualify(fn));
else if (statfailed && errno != ENOENT && errno != ENOTDIR) {
perror("find_path: stat");
exit(1);
}
}
return(NULL);
return (NULL);
}
@@ -156,108 +163,118 @@ char *find_path(file)
*/
char *qualify(n)
char *n; /* name to make fully qualified */
char *n; /* name to make fully qualified */
{
char *beg = NULL; /* begining of a path component */
char *end; /* end of a path component */
static char full[MAXPATHLEN+1]; /* the fully qualified name */
char name[MAXPATHLEN+1]; /* local copy of n */
struct stat statbuf; /* for lstat() */
char *tmp; /* temporary pointer */
char *beg = NULL; /* begining of a path component */
char *end; /* end of a path component */
static char full[MAXPATHLEN + 1]; /* the fully qualified name */
char name[MAXPATHLEN + 1]; /* local copy of n */
struct stat statbuf; /* for lstat() */
char *tmp; /* temporary pointer */
/* is it a bogus path? */
/*
* is it a bogus path?
*/
if (stat(n, &statbuf)) {
if (errno == ENOENT)
return(NULL);
if (errno == ENOENT)
return (NULL);
else {
perror("qualify: stat");
exit(1);
}
}
/* if n is relative, fill full with working dir */
/*
* if n is relative, fill full with working dir
*/
if (*n != '/') {
#ifdef USE_CWD
if (!getcwd(full, (size_t)(MAXPATHLEN+1))) {
if (!getcwd(full, (size_t) (MAXPATHLEN + 1))) {
#else
if (!getwd(full)) {
#endif
fprintf(stderr, "%s: Can't get working directory!\n", Argv[0]);
(void) fprintf(stderr, "%s: Can't get working directory!\n",
Argv[0]);
exit(1);
}
} else
full[0] = '\0';
(void)strcpy(name, n); /* working copy... */
(void) strcpy(name, n); /* working copy... */
do { /* while (end) */
do { /* while (end) */
if (beg)
beg = end + 1; /* skip past the NULL */
beg = end + 1; /* skip past the NULL */
else
beg = name; /* just starting out... */
beg = name; /* just starting out... */
/* find and terminate end of path component */
/*
* find and terminate end of path component
*/
if ((end = index(beg, '/')))
*end = '\0';
if (beg == end)
continue;
else if (!strcmp(beg, "."))
; /* ignore "." */
else if (!strcmp(beg, ".")); /* ignore "." */
else if (!strcmp(beg, "..")) {
if ((tmp = rindex(full, '/')))
*tmp = '\0';
} else {
strcat(full, "/");
strcat(full, beg); /* copy in new component */
strcat(full, beg); /* copy in new component */
}
/* if we used ../.. to go past the root dir just continue */
/*
* if we used ../.. to go past the root dir just continue
*/
if (!full[0])
continue;
/* check for symbolic links */
/*
* check for symbolic links
*/
if (lstat(full, &statbuf)) {
perror("qualify: lstat");
exit(1);
}
if ((statbuf.st_mode & S_IFMT) == S_IFLNK) {
int linklen; /* length of link contents */
char newname[MAXPATHLEN+1]; /* temp storage to build new name */
int linklen; /* length of link contents */
char newname[MAXPATHLEN + 1]; /* temp storage to build new
* name */
linklen = readlink(full, newname, sizeof(newname));
newname[linklen] = '\0';
/* check to make sure we don't go past MAXPATHLEN */
++end;
if (end != (char *)1) {
if (end != (char *) 1) {
if (linklen + strlen(end) >= MAXPATHLEN) {
fprintf(stderr, "%s: path too long: %s/%s\n", Argv[0],
newname, end);
(void )fprintf(stderr, "%s: path too long: %s/%s\n",
Argv[0], newname, end);
exit(1);
}
strcat(newname, "/");
strcat(newname, end); /* copy what's left of end */
}
if (newname[0] == '/') /* reset full if necesary */
full[0] = '\0';
else
if ((tmp = rindex(full, '/'))) /* remove component from full */
*tmp = '\0';
else if ((tmp = rindex(full, '/'))) /* remove component from full */
*tmp = '\0';
strcpy(name, newname); /* reset name with new path */
beg = NULL; /* since we have a new name */
beg = NULL; /* since we have a new name */
}
} while (end);
/* if we resolved to "/" full[0] will be NULL */
/*
* if we resolved to "/" full[0] will be NULL
*/
if (!full[0])
strcpy(full, "/");
return((char *)full);
return ((char *) full);
}
@@ -278,7 +295,7 @@ char *strdup(s1)
if ((s = (char *) malloc(strlen(s1) + 1)) == NULL)
return (NULL);
(void)strcpy(s, s1);
return(s);
(void) strcpy(s, s1);
return (s);
}
#endif

View File

@@ -24,7 +24,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getpass.c based on 5.3 (Berkeley) 9/22/88";
#endif /* LIBC_SCCS and not lint */
#endif /* LIBC_SCCS and not lint */
#include <fcntl.h>
#include <sgtty.h>
@@ -33,69 +33,68 @@ static char sccsid[] = "@(#)getpass.c based on 5.3 (Berkeley) 9/22/88";
#include <stdio.h>
char *
getpass(prompt)
char *prompt;
getpass(prompt)
char *prompt;
{
#if defined(sgi)
struct termio ttyb;
struct termio ttyb;
#else
struct sgttyb ttyb;
struct sgttyb ttyb;
#endif
register int ch;
register char *p;
FILE *fp, *outfp;
long omask;
int fd_tmp;
register int ch;
register char *p;
FILE *fp, *outfp;
long omask;
int fd_tmp;
#if defined(sgi)
tcflag_t svflagval;
tcflag_t svflagval;
#else
int svflagval;
int svflagval;
#endif
#define PASSWD_LEN 8
static char buf[PASSWD_LEN + 1];
/*
* read and write to /dev/tty if possible; else read from
* stdin and write to stderr.
*/
fd_tmp = open("/dev/tty", O_RDWR);
if (fd_tmp < 0 || (outfp = fp = fdopen(fd_tmp, "r+")) == NULL) {
outfp = stderr;
fp = stdin;
}
static char buf[PASSWD_LEN + 1];
/*
* read and write to /dev/tty if possible; else read from stdin and write
* to stderr.
*/
fd_tmp = open("/dev/tty", O_RDWR);
if (fd_tmp < 0 || (outfp = fp = fdopen(fd_tmp, "r+")) == NULL) {
outfp = stderr;
fp = stdin;
}
#if defined(sgi)
(void)ioctl(fileno(fp), TCGETA, &ttyb);
svflagval = ttyb.c_lflag;
ttyb.c_lflag &= ~ECHO;
omask = sigblock(sigmask(SIGINT));
(void)ioctl(fileno(fp), TCSETA, &ttyb);
(void) ioctl(fileno(fp), TCGETA, &ttyb);
svflagval = ttyb.c_lflag;
ttyb.c_lflag &= ~ECHO;
omask = sigblock(sigmask(SIGINT));
(void) ioctl(fileno(fp), TCSETA, &ttyb);
#else
(void)ioctl(fileno(fp), TIOCGETP, &ttyb);
svflagval = ttyb.sg_flags;
ttyb.sg_flags &= ~ECHO;
omask = sigblock(sigmask(SIGINT));
(void)ioctl(fileno(fp), TIOCSETP, &ttyb);
(void) ioctl(fileno(fp), TIOCGETP, &ttyb);
svflagval = ttyb.sg_flags;
ttyb.sg_flags &= ~ECHO;
omask = sigblock(sigmask(SIGINT));
(void) ioctl(fileno(fp), TIOCSETP, &ttyb);
#endif
fprintf(outfp, "%s", prompt);
rewind(outfp); /* implied flush */
for (p = buf; (ch = getc(fp)) != EOF && ch != '\n';)
if (p < buf + PASSWD_LEN)
*p++ = ch;
*p = '\0';
(void)write(fileno(outfp), "\n", 1);
(void) fprintf(outfp, "%s", prompt);
rewind(outfp); /* implied flush */
for (p = buf; (ch = getc(fp)) != EOF && ch != '\n';)
if (p < buf + PASSWD_LEN)
*p++ = ch;
*p = '\0';
(void) write(fileno(outfp), "\n", 1);
#if defined(sgi)
ttyb.c_lflag = svflagval;
(void)ioctl(fileno(fp), TCSETA, &ttyb);
ttyb.c_lflag = svflagval;
(void) ioctl(fileno(fp), TCSETA, &ttyb);
#else
ttyb.sg_flags = svflagval;
(void)ioctl(fileno(fp), TIOCSETP, &ttyb);
ttyb.sg_flags = svflagval;
(void) ioctl(fileno(fp), TIOCSETP, &ttyb);
#endif
(void)sigsetmask(omask);
if (fp != stdin)
(void)fclose(fp);
return(buf);
(void) sigsetmask(omask);
if (fp != stdin)
(void) fclose(fp);
return (buf);
}
#endif

520
logging.c
View File

@@ -20,7 +20,7 @@
* them to include in future releases. Feel free to send them to:
* Jeff Nieusma nieusma@rootgroup.com
* 3959 Arbol CT (303) 447-8093
* Boulder, CO 80301-1752
* Boulder, CO 80301-1752
*
****************************************************************
*
@@ -49,7 +49,7 @@ static void send_mail();
static void reapchild();
static int appropriate();
static char logline[MAXLOGLEN+8];
static char logline[MAXLOGLEN + 8];
/**********************************************************************
*
@@ -59,173 +59,177 @@ static char logline[MAXLOGLEN+8];
* syslogs the error or writes it to the log file
*/
void log_error( code )
int code;
void log_error(code)
int code;
{
char cwd[MAXPATHLEN+1];
int argc;
char **argv;
register char *p;
register int count;
char cwd[MAXPATHLEN + 1];
int argc;
char **argv;
register char *p;
register int count;
#ifndef SYSLOG
register FILE *fp;
time_t now;
register FILE *fp;
time_t now;
#else
register int pri; /* syslog priority */
register int pri; /* syslog priority */
#endif
/* there is no need to log the date and time twice if using syslog */
#ifndef SYSLOG
now=time ( (time_t) 0 );
sprintf( logline, "%19.19s : %8.8s : ", ctime (&now), user );
/*
* there is no need to log the date and time twice if using syslog
*/
#ifndef SYSLOG
now = time((time_t) 0);
(void) sprintf(logline, "%19.19s : %8.8s : ", ctime(&now), user);
#else
sprintf( logline, "%8.8s : ", user );
(void) sprintf(logline, "%8.8s : ", user);
#endif
p = logline + strlen(logline); /* we need a pointer to the end of logline */
#ifdef USE_CWD
getcwd(cwd, (size_t)(MAXPATHLEN+1)); /* so we know where we are... */
#else
getwd(cwd); /* so we know where we are... */
#endif
switch ( code ) {
case ALL_SYSTEMS_GO:
sprintf ( p, "PWD=%s ; COMMAND=", cwd );
#ifdef SYSLOG
pri=Syslog_priority_OK;
#endif
break;
case VALIDATE_NO_USER:
sprintf ( p, "user NOT in sudoers ; PWD=%s ; COMMAND=", cwd );
#ifdef SYSLOG
pri=Syslog_priority_NO;
#endif
break;
case VALIDATE_NOT_OK:
sprintf ( p, "command not allowed ; PWD=%s ; COMMAND=", cwd );
#ifdef SYSLOG
pri=Syslog_priority_NO;
#endif
break;
case VALIDATE_ERROR:
sprintf ( p, "error in %s ; PWD=%s ; command: ", SUDOERS, cwd );
#ifdef SYSLOG
pri=Syslog_priority_NO;
#endif
break;
case GLOBAL_NO_PW_ENT:
sprintf ( p, "There is no /etc/passwd entry for uid %d. ", uid );
#ifdef SYSLOG
pri=Syslog_priority_NO;
#endif
break;
case PASSWORD_NOT_CORRECT:
sprintf ( p, "%d incorrect passwords ; PWD=%s ; COMMAND=",
TRIES_FOR_PASSWORD, cwd );
#ifdef SYSLOG
pri=Syslog_priority_NO;
#endif
break;
case GLOBAL_NO_HOSTNAME:
strcat ( p, "This machine does not have a hostname " );
#ifdef SYSLOG
pri=Syslog_priority_NO;
#endif
break;
case NO_SUDOERS_FILE:
switch ( errno ) {
case ENOENT:
sprintf ( p, "There is no %s file. ", SUDOERS );
break;
case EACCES:
sprintf ( p, "%s needs to run setuid root. ", Argv[0] );
break;
default:
sprintf ( p, "There is a problem opening %s ", SUDOERS );
break;
}
#ifdef SYSLOG
pri=Syslog_priority_NO;
#endif
break;
case GLOBAL_HOST_UNREGISTERED:
sprintf ( p, "gethostbyname() cannot find host %s ", host );
#ifdef SYSLOG
pri=Syslog_priority_NO;
#endif
break;
default:
strcat ( p, "found a wierd error : ");
#ifdef SYSLOG
pri=Syslog_priority_NO;
#endif
break;
}
/* if this error is from load_globals() don't put argv in the message */
if ( ! ( code & GLOBAL_PROBLEM ) ) {
strcat ( logline, cmnd ); /* stuff the command into the logline */
strcat ( logline, " ");
argc = Argc-2;
argv = Argv; argv++;
/*
* we need a pointer to the end of logline
*/
p = logline + strlen(logline);
count = (int)(logline + MAXLOGLEN - p);
/* now stuff as much of the rest of the line as will fit */
while ( count > 0 && argc-- ) {
strncpy ( p, *++argv, count );
strcat ( p, " ");
p += 1 + (count < strlen(*argv) ? count : strlen(*argv) );
count = (int)(logline + MAXLOGLEN - p);
}
if ( count <= 0 ) /* if the line is too long, */
strcat ( p, " ... " ); /* add an elipsis to the end */
}
if ( appropriate(code) )
send_mail();
#ifdef SYSLOG
openlog ( Syslog_ident, Syslog_options, Syslog_facility );
syslog ( pri, logline );
closelog();
/*
* so we know where we are...
*/
#ifdef USE_CWD
getcwd(cwd, (size_t) (MAXPATHLEN + 1));
#else
if ( (fp = fopen ( LOGFILE, "a" )) == NULL ) {
sprintf ( logline, "Can\'t open log file: %s", LOGFILE );
send_mail();
}
else {
fprintf ( fp, "%s\n", logline );
(void) fclose (fp);
}
getwd(cwd);
#endif
}
switch (code) {
case ALL_SYSTEMS_GO:
(void) sprintf(p, "PWD=%s ; COMMAND=", cwd);
#ifdef SYSLOG
pri = Syslog_priority_OK;
#endif
break;
case VALIDATE_NO_USER:
(void) sprintf(p, "user NOT in sudoers ; PWD=%s ; COMMAND=", cwd);
#ifdef SYSLOG
pri = Syslog_priority_NO;
#endif
break;
case VALIDATE_NOT_OK:
(void) sprintf(p, "command not allowed ; PWD=%s ; COMMAND=", cwd);
#ifdef SYSLOG
pri = Syslog_priority_NO;
#endif
break;
case VALIDATE_ERROR:
(void) sprintf(p, "error in %s ; PWD=%s ; command: ", SUDOERS, cwd);
#ifdef SYSLOG
pri = Syslog_priority_NO;
#endif
break;
case GLOBAL_NO_PW_ENT:
(void) sprintf(p, "There is no /etc/passwd entry for uid %d. ",
uid);
#ifdef SYSLOG
pri = Syslog_priority_NO;
#endif
break;
case PASSWORD_NOT_CORRECT:
(void) sprintf(p, "%d incorrect passwords ; PWD=%s ; COMMAND=",
TRIES_FOR_PASSWORD, cwd);
#ifdef SYSLOG
pri = Syslog_priority_NO;
#endif
break;
case GLOBAL_NO_HOSTNAME:
strcat(p, "This machine does not have a hostname ");
#ifdef SYSLOG
pri = Syslog_priority_NO;
#endif
break;
case NO_SUDOERS_FILE:
switch (errno) {
case ENOENT:
(void) sprintf(p, "There is no %s file. ", SUDOERS);
break;
case EACCES:
(void) sprintf(p, "%s needs to run setuid root. ",
Argv[0]);
break;
default:
(void) sprintf(p, "There is a problem opening %s ",
SUDOERS);
break;
}
#ifdef SYSLOG
pri = Syslog_priority_NO;
#endif
break;
case GLOBAL_HOST_UNREGISTERED:
(void) sprintf(p, "gethostbyname() cannot find host %s ", host);
#ifdef SYSLOG
pri = Syslog_priority_NO;
#endif
break;
default:
strcat(p, "found a wierd error : ");
#ifdef SYSLOG
pri = Syslog_priority_NO;
#endif
break;
}
/*
* if this error is from load_globals() don't put argv in the message
*/
if (!(code & GLOBAL_PROBLEM)) {
strcat(logline, cmnd); /* stuff the command into the logline */
strcat(logline, " ");
argc = Argc - 2;
argv = Argv;
argv++;
p = logline + strlen(logline);
count = (int) (logline + MAXLOGLEN - p);
/*
* now stuff as much of the rest of the line as will fit
*/
while (count > 0 && argc--) {
strncpy(p, *++argv, count);
strcat(p, " ");
p += 1 + (count < strlen(*argv) ? count : strlen(*argv));
count = (int) (logline + MAXLOGLEN - p);
}
if (count <= 0) /* if the line is too long, */
strcat(p, " ... "); /* add an elipsis to the end */
}
if (appropriate(code))
send_mail();
#ifdef SYSLOG
openlog(Syslog_ident, Syslog_options, Syslog_facility);
syslog(pri, logline);
closelog();
#else
if ((fp = fopen(LOGFILE, "a")) == NULL) {
(void) sprintf(logline, "Can\'t open log file: %s", LOGFILE);
send_mail();
} else {
(void) fprintf(fp, "%s\n", logline);
(void) fclose(fp);
}
#endif
}
@@ -237,80 +241,69 @@ else {
*
*/
char *exec_argv[]= { "sendmail" ,
"-t" ,
ALERTMAIL ,
(char *) NULL };
char *exec_argv[] = {"sendmail",
"-t",
ALERTMAIL,
(char *) NULL};
static void send_mail()
{
char *mailer=MAILER;
char *subject=MAILSUBJECT;
int fd[2];
char buf[MAXLOGLEN+1024];
char *mailer = MAILER;
char *subject = MAILSUBJECT;
int fd[2];
char buf[MAXLOGLEN + 1024];
if ( (mailer = find_path ( mailer )) == NULL ) {
fprintf (stderr, "%s not found\n", mailer );
exit (1);
if ((mailer = find_path(mailer)) == NULL) {
(void) fprintf(stderr, "%s not found\n", mailer);
exit(1);
}
(void) signal(SIGCHLD, reapchild);
signal ( SIGCHLD, reapchild );
if (fork())
return;
if ( fork () ) return;
/* we don't want any security problems ... */
if ( setuid ( uid ) ) {
perror("setuid(uid)");
exit(1);
/*
* we don't want any security problems ...
*/
if (setuid(uid)) {
perror("setuid(uid)");
exit(1);
}
(void) signal(SIGHUP, SIG_IGN);
(void) signal(SIGINT, SIG_IGN);
(void) signal(SIGQUIT, SIG_IGN);
signal ( SIGHUP, SIG_IGN );
signal ( SIGINT, SIG_IGN );
signal ( SIGQUIT, SIG_IGN );
if ( pipe(fd) ) {
perror( "send_mail: pipe" );
exit ( 1 );
if (pipe(fd)) {
perror("send_mail: pipe");
exit(1);
}
(void) dup2(fd[0], 0);
(void) dup2(fd[1], 1);
(void) close(fd[0]);
(void) close(fd[1]);
(void) dup2 ( fd[0], 0 );
(void) dup2 ( fd[1], 1 );
(void) close (fd[0]);
(void) close (fd[1]);
if (!fork()) { /* child */
(void) close(1);
execve(mailer, exec_argv, Envp);
if ( ! fork () ) {
/* this should not happen */
perror("execve");
exit(1);
} else { /* parent */
(void) close(0);
/* feed the data to sendmail */
(void) sprintf(buf, "To: %s\nSubject: %s\n\n%s\n\n",
ALERTMAIL, subject, logline);
write(1, buf, strlen(buf));
close(1);
/* child parent */
(void) close(1);
execv ( mailer, exec_argv );
/* this should not happen */
perror( "execv");
exit (1);
exit(0);
}
else {
(void) close(0);
/* feed the data to sendmail */
sprintf (buf, "To: %s\nSubject: %s\n\n%s\n\n",
ALERTMAIL, subject, logline );
write ( 1, buf, strlen(buf));
close ( 1 );
exit ( 0 );
}
}
/****************************************************************
*
* reapchild()
@@ -318,15 +311,13 @@ else {
* This function gets rid fo all the ugly zombies
*/
static void reapchild ()
static void reapchild()
{
(void) wait ( NULL );
(void) wait(NULL);
}
/**********************************************************************
*
* inform_user ()
@@ -335,62 +326,57 @@ static void reapchild ()
* when an error occurs
*/
void inform_user( code )
int code;
void inform_user(code)
int code;
{
switch ( code ) {
switch (code) {
case VALIDATE_NO_USER:
(void) fprintf(stderr,
"%s is not in the sudoers file. This incident will be reported.\n\n",
user);
break;
case VALIDATE_NO_USER:
fprintf( stderr,
"%s is not in the sudoers file. This incident will be reported.\n\n",
user );
break;
case VALIDATE_NOT_OK:
(void) fprintf(stderr,
"Sorry, user %s is not allowed to execute %s\n\n",
user, cmnd);
break;
case VALIDATE_NOT_OK:
fprintf( stderr,
"Sorry, user %s is not allowed to execute %s\n\n",
user, cmnd );
break;
case VALIDATE_ERROR:
fprintf( stderr,
"Sorry, there is a fatal error in the sudoers file.\n\n" );
break;
case VALIDATE_ERROR:
(void) fprintf(stderr,
"Sorry, there is a fatal error in the sudoers file.\n\n");
break;
case GLOBAL_NO_PW_ENT:
fprintf ( stderr,
"Intruder Alert! You don\'t exist in the passwd file\n\n");
break;
case GLOBAL_NO_PW_ENT:
(void) fprintf(stderr,
"Intruder Alert! You don\'t exist in the passwd file\n\n");
break;
case GLOBAL_NO_HOSTNAME:
fprintf ( stderr,
"This machine does not have a hostname\n\n" );
break;
case GLOBAL_NO_HOSTNAME:
(void) fprintf(stderr,
"This machine does not have a hostname\n\n");
break;
case GLOBAL_HOST_UNREGISTERED:
fprintf ( stderr,
"This machine is not available via gethostbyname()\n\n");
break;
case GLOBAL_HOST_UNREGISTERED:
(void) fprintf(stderr,
"This machine is not available via gethostbyname()\n\n");
break;
case PASSWORD_NOT_CORRECT:
fprintf ( stderr, "Password not entered correctly after %d tries\n\n",
TRIES_FOR_PASSWORD );
break;
default:
fprintf ( stderr,
"Something wierd happened.\n\n" );
break;
case PASSWORD_NOT_CORRECT:
(void) fprintf(stderr, "Password not entered correctly after %d tries\n\n",
TRIES_FOR_PASSWORD);
break;
default:
(void) fprintf(stderr,
"Something wierd happened.\n\n");
break;
}
}
/****************************************************************
*
* appropriate()
@@ -398,18 +384,19 @@ switch ( code ) {
* This function determines whether to send mail or not...
*/
static int appropriate( code )
int code;
static int appropriate(code)
int code;
{
switch ( code ) {
switch (code) {
/* these will NOT send mail */
case VALIDATE_OK:
/*
* these will NOT send mail
*/
case VALIDATE_OK:
case PASSWORD_NOT_CORRECT:
/* case ALL_SYSTEMS_GO: this is the same as OK */
return (0);
return (0);
break;
case VALIDATE_NO_USER:
@@ -428,9 +415,10 @@ switch ( code ) {
#endif
break;
/* these WILL send mail */
case VALIDATE_ERROR:
/*
* these WILL send mail
*/
case VALIDATE_ERROR:
case NO_SUDOERS_FILE:
default:
return (1);

684
parse.c
View File

@@ -20,15 +20,17 @@
* them to include in future releases. Feel free to send them to:
* Jeff Nieusma nieusma@rootgroup.com
* 3959 Arbol CT (303) 447-8093
* Boulder, CO 80301-1752
* Boulder, CO 80301-1752
*
********************************************************************************
* parse.c, sudo project
* David R. Hieb
* March 18, 1991
*
* routines to implement and maintain the parsing and list management.
*******************************************************************************/
**************************************************************************
*
* parse.c, sudo project
* David R. Hieb
* March 18, 1991
*
* routines to implement and maintain the parsing and list management.
*/
#include <stdio.h>
#include <strings.h>
#include <ctype.h>
@@ -37,7 +39,9 @@
#include "sudo.h"
/* there are 3 main lists (User, Host_Alias, Cmnd_Alias) and 1 extra list */
/*
* there are 3 main lists (User, Host_Alias, Cmnd_Alias) and 1 extra list
*/
#define NUM_LISTS 3+1
extern char *user, *host, *cmnd;
@@ -49,357 +53,397 @@ int parse_error = FALSE, found_user = FALSE;
int next_type, num_host_alias = 0, num_cmnd_alias = 0;
LINK tmp_ptr, reset_ptr, save_ptr, list_ptr[NUM_LISTS];
/*******************************************************************************
* inserts a node into list 'list_num' and updates list_ptr[list_num]
*******************************************************************************/
/*
* inserts a node into list 'list_num' and updates list_ptr[list_num]
*/
void insert_member(list_num, token_type, op_type, data_string)
int token_type, list_num;
char op_type;
char *data_string;
int token_type, list_num;
char op_type;
char *data_string;
{
tmp_ptr = (LINK)malloc(sizeof(LIST));
tmp_ptr->type = token_type;
tmp_ptr->op = op_type;
tmp_ptr->data = (char *)malloc(strlen(data_string)+1);
strcpy(tmp_ptr->data, data_string);
tmp_ptr->next = (new_list[list_num] == TRUE) ? NULL : list_ptr[list_num];
tmp_ptr = (LINK) malloc(sizeof(LIST));
tmp_ptr -> type = token_type;
tmp_ptr -> op = op_type;
tmp_ptr -> data = (char *) malloc(strlen(data_string) + 1);
strcpy(tmp_ptr -> data, data_string);
tmp_ptr -> next = (new_list[list_num] == TRUE) ? NULL : list_ptr[list_num];
list_ptr[list_num] = list_ptr[EXTRA_LIST] = tmp_ptr;
}
/*******************************************************************************
* diagnostic list printing utility that prints list 'list_num'
*******************************************************************************/
/*
* diagnostic list printing utility that prints list 'list_num'
*/
void print_list(list_num)
int list_num;
int list_num;
{
LINK tmptmp_ptr;
LINK tmptmp_ptr;
tmptmp_ptr = list_ptr[list_num];
tmptmp_ptr = list_ptr[list_num];
while (list_ptr[list_num] != NULL) {
printf("type = %d, op = %c, data = %s\n", list_ptr[list_num]->type,
list_ptr[list_num]->op, list_ptr[list_num]->data);
tmp_ptr = list_ptr[list_num];
list_ptr[list_num] = tmp_ptr->next;
while (list_ptr[list_num] != NULL) {
(void) printf("type = %d, op = %c, data = %s\n",
list_ptr[list_num] -> type,
list_ptr[list_num] -> op, list_ptr[list_num] -> data);
tmp_ptr = list_ptr[list_num];
list_ptr[list_num] = tmp_ptr -> next;
}
list_ptr[list_num] = tmptmp_ptr;
list_ptr[list_num] = tmptmp_ptr;
}
/*******************************************************************************
* delete list utility that deletes list 'list_num'
*******************************************************************************/
/*
* delete list utility that deletes list 'list_num'
*/
void delete_list(list_num)
int list_num;
int list_num;
{
while (list_ptr[list_num] != NULL) {
tmp_ptr = list_ptr[list_num];
list_ptr[list_num] = tmp_ptr->next;
/* free(tmp_ptr); */
while (list_ptr[list_num] != NULL) {
tmp_ptr = list_ptr[list_num];
list_ptr[list_num] = tmp_ptr -> next;
/* free(tmp_ptr); */
}
}
/*******************************************************************************
* this routine is what the lex/yacc code calls to build the different lists.
* once the lists are all built, control eventually returns to validate().
*******************************************************************************/
/*
* this routine is what the lex/yacc code calls to build the different lists.
* once the lists are all built, control eventually returns to validate().
*/
int call_back(token_type, op_type, data_string)
int token_type;
char op_type;
char *data_string;
int token_type;
char op_type;
char *data_string;
{
/* all nodes start out in the extra list since the node name is received last */
list_num = EXTRA_LIST;
/*
* all nodes start out in the extra list since the node name
* is received last
*/
list_num = EXTRA_LIST;
/*
* if the last received node is TYPE1, then we can classify the list
* and effectively transfer the extra list to the correct list type.
*/
if (token_type == TYPE1) {
/* we have just build a "Host_Alias" list */
if (strcmp(data_string, "Host_Alias") == 0) {
list_num = HOST_LIST;
if (num_host_alias > 0) {
reset_ptr->next = list_ptr[HOST_LIST];
}
num_host_alias++;
}
/* we have just build a "Cmnd_Alias" list */
else if (strcmp(data_string, "Cmnd_Alias") == 0) {
list_num = CMND_LIST;
if (num_cmnd_alias > 0) {
reset_ptr->next = list_ptr[CMND_LIST];
}
num_cmnd_alias++;
}
/* we have just build a "User" list */
else {
list_num = USER_LIST;
user_list_found = TRUE;
}
new_list[EXTRA_LIST] = TRUE;
new_list[list_num] = FALSE;
list_ptr[list_num] = list_ptr[EXTRA_LIST];
/*
* if the last received node is TYPE1, then we can classify the list
* and effectively transfer the extra list to the correct list type.
*/
if (token_type == TYPE1) {
/*
* we have just build a "Host_Alias" list
*/
if (strcmp(data_string, "Host_Alias") == 0) {
list_num = HOST_LIST;
if (num_host_alias > 0) {
reset_ptr -> next = list_ptr[HOST_LIST];
}
num_host_alias++;
}
/*
* we have just build a "Cmnd_Alias" list
*/
else if (strcmp(data_string, "Cmnd_Alias") == 0) {
list_num = CMND_LIST;
if (num_cmnd_alias > 0) {
reset_ptr -> next = list_ptr[CMND_LIST];
}
num_cmnd_alias++;
}
/*
* we have just build a "User" list
*/
else {
list_num = USER_LIST;
user_list_found = TRUE;
}
new_list[EXTRA_LIST] = TRUE;
new_list[list_num] = FALSE;
list_ptr[list_num] = list_ptr[EXTRA_LIST];
}
/*
* actually link the new node into list 'list_num'
*/
insert_member(list_num, token_type, op_type, data_string);
/* actually link the new node into list 'list_num' */
insert_member(list_num, token_type, op_type, data_string);
if (new_list[list_num] == TRUE) {
reset_ptr = list_ptr[list_num];
new_list[list_num] = FALSE;
if (new_list[list_num] == TRUE) {
reset_ptr = list_ptr[list_num];
new_list[list_num] = FALSE;
}
/*
* we process one user record at a time from the sudoers file. if we
* find the user were looking for, we return to lex/yacc declaring
* that we have done so. otherwise, we reset the user list, delete the
* nodes and start over again looking for the user.
*/
if (user_list_found == TRUE) {
if (list_ptr[list_num]->type == TYPE1 &&
strcmp(list_ptr[list_num]->data, user) == 0) {
return(FOUND_USER);
}
else {
new_list[list_num] = TRUE;
user_list_found = FALSE;
delete_list(list_num);
}
/*
* we process one user record at a time from the sudoers file. if we
* find the user were looking for, we return to lex/yacc declaring
* that we have done so. otherwise, we reset the user list, delete the
* nodes and start over again looking for the user.
*/
if (user_list_found == TRUE) {
if (list_ptr[list_num] -> type == TYPE1 &&
strcmp(list_ptr[list_num] -> data, user) == 0) {
return (FOUND_USER);
} else {
new_list[list_num] = TRUE;
user_list_found = FALSE;
delete_list(list_num);
}
}
return(NOT_FOUND_USER);
return (NOT_FOUND_USER);
}
/*******************************************************************************
* this routine is called from cmnd_check() to resolve whether or not
* a user is permitted to perform a to-yet-be-determined command for
* a certain host name.
*******************************************************************************/
/*
* this routine is called from cmnd_check() to resolve whether or not
* a user is permitted to perform a to-yet-be-determined command for
* a certain host name.
*/
int host_type_ok()
{
/* check for the reserved keyword 'ALL'. if so, don't check the host name */
if (strcmp(list_ptr[USER_LIST]->data, "ALL") == 0) {
return(TRUE);
}
/* this case is the normal lowercase hostname */
else if (isupper(list_ptr[USER_LIST]->data[0]) == FALSE) {
return(strcmp(list_ptr[USER_LIST]->data, host) == 0);
}
/* by now we have a Host_Alias that will have to be expanded */
else {
save_ptr = list_ptr[HOST_LIST];
while (list_ptr[HOST_LIST] != NULL) {
if ((list_ptr[HOST_LIST]->type == TYPE2) &&
(strcmp(list_ptr[HOST_LIST]->data,
list_ptr[USER_LIST]->data) == 0)) {
next_type = list_ptr[HOST_LIST]->next->type;
tmp_ptr = list_ptr[HOST_LIST];
list_ptr[HOST_LIST] = tmp_ptr->next;
while (next_type == TYPE3) {
if (strcmp(list_ptr[HOST_LIST]->data, host) == 0) {
list_ptr[HOST_LIST] = save_ptr;
return(TRUE);
}
if (list_ptr[HOST_LIST]->next != NULL) {
next_type = list_ptr[HOST_LIST]->next->type;
tmp_ptr = list_ptr[HOST_LIST];
list_ptr[HOST_LIST] = tmp_ptr->next;
}
else {
next_type = ~TYPE3;
}
}
}
else {
tmp_ptr = list_ptr[HOST_LIST];
list_ptr[HOST_LIST] = tmp_ptr->next;
}
}
list_ptr[HOST_LIST] = save_ptr;
return(FALSE);
}
}
/*******************************************************************************
* this routine is called from cmnd_check() to resolve whether or not
* a user is permitted to perform a certain command on the already
* established host.
*******************************************************************************/
int cmnd_type_ok()
{
/* check for the reserved keyword 'ALL'. */
if (strcmp(list_ptr[USER_LIST]->data, "ALL") == 0) {
/* if the command has an absolute path, let them do it */
if (cmnd[0] == '/') {
return(MATCH);
}
/* if the command does not have an absolute path, forget it */
else {
return(NO_MATCH);
}
}
/* if the command has an absolute path, check it out */
else if (list_ptr[USER_LIST]->data[0] == '/') {
/* op | data | return value
*---------------------------------
* ' ' | No Match | return(NO_MATCH)
* '!' | No Match | return(NO_MATCH)
* ' ' | A Match | return(MATCH)
* '!' | A Match | return(QUIT_NOW)
*
* these special cases are important in subtracting from the
* Universe of commands in something like:
* user machine=ALL,!/bin/rm,!/etc/named ...
/*
* check for the reserved keyword 'ALL'. if so, don't check the host name
*/
if (strcmp(list_ptr[USER_LIST]->data, cmnd) == 0) {
if (list_ptr[USER_LIST]->op == '!') {
return(QUIT_NOW);
}
else {
return(MATCH);
}
}
else {
return(NO_MATCH);
}
if (strcmp(list_ptr[USER_LIST] -> data, "ALL") == 0) {
return (TRUE);
}
/* by now we have a Cmnd_Alias that will have to be expanded */
else {
save_ptr = list_ptr[CMND_LIST];
while (list_ptr[CMND_LIST] != NULL) {
if ((list_ptr[CMND_LIST]->type == TYPE2) &&
(strcmp(list_ptr[CMND_LIST]->data,
list_ptr[USER_LIST]->data) == 0)) {
next_type = list_ptr[CMND_LIST]->next->type;
tmp_ptr = list_ptr[CMND_LIST];
list_ptr[CMND_LIST] = tmp_ptr->next;
while (next_type == TYPE3) {
if (strcmp(list_ptr[CMND_LIST]->data, cmnd) == 0) {
if (list_ptr[USER_LIST]->op == '!') {
list_ptr[CMND_LIST] = save_ptr;
return(QUIT_NOW);
}
else {
list_ptr[CMND_LIST] = save_ptr;
return(MATCH);
}
}
if (list_ptr[CMND_LIST]->next != NULL) {
next_type = list_ptr[CMND_LIST]->next->type;
tmp_ptr = list_ptr[CMND_LIST];
list_ptr[CMND_LIST] = tmp_ptr->next;
}
else {
next_type = ~TYPE3;
}
}
}
else {
tmp_ptr = list_ptr[CMND_LIST];
list_ptr[CMND_LIST] = tmp_ptr->next;
}
}
list_ptr[CMND_LIST] = save_ptr;
return(NO_MATCH);
/*
* this case is the normal lowercase hostname
*/
else if (isupper(list_ptr[USER_LIST] -> data[0]) == FALSE) {
return (strcmp(list_ptr[USER_LIST] -> data, host) == 0);
}
/*
* by now we have a Host_Alias that will have to be expanded
*/
else {
save_ptr = list_ptr[HOST_LIST];
while (list_ptr[HOST_LIST] != NULL) {
if ((list_ptr[HOST_LIST] -> type == TYPE2) &&
(strcmp(list_ptr[HOST_LIST] -> data,
list_ptr[USER_LIST] -> data) == 0)) {
next_type = list_ptr[HOST_LIST] -> next -> type;
tmp_ptr = list_ptr[HOST_LIST];
list_ptr[HOST_LIST] = tmp_ptr -> next;
while (next_type == TYPE3) {
if (strcmp(list_ptr[HOST_LIST] -> data, host) == 0) {
list_ptr[HOST_LIST] = save_ptr;
return (TRUE);
}
if (list_ptr[HOST_LIST] -> next != NULL) {
next_type = list_ptr[HOST_LIST] -> next -> type;
tmp_ptr = list_ptr[HOST_LIST];
list_ptr[HOST_LIST] = tmp_ptr -> next;
} else {
next_type = ~TYPE3;
}
}
} else {
tmp_ptr = list_ptr[HOST_LIST];
list_ptr[HOST_LIST] = tmp_ptr -> next;
}
}
list_ptr[HOST_LIST] = save_ptr;
return (FALSE);
}
}
/*******************************************************************************
* this routine is called from validate() after the call_back() routine
* has built all the possible lists. this routine steps thru the user list
* calling on host_type_ok() and cmnd_type_ok() trying to resolve whether
* or not the user will be able to execute the command on the host.
*******************************************************************************/
int cmnd_check()
{
int return_code;
while (list_ptr[USER_LIST] != NULL) {
if ((list_ptr[USER_LIST]->type == TYPE2) && host_type_ok()) {
next_type = list_ptr[USER_LIST]->next->type;
tmp_ptr = list_ptr[USER_LIST];
list_ptr[USER_LIST] = tmp_ptr->next;
while (next_type == TYPE3) {
return_code = cmnd_type_ok();
if (return_code == MATCH) {
return(VALIDATE_OK);
}
else if (return_code == QUIT_NOW) {
return(VALIDATE_NOT_OK);
}
if (list_ptr[USER_LIST]->next != NULL) {
next_type = list_ptr[USER_LIST]->next->type;
tmp_ptr = list_ptr[USER_LIST];
list_ptr[USER_LIST] = tmp_ptr->next;
}
else {
next_type = ~TYPE3;
}
}
}
else {
tmp_ptr = list_ptr[USER_LIST];
list_ptr[USER_LIST] = tmp_ptr->next;
}
}
return(VALIDATE_NOT_OK);
}
/*******************************************************************************
* this routine is called from the sudo.c module and tries to validate
* the user, host and command triplet.
*******************************************************************************/
int validate()
{
FILE *sudoers_fp;
int i, return_code;
if ((sudoers_fp = fopen(SUDOERS, "r")) == NULL ) {
perror(SUDOERS);
log_error( NO_SUDOERS_FILE );
exit(1);
}
yyin = sudoers_fp;
yyout = stdout;
for (i = 0; i < NUM_LISTS; i++)
new_list[i] = TRUE;
/*
* yyparse() returns with one of 3 values: 0) yyparse() worked fine;
* 1) yyparse() failed; FOUND_USER) the user was found and yyparse()
* was returned from prematurely.
* this routine is called from cmnd_check() to resolve whether or not
* a user is permitted to perform a certain command on the already
* established host.
*/
return_code = yyparse();
/* don't need to keep this open... */
(void) fclose (sudoers_fp);
/* if a parsing error occurred, set return_code accordingly */
if (parse_error == TRUE) {
return_code = PARSE_ERROR;
int cmnd_type_ok()
{
/*
* check for the reserved keyword 'ALL'.
*/
if (strcmp(list_ptr[USER_LIST] -> data, "ALL") == 0) {
/* if the command has an absolute path, let them do it */
if (cmnd[0] == '/') {
return (MATCH);
}
/* if the command does not have an absolute path, forget it */
else {
return (NO_MATCH);
}
}
/* if the user was not found, set the return_code accordingly */
if (found_user == FALSE) {
return_code = NOT_FOUND_USER;
/*
* if the command has an absolute path, check it out
*/
else if (list_ptr[USER_LIST] -> data[0] == '/') {
/*
* op | data | return value
* ---------------------------------
* ' ' | No Match | return(NO_MATCH)
* '!' | No Match | return(NO_MATCH)
* ' ' | A Match | return(MATCH)
* '!' | A Match | return(QUIT_NOW)
*
* these special cases are important in subtracting from the Universe
* of commands in something like:
* user machine=ALL,!/bin/rm,!/etc/named ...
*/
if (strcmp(list_ptr[USER_LIST] -> data, cmnd) == 0) {
if (list_ptr[USER_LIST] -> op == '!') {
return (QUIT_NOW);
} else {
return (MATCH);
}
} else {
return (NO_MATCH);
}
}
/* handle the 3 cases individually &*/
switch(return_code) {
case FOUND_USER:
return_code = cmnd_check();
delete_list(USER_LIST);
delete_list(HOST_LIST);
delete_list(CMND_LIST);
return(return_code);
break;
case NOT_FOUND_USER:
return(VALIDATE_NO_USER);
break;
case PARSE_ERROR:
return(VALIDATE_ERROR);
break;
/*
* by now we have a Cmnd_Alias that will have to be expanded
*/
else {
save_ptr = list_ptr[CMND_LIST];
while (list_ptr[CMND_LIST] != NULL) {
if ((list_ptr[CMND_LIST] -> type == TYPE2) &&
(strcmp(list_ptr[CMND_LIST] -> data,
list_ptr[USER_LIST] -> data) == 0)) {
next_type = list_ptr[CMND_LIST] -> next -> type;
tmp_ptr = list_ptr[CMND_LIST];
list_ptr[CMND_LIST] = tmp_ptr -> next;
while (next_type == TYPE3) {
if (strcmp(list_ptr[CMND_LIST] -> data, cmnd) == 0) {
if (list_ptr[USER_LIST] -> op == '!') {
list_ptr[CMND_LIST] = save_ptr;
return (QUIT_NOW);
} else {
list_ptr[CMND_LIST] = save_ptr;
return (MATCH);
}
}
if (list_ptr[CMND_LIST] -> next != NULL) {
next_type = list_ptr[CMND_LIST] -> next -> type;
tmp_ptr = list_ptr[CMND_LIST];
list_ptr[CMND_LIST] = tmp_ptr -> next;
} else {
next_type = ~TYPE3;
}
}
} else {
tmp_ptr = list_ptr[CMND_LIST];
list_ptr[CMND_LIST] = tmp_ptr -> next;
}
}
list_ptr[CMND_LIST] = save_ptr;
return (NO_MATCH);
}
}
/*
* this routine is called from validate() after the call_back() routine
* has built all the possible lists. this routine steps thru the user list
* calling on host_type_ok() and cmnd_type_ok() trying to resolve whether
* or not the user will be able to execute the command on the host.
*/
int cmnd_check()
{
int return_code;
while (list_ptr[USER_LIST] != NULL) {
if ((list_ptr[USER_LIST] -> type == TYPE2) && host_type_ok()) {
next_type = list_ptr[USER_LIST] -> next -> type;
tmp_ptr = list_ptr[USER_LIST];
list_ptr[USER_LIST] = tmp_ptr -> next;
while (next_type == TYPE3) {
return_code = cmnd_type_ok();
if (return_code == MATCH) {
return (VALIDATE_OK);
} else if (return_code == QUIT_NOW) {
return (VALIDATE_NOT_OK);
}
if (list_ptr[USER_LIST] -> next != NULL) {
next_type = list_ptr[USER_LIST] -> next -> type;
tmp_ptr = list_ptr[USER_LIST];
list_ptr[USER_LIST] = tmp_ptr -> next;
} else {
next_type = ~TYPE3;
}
}
} else {
tmp_ptr = list_ptr[USER_LIST];
list_ptr[USER_LIST] = tmp_ptr -> next;
}
}
return (VALIDATE_NOT_OK);
}
/*
* this routine is called from the sudo.c module and tries to validate
* the user, host and command triplet.
*/
int validate()
{
FILE *sudoers_fp;
int i, return_code;
if ((sudoers_fp = fopen(SUDOERS, "r")) == NULL) {
perror(SUDOERS);
log_error(NO_SUDOERS_FILE);
exit(1);
}
yyin = sudoers_fp;
yyout = stdout;
for (i = 0; i < NUM_LISTS; i++)
new_list[i] = TRUE;
/*
* yyparse() returns with one of 3 values: 0) yyparse() worked fine;
* 1) yyparse() failed; FOUND_USER) the user was found and yyparse()
* was returned from prematurely.
*/
return_code = yyparse();
/*
* don't need to keep this open...
*/
(void) fclose(sudoers_fp);
/*
* if a parsing error occurred, set return_code accordingly
*/
if (parse_error == TRUE) {
return_code = PARSE_ERROR;
}
/*
* if the user was not found, set the return_code accordingly
*/
if (found_user == FALSE) {
return_code = NOT_FOUND_USER;
}
/*
* handle the 3 cases individually
*/
switch (return_code) {
case FOUND_USER:
return_code = cmnd_check();
delete_list(USER_LIST);
delete_list(HOST_LIST);
delete_list(CMND_LIST);
return (return_code);
break;
case NOT_FOUND_USER:
return (VALIDATE_NO_USER);
break;
case PARSE_ERROR:
return (VALIDATE_ERROR);
break;
}
}

239
sudo.c
View File

@@ -20,7 +20,7 @@
* them to include in future releases. Feel free to send them to:
* Jeff Nieusma nieusma@rootgroup.com
* 3959 Arbol CT (303) 447-8093
* Boulder, CO 80301-1752
* Boulder, CO 80301-1752
*
**************************************************************************
*
@@ -56,7 +56,7 @@
#include "sudo.h"
extern char *malloc();
int Argc;
int Argc;
char **Argv;
char **Envp;
char *host;
@@ -78,74 +78,79 @@ uid_t uid;
*/
main(argc, argv, envp)
int argc; char **argv; char **envp;
int argc;
char **argv;
char **envp;
{
static void usage();
int rtn;
static void usage();
int rtn;
Argv=argv;
Argc=argc;
Argv = argv;
Argc = argc;
/* if nothing is passed, we don't need to do anything... */
if ( argc < 2 ) usage();
/*
* if nothing is passed, we don't need to do anything...
*/
if (argc < 2)
usage();
/* close all file descriptors to make sure we have a nice
* clean slate from which to work.
*/
for ( rtn = getdtablesize() - 1 ; rtn > 3; rtn -- )
(void)close(rtn);
/*
* close all file descriptors to make sure we have a nice
* clean slate from which to work.
*/
for (rtn = getdtablesize() - 1; rtn > 3; rtn--)
(void) close(rtn);
load_globals(); /* load the user host cmnd and uid variables */
load_globals(); /* load the user host cmnd and uid variables */
clean_envp(envp); /* build Envp based on envp (w/o LD_*) */
clean_envp(envp); /* build Envp based on envp (w/o LD_*) */
if ( setuid(0) ) {
perror("setuid(0)");
exit(1);
if (setuid(0)) {
perror("setuid(0)");
exit(1);
}
rtn=validate();
if ( setruid(uid) ) {
rtn = validate();
if (setruid(uid)) {
#ifndef _AIX
perror("setruid(uid)");
exit(1);
perror("setruid(uid)");
exit(1);
#endif
}
switch ( rtn ) {
switch (rtn) {
case VALIDATE_OK:
check_user();
log_error( ALL_SYSTEMS_GO );
if ( setuid(0) ) {
perror("setuid(0)");
exit(1);
}
execve(cmnd, &Argv[1], Envp);
perror(cmnd);
break;
check_user();
log_error(ALL_SYSTEMS_GO);
if (setuid(0)) {
perror("setuid(0)");
exit(1);
}
execve(cmnd, &Argv[1], Envp);
perror(cmnd);
break;
case VALIDATE_NO_USER:
case VALIDATE_NOT_OK:
case VALIDATE_NOT_OK:
case VALIDATE_ERROR:
default:
log_error ( rtn );
if ( setuid ( uid ) ) {
perror("setuid(uid)");
exit(1);
}
inform_user ( rtn );
exit (1);
break;
log_error(rtn);
if (setuid(uid)) {
perror("setuid(uid)");
exit(1);
}
inform_user(rtn);
exit(1);
break;
}
return(-1); /* If we get here it's an error (execve failed) */
/*
* If we get here it's an error (execve failed)
*/
return (-1);
}
/**********************************************************************
*
* load_globals()
@@ -156,69 +161,72 @@ switch ( rtn ) {
void load_globals()
{
struct passwd *pw_ent;
struct hostent *h_ent;
char path[MAXPATHLEN+1];
char *p;
struct passwd *pw_ent;
struct hostent *h_ent;
char path[MAXPATHLEN + 1];
char *p;
if ( (user=malloc(9)) == NULL ) {
perror ("malloc");
exit (1);
if ((user = malloc(9)) == NULL) {
perror("malloc");
exit(1);
}
if ( (host=malloc(MAXHOSTNAMELEN+1)) == NULL ) {
perror ("malloc");
exit (1);
if ((host = malloc(MAXHOSTNAMELEN + 1)) == NULL) {
perror("malloc");
exit(1);
}
uid = getuid(); /* we need to tuck this away for safe keeping */
uid = getuid(); /* we need to tuck this away for safe keeping */
/* loading the cmnd global variable from argv[1] */
strncpy(path, Argv[1], MAXPATHLEN)[MAXPATHLEN] = 0;
cmnd = find_path ( path ); /* get the absolute path */
if ( cmnd == NULL ) {
fprintf ( stderr, "%s: %s: command not found\n", Argv[0], Argv[1] );
exit (1);
/*
* loading the cmnd global variable from argv[1]
*/
strncpy(path, Argv[1], MAXPATHLEN)[MAXPATHLEN] = 0;
cmnd = find_path(path); /* get the absolute path */
if (cmnd == NULL) {
(void) fprintf(stderr, "%s: %s: command not found\n", Argv[0], Argv[1]);
exit(1);
}
cmnd = strdup ( cmnd );
cmnd = strdup(cmnd);
#ifdef NO_ROOT_SUDO
if ( uid == 0 ) {
fprintf(stderr, "You are already root, you don\'t need to use sudo.\n");
exit (1);
if (uid == 0) {
(void) fprintf(stderr, "You are already root, you don\'t need to use sudo.\n");
exit(1);
}
#endif
/* loading the user global variable from the passwd file */
if ( (pw_ent = getpwuid( uid )) == NULL ) {
sprintf ( user, "%u", uid );
log_error( GLOBAL_NO_PW_ENT );
inform_user ( GLOBAL_NO_PW_ENT );
exit (1);
/*
* loading the user global variable from the passwd file
*/
if ((pw_ent = getpwuid(uid)) == NULL) {
(void) sprintf(user, "%u", uid);
log_error(GLOBAL_NO_PW_ENT);
inform_user(GLOBAL_NO_PW_ENT);
exit(1);
}
strncpy ( user, pw_ent -> pw_name, 8 ) [8] = '\0';
strncpy(user, pw_ent -> pw_name, 8)[8] = '\0';
/* loading the host global variable from gethostname() & gethostbyname() */
if (( gethostname ( host, MAXHOSTNAMELEN ))) {
strcpy ( host, "amnesiac" );
log_error ( GLOBAL_NO_HOSTNAME );
inform_user ( GLOBAL_NO_HOSTNAME );
}
else {
if ( ( h_ent = gethostbyname ( host) ) == NULL )
log_error ( GLOBAL_HOST_UNREGISTERED );
else
strcpy ( host, h_ent -> h_name );
/* We don't want to return the fully quallified name all the time... */
/*
* loading the host global variable from gethostname() & gethostbyname()
*/
if ((gethostname(host, MAXHOSTNAMELEN))) {
strcpy(host, "amnesiac");
log_error(GLOBAL_NO_HOSTNAME);
inform_user(GLOBAL_NO_HOSTNAME);
} else {
if ((h_ent = gethostbyname(host)) == NULL)
log_error(GLOBAL_HOST_UNREGISTERED);
else
strcpy(host, h_ent -> h_name);
/*
* We don't want to return the fully quallified name all the time...
*/
#ifndef FQDN
if ( (p = index ( host, '.' )) ) *p='\0';
if ((p = index(host, '.')))
*p = '\0';
#endif
}
@@ -226,7 +234,6 @@ else {
/**********************************************************************
*
* usage()
@@ -236,13 +243,12 @@ else {
static void usage()
{
fprintf( stderr, "usage: %s command\n", *Argv);
exit (1);
(void) fprintf(stderr, "usage: %s command\n", *Argv);
exit(1);
}
/**********************************************************************
*
* clean_envp()
@@ -252,26 +258,27 @@ exit (1);
*/
void clean_envp(envp)
char **envp;
char **envp;
{
int envlen;
char ** tenvp;
int envlen;
char **tenvp;
for ( envlen=0; envp[envlen]; envlen++ )
; /* noop */
++envlen;
for (envlen = 0; envp[envlen]; envlen++); /* noop */
++envlen;
Envp = (char **) malloc ( sizeof (char **) * envlen );
Envp = (char **) malloc(sizeof(char **) * envlen);
if ( Envp == NULL ) {
perror ("clean_envp: malloc");
exit (1);
}
/* omit all LD_* environmental vars */
for ( tenvp=Envp; *envp; envp++ )
if ( strncmp ("LD_", *envp, 3) )
*tenvp++ = *envp;
*tenvp = NULL;
if (Envp == NULL) {
perror("clean_envp: malloc");
exit(1);
}
/*
* omit all LD_* environmental vars
*/
for (tenvp = Envp; *envp; envp++)
if (strncmp("LD_", *envp, 3))
*tenvp++ = *envp;
*tenvp = NULL;
}

87
sudo.h
View File

@@ -24,27 +24,27 @@
*/
/* The following macros can be defined when compiling
FQDN - if you have fully qualified hostnames
in your SUDOERS files
SYSLOG - if you want to use syslog instead
of a log file
( This is a nice feature. You can
collect all you sudo logs at a
central host. The default is for
sudo to log at the local2 facility. )
SEND_MAIL_WHEN_NOT_OK - if you want a message sent to ALERTMAIL
when the user is in the SUDOERS but
does not have permission to execute
the command entered
( This can be used at paranoid sites )
SEND_MAIL_WHEN_NO_USER - if you want a message sent to ALERTMAIL
when the user is not in the SUDOERS file
( This is generally the case )
BROKEN_GETPASS - if your os has a broken version of getpass()
sysV and variants are suspect. Test by
doing an rsh host "sudo echo hi" when
@@ -56,33 +56,33 @@
rsh hostname "sudo whoami" and see if getpass
will read from stdin as well as /dev/tty.
If not, define BROKEN_GETPASS.
USE_CWD - if your os has getcwd() and not getwd()
you should define this (done automatically
for hpux)
NEED_STRDUP - if your os lacks strdup(3) you need to
define this
SHORT_MESSAGE - if you don't want a copyright notice when
someone runs sudo for the first time
*/
#ifndef TIMEDIR
#define TIMEDIR "/tmp/.odus"
#define TIMEDIR "/tmp/.odus"
#endif
#ifndef TIMEOUT
#define TIMEOUT 5
#define TIMEOUT 5
#endif
#ifndef TRIES_FOR_PASSWORD
#define TRIES_FOR_PASSWORD 3
#define TRIES_FOR_PASSWORD 3
#endif
#ifndef INCORRECT_PASSWORD
#define INCORRECT_PASSWORD "Sorry, try again."
#define INCORRECT_PASSWORD "Sorry, try again."
#endif
/*
@@ -93,47 +93,46 @@
*/
#ifndef MAILER
#define MAILER "/usr/lib/sendmail"
#define MAILER "/usr/lib/sendmail"
#endif
#ifndef MAILSUBJECT
#define MAILSUBJECT "*** SECURITY information ***"
#define MAILSUBJECT "*** SECURITY information ***"
#endif
#ifndef ALERTMAIL
#define ALERTMAIL "root"
#define ALERTMAIL "root"
#endif
#ifndef SUDOERS
#define SUDOERS "/etc/sudoers"
#define SUDOERS "/etc/sudoers"
#endif
#ifndef TMPSUDOERS
#define TMPSUDOERS "/etc/stmp"
#define TMPSUDOERS "/etc/stmp"
#endif
#ifndef EDITOR
#define EDITOR "/usr/ucb/vi"
#define EDITOR "/usr/ucb/vi"
#endif
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#define MAXHOSTNAMELEN 64
#endif
/* 48 chars is not enough */
#define MAXCOMMANDLENGTH MAXPATHLEN
typedef union {
int int_val;
char char_val[MAXCOMMANDLENGTH];
} YYSTYPE;
} YYSTYPE;
typedef struct list {
int type;
char op;
char *data;
struct list *next;
} LIST, *LINK;
} LIST, *LINK;
#ifndef hpux
YYSTYPE yylval, yyval;
@@ -141,10 +140,10 @@ YYSTYPE yylval, yyval;
YYSTYPE yylval;
#endif
#ifdef SYSLOG /* SYSLOG should be defined in the makefile */
/*
* SYSLOG should be defined in the makefile
*/
#ifdef SYSLOG
#include <syslog.h>
#ifndef Syslog_ident
#define Syslog_ident "sudo"
@@ -158,7 +157,7 @@ YYSTYPE yylval;
#ifndef Syslog_priority_OK
#define Syslog_priority_OK LOG_NOTICE
#endif
#ifndef Syslog_priority_NO
#ifndef Syslog_priority_NO
#define Syslog_priority_NO LOG_ALERT
#endif
#else
@@ -167,16 +166,20 @@ YYSTYPE yylval;
#define LOGFILE "/var/adm/sudo.log"
#else
#define LOGFILE "/usr/adm/sudo.log"
#endif /* /var vs. /usr */
#endif /* LOGFILE */
#endif /* SYSLOG */
/* Maximum number of characters to log per entry. */
#ifndef MAXLOGLEN /* The syslogger will log this much, after that, */
#define MAXLOGLEN 990 /* it truncates the log line. We need this here */
#endif /* to make sure that we get ellipses when the log */
/* line is longer than 990 characters. */
#endif /* /var vs. /usr */
#endif /* LOGFILE */
#endif /* SYSLOG */
/*
* Maximum number of characters to log per entry.
* The syslogger will log this much, after that,
* it truncates the log line. We need this here
* to make sure that we get ellipses when the log
* line is longer than 990 characters.
*/
#ifndef MAXLOGLEN
#define MAXLOGLEN 990
#endif
#define VALIDATE_OK 0x00
#define VALIDATE_NO_USER 0x01
@@ -226,6 +229,7 @@ void load_globals();
void log_error();
void inform_user();
void check_user();
void clean_envp();
int validate();
/* Most of these variables are declared in main() so they don't need
@@ -240,16 +244,19 @@ extern uid_t uid;
extern char *host;
extern char *user;
extern char *cmnd;
extern int Argc;
extern char **Argv;
extern int Argc;
extern char **Envp;
#endif
extern int errno;
/* This is to placate hpux */
/*
* This is to placate hpux
*/
#ifdef hpux
#define setruid(__RUID) (setresuid((uid_t)(__RUID), (uid_t) -1, (uid_t) -1))
#define getdtablesize() (sysconf(_SC_OPEN_MAX))
#ifndef USE_CWD
#define USE_CWD
#endif
#endif
#endif /* USE_CWD */
#endif /* hpux */