Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37037558
en ru br
Репозитории ALT
S:1.9.14p1-alt2.1
5.1: 1.6.8p12-alt7
4.1: 1.6.8p12-alt5.M41.1
4.0: 1.6.8p12-alt5
+updates:1.6.8p12-alt5
3.0: 1.6.7p5-alt5
www.altlinux.org/Changes

Группа :: Система/Основа
Пакет: sudo

 Главная   Изменения   Спек   Патчи   Sources   Загрузить   Gear   Bugs and FR  Repocop 

Патч: sudo-1.6.8p12-alt5.M41.1.patch
Скачать


 Makefile.in     |    5 +-
 UPGRADE         |   12 +++
 aclocal.m4      |   16 +---
 auth/pam.c      |   23 +++++-
 check.c         |   18 ++++
 config.h.in     |    3 +
 configure.in    |   35 ++++++---
 defaults.c      |    3 +-
 logging.c       |    5 +-
 parse.c         |  234 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 parse.yacc      |   13 +++
 pathnames.h.in  |    7 ++
 rpminst.sudoers |   19 +++++
 sample.pam      |   33 +-------
 sudo.c          |   92 ++--------------------
 sudo.control    |   17 ++++
 sudo.h          |    1 -
 sudo.pod        |   15 ++--
 sudoers         |   22 +++---
 sudoers.control |   19 +++++
 sudoers.man.in  |    2 +-
 sudoers.pod     |    9 +-
 tgetpass.c      |    7 +-
 visudo.man.in   |    2 +-
 visudo.pod      |    5 +-
 25 files changed, 425 insertions(+), 192 deletions(-)
diff --git a/Makefile.in b/Makefile.in
index 893ac81..f0a6772 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -88,9 +88,10 @@ install_gid = 0
 sudoers_uid = @SUDOERS_UID@
 sudoers_gid = @SUDOERS_GID@
 sudoers_mode = @SUDOERS_MODE@
+sudoers_dir_mode = @SUDOERS_DIR_MODE@
 
 # Pass in paths and uid/gid + OS dependent defined
-DEFS = @OSDEFS@ -D_PATH_SUDOERS=\"$(sudoersdir)/sudoers\" -D_PATH_SUDOERS_TMP=\"$(sudoersdir)/sudoers.tmp\" -DSUDOERS_UID=$(sudoers_uid) -DSUDOERS_GID=$(sudoers_gid) -DSUDOERS_MODE=$(sudoers_mode)
+DEFS = @OSDEFS@ -D_PATH_SUDOERS=\"$(sudoersdir)/sudoers\" -D_PATH_SUDOERS_TMP=\"$(sudoersdir)/sudoers.tmp\" -DSUDOERS_UID=$(sudoers_uid) -DSUDOERS_GID=$(sudoers_gid) -DSUDOERS_MODE=$(sudoers_mode) -DSUDOERS_DIR_MODE=$(sudoers_dir_mode)
 
 #### End of system configuration section. ####
 
@@ -181,7 +182,7 @@ testsudoers: $(TESTOBJS) $(LIBOBJS)
 	$(CC) -o $@ $(TESTOBJS) $(LIBOBJS) $(LDFLAGS) $(LIBS) $(NET_LIBS)
 
 sudo_noexec.la: sudo_noexec.lo
-	$(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ sudo_noexec.lo -avoid-version -rpath $(noexecdir)
+	$(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ sudo_noexec.lo -avoid-version -module -rpath $(noexecdir)
 
 # Uncomment the following if you want "make distclean" to clean the parser
 @DEV@PARSESRCS = sudo.tab.h sudo.tab.c lex.yy.c def_data.c def_data.h
diff --git a/UPGRADE b/UPGRADE
index c0e73af..2880a28 100644
--- a/UPGRADE
+++ b/UPGRADE
@@ -1,6 +1,18 @@
 Notes on upgrading from an older release
 ========================================
 
+o Upgrading from a version prior to 1.7
+
+    Starting with sudo 1.7, if an OS supports a modular authentication
+    method such as PAM, it will be used by default.
+
+    Prior to version 1.7, sudo would preserve the user's environment,
+    pruning out potentially dangerous variables.  Starting with sudo
+    1.7 the envionment is reset to a default set of values.  To
+    preserve specific environment variables, add them to the "env_keep"
+    list in sudoers.  The old behavior can be restored by negating the
+    "env_reset" option in sudoers.
+
 o Upgrading from a version prior to 1.6.8:
 
     Prior to sudo 1.6.8, if /var/run did not exist, sudo would put
diff --git a/aclocal.m4 b/aclocal.m4
index e6c2994..b8206a2 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -214,21 +214,15 @@ dnl
 dnl check for working fnmatch(3)
 dnl
 AC_DEFUN(SUDO_FUNC_FNMATCH,
-[AC_MSG_CHECKING(for working fnmatch with FNM_CASEFOLD)
+[AC_MSG_CHECKING([for working fnmatch with FNM_CASEFOLD])
 AC_CACHE_VAL(sudo_cv_func_fnmatch,
 [rm -f conftestdata; > conftestdata
 AC_TRY_RUN([#include <fnmatch.h>
-main() { exit(fnmatch("/*/bin/echo *", "/usr/bin/echo just a test", FNM_CASEFOLD)); }
-], sudo_cv_func_fnmatch=yes, sudo_cv_func_fnmatch=no,
-  sudo_cv_func_fnmatch=no)
-rm -f core core.* *.core])dnl
+main() { exit(fnmatch("/*/bin/echo *", "/usr/bin/echo just a test", FNM_CASEFOLD)); }], [sudo_cv_func_fnmatch=yes], [sudo_cv_func_fnmatch=no],
+  [sudo_cv_func_fnmatch=no])
+rm -f core core.* *.core])
 AC_MSG_RESULT($sudo_cv_func_fnmatch)
-if test $sudo_cv_func_fnmatch = yes; then
-  [$1]
-else
-  [$2]
-fi
-])
+AS_IF([test $sudo_cv_func_fnmatch = yes], [$1], [$2])])
 
 dnl
 dnl check for isblank(3)
diff --git a/auth/pam.c b/auth/pam.c
index d289a06..d0c9194 100644
--- a/auth/pam.c
+++ b/auth/pam.c
@@ -56,7 +56,7 @@
 #include "sudo_auth.h"
 
 /* Only OpenPAM and Linux PAM use const qualifiers. */
