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
|
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.
|
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@
|
PROGS = @PROGS@
|
||||||
|
|
||||||
SRCS = alloc.c check.c find_path.c getspwuid.c goodpath.c interfaces.c \
|
SRCS = alloc.c check.c fileops.c find_path.c getspwuid.c goodpath.c \
|
||||||
logging.c parse.c parse.lex parse.yacc sudo.c sudo_setenv.c tgetpass.c \
|
interfaces.c logging.c parse.c parse.lex parse.yacc sudo.c \
|
||||||
version.c visudo.c $(AUTH_SRCS)
|
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_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 \
|
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
|
PARSEOBJS = sudo.tab.o lex.yy.o alloc.o
|
||||||
|
|
||||||
SUDOBJS = check.o getspwuid.o goodpath.o find_path.o interfaces.o logging.o \
|
SUDOBJS = check.o getspwuid.o goodpath.o fileops.o find_path.o interfaces.o \
|
||||||
parse.o sudo.o sudo_setenv.o tgetpass.o version.o \
|
logging.o parse.o sudo.o sudo_setenv.o tgetpass.o version.o \
|
||||||
$(AUTH_OBJS) $(PARSEOBJS)
|
$(AUTH_OBJS) $(PARSEOBJS)
|
||||||
|
|
||||||
VISUDOBJS = visudo.o $(PARSEOBJS)
|
VISUDOBJS = visudo.o fileops.o $(PARSEOBJS)
|
||||||
|
|
||||||
TESTOBJS = interfaces.o testsudoers.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
|
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.
|
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."
|
Q) When I run "visudo" it says "sudoers file busy, try again later."
|
||||||
and doesn't do anything.
|
and doesn't do anything.
|
||||||
A) You have a stale sudoers temporary file. The default location is
|
A) Someone else is currently editing the sudoers file with visudo.
|
||||||
/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.
|
|
||||||
|
|
||||||
Q) When I try to use "cd" with sudo it says "cd: command not found".
|
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
|
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 <sys/file.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.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"
|
#include "sudo.h"
|
||||||
|
|
||||||
@@ -81,7 +74,6 @@ static const char rcsid[] = "$Sudo$";
|
|||||||
int user_is_exempt __P((void));
|
int user_is_exempt __P((void));
|
||||||
static void build_timestamp __P((char **, char **));
|
static void build_timestamp __P((char **, char **));
|
||||||
static int timestamp_status __P((char *, char *, char *, int));
|
static int timestamp_status __P((char *, char *, char *, int));
|
||||||
static int touch __P((char *, time_t));
|
|
||||||
#ifndef NO_PASSWD
|
#ifndef NO_PASSWD
|
||||||
static char *expand_prompt __P((char *, char *, char *));
|
static char *expand_prompt __P((char *, char *, char *));
|
||||||
static void lecture __P((void));
|
static void lecture __P((void));
|
||||||
@@ -265,29 +257,6 @@ user_is_exempt()
|
|||||||
return(FALSE);
|
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.
|
* Fills in timestampdir as well as timestampfile if using tty tickets.
|
||||||
*/
|
*/
|
||||||
|
25
compat.h
25
compat.h
@@ -68,8 +68,8 @@
|
|||||||
* 4.2BSD lacks FD_* macros (we only use FD_SET and FD_ZERO)
|
* 4.2BSD lacks FD_* macros (we only use FD_SET and FD_ZERO)
|
||||||
*/
|
*/
|
||||||
#ifndef FD_SETSIZE
|
#ifndef FD_SETSIZE
|
||||||
#define FD_SET(fd, fds) ((fds) -> fds_bits[0] |= (1 << (fd)))
|
# define FD_SET(fd, fds) ((fds) -> fds_bits[0] |= (1 << (fd)))
|
||||||
#define FD_ZERO(fds) ((fds) -> fds_bits[0] = 0)
|
# define FD_ZERO(fds) ((fds) -> fds_bits[0] = 0)
|
||||||
#endif /* !FD_SETSIZE */
|
#endif /* !FD_SETSIZE */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
# define _S_IFDIR S_IFDIR
|
# define _S_IFDIR S_IFDIR
|
||||||
#endif /* _S_IFDIR */
|
#endif /* _S_IFDIR */
|
||||||
#ifndef _S_IFLNK
|
#ifndef _S_IFLNK
|
||||||
#define _S_IFLNK S_IFLNK
|
# define _S_IFLNK S_IFLNK
|
||||||
#endif /* _S_IFLNK */
|
#endif /* _S_IFLNK */
|
||||||
#ifndef S_ISREG
|
#ifndef S_ISREG
|
||||||
# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
|
# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
|
||||||
@@ -105,7 +105,7 @@
|
|||||||
* In case this is not defined in <sys/types.h> or <sys/select.h>
|
* In case this is not defined in <sys/types.h> or <sys/select.h>
|
||||||
*/
|
*/
|
||||||
#ifndef howmany
|
#ifndef howmany
|
||||||
#define howmany(x, y) (((x) + ((y) - 1)) / (y))
|
# define howmany(x, y) (((x) + ((y) - 1)) / (y))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -121,14 +121,27 @@
|
|||||||
# define STDERR_FILENO 2
|
# define STDERR_FILENO 2
|
||||||
#endif
|
#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.
|
* BSD defines these in <sys/param.h> but others may not.
|
||||||
*/
|
*/
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
# define MIN(a,b) (((a)<(b))?(a):(b))
|
||||||
#endif
|
#endif
|
||||||
#ifndef MAX
|
#ifndef MAX
|
||||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
# define MAX(a,b) (((a)>(b))?(a):(b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -292,6 +292,9 @@
|
|||||||
/* Define if you have flock(2). */
|
/* Define if you have flock(2). */
|
||||||
#undef HAVE_FLOCK
|
#undef HAVE_FLOCK
|
||||||
|
|
||||||
|
/* Define if you have ftruncate(2). */
|
||||||
|
#undef HAVE_FTRUNCATE
|
||||||
|
|
||||||
/* Define if you have snprintf(3). */
|
/* Define if you have snprintf(3). */
|
||||||
#undef HAVE_SNPRINTF
|
#undef HAVE_SNPRINTF
|
||||||
|
|
||||||
|
2
configure
vendored
2
configure
vendored
@@ -5254,7 +5254,7 @@ EOF
|
|||||||
|
|
||||||
;;
|
;;
|
||||||
esac
|
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
|
do
|
||||||
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
|
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
|
||||||
echo "configure:5261: checking for $ac_func" >&5
|
echo "configure:5261: checking for $ac_func" >&5
|
||||||
|
@@ -1349,7 +1349,7 @@ esac
|
|||||||
dnl
|
dnl
|
||||||
dnl Function checks
|
dnl Function checks
|
||||||
dnl
|
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
|
if test -n "$SECUREWARE"; then
|
||||||
AC_CHECK_FUNCS(bigcrypt)
|
AC_CHECK_FUNCS(bigcrypt)
|
||||||
AC_CHECK_FUNCS(set_auth_parameters)
|
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
|
#ifdef HAVE_STRINGS_H
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#endif /* HAVE_STRINGS_H */
|
#endif /* HAVE_STRINGS_H */
|
||||||
#include <fcntl.h>
|
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -68,7 +67,6 @@ static void do_syslog __P((int, char *));
|
|||||||
#endif
|
#endif
|
||||||
#if (LOGGING & SLOG_FILE)
|
#if (LOGGING & SLOG_FILE)
|
||||||
static void do_logfile __P((char *));
|
static void do_logfile __P((char *));
|
||||||
static int lock_file __P((FILE *, int));
|
|
||||||
#endif
|
#endif
|
||||||
static void send_mail __P((char *));
|
static void send_mail __P((char *));
|
||||||
|
|
||||||
@@ -179,7 +177,7 @@ do_logfile(msg)
|
|||||||
_PATH_SUDO_LOGFILE, strerror(errno));
|
_PATH_SUDO_LOGFILE, strerror(errno));
|
||||||
send_mail(full_line);
|
send_mail(full_line);
|
||||||
free(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",
|
easprintf(&full_line, "Can't lock log file: %s: %s",
|
||||||
_PATH_SUDO_LOGFILE, strerror(errno));
|
_PATH_SUDO_LOGFILE, strerror(errno));
|
||||||
send_mail(full_line);
|
send_mail(full_line);
|
||||||
@@ -252,7 +250,7 @@ do_logfile(msg)
|
|||||||
free(full_line);
|
free(full_line);
|
||||||
# endif
|
# endif
|
||||||
(void) fflush(fp);
|
(void) fflush(fp);
|
||||||
(void) lock_file(fp, FALSE);
|
(void) lock_file(fileno(fp), SUDO_UNLOCK);
|
||||||
(void) fclose(fp);
|
(void) fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,50 +570,3 @@ reapchild(sig)
|
|||||||
#endif /* POSIX_SIGNALS */
|
#endif /* POSIX_SIGNALS */
|
||||||
errno = serrno;
|
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
|
#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
|
* Function prototypes
|
||||||
*/
|
*/
|
||||||
@@ -164,6 +171,8 @@ char *estrdup __P((const char *));
|
|||||||
void easprintf __P((char **, const char *, ...));
|
void easprintf __P((char **, const char *, ...));
|
||||||
void evasprintf __P((char **, const char *, va_list));
|
void evasprintf __P((char **, const char *, va_list));
|
||||||
void print_version __P((void));
|
void print_version __P((void));
|
||||||
|
int lock_file __P((int, int));
|
||||||
|
int touch __P((char *, time_t));
|
||||||
YY_DECL;
|
YY_DECL;
|
||||||
|
|
||||||
/* Only provide extern declarations outside of sudo.c. */
|
/* 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.
|
* 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) {
|
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
|
#ifdef WITHOUT_PASSWD
|
||||||
(void) puts("\nNo Authentication configured\n");
|
(void) puts("No Authentication configured\n");
|
||||||
#else
|
#else
|
||||||
(void) fputs("\nAuthentication methods:", stdout);
|
(void) fputs("Authentication methods:", stdout);
|
||||||
for (auth = auth_switch; auth->name; auth++) {
|
for (auth = auth_switch; auth->name; auth++) {
|
||||||
(void) putchar(' ');
|
(void) putchar(' ');
|
||||||
(void) fputs(auth->name, stdout);
|
(void) fputs(auth->name, stdout);
|
||||||
@@ -137,6 +144,8 @@ print_version()
|
|||||||
(void) fputs(" goons", stdout);
|
(void) fputs(" goons", stdout);
|
||||||
# endif
|
# endif
|
||||||
(void) putchar('\n');
|
(void) putchar('\n');
|
||||||
|
# else
|
||||||
|
(void) printf("Incorrect password message: %s\n", INCORRECT_PASSWORD);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SUDO_UMASK
|
#ifdef SUDO_UMASK
|
||||||
@@ -169,14 +178,39 @@ print_version()
|
|||||||
(void) printf("Editor for visudo: %s\n", EDITOR);
|
(void) printf("Editor for visudo: %s\n", EDITOR);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(IGNORE_DOT_PATH) || defined(DONT_LEAK_PATH_INFO) || defined(SECURE_PATH)
|
||||||
|
puts("$PATH options:");
|
||||||
#ifdef SECURE_PATH
|
#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
|
#endif
|
||||||
|
|
||||||
#ifdef _PATH_SENDMAIL
|
#ifdef _PATH_SENDMAIL
|
||||||
(void) printf("Mailer path: %s\n", _PATH_SENDMAIL);
|
(void) printf("Mailer path: %s\n", _PATH_SENDMAIL);
|
||||||
(void) printf("Send mail to: %s\n", ALERTMAIL);
|
(void) printf("Send mail to: %s\n", ALERTMAIL);
|
||||||
(void) printf("Mail subject: %s\n", MAILSUBJECT);
|
(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
|
#endif
|
||||||
|
|
||||||
(void) printf("Default password prompt: %s\n", PASSPROMPT);
|
(void) printf("Default password prompt: %s\n", PASSPROMPT);
|
||||||
@@ -187,14 +221,6 @@ print_version()
|
|||||||
#else
|
#else
|
||||||
(void) puts("no");
|
(void) puts("no");
|
||||||
#endif
|
#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
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
51
visudo.c
51
visudo.c
@@ -56,6 +56,7 @@
|
|||||||
#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
|
#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
#include <time.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -124,8 +125,9 @@ main(argc, argv)
|
|||||||
int sudoers_fd; /* sudoers file descriptor */
|
int sudoers_fd; /* sudoers file descriptor */
|
||||||
int stmp_fd; /* stmp file descriptor */
|
int stmp_fd; /* stmp file descriptor */
|
||||||
int n; /* length parameter */
|
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
|
* Parse command line options
|
||||||
@@ -166,30 +168,44 @@ main(argc, argv)
|
|||||||
#endif /* ENV_EDITOR */
|
#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 (stmp_fd < 0) {
|
||||||
if (errno == EEXIST) {
|
(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",
|
(void) fprintf(stderr, "%s: sudoers file busy, try again later.\n",
|
||||||
Argv[0]);
|
Argv[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
(void) fprintf(stderr, "%s: %s\n", Argv[0], strerror(errno));
|
#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);
|
Exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Install signal handlers to clean up stmp if we are killed. */
|
/* Install signal handlers to clean up stmp if we are killed. */
|
||||||
setup_signals();
|
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);
|
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));
|
(void) fprintf(stderr, "%s: %s\n", Argv[0], strerror(errno));
|
||||||
Exit(-1);
|
Exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy sudoers -> stmp */
|
/* Copy sudoers -> stmp and reset the mtime */
|
||||||
if (sudoers_fd >= 0) {
|
if (sudoers_fd != -1) {
|
||||||
while ((n = read(sudoers_fd, buf, sizeof(buf))) > 0)
|
while ((n = read(sudoers_fd, buf, sizeof(buf))) > 0)
|
||||||
if (write(stmp_fd, buf, n) != n) {
|
if (write(stmp_fd, buf, n) != n) {
|
||||||
(void) fprintf(stderr, "%s: Write failed: %s\n", Argv[0],
|
(void) fprintf(stderr, "%s: Write failed: %s\n", Argv[0],
|
||||||
@@ -200,6 +216,7 @@ main(argc, argv)
|
|||||||
(void) close(sudoers_fd);
|
(void) close(sudoers_fd);
|
||||||
}
|
}
|
||||||
(void) close(stmp_fd);
|
(void) close(stmp_fd);
|
||||||
|
(void) touch(stmp, sudoers_sb.st_mtime);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Edit the temp file and parse it (for sanity checking)
|
* Edit the temp file and parse it (for sanity checking)
|
||||||
@@ -219,20 +236,19 @@ main(argc, argv)
|
|||||||
(void) sprintf(buf, "%s %s", Editor, stmp);
|
(void) sprintf(buf, "%s %s", Editor, stmp);
|
||||||
|
|
||||||
/* Do the edit -- some SYSV editors exit with 1 instead of 0 */
|
/* Do the edit -- some SYSV editors exit with 1 instead of 0 */
|
||||||
|
now = time(NULL);
|
||||||
n = system(buf);
|
n = system(buf);
|
||||||
if (n != -1 && ((n >> 8) == 0 || (n >> 8) == 1)) {
|
if (n != -1 && ((n >> 8) == 0 || (n >> 8) == 1)) {
|
||||||
struct stat statbuf; /* for sanity checking */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sanity checks.
|
* Sanity checks.
|
||||||
*/
|
*/
|
||||||
if (stat(stmp, &statbuf) < 0) {
|
if (stat(stmp, &stmp_sb) < 0) {
|
||||||
(void) fprintf(stderr,
|
(void) fprintf(stderr,
|
||||||
"%s: Can't stat temporary file (%s), %s unchanged.\n",
|
"%s: Can't stat temporary file (%s), %s unchanged.\n",
|
||||||
Argv[0], stmp, sudoers);
|
Argv[0], stmp, sudoers);
|
||||||
Exit(-1);
|
Exit(-1);
|
||||||
}
|
}
|
||||||
if (statbuf.st_size == 0) {
|
if (stmp_sb.st_size == 0) {
|
||||||
(void) fprintf(stderr,
|
(void) fprintf(stderr,
|
||||||
"%s: Zero length temporary file (%s), %s unchanged.\n",
|
"%s: Zero length temporary file (%s), %s unchanged.\n",
|
||||||
Argv[0], stmp, sudoers);
|
Argv[0], stmp, sudoers);
|
||||||
@@ -285,6 +301,15 @@ main(argc, argv)
|
|||||||
}
|
}
|
||||||
} while (parse_error == TRUE);
|
} 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
|
* Change mode and ownership of temp file so when
|
||||||
* we move it to sudoers things are kosher.
|
* we move it to sudoers things are kosher.
|
||||||
@@ -469,5 +494,5 @@ static void
|
|||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
(void) fprintf(stderr, "usage: %s [-V]\n", Argv[0]);
|
(void) fprintf(stderr, "usage: %s [-V]\n", Argv[0]);
|
||||||
Exit(-1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user