o Move lock_file() and touch() into fileops.c so visudo can use them
o Visudo now locks the sudoers temp file instead of bailing when the temp file already exists. This fixes the problem of stale temp files but it does *require* that you not try to put the temp file in a world-writable directory. This shoud not be an issue as the temp file should live in the same dir as sudoers. o Visudo now only installs the temp file as sudoers if it changed.
This commit is contained in:
16
CHANGES
16
CHANGES
@@ -1106,3 +1106,19 @@ Sudo 1.5.9 released.
|
||||
|
||||
346) Sudo is now available under a BSD/Apache style license. This is
|
||||
possible because it no longer contains any of the original 1.1 code.
|
||||
|
||||
347) Added configuration info when sudo is run with the -V flag by root.
|
||||
|
||||
348) Change visudo tmp file from /etc/stmp -> /etc/sudoers.tmp since
|
||||
Solaris uses stmp for shadow temp file. Also rename _PATH_SUDO_SUDOERS
|
||||
to _PATH_SUDOERS and _PATH_SUDO_STMP to _PATH_SUDOERS_TMP.
|
||||
|
||||
349) Added configure option to set syslog priorities.
|
||||
|
||||
350) Sudo now locks its log file to prevent mangled entries.
|
||||
|
||||
351) Visudo now locks the sudoers temp file instead of bailing when
|
||||
the temp file already exists. This fixes the problem of stale
|
||||
temp files but it does *require* that you not try to put the
|
||||
temp file in a world-writable directory. This shoud not be
|
||||
an issue as the temp file should live in the same dir as sudoers.
|
||||
|
12
Makefile.in
12
Makefile.in
@@ -108,9 +108,9 @@ SHELL = /bin/sh
|
||||
|
||||
PROGS = @PROGS@
|
||||
|
||||
SRCS = alloc.c check.c find_path.c getspwuid.c goodpath.c interfaces.c \
|
||||
logging.c parse.c parse.lex parse.yacc sudo.c sudo_setenv.c tgetpass.c \
|
||||
version.c visudo.c $(AUTH_SRCS)
|
||||
SRCS = alloc.c check.c fileops.c find_path.c getspwuid.c goodpath.c \
|
||||
interfaces.c logging.c parse.c parse.lex parse.yacc sudo.c \
|
||||
sudo_setenv.c tgetpass.c version.c visudo.c $(AUTH_SRCS)
|
||||
|
||||
AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/dce.c auth/fwtk.c auth/kerb4.c \
|
||||
auth/kerb5.c auth/pam.c auth/passwd.c auth/rfc1938.c \
|
||||
@@ -120,11 +120,11 @@ AUTH_OBJS = sudo_auth.o @AUTH_OBJS@
|
||||
|
||||
PARSEOBJS = sudo.tab.o lex.yy.o alloc.o
|
||||
|
||||
SUDOBJS = check.o getspwuid.o goodpath.o find_path.o interfaces.o logging.o \
|
||||
parse.o sudo.o sudo_setenv.o tgetpass.o version.o \
|
||||
SUDOBJS = check.o getspwuid.o goodpath.o fileops.o find_path.o interfaces.o \
|
||||
logging.o parse.o sudo.o sudo_setenv.o tgetpass.o version.o \
|
||||
$(AUTH_OBJS) $(PARSEOBJS)
|
||||
|
||||
VISUDOBJS = visudo.o $(PARSEOBJS)
|
||||
VISUDOBJS = visudo.o fileops.o $(PARSEOBJS)
|
||||
|
||||
TESTOBJS = interfaces.o testsudoers.o $(PARSEOBJS)
|
||||
|
||||
|
2
TODO
2
TODO
@@ -47,5 +47,3 @@ TODO list (most will be addressed in the next rewrite)
|
||||
|
||||
19) Sudo should have a separate error message for when the user is in sudoers
|
||||
but not allowed to run stuff on that host, and send mail.
|
||||
|
||||
20) Add configure check for locking functions and lock logfile.
|
||||
|
@@ -120,10 +120,7 @@ A) You probably didn't install the gcc-fixed include files.
|
||||
|
||||
Q) When I run "visudo" it says "sudoers file busy, try again later."
|
||||
and doesn't do anything.
|
||||
A) You have a stale sudoers temporary file. The default location is
|
||||
/etc/sudoers.tmp. If you delete this file visudo will be happy again,
|
||||
but make sure to check that no one else is running visudo at
|
||||
the time.
|
||||
A) Someone else is currently editing the sudoers file with visudo.
|
||||
|
||||
Q) When I try to use "cd" with sudo it says "cd: command not found".
|
||||
A) "cd" is a shell builtin, you can't run it as a command since
|
||||
|
31
check.c
31
check.c
@@ -57,13 +57,6 @@
|
||||
#include <sys/file.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#ifdef HAVE_UTIME
|
||||
# ifdef HAVE_UTIME_H
|
||||
# include <utime.h>
|
||||
# endif /* HAVE_UTIME_H */
|
||||
#else
|
||||
# include "emul/utime.h"
|
||||
#endif /* HAVE_UTIME */
|
||||
|
||||
#include "sudo.h"
|
||||
|
||||
@@ -81,7 +74,6 @@ static const char rcsid[] = "$Sudo$";
|
||||
int user_is_exempt __P((void));
|
||||
static void build_timestamp __P((char **, char **));
|
||||
static int timestamp_status __P((char *, char *, char *, int));
|
||||
static int touch __P((char *, time_t));
|
||||
#ifndef NO_PASSWD
|
||||
static char *expand_prompt __P((char *, char *, char *));
|
||||
static void lecture __P((void));
|
||||
@@ -265,29 +257,6 @@ user_is_exempt()
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the access and modify times on a file.
|
||||
*/
|
||||
static int
|
||||
touch(path, when)
|
||||
char *path;
|
||||
time_t when;
|
||||
{
|
||||
#ifdef HAVE_UTIME_POSIX
|
||||
struct utimbuf ut, *utp;
|
||||
|
||||
ut.actime = ut.modtime = when;
|
||||
utp = &ut;
|
||||
#else
|
||||
/* BSD <= 4.3 has no struct utimbuf */
|
||||
time_t utp[2];
|
||||
|
||||
utp[0] = utp[1] = when;
|
||||
#endif /* HAVE_UTIME_POSIX */
|
||||
|
||||
return(utime(path, utp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Fills in timestampdir as well as timestampfile if using tty tickets.
|
||||
*/
|
||||
|
67
compat.h
67
compat.h
@@ -43,103 +43,116 @@
|
||||
|
||||
/* Deal with ANSI stuff reasonably. */
|
||||
#ifndef __P
|
||||
# if defined (__cplusplus) || defined (__STDC__)
|
||||
# define __P(args) args
|
||||
# else
|
||||
# define __P(args) ()
|
||||
# endif
|
||||
# if defined (__cplusplus) || defined (__STDC__)
|
||||
# define __P(args) args
|
||||
# else
|
||||
# define __P(args) ()
|
||||
# endif
|
||||
#endif /* __P */
|
||||
|
||||
/*
|
||||
* Some systems (ie ISC V/386) do not define MAXPATHLEN even in param.h
|
||||
*/
|
||||
#ifndef MAXPATHLEN
|
||||
# define MAXPATHLEN 1024
|
||||
# define MAXPATHLEN 1024
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some systems do not define MAXHOSTNAMELEN.
|
||||
*/
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
# define MAXHOSTNAMELEN 64
|
||||
# define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 4.2BSD lacks FD_* macros (we only use FD_SET and FD_ZERO)
|
||||
*/
|
||||
#ifndef FD_SETSIZE
|
||||
#define FD_SET(fd, fds) ((fds) -> fds_bits[0] |= (1 << (fd)))
|
||||
#define FD_ZERO(fds) ((fds) -> fds_bits[0] = 0)
|
||||
# define FD_SET(fd, fds) ((fds) -> fds_bits[0] |= (1 << (fd)))
|
||||
# define FD_ZERO(fds) ((fds) -> fds_bits[0] = 0)
|
||||
#endif /* !FD_SETSIZE */
|
||||
|
||||
/*
|
||||
* Posix versions for those without...
|
||||
*/
|
||||
#ifndef _S_IFMT
|
||||
# define _S_IFMT S_IFMT
|
||||
# define _S_IFMT S_IFMT
|
||||
#endif /* _S_IFMT */
|
||||
#ifndef _S_IFREG
|
||||
# define _S_IFREG S_IFREG
|
||||
# define _S_IFREG S_IFREG
|
||||
#endif /* _S_IFREG */
|
||||
#ifndef _S_IFDIR
|
||||
# define _S_IFDIR S_IFDIR
|
||||
# define _S_IFDIR S_IFDIR
|
||||
#endif /* _S_IFDIR */
|
||||
#ifndef _S_IFLNK
|
||||
#define _S_IFLNK S_IFLNK
|
||||
# define _S_IFLNK S_IFLNK
|
||||
#endif /* _S_IFLNK */
|
||||
#ifndef S_ISREG
|
||||
# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
|
||||
# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
|
||||
#endif /* S_ISREG */
|
||||
#ifndef S_ISDIR
|
||||
# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
|
||||
# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
|
||||
#endif /* S_ISDIR */
|
||||
|
||||
/*
|
||||
* Some OS's may not have this.
|
||||
*/
|
||||
#ifndef S_IRWXU
|
||||
# define S_IRWXU 0000700 /* rwx for owner */
|
||||
# define S_IRWXU 0000700 /* rwx for owner */
|
||||
#endif /* S_IRWXU */
|
||||
|
||||
/*
|
||||
* In case this is not defined in <sys/types.h> or <sys/select.h>
|
||||
*/
|
||||
#ifndef howmany
|
||||
#define howmany(x, y) (((x) + ((y) - 1)) / (y))
|
||||
# define howmany(x, y) (((x) + ((y) - 1)) / (y))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These should be defined in <unistd.h> but not everyone has them.
|
||||
*/
|
||||
#ifndef STDIN_FILENO
|
||||
# define STDIN_FILENO 0
|
||||
# define STDIN_FILENO 0
|
||||
#endif
|
||||
#ifndef STDOUT_FILENO
|
||||
# define STDOUT_FILENO 1
|
||||
# define STDOUT_FILENO 1
|
||||
#endif
|
||||
#ifndef STDERR_FILENO
|
||||
# define STDERR_FILENO 2
|
||||
# define STDERR_FILENO 2
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These should be defined in <unistd.h> but not everyone has them.
|
||||
*/
|
||||
#ifndef SEEK_SET
|
||||
# define SEEK_SET 0
|
||||
#endif
|
||||
#ifndef SEEK_CUR
|
||||
# define SEEK_CUR 1
|
||||
#endif
|
||||
#ifndef SEEK_END
|
||||
# define SEEK_END 2
|
||||
#endif
|
||||
|
||||
/*
|
||||
* BSD defines these in <sys/param.h> but others may not.
|
||||
*/
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
# define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
# define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Emulate seteuid() for HP-UX via setresuid(2) and seteuid(2) for others.
|
||||
*/
|
||||
#ifndef HAVE_SETEUID
|
||||
# ifdef __hpux
|
||||
# define seteuid(_EUID) (setresuid((uid_t) -1, _EUID, (uid_t) -1))
|
||||
# else
|
||||
# define seteuid(_EUID) (setreuid((uid_t) -1, _EUID))
|
||||
# endif /* __hpux */
|
||||
# ifdef __hpux
|
||||
# define seteuid(_EUID) (setresuid((uid_t) -1, _EUID, (uid_t) -1))
|
||||
# else
|
||||
# define seteuid(_EUID) (setreuid((uid_t) -1, _EUID))
|
||||
# endif /* __hpux */
|
||||
#endif /* HAVE_SETEUID */
|
||||
|
||||
#endif /* _SUDO_COMPAT_H */
|
||||
|
@@ -292,6 +292,9 @@
|
||||
/* Define if you have flock(2). */
|
||||
#undef HAVE_FLOCK
|
||||
|
||||
/* Define if you have ftruncate(2). */
|
||||
#undef HAVE_FTRUNCATE
|
||||
|
||||
/* Define if you have snprintf(3). */
|
||||
#undef HAVE_SNPRINTF
|
||||
|
||||
|
2
configure
vendored
2
configure
vendored
@@ -5254,7 +5254,7 @@ EOF
|
||||
|
||||
;;
|
||||
esac
|
||||
for ac_func in strchr strrchr memcpy memset sysconf sigaction tzset strcasecmp seteuid
|
||||
for ac_func in strchr strrchr memcpy memset sysconf sigaction tzset strcasecmp seteuid ftruncate
|
||||
do
|
||||
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
|
||||
echo "configure:5261: checking for $ac_func" >&5
|
||||
|
@@ -1349,7 +1349,7 @@ esac
|
||||
dnl
|
||||
dnl Function checks
|
||||
dnl
|
||||
AC_CHECK_FUNCS(strchr strrchr memcpy memset sysconf sigaction tzset strcasecmp seteuid)
|
||||
AC_CHECK_FUNCS(strchr strrchr memcpy memset sysconf sigaction tzset strcasecmp seteuid ftruncate)
|
||||
if test -n "$SECUREWARE"; then
|
||||
AC_CHECK_FUNCS(bigcrypt)
|
||||
AC_CHECK_FUNCS(set_auth_parameters)
|
||||
|
149
fileops.c
Normal file
149
fileops.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* 4. Products derived from this software may not be called "Sudo" nor
|
||||
* may "Sudo" appear in their names without specific prior written
|
||||
* permission from the author.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#ifdef HAVE_UTIME
|
||||
# ifdef HAVE_UTIME_H
|
||||
# include <utime.h>
|
||||
# endif /* HAVE_UTIME_H */
|
||||
#else
|
||||
# include "emul/utime.h"
|
||||
#endif /* HAVE_UTIME */
|
||||
|
||||
#include "sudo.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char rcsid[] = "$Sudo$";
|
||||
#endif /* lint */
|
||||
|
||||
/*
|
||||
* Update the access and modify times on a file.
|
||||
*/
|
||||
int
|
||||
touch(path, when)
|
||||
char *path;
|
||||
time_t when;
|
||||
{
|
||||
#ifdef HAVE_UTIME_POSIX
|
||||
struct utimbuf ut, *utp;
|
||||
|
||||
ut.actime = ut.modtime = when;
|
||||
utp = &ut;
|
||||
#else
|
||||
/* BSD <= 4.3 has no struct utimbuf */
|
||||
time_t utp[2];
|
||||
|
||||
utp[0] = utp[1] = when;
|
||||
#endif /* HAVE_UTIME_POSIX */
|
||||
|
||||
return(utime(path, utp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock/unlock a file.
|
||||
*/
|
||||
#ifdef HAVE_LOCKF
|
||||
int
|
||||
lock_file(fd, lockit)
|
||||
int fd;
|
||||
int lockit;
|
||||
{
|
||||
int op = 0;
|
||||
|
||||
switch (lockit) {
|
||||
case SUDO_LOCK:
|
||||
op = F_LOCK;
|
||||
break;
|
||||
case SUDO_TLOCK:
|
||||
op = F_TLOCK;
|
||||
break;
|
||||
case SUDO_UNLOCK:
|
||||
op = F_ULOCK;
|
||||
break;
|
||||
}
|
||||
return(lockf(fd, op, 0) == 0);
|
||||
}
|
||||
#elif HAVE_FLOCK
|
||||
int
|
||||
lock_file(fd, lockit)
|
||||
int fd;
|
||||
int lockit;
|
||||
{
|
||||
int op = 0;
|
||||
|
||||
switch (lockit) {
|
||||
case SUDO_LOCK:
|
||||
op = LOCK_EX;
|
||||
break;
|
||||
case SUDO_TLOCK:
|
||||
op = LOCK_EX | LOCK_NB;
|
||||
break;
|
||||
case SUDO_UNLOCK:
|
||||
op = LOCK_EX;
|
||||
break;
|
||||
}
|
||||
return(flock(fd, op) == 0);
|
||||
}
|
||||
#else
|
||||
int
|
||||
lock_file(fd, lockit)
|
||||
int fd;
|
||||
int lockit;
|
||||
{
|
||||
#ifdef F_SETLK
|
||||
int func;
|
||||
struct flock lock;
|
||||
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 0;
|
||||
lock.l_pid = getpid();
|
||||
lock.l_type = (lockit == SUDO_UNLOCK) ? F_UNLCK : F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
func = (lockit == SUDO_TLOCK) ? F_SETLK : F_SETLKW;
|
||||
|
||||
return(fcntl(fd, func, &lock) == 0);
|
||||
#else
|
||||
return(TRUE);
|
||||
#endif
|
||||
}
|
||||
#endif
|
53
logging.c
53
logging.c
@@ -47,7 +47,6 @@
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif /* HAVE_STRINGS_H */
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
@@ -68,7 +67,6 @@ static void do_syslog __P((int, char *));
|
||||
#endif
|
||||
#if (LOGGING & SLOG_FILE)
|
||||
static void do_logfile __P((char *));
|
||||
static int lock_file __P((FILE *, int));
|
||||
#endif
|
||||
static void send_mail __P((char *));
|
||||
|
||||
@@ -179,7 +177,7 @@ do_logfile(msg)
|
||||
_PATH_SUDO_LOGFILE, strerror(errno));
|
||||
send_mail(full_line);
|
||||
free(full_line);
|
||||
} else if (!lock_file(fp, TRUE)) {
|
||||
} else if (!lock_file(fileno(fp), SUDO_LOCK)) {
|
||||
easprintf(&full_line, "Can't lock log file: %s: %s",
|
||||
_PATH_SUDO_LOGFILE, strerror(errno));
|
||||
send_mail(full_line);
|
||||
@@ -252,7 +250,7 @@ do_logfile(msg)
|
||||
free(full_line);
|
||||
# endif
|
||||
(void) fflush(fp);
|
||||
(void) lock_file(fp, FALSE);
|
||||
(void) lock_file(fileno(fp), SUDO_UNLOCK);
|
||||
(void) fclose(fp);
|
||||
}
|
||||
|
||||
@@ -572,50 +570,3 @@ reapchild(sig)
|
||||
#endif /* POSIX_SIGNALS */
|
||||
errno = serrno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock/unlock a file.
|
||||
*/
|
||||
#ifdef HAVE_LOCKF
|
||||
static int
|
||||
lock_file(fp, lockit)
|
||||
FILE *fp;
|
||||
int lockit;
|
||||
{
|
||||
int op;
|
||||
|
||||
op = lockit ? F_LOCK : F_ULOCK;
|
||||
return(lockf(fileno(fp), op, 0) == 0);
|
||||
}
|
||||
#elif HAVE_FLOCK
|
||||
static int
|
||||
lock_file(fp, lockit)
|
||||
FILE *fp;
|
||||
int lockit;
|
||||
{
|
||||
int op;
|
||||
|
||||
op = lockit ? LOCK_EX : LOCK_UN;
|
||||
return(flock(fileno(fp), op) == 0);
|
||||
}
|
||||
#else
|
||||
static int
|
||||
lock_file(fp, lockit)
|
||||
FILE *fp;
|
||||
int lockit;
|
||||
{
|
||||
#ifdef F_SETLK
|
||||
struct flock lock;
|
||||
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 0;
|
||||
lock.l_pid = getpid();
|
||||
lock.l_type = lockit ? F_WRLCK : F_UNLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
|
||||
return(fcntl(fileno(fp), F_SETLKW, &lock) == 0);
|
||||
#else
|
||||
return(TRUE);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
9
sudo.h
9
sudo.h
@@ -133,6 +133,13 @@ struct sudo_user {
|
||||
*/
|
||||
#define SUDO_PASS_MAX 256
|
||||
|
||||
/*
|
||||
* Flags for lock_file()
|
||||
*/
|
||||
#define SUDO_LOCK 1 /* lock a file */
|
||||
#define SUDO_TLOCK 2 /* test & lock a file (non-blocking) */
|
||||
#define SUDO_UNLOCK 4 /* unlock a file */
|
||||
|
||||
/*
|
||||
* Function prototypes
|
||||
*/
|
||||
@@ -164,6 +171,8 @@ char *estrdup __P((const char *));
|
||||
void easprintf __P((char **, const char *, ...));
|
||||
void evasprintf __P((char **, const char *, va_list));
|
||||
void print_version __P((void));
|
||||
int lock_file __P((int, int));
|
||||
int touch __P((char *, time_t));
|
||||
YY_DECL;
|
||||
|
||||
/* Only provide extern declarations outside of sudo.c. */
|
||||
|
48
version.c
48
version.c
@@ -76,12 +76,19 @@ print_version()
|
||||
|
||||
/*
|
||||
* Print compile-time options if root.
|
||||
* At some point these will all be in a structure of some kind
|
||||
* to allow overriding the defaults from sudoers.
|
||||
* XXX - reorganize for readability.
|
||||
*/
|
||||
if (getuid() == 0) {
|
||||
(void) printf("\nSudoers file: %s, mode 0%o, uid %d, gid %d\n",
|
||||
_PATH_SUDOERS, SUDOERS_MODE, SUDOERS_UID, SUDOERS_GID);
|
||||
(void) printf("Sudoers temp file: %s\n", _PATH_SUDOERS_TMP);
|
||||
|
||||
#ifdef WITHOUT_PASSWD
|
||||
(void) puts("\nNo Authentication configured\n");
|
||||
(void) puts("No Authentication configured\n");
|
||||
#else
|
||||
(void) fputs("\nAuthentication methods:", stdout);
|
||||
(void) fputs("Authentication methods:", stdout);
|
||||
for (auth = auth_switch; auth->name; auth++) {
|
||||
(void) putchar(' ');
|
||||
(void) fputs(auth->name, stdout);
|
||||
@@ -137,6 +144,8 @@ print_version()
|
||||
(void) fputs(" goons", stdout);
|
||||
# endif
|
||||
(void) putchar('\n');
|
||||
# else
|
||||
(void) printf("Incorrect password message: %s\n", INCORRECT_PASSWORD);
|
||||
#endif
|
||||
|
||||
#ifdef SUDO_UMASK
|
||||
@@ -169,14 +178,39 @@ print_version()
|
||||
(void) printf("Editor for visudo: %s\n", EDITOR);
|
||||
#endif
|
||||
|
||||
#if defined(IGNORE_DOT_PATH) || defined(DONT_LEAK_PATH_INFO) || defined(SECURE_PATH)
|
||||
puts("$PATH options:");
|
||||
#ifdef SECURE_PATH
|
||||
(void) printf("Secure PATH: %s\n", SECURE_PATH);
|
||||
(void) printf(" PATH override: %s\n", SECURE_PATH);
|
||||
#endif
|
||||
# ifdef IGNORE_DOT_PATH
|
||||
(void) puts(" ignore '.'");
|
||||
# endif
|
||||
# ifdef DONT_LEAK_PATH_INFO
|
||||
(void) puts(" no information leakage");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _PATH_SENDMAIL
|
||||
(void) printf("Mailer path: %s\n", _PATH_SENDMAIL);
|
||||
(void) printf("Send mail to: %s\n", ALERTMAIL);
|
||||
(void) printf("Mail subject: %s\n", MAILSUBJECT);
|
||||
(void) fputs("Send mail on: 'error'", stdout);
|
||||
# ifdef SEND_MAIL_WHEN_NO_USER
|
||||
(void) fputs(" 'unlisted user'", stdout);
|
||||
# endif
|
||||
# ifdef SEND_MAIL_WHEN_NOT_OK
|
||||
(void) fputs(" 'authentication failure'", stdout);
|
||||
# endif
|
||||
(void) putchar('\n');
|
||||
#endif
|
||||
|
||||
#ifdef SHELL_IF_NO_ARGS
|
||||
puts("When invoked with no arguments sudo will start a shell")
|
||||
#endif
|
||||
|
||||
#ifdef SHELL_SETS_HOME
|
||||
puts("Sudo will set $HOME to the homedir of the target user");
|
||||
#endif
|
||||
|
||||
(void) printf("Default password prompt: %s\n", PASSPROMPT);
|
||||
@@ -187,14 +221,6 @@ print_version()
|
||||
#else
|
||||
(void) puts("no");
|
||||
#endif
|
||||
|
||||
/* stopped at INCORRECT_PASSWORD */
|
||||
|
||||
/* XXX - more */
|
||||
|
||||
/*
|
||||
-D_PATH_SUDO_SUDOERS=\"/etc/sudoers\" -D_PATH_SUDO_STMP=\"/etc/stmp\" -DSUDOERS_UID=0 -DSUDOERS_GID=0 -DSUDOERS_MODE=0440
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
57
visudo.c
57
visudo.c
@@ -56,6 +56,7 @@
|
||||
#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@@ -124,8 +125,9 @@ main(argc, argv)
|
||||
int sudoers_fd; /* sudoers file descriptor */
|
||||
int stmp_fd; /* stmp file descriptor */
|
||||
int n; /* length parameter */
|
||||
time_t now; /* time now */
|
||||
struct stat stmp_sb, sudoers_sb; /* to check for changes */
|
||||
|
||||
(void) setbuf(stderr, (char *)NULL); /* unbuffered stderr */
|
||||
|
||||
/*
|
||||
* Parse command line options
|
||||
@@ -166,30 +168,44 @@ main(argc, argv)
|
||||
#endif /* ENV_EDITOR */
|
||||
|
||||
/*
|
||||
* Copy sudoers file to stmp
|
||||
* Open sudoers temp file and grab a lock.
|
||||
*/
|
||||
stmp_fd = open(stmp, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
stmp_fd = open(stmp, O_WRONLY | O_CREAT, 0600);
|
||||
if (stmp_fd < 0) {
|
||||
if (errno == EEXIST) {
|
||||
(void) fprintf(stderr, "%s: sudoers file busy, try again later.\n",
|
||||
Argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
(void) fprintf(stderr, "%s: %s\n", Argv[0], strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (!lock_file(stmp_fd, SUDO_TLOCK)) {
|
||||
(void) fprintf(stderr, "%s: sudoers file busy, try again later.\n",
|
||||
Argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
if (ftruncate(stmp_fd, 0) == -1) {
|
||||
#else
|
||||
if (truncate(stmp, 0) == -1) {
|
||||
#endif
|
||||
(void) fprintf(stderr, "%s: can't truncate %s: %s\n", Argv[0],
|
||||
stmp, strerror(errno));
|
||||
Exit(-1);
|
||||
}
|
||||
|
||||
/* Install signal handlers to clean up stmp if we are killed. */
|
||||
setup_signals();
|
||||
|
||||
(void) memset(&sudoers_sb, 0, sizeof(sudoers_sb));
|
||||
if (stat(sudoers, &sudoers_sb) == -1 && errno != ENOENT) {
|
||||
(void) fprintf(stderr, "%s: %s\n", Argv[0], strerror(errno));
|
||||
Exit(-1);
|
||||
}
|
||||
sudoers_fd = open(sudoers, O_RDONLY);
|
||||
if (sudoers_fd < 0 && errno != ENOENT) {
|
||||
if (sudoers_fd == -1 && errno != ENOENT) {
|
||||
(void) fprintf(stderr, "%s: %s\n", Argv[0], strerror(errno));
|
||||
Exit(-1);
|
||||
}
|
||||
|
||||
/* Copy sudoers -> stmp */
|
||||
if (sudoers_fd >= 0) {
|
||||
/* Copy sudoers -> stmp and reset the mtime */
|
||||
if (sudoers_fd != -1) {
|
||||
while ((n = read(sudoers_fd, buf, sizeof(buf))) > 0)
|
||||
if (write(stmp_fd, buf, n) != n) {
|
||||
(void) fprintf(stderr, "%s: Write failed: %s\n", Argv[0],
|
||||
@@ -200,6 +216,7 @@ main(argc, argv)
|
||||
(void) close(sudoers_fd);
|
||||
}
|
||||
(void) close(stmp_fd);
|
||||
(void) touch(stmp, sudoers_sb.st_mtime);
|
||||
|
||||
/*
|
||||
* Edit the temp file and parse it (for sanity checking)
|
||||
@@ -219,20 +236,19 @@ main(argc, argv)
|
||||
(void) sprintf(buf, "%s %s", Editor, stmp);
|
||||
|
||||
/* Do the edit -- some SYSV editors exit with 1 instead of 0 */
|
||||
now = time(NULL);
|
||||
n = system(buf);
|
||||
if (n != -1 && ((n >> 8) == 0 || (n >> 8) == 1)) {
|
||||
struct stat statbuf; /* for sanity checking */
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
if (stat(stmp, &statbuf) < 0) {
|
||||
if (stat(stmp, &stmp_sb) < 0) {
|
||||
(void) fprintf(stderr,
|
||||
"%s: Can't stat temporary file (%s), %s unchanged.\n",
|
||||
Argv[0], stmp, sudoers);
|
||||
Exit(-1);
|
||||
}
|
||||
if (statbuf.st_size == 0) {
|
||||
if (stmp_sb.st_size == 0) {
|
||||
(void) fprintf(stderr,
|
||||
"%s: Zero length temporary file (%s), %s unchanged.\n",
|
||||
Argv[0], stmp, sudoers);
|
||||
@@ -285,6 +301,15 @@ main(argc, argv)
|
||||
}
|
||||
} while (parse_error == TRUE);
|
||||
|
||||
/*
|
||||
* If the user didn't change the temp file, just unlink it.
|
||||
*/
|
||||
if (sudoers_sb.st_mtime != now && sudoers_sb.st_mtime == stmp_sb.st_mtime &&
|
||||
sudoers_sb.st_size == stmp_sb.st_size) {
|
||||
(void) fprintf(stderr, "%s: sudoers file unchanged.\n", Argv[0]);
|
||||
Exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change mode and ownership of temp file so when
|
||||
* we move it to sudoers things are kosher.
|
||||
@@ -469,5 +494,5 @@ static void
|
||||
usage()
|
||||
{
|
||||
(void) fprintf(stderr, "usage: %s [-V]\n", Argv[0]);
|
||||
Exit(-1);
|
||||
exit(1);
|
||||
}
|
||||
|
Reference in New Issue
Block a user