-#if defined(_OPENPAM) || defined(__LIBPAM_VERSION)
+#if defined(_OPENPAM) || defined(__LIBPAM_VERSION) || defined(__LINUX_PAM__)
 # define PAM_CONST	const
 #else
 # define PAM_CONST
@@ -175,6 +175,8 @@ int
 pam_prep_user(pw)
     struct passwd *pw;
 {
+    int eval;
+
     if (pamh == NULL)
 	pam_init(pw, NULL, NULL);
 
@@ -195,6 +197,18 @@ pam_prep_user(pw)
      */
     (void) pam_setcred(pamh, PAM_ESTABLISH_CRED);
 
+    /*
+     * To fully utilize PAM sessions we would need to keep a
+     * sudo process around until the command exits.  However, we
+     * can at least cause pam_limits to be run by opening and then
+     * immediately closing the session.
+     */
+    if ((eval = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
+	(void) pam_end(pamh, eval | PAM_DATA_SILENT);
+	return(AUTH_FAILURE);
+    }
+    (void) pam_close_session(pamh, 0);
+
     if (pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT) == PAM_SUCCESS)
 	return(AUTH_SUCCESS);
     else
@@ -235,7 +249,12 @@ sudo_conv(num_msg, msg, response, appdata_ptr)
 		    p = pm->msg;
 		/* Read the password. */
 		pass = tgetpass(p, def_passwd_timeout * 60, flags);
-		pr->resp = estrdup(pass ? pass : "");
+		if (pass == NULL) {
+		    /* We got ^C instead of a password; abort quickly. */
+		    nil_pw = 1;
+		    return(PAM_CONV_ERR);
+		}
+		pr->resp = estrdup(pass);
 		if (*pr->resp == '\0')
 		    nil_pw = 1;		/* empty password */
 		else
diff --git a/check.c b/check.c
index b8bd988..c118d88 100644
--- a/check.c
+++ b/check.c
@@ -299,6 +299,24 @@ user_is_exempt()
 	    return(TRUE);
     }
 
+#ifdef HAVE_GETGROUPLIST
+    {
+	gid_t *grouplist, grouptmp;
+	int i, n_groups = 1;
+
+	if (getgrouplist(user_name, user_gid, &grouptmp, &n_groups) == -1) {
+	    grouplist = (gid_t *) emalloc2(sizeof(gid_t), (n_groups + 1));
+	    if (getgrouplist(user_name, user_gid, grouplist, &n_groups) > 0)
+		for (i = 0; i < n_groups; ++i)
+		    if (grouplist[i] == grp->gr_gid) {
+			free(grouplist);
+			return(TRUE);
+		    }
+	    free(grouplist);
+	}
+    }
+#endif
+
     return(FALSE);
 }
 
diff --git a/config.h.in b/config.h.in
index 5decf69..676d187 100644
--- a/config.h.in
+++ b/config.h.in
@@ -122,6 +122,9 @@
 /* Define to 1 if you have the `getdomainname' function. */
 #undef HAVE_GETDOMAINNAME
 
+/* Define to 1 if you have the `getgrouplist' function. */
+#undef HAVE_GETGROUPLIST
+
 /* Define to 1 if you have the `getifaddrs' function. */
 #undef HAVE_GETIFADDRS
 
diff --git a/configure.in b/configure.in
index a963b48..642ec55 100644
--- a/configure.in
+++ b/configure.in
@@ -29,6 +29,7 @@ AC_SUBST(AUTH_OBJS)dnl
 AC_SUBST(MANTYPE)dnl
 AC_SUBST(MAN_POSTINSTALL)dnl
 AC_SUBST(SUDOERS_MODE)dnl
+AC_SUBST(SUDOERS_DIR_MODE)dnl
 AC_SUBST(SUDOERS_UID)dnl
 AC_SUBST(SUDOERS_GID)dnl
 AC_SUBST(DEV)
@@ -102,9 +103,10 @@ PROGS="sudo visudo"
 test -n "$MANTYPE" || MANTYPE="man"
 test -n "$mansrcdir" || mansrcdir="."
 test -n "$SUDOERS_MODE" || SUDOERS_MODE=0440
+test -n "$SUDOERS_DIR_MODE" || SUDOERS_DIR_MODE=0700
 test -n "$SUDOERS_UID" || SUDOERS_UID=0
 test -n "$SUDOERS_GID" || SUDOERS_GID=0
-DEV="#"
+DEV=""
 
 dnl
 dnl Other vaiables
@@ -668,6 +670,20 @@ AC_ARG_WITH(sudoers-mode, [  --with-sudoers-mode     mode of sudoers file (defau
 		;;
     0*)		SUDOERS_MODE=$with_sudoers_mode
 		;;
+    *)		AC_MSG_ERROR(["you must use a numeric uid, not a name."])
+		;;
+esac])
+
+AC_ARG_WITH(sudoers-dir-mode, [  --with-sudoers-dir-mode     mode of sudoers directory (defaults to 0700)],
+[case $with_sudoers_dir_mode in
+    yes)	AC_MSG_ERROR(["must give --with-sudoers-dir-mode an argument."])
+		;;
+    no)		AC_MSG_ERROR(["--without-sudoers-dir-mode not supported."])
+		;;
+    [[1-9]]*)	SUDOERS_DIR_MODE=0${with_sudoers_dir_mode}
+		;;
+    0*)		SUDOERS_DIR_MODE=$with_sudoers_dir_mode
+		;;
     *)		AC_MSG_ERROR(["you must use an octal mode, not a name."])
 		;;
 esac])
@@ -1152,6 +1168,7 @@ fi
 dnl
 dnl C compiler checks
 dnl
+AC_GNU_SOURCE
 AC_ISC_POSIX
 AC_PROG_CC_STDC
 AC_PROG_CPP
@@ -1609,7 +1626,8 @@ if test "$CHECKSHADOW" = "true"; then
     AC_CHECK_FUNCS(getspnam, [CHECKSHADOW="false"], [AC_CHECK_LIB(gen, getspnam, AC_DEFINE(HAVE_GETSPNAM) [SUDO_LIBS="${SUDO_LIBS} -lgen"; LIBS="${LIBS} -lgen"])])
 fi
 if test "$CHECKSHADOW" = "true"; then
-    AC_CHECK_FUNC(getprpwnam, [AC_DEFINE(HAVE_GETPRPWNAM) [CHECKSHADOW="false"; SECUREWARE=1], AC_CHECK_LIB(sec, getprpwnam, AC_DEFINE(HAVE_GETPRPWNAM) [CHECKSHADOW="false"; SECUREWARE=1; SUDO_LIBS="${SUDO_LIBS} -lsec"; LIBS="${LIBS} -lsec"], AC_CHECK_LIB(security, getprpwnam, AC_DEFINE(HAVE_GETPRPWNAM) [CHECKSHADOW="false"; SECUREWARE=1; SUDO_LIBS="${SUDO_LIBS} -lsecurity"; LIBS="${LIBS} -lsecurity"], AC_CHECK_LIB(prot, getprpwnam, AC_DEFINE(HAVE_GETPRPWNAM) [CHECKSHADOW="false"; SECUREWARE=1; SUDO_LIBS="${SUDO_LIBS} -lprot"; LIBS="${LIBS} -lprot"])))])
+    AC_CHECK_FUNC(getprpwnam, [AC_DEFINE(HAVE_GETPRPWNAM) [CHECKSHADOW="false"; SECUREWARE=1]
+      AC_CHECK_LIB(sec, getprpwnam, AC_DEFINE(HAVE_GETPRPWNAM) [CHECKSHADOW="false"; SECUREWARE=1; SUDO_LIBS="${SUDO_LIBS} -lsec"; LIBS="${LIBS} -lsec"], AC_CHECK_LIB(security, getprpwnam, AC_DEFINE(HAVE_GETPRPWNAM) [CHECKSHADOW="false"; SECUREWARE=1; SUDO_LIBS="${SUDO_LIBS} -lsecurity"; LIBS="${LIBS} -lsecurity"], AC_CHECK_LIB(prot, getprpwnam, AC_DEFINE(HAVE_GETPRPWNAM) [CHECKSHADOW="false"; SECUREWARE=1; SUDO_LIBS="${SUDO_LIBS} -lprot"; LIBS="${LIBS} -lprot"])))])
 fi
 
 dnl
@@ -1683,7 +1701,7 @@ dnl
 dnl Function checks
 dnl
 AC_CHECK_FUNCS(strchr strrchr memchr memcpy memset sysconf tzset \
-	       strftime setrlimit initgroups fstat gettimeofday)
+	       strftime setrlimit initgroups fstat getgrouplist gettimeofday)
 AC_CHECK_FUNCS(seteuid, , [AC_DEFINE(NO_SAVED_IDS)])
 if test -z "$SKIP_SETRESUID"; then
     AC_CHECK_FUNCS(setresuid, [SKIP_SETREUID=yes])
@@ -1703,9 +1721,10 @@ fi
 AC_CHECK_FUNCS(lockf flock, [break])
 AC_CHECK_FUNCS(waitpid wait3, [break])
 AC_CHECK_FUNCS(innetgr _innetgr, [AC_CHECK_FUNCS(getdomainname) [break]])
-AC_CHECK_FUNCS(lsearch, , [AC_CHECK_LIB(compat, lsearch, AC_CHECK_HEADER(search.h, AC_DEFINE(HAVE_LSEARCH) [LIBS="${LIBS} -lcompat"], AC_LIBOBJ(lsearch), -), AC_LIBOBJ(lsearch))])
+AC_CHECK_FUNCS(lsearch, , [AC_CHECK_LIB([compat], [lsearch], [AC_CHECK_HEADER([search.h], [AC_DEFINE(HAVE_LSEARCH)]
+[LIBS="${LIBS} -lcompat"], [AC_LIBOBJ(lsearch)], [-])], [AC_LIBOBJ(lsearch)])])
 AC_CHECK_FUNCS(utimes, [AC_CHECK_FUNCS(futimes futimesat, [break])], [AC_CHECK_FUNCS(futime) AC_LIBOBJ(utimes)])
-SUDO_FUNC_FNMATCH(AC_DEFINE(HAVE_FNMATCH), AC_LIBOBJ(fnmatch))
+AC_FUNC_FNMATCH_GNU
 SUDO_FUNC_ISBLANK
 AC_REPLACE_FUNCS(strerror strcasecmp sigaction strlcpy strlcat closefrom)
 AC_CHECK_FUNCS(snprintf vsnprintf asprintf vasprintf, , [NEED_SNPRINTF=1])
@@ -2299,12 +2318,6 @@ AH_TEMPLATE(sig_atomic_t, [Define to `int' if <signal.h> does not define.])
 dnl
 dnl Bits to copy verbatim into config.h.in
 dnl
-AH_VERBATIM([_GNU_SOURCE],
-[/* Enable GNU extensions on systems that have them. */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE	1
-#endif])
-
 AH_VERBATIM([_ALL_SOURCE],
 [/* Enable non-POSIX extensions on AIX. */
 #ifndef _ALL_SOURCE
diff --git a/defaults.c b/defaults.c
index 667f44a..287430c 100644
--- a/defaults.c
+++ b/defaults.c
@@ -438,6 +438,7 @@ init_defaults()
 #ifdef ENV_EDITOR
     def_env_editor = TRUE;
 #endif
+    def_env_reset = TRUE;
     def_set_logname = TRUE;
 
     /* Syslog options need special care since they both strings and ints */
@@ -450,7 +451,7 @@ init_defaults()
 #endif
 
     /* Password flags also have a string and integer component. */
-    (void) store_tuple("any", &sudo_defs_table[I_LISTPW], TRUE);
+    (void) store_tuple("all", &sudo_defs_table[I_LISTPW], TRUE);
     (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], TRUE);
 
     /* Then initialize the int-like things. */
diff --git a/logging.c b/logging.c
index 1e1b997..cb5f55a 100644
--- a/logging.c
+++ b/logging.c
@@ -102,9 +102,9 @@ mysyslog(pri, fmt, va_alist)
     va_start(ap);
 #endif
 #ifdef LOG_NFACILITIES
-    openlog("sudo", 0, def_syslog);
+    openlog("sudo", LOG_PID, def_syslog);
 #else
-    openlog("sudo", 0);
+    openlog("sudo", LOG_PID);
 #endif
     vsnprintf(buf, sizeof(buf), fmt, ap);
 #ifdef BROKEN_SYSLOG
@@ -120,7 +120,6 @@ mysyslog(pri, fmt, va_alist)
     syslog(pri, "%s", buf);
 #endif /* BROKEN_SYSLOG */
     va_end(ap);
-    closelog();
 }
 
 /*
diff --git a/parse.c b/parse.c
index c045b9c..5afdc6a 100644
--- a/parse.c
+++ b/parse.c
@@ -72,6 +72,12 @@
 #  include <ndir.h>
 # endif
 #endif
+#ifdef HAVE_ERR_H
+# include <err.h>
+#else
+# include "emul/err.h"
+#endif /* HAVE_ERR_H */
+#include <errno.h>
 
 #include "sudo.h"
 #include "parse.h"
@@ -91,12 +97,217 @@ static const char rcsid[] = "$Sudo: parse.c,v 1.161 2004/08/24 18:01:13 millert
 int parse_error = FALSE;
 extern int keepall;
 extern FILE *yyin, *yyout;
+extern int errorlineno;
 
 /*
  * Prototypes
  */
 static int has_meta	__P((char *));
        void init_parser	__P((void));
+       void reset_parser	__P((void));
+
+/*
+ * Sanity check sudoers mode/owner/type.
+ * Leaves a file pointer to the sudoers file open in ``fp''.
+ */
+static FILE *
+check_sudoers(const char *path)
+{
+    FILE *fp = NULL;
+    struct stat statbuf;
+    int rootstat, i;
+    char c;
+
+    /*
+     * Fix the mode and group on sudoers file from old default.
+     * Only works if file system is readable/writable by root.
+     */
+    if ((rootstat = stat_sudoers(path, &statbuf)) == 0 &&
+	SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 &&
+	(statbuf.st_mode & 0007777) == 0400) {
+
+	if (chmod(path, SUDOERS_MODE) == 0) {
+	    warnx("fixed mode on %s", path);
+	    SET(statbuf.st_mode, SUDOERS_MODE);
+	    if (statbuf.st_gid != SUDOERS_GID) {
+		if (!chown(path,(uid_t) -1,SUDOERS_GID)) {
+		    warnx("set group on %s", path);
+		    statbuf.st_gid = SUDOERS_GID;
+		} else
+		    warn("unable to set group on %s", path);
+	    }
+	} else
+	    warn("unable to fix mode on %s", path);
+    }
+
+    /*
+     * Sanity checks on sudoers file.  Must be done as sudoers
+     * file owner.  We already did a stat as root, so use that
+     * data if we can't stat as sudoers file owner.
+     */
+    set_perms(PERM_SUDOERS);
+
+    if (rootstat != 0 && stat_sudoers(path, &statbuf) != 0)
+	log_error(USE_ERRNO, "can't stat %s", path);
+    else if (!S_ISREG(statbuf.st_mode))
+	log_error(0, "%s is not a regular file", path);
+    else if (statbuf.st_size == 0)
+	log_error(0, "%s is zero length", path);
+    else if ((statbuf.st_mode & 07777) != SUDOERS_MODE)
+	log_error(0, "%s is mode 0%o, should be 0%o", path,
+	    (statbuf.st_mode & 07777), SUDOERS_MODE);
+    else if (statbuf.st_uid != SUDOERS_UID)
+	log_error(0, "%s is owned by uid %lu, should be %lu", path,
+	    (unsigned long) statbuf.st_uid, (unsigned long) SUDOERS_UID);
+    else if (statbuf.st_gid != SUDOERS_GID)
+	log_error(0, "%s is owned by gid %lu, should be %lu", path,
+	    (unsigned long) statbuf.st_gid, (unsigned long) SUDOERS_GID);
+    else {
+	/* Solaris sometimes returns EAGAIN so try 10 times */
+	for (i = 0; i < 10 ; i++) {
+	    errno = 0;
+	    if ((fp = fopen(path, "r")) == NULL ||
+		fread(&c, sizeof(c), 1, fp) != 1) {
+		fp = NULL;
+		if (errno != EAGAIN && errno != EWOULDBLOCK)
+		    break;
+	    } else
+		break;
+	    sleep(1);
+	}
+	if (fp == NULL)
+	    log_error(USE_ERRNO, "can't open %s", path);
+    }
+
+    set_perms(PERM_ROOT);		/* change back to root */
+    return fp;
+}
+
+static int
+skip_sudoers(const char *s)
+{
+    char allowed[] = "_-";
+
+    for (; *s; ++s) {
+	if (!isalnum(*s) && !strchr(allowed, *s))
+	    return TRUE;
+    }
+
+    return FALSE;
+}
+
+/*
+ * Load given sudoers file.
+ */
+static int
+load_sudoers(const char *path)
+{
+    FILE *fp = check_sudoers(path);	/* check mode/owner */
+    int error;
+
+    if (!fp)
+	return 1;
+
+    rewind(fp);
+    yyin = fp;
+    yyout = stdout;
+
+    /* Reset data structures in the parser. */
+    reset_parser();
+
+    /* Need to be runas user while stat'ing things in the parser. */
+    set_perms(PERM_RUNAS);
+    error = yyparse();
+    set_perms(PERM_ROOT);
+
+    /* Close the sudoers file now that we are done with it. */
+    (void) fclose(fp);
+    fp = NULL;
+
+    if (error || parse_error) {
+	log_error(0, "parse error in %s near line %d", path, errorlineno);
+	return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * Load all sudoers files.
+ */
+static int
+load_all_sudoers(void)
+{
+    int error, rc;
+    struct stat statbuf;
+
+    /* check mode/owner and parse */
+    if ((error = load_sudoers(_PATH_SUDOERS)))
+	return error;
+
+    /*
+     * Sanity checks on sudoers directory.  Must be done as sudoers
+     * file owner.  We already did a stat as root, so use that
+     * data if we can't stat as sudoers file owner.
+     */
+    set_perms(PERM_SUDOERS);
+    rc = stat_sudoers(_PATH_SUDOERS_DIR, &statbuf);
+    set_perms(PERM_ROOT);
+
+    if (rc) {
+	if (ENOENT == errno)
+	    return error;	/* do not complain if sudoers directory is missing */
+	log_error(USE_ERRNO, "can't stat %s", _PATH_SUDOERS_DIR);
+	error = 1;
+    }
+    else if (!S_ISDIR(statbuf.st_mode)) {
+	log_error(0, "%s is not a directory", _PATH_SUDOERS_DIR);
+	error = 1;
+    }
+    else if ((statbuf.st_mode & 07777) != SUDOERS_DIR_MODE) {
+	log_error(0, "%s is mode 0%o, should be 0%o", _PATH_SUDOERS_DIR,
+	    (statbuf.st_mode & 07777), SUDOERS_DIR_MODE);
+	error = 1;
+    }
+    else if (statbuf.st_uid != SUDOERS_UID) {
+	log_error(0, "%s is owned by uid %lu, should be %lu", _PATH_SUDOERS_DIR,
+	    (unsigned long) statbuf.st_uid, SUDOERS_UID);
+	error = 1;
+    }
+    else if (statbuf.st_gid != SUDOERS_GID) {
+	log_error(0, "%s is owned by gid %lu, should be %lu", _PATH_SUDOERS_DIR,
+	    (unsigned long) statbuf.st_gid, SUDOERS_GID);
+	error = 1;
+    }
+    else {
+	DIR *dirp;
+	struct dirent *dent;
+
+	set_perms(PERM_SUDOERS);
+	dirp = opendir(_PATH_SUDOERS_DIR);
+	set_perms(PERM_ROOT);
+
+	if (!dirp) {
+	    log_error(USE_ERRNO, "can't open %s", _PATH_SUDOERS_DIR);
+	    error = 1;
+	}
+	else {
+	    while ((dent = readdir(dirp))) {
+		char *fname;
+
+		if (skip_sudoers(dent->d_name))
+		    continue;
+
+		easprintf(&fname, "%s/%s", _PATH_SUDOERS_DIR, dent->d_name);
+		error |= load_sudoers(fname);
+		free(fname);
+	    }
+	    closedir(dirp);
+	}
+    }
+
+    return error;
+}
 
 /*
  * Look up the user in the sudoers file and check to see if they are
@@ -109,11 +320,6 @@ sudoers_lookup(pwflag)
     int error, nopass;
     enum def_tupple pwcheck;
 
-    /* We opened _PATH_SUDOERS in check_sudoers() so just rewind it. */
-    rewind(sudoers_fp);
-    yyin = sudoers_fp;
-    yyout = stdout;
-
     /* Allocate space for data structures in the parser. */
     init_parser();
 
@@ -121,16 +327,10 @@ sudoers_lookup(pwflag)
     if (pwflag > 0)
 	keepall = TRUE;
 
-    /* Need to be runas user while stat'ing things in the parser. */
-    set_perms(PERM_RUNAS);
-    error = yyparse();
-
-    /* Close the sudoers file now that we are done with it. */
-    (void) fclose(sudoers_fp);
-    sudoers_fp = NULL;
+    /* Check mode/owner and parse all sudoers files */
+    error = load_all_sudoers();
 
-    if (error || parse_error) {
-	set_perms(PERM_ROOT);
+    if (error) {
 	return(VALIDATE_ERROR);
     }
 
@@ -184,7 +384,6 @@ sudoers_lookup(pwflag)
 	    top--;
 	}
 	if (found) {
-	    set_perms(PERM_ROOT);
 	    if (nopass == -1)
 		nopass = 0;
 	    return(VALIDATE_OK | nopass);
@@ -197,7 +396,6 @@ sudoers_lookup(pwflag)
 		    /*
 		     * User was granted access to cmnd on host as user.
 		     */
-		    set_perms(PERM_ROOT);
 		    return(VALIDATE_OK |
 			(no_passwd == TRUE ? FLAG_NOPASS : 0) |
 			(no_execve == TRUE ? FLAG_NOEXEC : 0));
@@ -206,7 +404,6 @@ sudoers_lookup(pwflag)
 		    /*
 		     * User was explicitly denied access to cmnd on host.
 		     */
-		    set_perms(PERM_ROOT);
 		    return(VALIDATE_NOT_OK |
 			(no_passwd == TRUE ? FLAG_NOPASS : 0) |
 			(no_execve == TRUE ? FLAG_NOEXEC : 0));
@@ -215,7 +412,6 @@ sudoers_lookup(pwflag)
 	    top--;
 	}
     }
-    set_perms(PERM_ROOT);
 
     /*
      * The user was neither explicitly granted nor denied access.
@@ -240,7 +436,7 @@ command_matches(sudoers_cmnd, sudoers_args)
     DIR *dirp;
 
     /* Check for pseudo-commands */
-    if (strchr(user_cmnd, '/') == NULL) {
+    if (sudoers_cmnd[0] != '/') {
 	/*
 	 * Return true if both sudoers_cmnd and user_cmnd are "sudoedit" AND
 	 *  a) there are no args in sudoers OR
diff --git a/parse.yacc b/parse.yacc
index 46dce22..1fbd685 100644
--- a/parse.yacc
+++ b/parse.yacc
@@ -1240,3 +1240,16 @@ init_parser()
     if (printmatches == TRUE)
 	expand_match_list();
 }
+
+/*
+ * Resets data structures used by a previous parser run.
+ */
+void
+reset_parser()
+{
+    /* Reset data structures if we run the parser more than once. */
+    parse_error = FALSE;
+    used_runas = FALSE;
+    errorlineno = -1;
+    sudolineno = 1;
+}
diff --git a/pathnames.h.in b/pathnames.h.in
index 14f4adf..e7eef8a 100644
--- a/pathnames.h.in
+++ b/pathnames.h.in
@@ -58,6 +58,13 @@
 #endif /* _PATH_SUDOERS_TMP */
 
 /*
+ * NOTE: _PATH_SUDOERS_DIR is usually overriden by the Makefile.
+ */
+#ifndef _PATH_SUDOERS_DIR
+#define _PATH_SUDOERS_DIR	"/etc/sudo.d"
+#endif /* _PATH_SUDOERS_DIR */
+
+/*
  * The following paths are controlled via the configure script.
  */
 
diff --git a/rpminst.sudoers b/rpminst.sudoers
new file mode 100644
index 0000000..5339dfb
--- /dev/null
+++ b/rpminst.sudoers
@@ -0,0 +1,19 @@
+# This example sudoers file allows members of rpminst group to execute /bin/rpm
+# Beware, ability to execute rpm with root permissions de facto means full
+# root privileges granted to the user.
+#
+# This file MUST be edited with the 'visudo' command as root.
+#
+# See the sudoers man page for the details on how to write a sudoers file.
+
+# User alias specification
+User_Alias	RPMINST_USER = %rpminst
+
+# Runas alias specification
+Runas_Alias	RPMINST_RUN_AS = root
+
+# Cmnd alias specification
+Cmnd_Alias	RPMINST_CMD = /bin/rpm, /usr/bin/rpmi
+
+# User privilege specification
+RPMINST_USER	ALL = (RPMINST_RUN_AS) RPMINST_CMD
diff --git a/sample.pam b/sample.pam
index 603fded..de450a3 100644
--- a/sample.pam
+++ b/sample.pam
@@ -1,30 +1,5 @@
 #%PAM-1.0
-# Sample /etc/pam.d/sudo file for RedHat 9 / Fedora Core.
-#   For other Linux distributions you may want to
-#   use /etc/pam.d/sshd or /etc/pam.d/su as a guide.
-#
-#   There are two basic ways to configure PAM, either via pam_stack
-#   or by explicitly specifying the various methods to use.
-#   
-# Here we use pam_stack
-auth       required	pam_stack.so service=system-auth
-account    required	pam_stack.so service=system-auth
-password   required	pam_stack.so service=system-auth
-session    required	pam_stack.so service=system-auth
-#
-# Alternately, you can specify the authentication method directly.
-# Here we use pam_unix for normal password authentication.
-#auth       required	pam_env.so
-#auth       sufficient	pam_unix.so
-#account    required	pam_unix.so
-#password   required	pam_cracklib.so retry=3 type=
-#password   required	pam_unix.so nullok use_authtok md5 shadow
-#session    required	pam_limits.so
-#session    required	pam_unix.so
-#
-# Another option is to use SMB for authentication.
-#auth       required	pam_env.so
-#auth       sufficient	pam_smb_auth.so
-#account    required	pam_smb_auth.so
-#password   required	pam_smb_auth.so
-#session    required	pam_limits.so
+auth     include	system-auth
+account  include	system-auth
+password required	pam_deny.so
+session  include	system-auth
diff --git a/sudo.c b/sudo.c
index 3313b00..3f2257d 100644
--- a/sudo.c
+++ b/sudo.c
@@ -101,7 +101,6 @@ static const char rcsid[] = "$Sudo: sudo.c,v 1.370 2004/08/24 18:01:13 millert E
  */
 static int init_vars			__P((int));
 static int parse_args			__P((int, char **));
-static void check_sudoers		__P((void));
 static void initial_setup		__P((void));
 static void set_loginclass		__P((struct passwd *));
 static void usage			__P((int));
@@ -123,12 +122,10 @@ char **Argv, **NewArgv;
 char *prev_user;
 struct sudo_user sudo_user;
 struct passwd *auth_pw;
-FILE *sudoers_fp;
 struct interface *interfaces;
 int num_interfaces;
 int tgetpass_flags;
 uid_t timestamp_uid;
-extern int errorlineno;
 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
 static struct rlimit corelimit;
 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
@@ -203,6 +200,12 @@ main(argc, argv, envp)
     /* Setup defaults data structures. */
     init_defaults();
 
+#ifdef LOG_NFACILITIES
+    openlog("sudo", LOG_PID, def_syslog);
+#else
+    openlog("sudo", LOG_PID);
+#endif
+
     /* Load the list of local ip addresses and netmasks.  */
     load_interfaces();
 
@@ -260,8 +263,6 @@ main(argc, argv, envp)
     else if (ISSET(validated, VALIDATE_OK) && !printmatches); /* skips */
     else if (ISSET(validated, VALIDATE_OK) && printmatches)
     {
-	check_sudoers();	/* check mode/owner on _PATH_SUDOERS */
-
 	/* User is found in LDAP and we want a list of all sudo commands the
 	 * user can do, so consult sudoers but throw away result.
 	 */
@@ -270,8 +271,6 @@ main(argc, argv, envp)
     else
 #endif
     {
-	check_sudoers();	/* check mode/owner on _PATH_SUDOERS */
-
 	/* Validate the user but don't search for pseudo-commands. */
 	validated = sudoers_lookup(pwflag);
     }
@@ -316,10 +315,6 @@ main(argc, argv, envp)
 	exit(0);
     }
 
-    if (ISSET(validated, VALIDATE_ERROR))
-	log_error(0, "parse error in %s near line %d", _PATH_SUDOERS,
-	    errorlineno);
-
     /* Is root even allowed to run sudo? */
     if (user_uid == 0 && !def_root_sudo) {
 	(void) fprintf(stderr,
@@ -845,81 +840,6 @@ parse_args(argc, argv)
 }
 
 /*
- * Sanity check sudoers mode/owner/type.
- * Leaves a file pointer to the sudoers file open in ``fp''.
- */
-static void
-check_sudoers()
-{
-    struct stat statbuf;
-    int rootstat, i;
-    char c;
-
-    /*
-     * Fix the mode and group on sudoers file from old default.
-     * Only works if file system is readable/writable by root.
-     */
-    if ((rootstat = stat_sudoers(_PATH_SUDOERS, &statbuf)) == 0 &&
-	SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 &&
-	(statbuf.st_mode & 0007777) == 0400) {
-
-	if (chmod(_PATH_SUDOERS, SUDOERS_MODE) == 0) {
-	    warnx("fixed mode on %s", _PATH_SUDOERS);
-	    SET(statbuf.st_mode, SUDOERS_MODE);
-	    if (statbuf.st_gid != SUDOERS_GID) {
-		if (!chown(_PATH_SUDOERS,(uid_t) -1,SUDOERS_GID)) {
-		    warnx("set group on %s", _PATH_SUDOERS);
-		    statbuf.st_gid = SUDOERS_GID;
-		} else
-		    warn("unable to set group on %s", _PATH_SUDOERS);
-	    }
-	} else
-	    warn("unable to fix mode on %s", _PATH_SUDOERS);
-    }
-
-    /*
-     * Sanity checks on sudoers file.  Must be done as sudoers
-     * file owner.  We already did a stat as root, so use that
-     * data if we can't stat as sudoers file owner.
-     */
-    set_perms(PERM_SUDOERS);
-
-    if (rootstat != 0 && stat_sudoers(_PATH_SUDOERS, &statbuf) != 0)
-	log_error(USE_ERRNO, "can't stat %s", _PATH_SUDOERS);
-    else if (!S_ISREG(statbuf.st_mode))
-	log_error(0, "%s is not a regular file", _PATH_SUDOERS);
-    else if (statbuf.st_size == 0)
-	log_error(0, "%s is zero length", _PATH_SUDOERS);
-    else if ((statbuf.st_mode & 07777) != SUDOERS_MODE)
-	log_error(0, "%s is mode 0%o, should be 0%o", _PATH_SUDOERS,
-	    (statbuf.st_mode & 07777), SUDOERS_MODE);
-    else if (statbuf.st_uid != SUDOERS_UID)
-	log_error(0, "%s is owned by uid %lu, should be %lu", _PATH_SUDOERS,
-	    (unsigned long) statbuf.st_uid, (unsigned long) SUDOERS_UID);
-    else if (statbuf.st_gid != SUDOERS_GID)
-	log_error(0, "%s is owned by gid %lu, should be %lu", _PATH_SUDOERS,
-	    (unsigned long) statbuf.st_gid, (unsigned long) SUDOERS_GID);
-    else {
-	/* Solaris sometimes returns EAGAIN so try 10 times */
-	for (i = 0; i < 10 ; i++) {
-	    errno = 0;
-	    if ((sudoers_fp = fopen(_PATH_SUDOERS, "r")) == NULL ||
-		fread(&c, sizeof(c), 1, sudoers_fp) != 1) {
-		sudoers_fp = NULL;
-		if (errno != EAGAIN && errno != EWOULDBLOCK)
-		    break;
-	    } else
-		break;
-	    sleep(1);
-	}
-	if (sudoers_fp == NULL)
-	    log_error(USE_ERRNO, "can't open %s", _PATH_SUDOERS);
-    }
-
-    set_perms(PERM_ROOT);		/* change back to root */
-}
-
-/*
  * Close all open files (except std*) and turn off core dumps.
  * Also sets the set_perms() pointer to the correct function.
  */
diff --git a/sudo.control b/sudo.control
new file mode 100644
index 0000000..66e46ba
--- /dev/null
+++ b/sudo.control
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. /etc/control.d/functions
+
+BINARY=/usr/bin/sudo
+
+new_fmode public 4711 root root
+new_fmode wheelonly 4710 root wheel
+new_fmode restricted 700 root root
+
+new_help public "Any user can execute $BINARY"
+new_help wheelonly "Only \"wheel\" group members can execute $BINARY"
+new_help restricted "Only root can execute $BINARY"
+
+new_summary 'Execute a command as another user'
+
+control_fmode "$BINARY" "$*" || exit 1
diff --git a/sudo.h b/sudo.h
index 51dc51f..b189d38 100644
--- a/sudo.h
+++ b/sudo.h
@@ -248,7 +248,6 @@ YY_DECL;
 extern struct sudo_user sudo_user;
 extern struct passwd *auth_pw;
 
-extern FILE *sudoers_fp;
 extern int tgetpass_flags;
 extern uid_t timestamp_uid;
 
diff --git a/sudo.pod b/sudo.pod
index 3b913d4..a04d044 100644
--- a/sudo.pod
+++ b/sudo.pod
@@ -40,7 +40,7 @@ file [...]
 =head1 DESCRIPTION
 
 B<sudo> allows a permitted user to execute a I<command> as the
-superuser or another user, as specified in the I<sudoers> file.
+superuser or another user, as specified in the I<sudoers> files.
 The real and effective uid and gid are set to match those of the
 target user as specified in the passwd file and the group vector
 is initialized based on the group file (unless the B<-P> option was
@@ -57,15 +57,16 @@ When invoked as B<sudoedit>, the B<-e> option (described below),
 is implied.
 
 B<sudo> determines who is an authorized user by consulting the file
-F<@sysconfdir@/sudoers>.  By giving B<sudo> the B<-v> flag a user
+F<@sysconfdir@/sudoers> and all files with valid names from
+F<@sysconfdir@/sudo.d> directory.  By giving B<sudo> the B<-v> flag a user
 can update the time stamp without running a I<command.> The password
 prompt itself will also time out if the user's password is not
 entered within C<@password_timeout@> minutes (unless overridden via
 I<sudoers>).
 
-If a user who is not listed in the I<sudoers> file tries to run a
+If a user who is not listed in the I<sudoers> files tries to run a
 command via B<sudo>, mail is sent to the proper authorities, as
-defined at configure time or in the I<sudoers> file (defaults to
+defined at configure time or in the I<sudoers> files (defaults to
 C<@mailto@>).  Note that the mail will not be sent if an unauthorized
 user tries to run sudo with the B<-l> or B<-v> flags.  This allows
 users to determine for themselves whether or not they are allowed
@@ -82,7 +83,7 @@ root, not the user specified by C<SUDO_USER>.
 B<sudo> can log both successful and unsuccessful attempts (as well
 as errors) to syslog(3), a log file, or both.  By default B<sudo>
 will log via syslog(3) but this is changeable at configure time
-or via the I<sudoers> file.
+or via the I<sudoers> files.
 
 =head1 OPTIONS
 
@@ -95,6 +96,7 @@ B<sudo> accepts the following command line options:
 The B<-H> (I<HOME>) option sets the C<HOME> environment variable
 to the homedir of the target user (root by default) as specified
 in passwd(@mansectform@).  By default, B<sudo> does not modify C<HOME>
+unless B<-s> (I<shell>) option is also given
 (see I<set_home> and I<always_set_home> in L<sudoers(@mansectform@)>).
 
 =item -K
@@ -405,7 +407,8 @@ B<sudo> utilizes the following environment variables:
 
 =head1 FILES
 
- @sysconfdir@/sudoers		List of who can run what
+ @sysconfdir@/sudoers,
+ @sysconfdir@/sudo.d/*		List of who can run what
  @timedir@		Directory containing timestamps
 
 =head1 EXAMPLES
diff --git a/sudoers b/sudoers
index 36f78b3..6b81a34 100644
--- a/sudoers
+++ b/sudoers
@@ -8,22 +8,22 @@
 # Host alias specification
 
 # User alias specification
+User_Alias	WHEEL_USERS = %wheel
+User_Alias	XGRP_USERS = %xgrp
 
 # Cmnd alias specification
 
 # Defaults specification
 
-# Runas alias specification
+# If env_reset is disabled, sudo will NOT reset the environment
+# to only contain the fixed list of variables.
+# See sudoers(5) for details.
+#Defaults:WHEEL_USERS	!env_reset
 
-# User privilege specification
-root	ALL=(ALL) ALL
-
-# Uncomment to allow people in group wheel to run all commands
-# %wheel	ALL=(ALL)	ALL
+# Preserve DISPLAY and XAUTHORITY environment variables
+# for "xgrp" group members.
+Defaults:XGRP_USERS	env_keep += "DISPLAY XAUTHORITY"
 
-# Same thing without a password
-# %wheel	ALL=(ALL)	NOPASSWD: ALL
+# User privilege specification
+#root	ALL=(ALL) ALL
 
-# Samples
-# %users  ALL=/sbin/mount /cdrom,/sbin/umount /cdrom
-# %users  localhost=/sbin/shutdown -h now
diff --git a/sudoers.control b/sudoers.control
new file mode 100755
index 0000000..72dabcf
--- /dev/null
+++ b/sudoers.control
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+. /etc/control.d/functions
+
+CONFIG=/etc/sudoers
+
+new_subst strict \
+	'^#Defaults:WHEEL_USERS[[:space:]]+!env_reset$' \
+	's,^\(Defaults:WHEEL_USERS[[:space:]]\+!env_reset\)$,#\1,'
+new_subst relaxed \
+	'^Defaults:WHEEL_USERS[[:space:]]+!env_reset$' \
+	's,^#\(Defaults:WHEEL_USERS[[:space:]]\+!env_reset\)$,\1,'
+
+new_help strict 'Enable strict environment rules'
+new_help relaxed 'Disable strict environment rules'
+
+new_summary 'sudoers environment rules'
+
+control_subst "$CONFIG" "$*"
diff --git a/sudoers.man.in b/sudoers.man.in
index 101a3d0..ba7b279 100644
--- a/sudoers.man.in
+++ b/sudoers.man.in
@@ -810,7 +810,7 @@ The user must always enter a password to use the \fB\-l\fR flag.
 .Sp
 If no value is specified, a value of \fIany\fR is implied.
 Negating the option results in a value of \fInever\fR being used.
-The default value is \fIany\fR.
+The default value is \fIall\fR.
 .RE
 .PP
 \&\fBLists that can be used in a boolean context\fR:
diff --git a/sudoers.pod b/sudoers.pod
index 3ad6b2a..df22dcb 100644
--- a/sudoers.pod
+++ b/sudoers.pod
@@ -325,7 +325,7 @@ set, falling back on the shell listed in the invoking user's
 If set and B<sudo> is invoked with the B<-s> flag the C<HOME>
 environment variable will be set to the home directory of the target
 user (which is root unless the B<-u> option is used).  This effectively
-makes the B<-s> flag imply B<-H>.  This flag is I<off> by default.
+makes the B<-s> flag imply B<-H>.  This flag is I<on> by default.
 
 =item always_set_home
 
@@ -380,7 +380,7 @@ tty.  This will disallow things like C<"rsh somehost sudo ls"> since
 L<rsh(1)> does not allocate a tty.  Because it is not possible to turn
 off echo when there is no tty present, some sites may with to set
 this flag to prevent a user from entering a visible password.  This
-flag is I<off> by default.
+flag is I<on> by default.
 
 =item env_editor
 
@@ -732,7 +732,7 @@ The user must always enter a password to use the B<-l> flag.
 
 If no value is specified, a value of I<any> is implied.
 Negating the option results in a value of I<never> being used.
-The default value is I<any>.
+The default value is I<all>.
 
 =back
 
@@ -990,7 +990,8 @@ used as part of a word (e.g. a username or hostname):
 
 =head1 FILES
 
- @sysconfdir@/sudoers		List of who can run what
+ @sysconfdir@/sudoers,
+ @sysconfdir@/sudo.d/*		List of who can run what
  /etc/group		Local groups file
  /etc/netgroup		List of network groups
 
diff --git a/tgetpass.c b/tgetpass.c
index 0cc2872..56a5b2a 100644
--- a/tgetpass.c
+++ b/tgetpass.c
@@ -136,10 +136,13 @@ tgetpass(prompt, timeout, flags)
     (void) fflush(stdout);
 restart:
     /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
-    if (ISSET(flags, TGP_STDIN) ||
-	(input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
+    if (ISSET(flags, TGP_STDIN)) {
 	input = STDIN_FILENO;
 	output = STDERR_FILENO;
+    } else if ((input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
+	log_error(NO_EXIT|NO_MAIL, "must be run from a terminal");
+	buf[0] = '\0';
+	return buf;
     }
 
     /*
diff --git a/visudo.man.in b/visudo.man.in
index ad8e8c4..67dafa5 100644
--- a/visudo.man.in
+++ b/visudo.man.in
@@ -268,7 +268,7 @@ or User specifications.  In \fB\-s\fR (strict) mode this is an error,
 not a warning.
 .SH "SEE ALSO"
 .IX Header "SEE ALSO"
-\&\fIvi\fR\|(1), sudoers(@mansectform@), sudo(@mansectsu@), vipw(@mansectsu@)
+\&\fIvitmp\fR\|(1), sudoers(@mansectform@), sudo(@mansectsu@), vipw(@mansectsu@)
 .SH "AUTHOR"
 .IX Header "AUTHOR"
 Many people have worked on \fIsudo\fR over the years; this version of
diff --git a/visudo.pod b/visudo.pod
index 735ce8f..541e3e3 100644
--- a/visudo.pod
+++ b/visudo.pod
@@ -116,7 +116,8 @@ was configured with the I<--with-env-editor> option:
 
 =head1 FILES
 
- @sysconfdir@/sudoers		List of who can run what
+ @sysconfdir@/sudoers,
+ @sysconfdir@/sudo.d/*		List of who can run what
  @sysconfdir@/sudoers.tmp	Lock file for visudo
 
 =head1 DIAGNOSTICS
@@ -160,7 +161,7 @@ not a warning.
 
 =head1 SEE ALSO
 
-L<vi(1)>, L<sudoers(@mansectform@)>, L<sudo(@mansectsu@)>, L<vipw(@mansectsu@)>
+L<vitmp(1)>, L<sudoers(@mansectform@)>, L<sudo(@mansectsu@)>, L<vipw(@mansectsu@)>
 
 =head1 AUTHOR
 
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin