Imported Upstream version 1.7.0 origin/upstream upstream/1.7.0
authorBdale Garbee <bdale@gag.com>
Sat, 28 Mar 2009 12:33:43 +0000 (06:33 -0600)
committerBdale Garbee <bdale@gag.com>
Sat, 28 Mar 2009 12:33:43 +0000 (06:33 -0600)
141 files changed:
BUGS [deleted file]
CHANGES [deleted file]
ChangeLog [new file with mode: 0644]
HISTORY
INSTALL
LICENSE
Makefile.in
README
README.LDAP
TROUBLESHOOTING
UPGRADE
WHATSNEW [new file with mode: 0644]
aclocal.m4
aix.c [new file with mode: 0644]
alias.c [new file with mode: 0644]
alloc.c
alloca.c [deleted file]
auth/API
auth/afs.c
auth/aix_auth.c
auth/bsdauth.c
auth/dce.c
auth/fwtk.c
auth/kerb4.c
auth/kerb5.c
auth/pam.c
auth/passwd.c
auth/rfc1938.c
auth/secureware.c
auth/securid.c
auth/securid5.c
auth/sia.c
auth/sudo_auth.c
auth/sudo_auth.h
check.c
closefrom.c
compat.h
config.h.in
configure
configure.in
def_data.c
def_data.h
def_data.in
defaults.c
defaults.h
emul/charclass.h [new file with mode: 0644]
emul/err.h [deleted file]
emul/fnmatch.h
emul/search.h [deleted file]
emul/timespec.h
env.c
err.c [deleted file]
error.c [new file with mode: 0644]
error.h [new file with mode: 0644]
fileops.c
find_path.c
fnmatch.3 [deleted file]
fnmatch.c
getcwd.c
getprogname.c
getspwuid.c
gettime.c
glob.c
goodpath.c
gram.c [new file with mode: 0644]
gram.h [new file with mode: 0644]
gram.y [new file with mode: 0644]
indent.pro
ins_csops.h
install-sh
insults.h
interfaces.c
interfaces.h
isblank.c [new file with mode: 0644]
lbuf.c [new file with mode: 0644]
lbuf.h [new file with mode: 0644]
ldap.c
lex.yy.c [deleted file]
list.c [new file with mode: 0644]
list.h [new file with mode: 0644]
logging.c
logging.h
lsearch.c [deleted file]
match.c [new file with mode: 0644]
memrchr.c
mkstemp.c
parse.c
parse.h
parse.lex [deleted file]
parse.yacc [deleted file]
pathnames.h.in
pwutil.c [new file with mode: 0644]
redblack.c [new file with mode: 0644]
redblack.h [new file with mode: 0644]
sample.pam
sample.sudoers
sample.syslog.conf
schema.ActiveDirectory [new file with mode: 0644]
schema.OpenLDAP
schema.iPlanet
selinux.c
sesh.c
set_perms.c
sigaction.c
snprintf.c
strcasecmp.c
strerror.c
strlcat.c
strlcpy.c
sudo.c
sudo.cat
sudo.h
sudo.man.in
sudo.pod
sudo.psf [new file with mode: 0644]
sudo.tab.c [deleted file]
sudo.tab.h [deleted file]
sudo_edit.c
sudo_noexec.c
sudo_nss.c [new file with mode: 0644]
sudo_nss.h [new file with mode: 0644]
sudo_usage.h.in [new file with mode: 0644]
sudoers.cat
sudoers.ldap.cat [new file with mode: 0644]
sudoers.ldap.man.in [new file with mode: 0644]
sudoers.ldap.pod [new file with mode: 0644]
sudoers.man.in
sudoers.pod
sudoers2ldif
testsudoers.c
tgetpass.c
toke.c [new file with mode: 0644]
toke.l [new file with mode: 0644]
tsgetgrpw.c [new file with mode: 0644]
utimes.c
version.h
visudo.c
visudo.cat
visudo.man.in
visudo.pod
zero_bytes.c

diff --git a/BUGS b/BUGS
deleted file mode 100644 (file)
index 67b0797..0000000
--- a/BUGS
+++ /dev/null
@@ -1,25 +0,0 @@
-Known bugs in sudo version 1.6.9
-================================
-
-1) Sudo should have an option to log when removing "dangerous"
-   environment variables.
-
-2) On DUNIX in sia mode, hitting return at the prompt does not quit.
-
-3) In parse.lex, '@' should not need to be a special character.
-   However, because lex does greedy matching, {WORD} will match
-   instead of the "^Defaults[:@]?" line.
-
-4) In list mode (sudo -l), characters escaped with a backslash
-   are shown verbatim with the backslash.
-
-5) Because the parser only does a single pass it is possible to
-   make a sudoers file where the "defaults" options are set after
-   a user's entry has been validated, changing the permissions for
-   the user.  The work-around is to put all 'defaults' entries
-   before the "User privilege specification" section but after all
-   the "alias specifications".  In the future the parser will
-   converted to a two-pass parser.
-
-6) For the same reason as #5, changing the value of "ignore_dot" has
-   no effect (find_path() is called before sudoers is parsed).
diff --git a/CHANGES b/CHANGES
deleted file mode 100644 (file)
index 42c7862..0000000
--- a/CHANGES
+++ /dev/null
@@ -1,2112 +0,0 @@
-CHANGES since sudo 1.2
-
-01) sudo now works under hpux, aix, sunos, bsd43, ultrix, linux, osf and irix.
-
-02) Files w/o the executable bit will be ignored if they are in your PATH.
-
-03) If execv() fails, perror is called (which prints out an error based on
-       errno) and sudo exits with -1.
-
-04) Included in this shar should also be a version of getpass() derived from
-       the bsd net-2 source which works on bsd, ultrix, hpux, aix, and irix
-       at least.  The latter three unixes have what i consider to be a broken
-       getpass() in that if /dev/tty can't be opened it doesn't just use stdin
-       like bsd getpass().  This means you cannot do: rsh host "sudo command"
-       and have it work if your ticket has expired.
-
-05) The Makefile has changed significantly.  It now has defines for all
-       supported architectures.
-
-06) Changed MAXCOMMANDLENGTH from 48 bytes to MAXPATHLEN and included
-       sys/param.h where appropriate.
-
-07) Rewrote the code that expands links & paths.  It now works correctly.
-       (rewrote find_path.c)
-
-08) Added a define NEED_STRDUP so we don't conflict with the system's strdup(3)
-
-09) Now does *not* pass LD_* environmental vars on to programs that get
-       exec'd.  Also removes SHLIB_PATH for hpux and _RLD_* for dec osf.
-
-10) Now searches current dir last if '.' or '' are in PATH.  Misses braindeath
-    like './' but if that's in your path you deserve all the trojans you get.
-
-11) Added in linux patches from drew + flex support.
-
-12) Added insults back in from original sudo(8) (define USE_INSULTS).
-
-13) visudo now uses EDITOR envar (from John_Rouillard@dl5000.bc.edu)
-
-14) you can now specify a dir containing commands that a sudoer can do.
-    (from John_Rouillard@dl5000.bc.edu)
-
-15) Ported to Solaris 2.x (based on a port of sudo 1.1 done by UnixOps).
-
-16) Took out setuid(0); setruid(uid); pairs that bracketed calls to
-    update_timestamp() since they are unnecessary and setruid() is
-    broken on systems without a setreuid(2) or setresuid(2) system call.
-    (Ie: AIX and Solaris 2.x).
-
-17) The bulk of sudo now runs with the caller's real uid.  Grep for
-    be_root() to find the exceptions.
-
-CHANGES from sudo 1.3
-
-18) Added SECURE_PATH as suggested by russells@ccu1.auckland.ac.nz.
-
-19) Reworked clean_envp() to modify environ (not envp) so we can use
-    execvp() safely.
-
-20) Now use execvp() instead of execve() so sudo /bin/kill works under
-    broken solaris.  This also fixed sudo /etc/fastboot under stock
-    4.3 BSD.  Basically, this means that any executable shell script that
-    lacks a '#!/bin/sh' magic number will now work with sudo.  Personally
-    I think that the broken scripts should be fixed rather than changing
-    sudo, but vendors will be broken.  Sigh.
-
-21) Added USE_EXECV define so you can make sudo use execv() if you
-    want.  Using execvp() shouldn't be a problem since it is always
-    handed a non-relative path that begins with '/' but some people
-    may not trust execvp().
-
-22) Log file lines will no longer get truncated.  Syslog entries that
-    would overrun the syslog(3) line limit are continued on another entry.
-
-23) When logging to a log file, long entries are indented to improve
-    readability.
-
-24) Whenever the umask is changed, it is changed back to what it was
-    before.
-
-25) Log file is written as mode 600 instead of 644
-
-26) Umask that sudo runs with may now be specified.
-
-27) There is now a "configure" script.
-
-28) Sudo will use ultra fast crypt (ufc) if it finds it for systems w/o
-    a real crypt(3) (non-US ConvexOS/Secure for instance).
-
-29) _BSD_COMPAT is now defined for Irix.
-
-30) The global variable uid is now initialized to -2 because I'm paranoid.
-
-31) Native Solaris 2 port from Matthew.Stier@aisg.com
-
-32) Now use sysconf(2) instead of getdtablesize(2) if it is available
-    (see change #31).  Because of the the getdtablesize() emulation for
-    hpux is no longer necessary.
-
-33) Now only do a getcwd(3) or getwd(3) once and do it as the real user.
-    Sudo should no longer complain that it can't get the cwd unless
-    there is a real problem.
-
-34) Changed some malloc'd globals of fixed length to be allocated from
-    the stack instead as there was no win in allocating them from the
-    heap.
-
-35) Fixed AIX STATIC_FLAGS as per the AIX faq.
-
-36) Added -V flag to sudo and visudo (for version)
-
-37) Now treat EACCESS like EPERM when doing stat(2) in find_path.c
-
-38) Added prototypes for sudo functions (via __P macro)
-
-39) configure now uses uname(1) if it exists
-
-40) gethostbyname(3) is now only called if you define FQDN.  There's really
-    no reason to not trust gethostname(2) and this way if name service is
-    hosed sudo isn't...
-
-41) added -v (validate) flag to sudo to update a timestamp w/o running
-    a command
-
-42) now use tgetpass() (getpass with a timeout)
-
-43) find_path() now uses realpath(3)
-
-44) wrote versions of realpath(3) and getcwd(3) for those without
-
-45) wrote tgetpass()--a getpass() that times out via select(2)
-
-46) sudo now uses posix signals if available
-
-47) Finally added ConvexOS C2 security support from
-    "Peter A. Nikitser, Systems Software Support, QUT" <P.NIKITSER@qut.edu.au>
-
-48) You can now #undef MAILER if you don't run sendmail or the equivalent.
-
-49) AFS support from adamh@austin.ibm.com
-
-50) If you define BOTH_LOGS in sudo.h you can log both via syslog(3) *ans*
-    to a log file.
-
-51) Added ultrix /etc/auth (enhanced security) support.
-
-52) Sudo now will work with a 4.2BSD syslog (SunOS < 4 && ultrix).
-    Personally, I'd say you are better off logging to a file if
-    your syslog is this ancient.
-
-53) Changed realpath(3) to sudo_realpath() since we need to do the
-    chdir(2) with the invoking uid.  sudo_realpath() should be
-    faster than vendor-supplied realpath(3)'s anyway...
-
-54) No longer create a static binary on AIX since it reportedly
-    causes problem on newer versions on AIX 3.x.
-
-55) If sudo_realpath cannot chdir() back to cwd sudo will print
-    and error and exit.  Previously it would either fail silently
-    or print an incorrect error message.
-
-56) Moved code to send error mail to be after the log message.
-    From rouilj@cs.umb.edu.
-
-57) Added SUDO_USER and SUDO_UID envars.  Suggested by John P. Rouillard
-   (<rouilj@cs.umb.edu).
-
-58) Added -k and -h options and rearranged some of the code to be
-    more modular and less braindamaged.  This introduces the concept
-    of "run modes" to sudo.
-
-59) Fixed visudo and flex.  visudo now calls yyrestart() if you are using
-    flex instead of lex.  From bostley@cs.colorado.edu.
-
-60) Added a "cat page" for systems w/o nroff.
-
-61) Fixed a bug whereby only the last directory specified in a Cmnd_Alias
-    was checked.  Reported by "James R. Hendrick" <hendrick@ctron.com>.
-
-62) All .{c,lex,yacc} files now include both sys/types.h and unistd.h so
-    we are sure to get the typedef of uid_t.
-
-CHANGES from sudo 1.3.1
-
-63) Added preliminary support for DEC OSF/1 protected passwords
-    (shadow passwords).
-
-CHANGES from sudo 1.3.1pl1
-
-64) More support for DEC OSF/1 protected passwords (shadow passwords).
-
-CHANGES from sudo 1.3.1pl2
-
-65) Fixed mail logging to include the username as it should have.
-
-66) Added hostname to log message in error mail.
-
-67) Added -l flag to sudo to list the allowed/forbidden commands.
-    Suggested by matthew@gateway.bsis.com (Matthew Stier)
-
-68) Fixed bison warnings for parse.yacc and visudo.yacc.
-    Pointed out by alfie@dcs.warwick.ac.uk (Nick Holloway).
-
-CHANGES from sudo 1.3.1pl3
-
-69) Sudo will now exit with an error if the command to be run is > MAXPATHLEN.
-
-70) Test in configure for termios support was insufficient.  It thought
-    Nextstep 3.2 had termios just because it as termios.h (need to link
-    with -posix for termios on NeXT's)
-
-CHANGES from sudo 1.3.1pl4
-
-71) First stab at Skey support.
-
-72) Sudo now sets IFS to be SPACE, TAB, NEWLINE.
-
-73) Sudo now sets the real and effective gid to root's group
-    (based on passwd file).
-
-74) Sudo now checks that the sudoers file is owned by a certain user
-    and not readable or writable by anyone else.
-    (based on a suggestion by Joerg Schumacher <schuma@ips.cs.tu-bs.de>)
-
-75) Visudo now sets the owner on the new sudoers file based on #74
-
-76) Sudo and visudo will now compile with byacc (Berkeley yacc).
-
-77) If the rename(2) of stmp -> sudoers fails /bin/mv is executed before
-    bailing.  Based on code from Case Larsen <clarsen@mh1.lbl.gov>.
-
-78) User-level configuration is now done in options.h.
-
-79) Moved all compatibility #defines to compat.h
-
-80) Incorporated new parsing code from Chris Jepeway <jepeway@cs.utk.edu>.
-    This is much better than the previous parser.
-
-81) Rewrote visudo.c and tickled parse.yacc to work with it.  Visudo
-    now gives you options if a parse error occurs rather than blindly
-    dumping you back in the editor.
-
-82) Took out all references to realpath since we are now checking based
-    in inode and device (with Chris' new parser).  The upshot of this
-    is that path matches are done safely and the symlink problem has
-    gone away.
-
-83) Fixed bison warnings from new parse.yacc.
-
-84) Added a default case to parse.lex to error on unmatched tokens as Chris
-    suggested.
-
-85) Converted configure.in and acsite.m4 to autoconf 2.1.
-
-86) Added lsearch.c and search.h for os's w/o lsearch()/lfind().
-
-87) Sudo now checks to see that the file it is executing is a regular file
-    (was just checking the execute bit so dirs slipped through).
-    Pointed out by Barb Dijker <barb@labyrinth.com>.
-
-88) Fixed a problem on HP-UX trusted systems with getpwuid() returning "*"
-    unless the real uid is 0.  Reported by Brian Cunnie (cunnie@nyc.hp.com).
-
-89) configure now checks for size_t and ssize_t in unistd.h as well
-    as sys/types.h.
-
-90) configure now checks for egrep before actually using it.
-
-91) configure now checks for a working void implementation (ie: void * as
-    a generic pointer) and sets VOID to void or char accordingly.
-
-92) Added support for SunOS 4.x C2 security (shadow passwords) from
-    Kendall Libby (fubar@shore.net)
-
-93) Changed all occurrences of bzero() to memset() and bcopy() to
-    memmove().
-
-94) Fixed a bug in sudo.c.  If a user has no passwd entry sudo would
-    dump core (writing to a garbage pointer).  Pointed out by
-    Stephen Schaefer <sps@gateway.bsis.com>.
-
-95) Worked around a bug in AIX's lex in parse.c.  AIX lex doesn't seem
-    to handle {x,y} range notation correctly.  Bleah.
-
-96) Sudo would not report a failed attempt if the user entered return
-    at the 2nd password: prompt so someone trying to guess a password
-    could just invoked sudo multiple times and try one passwd at a time.
-    Reported by Jonathan Adams <jonathan@smada.com>.
-
-97) Added User_Alias facility.
-
-98) Rewrote most of the ip address / network support.  Now works on all
-    systems sudo has currently been tested on.
-
-99) Sudo now sets SUDO_COMMAND and SUDO_GID envariables in addition to
-    SUDO_USER and SUDO_UID.
-
-100) Added changes to configure.in for UnixWare.
-     (from John Warburton <jwarb@SACBH.com.au>)
-
-101) Merged in changes for Interactive Unix and RISCos.
-     (from Andy Smith <abs@maunsell.co.uk>)
-
-102) Added testsudoers (from Chris Jepeway <jepeway@cs.utk.edu>).
-
-103) Added fix for parse.yacc to avoid the kludge I was doing.
-     (from Chris Jepeway <jepeway@cs.utk.edu>)
-
-104) Now remove the IFS envar if set instead of setting it to a "safe"
-     value to avoid problems with make and others.
-
-105) Added FAST_MATCH option to check basenames of sudo command and
-     paths listed in sudoers file.  If the basename doesn't match
-     then it is not a match.  If the basename matches, then do
-     a stat to make sure it is a valid match.
-
-106) Now only stat(2) cmnd once in path_matches() (in parse.c).  Sudo
-     was stating cmnd for *every* attempted match.  Now the stat struct
-     is cached (ie: the var is a static).
-
-107) Signal handlers in visudo are now only installed after the stmp
-     file is opened.  Previously, it was possible to erase an open
-     stmp file by sending visudo a signal within a small window.
-
-108) Added Goon Show insults from  Russell Street <r.street@auckland.ac.nz>.
-
-109) Broke out the insults into separate include files (insults.h
-     is the master and includes the appropriate one).
-
-110) Now use getwd() instead of getcwd() and provide emulation for
-     OS's w/o it.  This was done since some OS's with getwd()
-     implement getcwd() via a pipe to pwd(1).  By emulating getwd()
-     by calling getcwd() on OS's w/o getwd() we lose nothing since
-     the compiler should optimize away the extra function call.
-
-111) Added crypt() for DEC OSF/1 3.x enhanced security.
-     From "Richard L Jackson Jr" <rjackson@osf1.gmu.edu>.
-
-112) Added an option to run the command in the background (-b) as
-     suggested by Jonathan Adams <jonathan@smada.com>
-
-113) First stab at kerberos support.  I'm not really sure it is
-     possible to do this in a sane manor.  Sigh.
-
-114) Better kerberos support.  Had to use setreuid(2) but falls
-     back on a kludge if that does not exist or is broken.
-
-115) Added -p (password prompt) support.
-     Suggested by "David W. Cooley" <dwcooley@COLBY.EDU>
-
-116) Added partial implementation of -l (list) flag.
-     This is probably as good as it will get until sudo:tng.
-
-117) Added anti-spoofing code to tighten up a race condition
-     where a user could run sudo some_link and then change
-     where the link pointed after the old link had been
-     validated but before the exec().
-
-118) Now update timestamp file via utime() (and emulate via utimes()
-     if necessary) to eliminate a small race.  Works with
-     both POSIX utime() as well as old utime() in BSD <= 4.3.
-
-119) Kerberos ticket file now lives in same dirs as sudo timestamp
-     files (to avoid trouncing on normal ticket file) and is removed
-     after validation.
-
-120) Now log tty user is on as well as pwd in sudo logs.
-
-CHANGES from sudo 1.3.2 BETA
-
-121) Fixed a bug in the anti-spoofing check.
-
-122) Fixed up ISC support so that it works and looks like non-streams
-     stuff in interfaces.c.
-
-123) Now deal correctly with ip implementations that has an sa_len
-     field in struct sockaddr.
-
-124) Check ownership and permissions on timestamp dir and ignore if
-     not owned by root and mode 0700.  Problem pointed out by Larry Auton
-     <lda@research.AT&T.com> and Navjot Singh <singh@research.AT&T.com>.
-
-125) Ignore timestamp files with preposterous dates to keep people from
-     faking out sudo on OS's that allow you to give away files to root.
-     Problem pointed out by Larry Auton <lda@research.AT&T.com> and
-     Navjot Singh <singh@research.AT&T.com>.
-
-126) A timeout of 0 will now cause a password to be entered every
-     time.  Based on a suggestion by Larry Auton <lda@research.AT&T.com>
-     and Navjot Singh <singh@research.AT&T.com>.
-
-CHANGES from sudo 1.3.3 BETA
-
-127) Cleaned up interfaces.c so that it is more readable.
-
-128) Added support for syslog()'s that don't guarantee delivery
-     of a message.  HP-UX is the only known offender.
-
-129) No longer use memmove() since memcpy() does what we need and
-     configure doesn't always catch memmove() even when it is
-     there (may be a library problem).
-
-130) Updated man page to reflect two more security issues.
-
-131) Cleaned up shadow password support in check.c.  It should now
-     be readable.
-
-132) Added SCO support.
-
-133) Added check to configure to find the max length of a uid_t
-     in characters.
-
-134) Removed uid2str() since we now know how big a uid_t/gid_t
-     can be.  This elminates a few malloc()'s.
-
-135) Added support for multiple insult types.  Based on code and
-     a suggestion from Dieter Dworkin Muller <dworkin@village.org>.
-
-136) Replaced clean_env() and rmenv() with a rewritten clean_env()
-     that should be a little faster.  This also makes it easier to
-     add to the list of "dangerous" envariables.
-
-137) Added netgroup support.  Netgroups must start with a leading
-     "+" to that sudo knows it is a netgroup.
-
-138) Split out sudoers file format into its own man page.
-     As suggested by Andy Smith <abs@maunsell.co.uk>.
-
-139) Updated testsudoers.c to grok netgroups.
-
-CHANGES from sudo 1.3.4 BETA
-
-140) Added SecurID support from Giles Todd <giles@gt.demon.co.uk>.
-
-141) Added -s flag to start a root shell and -- to signify end of args.
-
-142) Sped up logging routines by replacing strncpy()'s with strcat()'s.
-     This is safe because we dyanically allocate logline to be big enough.
-
-143) Now support command line arguments in the sudoers file.
-
-144) Sped up the loading on command line arguments.  This fixes the
-     "commands with large argc's take forever to run" bug.
-
-145) Expanded MAXCOMMANDLEN to 8K since we now have to deal with
-     command line arguments.  Added bounds checking in fill() and
-     append() so we don't drop core.
-     XXX - 8k makes sudo *SLOW*
-
-146) Added support in the lexer for "termination characters" to be
-     escaped.  Ie: you can now use [\,:=] in command line args
-     as long as you escape with a \.
-
-147) Testsudoers can now deal with commands that have arguments.
-
-148) If a file is not executable or not a regular file sudo will
-     now give the appropriate error message instead of just
-     "command not found" which is misleading.
-
-149) Fixed a bug where if FQDN is set, load_interfaces() was never
-     called.
-
-150) tty is now a global so it can be used in the ticket file
-     at a later date.
-
-151) Strings in the parser are now allocated dynamically.  This results
-     in a large speedup as compared to a 1K array on the stack. I
-     have freed the strings in the parser where appropriate but that
-     may not catch all instances.  Even so, the average sudo now
-     takes up less memory than the 1K array version.
-
-152) Fixed a bug in tgetpass() and configure that broke termio/termios
-     support for some OS's.
-
-153) Added cheapo implementation of tty-based timestamps.  The correct
-     way is to have username be a directory with the tty tickets
-     inside.  However, the current code does not take to that very
-     well, and it does not allow the two systems to coexist. Therefore,
-     instead of timestampdir/user/tty it is timestampdir/user.tty.
-
-154) Added support for building in other than the source directory.
-     Based on changes from "Simon J. Gerraty" <sjg@frodo.dn.itg.telecom.com.au>
-
-155) options.h and pathnames.h are now included via angle brackets
-     (<>) so as to use the -I include path.  This way, those using
-     a shadow build tree may have local copies of these headers
-     w/o clobbering the distribution ones.
-
-156) EXEMPTGROUP is now a string (group name) and user_is_exempt()
-     is now less of a hack.  It uses getgrnam(EXEMPTGROUP) to
-     get a list of users in the exempted group.
-
-157) --prefix and --exe_prefix are now honored in the Makefile.
-
-158) Sudo will now behave reasonably in the case where the sudoers
-     file location is mounted via NFS and the client does not
-     have "root" NFS privs.
-
-159) _PATH_SUDO_SUDOERS, _PATH_SUDO_STMP, and SUDOERS_OWNER are
-     now set via the Makefile since that appears to be what
-     most people expect...
-
-160) Now include a pre-generated version of parse.lex since so many
-     versions of lex are brain damaged.  If parse.lex is changed
-     a new lex.yy.c will be generated.  The distribution copy is
-     sudo-lex.yy.c.
-
-161) Upgraded to GNU autoconf version 1.5.  There are now even
-     *more* options.
-
-CHANGES from sudo 1.3.5 BETA
-
-162) Fixed S/Key support.
-
-163) Cleaned up shadow password support further by moving much of
-     it to getspwuid.c.
-
-164) First cut at DCE support. [needs work to be functional]
-
-165) New Digital UNIX C2 support based on code from
-     "Randy M. Hayman" <haymanr@icefog.sois.alaska.edu>
-
-166) S/key support now works with the generic bellcore s/key
-     as well as the s/key from Wietse Venema's logdaemon.
-     (Previously only worked with the logdaemon s/key).
-     As an added bonus the s/key challenge is now embedded
-     in the password prompt for a cleaner look.
-
-167) lsearch.c will now compile on a strict ANSI C compiler.
-     ANSI doesn't allow pointer arithmetic on a "void *"
-     but gcc does.
-
-168) Bought back latest HP-UX DCE support from Jeff Earickson
-     <jaearick@colby.edu>.
-
-169) configure now comletely groks $SUDO_LIBS and $VISUDO_LIBS.
-     Plain old $LIBS is no longer used.  LDFLAGS has also been
-     split up into $SUDO_LDFLAGS and $VISUDO_LDFLAGS.
-     The reason for this is that sudo often needs extra libs
-     for alternate authentication schemes but visudo rarely does.
-
-170) The code to copy command arguments flaied for large values of
-     argc due to realloc() lossage.  We now cheat and treat argv[]
-     as a flat string (since that's what it is) and use pointer
-     arithmetic to compute the length.  Kind of sneaky but it
-     works (and is relatively fast).
-
-CHANGES from sudo 1.3.6 BETA
-
-171) Added support for UN*X groups in sudoers based on code from
-     Dougal Scott <dwagon@aaii.oz.au>.
-
-172) interfaces.c should work on ISC UN*X again.
-
-173) All source files are <= 14 characters for old SYSV file systems.
-
-CHANGES from sudo 1.3.7 GAMMA
-
-174) Minor configure[.in] fixes.
-
-175) tgetpass.c now compiles on OS's that put the definition of
-     fd_set in <sys/bsdtypes.h>
-
-CHANGES from sudo 1.4
-
-176) Command args in sudoers are now stored in an argument vector
-     instead of a flat string to make wildcard matching simpler.
-
-177) Added NewArgv and NewArgc that describe the command to be
-     executed.  The copy of args in cmnd_args is no longer necessary
-     and has been removed.
-
-178) Using strcmp(3) for argument matching in command_matches()
-     (was path_matches()) is no longer sufficient since we don't
-     have a flat string.  compare_args() is used instead which
-     calls either strcmp(3) or wildmat(3l) depending on whether
-     there are shell-style meta chars (wildcards) present.
-
-179) Shell-style wildcard matches are now available in the sudoers
-     file.  Matches are done via Rich $alz's wildmat(3).
-     This required the tweaks described in #176-178 as well as
-     other, more minor, changes.
-
-180) Commented out rule to build lex.yy.c from parse.lex since
-     we ship with a pre-flex'd parser and can't rely on file
-     dates being set correctly.
-
-181) Fixed visudo and testsudoers to deal with new argument
-     vector handling.
-
-182) A null string ("") as shell in passwd file (or $SHELL) is
-     now treated as the bourne shell.
-
-183) Converted *.man to pod format for easy conversion to man,
-     html, latex, and just plain text.  Tried to make the
-     sudoers manual easier to read in the process.
-
-184) Updated sample.sudoers and sudoers.pod to include info
-     on wildcards.
-
-CHANGES from sudo 1.4.1
-
-185) compat.h now defines _PASSWD_LEN based on PASS_MAX if it
-     is defined (from limits.h on SYSV).
-
-186) Both short and long hostnames may now be used in the sudoers
-     file if FQDN is defined.  From patches submitted by
-     Michael Meskes <meskes@Informatik.RWTH-Aachen.DE>.
-
-187) Now use skeylookup() instead of skeychallenge().  Hopefully
-     this will work around a problem some people have reported
-     on Solaris 2.5 with sudo and logdaemon 5.0's skey.
-
-188) Now uses /var/run to hold timestamp files if it exists.  This
-     is more secure.
-
-189) configure now puts the timestamp dir in /var/run if it exists.
-     Sugestion by Michael Meskes <meskes@Informatik.RWTH-Aachen.DE>.
-
-190) Both short and long hostnames now exist even if FQDN is not set.
-     This allows machines with fully qualified hostnames set via
-     hostname(1) to use them in the sudoers file.
-
-191) sudo was not honoring "." in $PATH due to a bug in find_path().
-
-192) Added IGNORE_DOT_PATH option to ignore "." in $PATH.
-
-193) tgetpass() now uses raw read(2) and write(2) instead of stdio.
-     This should make it work on more OS's.  Previously, it used
-     stdio (buffered) fgets(3) and fputs(3) with select(2) which
-     may not be legal.  Also got rid of the nasty goto's and
-     generally simplified the code.
-
-194) Parser now supports hostnames like UPPERCASE.foo.com.  Previously,
-     `UPPERCASE' was interpreted as an Alias.  This means that
-     the `fqdn' stuff has been moved to the lexer (FQHOST is used
-     to avoid collision with FQDN option).
-
-195) Reworked --with-FOO in configure.in to support --without-FOO.
-     Made shadow passwords the default for appropriate OS's.  They
-     can be turned off with --without-C2.
-
-196) Added NO_PASSWD option for those who don't want to be bothered
-     by a password prompt from sudo.  This is really just a hack.
-
-197) Added support for double quotes to mean "treat these words as one
-     argument".  This is similar to what most shells do.
-
-198) Added mkinstalldirs to make install destination dirs if
-     they do not already exist.
-
-CHANGES from sudo 1.4.2
-
-199) Added support for --with-CC (which C compiler to use).
-
-200) Added support for NOPASSWD token and running commands a
-     specified users (sudo -u) from Keith Garry Boyce
-     <garp@opustel.com>
-
-201) Only link with -lshadow for Linux if libc lacks getspnam().  Problem
-     pointed out by Michael Meskes <meskes@Informatik.RWTH-Aachen.DE>.
-
-202) Replaced SUDOERS_OWNER with SUDOERS_UID and SUDOERS_GID.  Added
-     SUDOERS_MODE and changed the default to 0440 (from 0400).
-     It is now possible to NFS-mount sudoers without doing anything fancy.
-
-202) If a runas list is specified, a user may only run commands as
-     "root" if "root" is a member of the runas list.  The old behavior
-     was to always allow commands to be run as root, even if a runas
-     list was specified.  Now you can give someone "sudo -u operator"
-     and not have the equivalent of "sudo -u root" as well.
-
-203) Added "USER=%s" to logging functions.
-
-204) configure will now add -lPW to (VI)?SUDO_LIBS if using bison
-     or DCE and alloca(3) is not in libc (or provided by gcc) but
-     is in libPW.a.
-
-205) sudo would give an incorrect error message if the sudoers file
-     didn't exist due to close() stomping errno if the open() failed.
-
-206) Fixed "shell" mode (sudo -s).  When building NewArgv sudo was
-     not allocating space for the NULL.
-
-207) Added support for wildcards in the pathname.  Ie: /bin/*.
-
-208) 'command ""' in sudoers now means no args allowed.
-
-209) Added command line args to SUDO_COMMAND envariable.
-
-210) HP-UX 10.x with C2 now uses bigcrypt().
-     Changes from david_dill@Merck.Com (David Dill).
-
-211) lsearch.c will now compile w/o compiler warnings.
-     (Updated from NetBSD lsearch.c)
-
-212) Now uses POSIX fnmatch(3) (which uses ! instead of ^ in ranges)
-
-CHANGES from sudo 1.4.3
-
-213) Now allows network/netmask in sudoers to override per-interface
-     netmask.
-
-214) Fixed -u support with multiple user lists on a line.
-
-215) Fixed a core dump problem when built with -DSHELL_IF_NO_ARGS.
-
-216) Fixed 2 typos in parse.yacc and removed some unnecessary if's.
-
-217) Now always use install-sh since SunOS install can't do uid/gid's.
-     Other BSD installs are probably similarly afflicted.
-
-218) Fixed NFS-mounted sudoers file under solaris both uid *and* gid
-     were being set to -2.  Now set uid to 1 to avoid group being
-     remapped.
-
-219) Now includes alloca.c (from gcc) for those w/o it.  Linking
-     against -lPW breaks visudo on HP-UX and probably others.
-
-220) Added --with-libpath, --with-libraries, --with-incpath options
-     to configure.
-
-221) configure now uses shicc instead of gcc on BSD/OS >= 2.0 to
-     generate binaries linked with shared libs.
-
-222) The parser was setting no_passwd even if there wasn't a
-     runas match.  I reordered some things in parse.yacc
-     to fix this.
-
-223) `sudo -v' (validate) wasn't paying attention to NOPASSWD.
-     Now it does.
-
-224) testsudoers now groks "-u user".
-
-225) Updated AFS support based on what tcsh 6.06 does.
-
-226) Fixed a typo/thinko that broke BSD > 4.3reno wrt interfaces.c.
-
-227) HPUX 10.X shadow password stuff now uses SecureWare routines.
-
-228) SecureWare passwd checking now uses bigcrypt() if available.
-     Now uses AUTH_MAX_PASSWD_LENGTH if defined.
-
-229) configure now makes sure you don't have a config.cache file
-     from another OS.
-
-230) Added better shadow password detection.
-     BSD >= 4.3reno -> /etc/master.passwd
-     hpux9: getspwnam() -> /.secure/etc/passwd
-     hpux10: getspnam() or getprpwnam() -> /tcb/files/auth/*/* (link with -lsec)
-     SVR4: getspnam() -> /etc/shadow
-     solaris: getspnam() -> /etc/shadow
-     irix[56].x: getspnam() -> /etc/shadow
-     sunos 4.x: getpwanam() -> /etc/security/passwd.adjunct
-     DUNIX: getprpwnam() -> /tcb/files/auth/*/* (link with -lsecurity)
-     SecureWare: getprpwnam() -> /tcb/files/auth/*/*
-     ultrix 4.x: getauthuid() -> /etc/auth.{pag,dir}
-
-231) '(' in command args no longer are a syntax error.
-
-232) '!command' now works in the presence of a runas or NOPASSWD token.
-     Simplified parse rules wrt runas and NOPASSWD (more consistent).
-
-233) Command args and now compared as a flat string again.  This makes
-     wildcard matches more consistent.
-
-234) DUNIX C2 support now groks AUTH_CRYPT_OLDCRYPT and AUTH_CRYPT_C1CRYPT.
-
-235) configure now uses config.{sub,guess} to guess OS type.
-     Sudo should work out of the box on more OS's now.
-
-236) Got rid of HAVE_C2_SECURITY, now just use SHADOW_TYPE.
-
-237) Fixed race in tgetpass() where echo can be turned off and
-     left off if sudo is used in a pipeline and a password is
-     required.
-
-CHANGES from sudo 1.4.4
-
-238) `sudo -l' output now includes runas and NOPASSWD info and
-     asks for a password unless NOPASSWD for ALL is set.
-
-239) Sudo can now deal with all-caps user and host names.
-
-240) Sudo will now remove the "ENV" and "BASH_ENV" envariables.
-     From Michael Meskes <meskes@Informatik.RWTH-Aachen.DE>.
-
-241) `sudo -l' will now expand Cmnd_Alias's (could be prettier).
-
-242) `sudo -s' will now set $HOME to root's homedir (or that of
-     the user specified -u) so dot files get sourced.
-
-CHANGES from sudo 1.4.5
-
-243) $HOME was always being set, not just with `-s'.
-
-244) In visudo, the owner and group of the sudoers file were
-     being set too early; an editor could change them and change
-     the owner/group of the resulting sudoers file.
-
-CHANGES from sudo 1.5
-
-245) Added SHELL_SETS_HOME option.
-
-246) Added NO_MESSAGE option.
-
-247) Added %u and %h escapes in PASSPROMPT to expand to user's name
-     and host.
-
-248) Added "SUDO_PROMPT" envariable.
-
-249) Usernames may now begin with a digit.  Gross, but people do it.
-
-Sudo 1.5.1 released.
-
-250) Added `opie' support.
-
-251) Added check to make sure fnmatch() really works.
-
-252) Now use the prompt S/Key gives us instead of rolling our own.
-
-253) Added -H flag from Danny Barron <dcbarro@nppd.com>.
-
-254) Add SUDO_PS1 envariable support.
-
-255) Attempt at sequent support.
-
-Sudo 1.5.2 released.
-
-256) visudo acts sanely when there is no sudoers file.
-
-257) Added Runas_Alias support.
-
-258) Sudo will now work with SUDOERS_MODE == 400 and SUDO_UID = 0.
-
-259) Alias's in a runas list are now expanded.
-
-260) Fixed bug with > 32 saved aliases.  Reported by BHH@capgroup.com.
-
-261) Code that uses sprintf() is now more paranoid about buffer
-     overflows.
-
-262) Whitespace is now allowed after a line continuation character before
-     a newline in sudoers.
-
-263) %h in MAILSUBJECT expands to local hostname.
-
-Sudo 1.5.3 released.
-
-264) Don't pass getdtablesize() as first arg to select(2).  No need
-     to do this since we only select on one fd--use (fd+1) as nfds
-     and the old way caused problems on some systems (arguably
-     a bug in those OS's).  From Marc Slemko marcs@znep.com.
-
-265) Fixed coredump when passwd file is missing or unavailable.
-     Reported by Jason Downs <downsj@teeny.org> and
-     Klee Dienes <klee@mit.edu> (via a Debian Linux bug report).
-
-266) Fixed bug wrt exclusion lists and relative pathnames.
-     Reported by osiris@COURIER.CB.LUCENT.COM.
-
-267) exit(1) if user doesn't enter a passwd.
-     Noted by Alex Parchkov <alexp@ind.tansu.com.au>.
-
-Sudo 1.5.4 released.
-
-268) Newer versions of Irix use _RLDN32_* envariables for 32-bit binaries
-     so ignore _RLD* instead of _RLD_*.  From tarrall@bamboo.Colorado.EDU.
-
-269) Only open sudoers file once as opposed to once for sanity checks and
-     once for the parser.  Also try to open ten times if we get EAGAIN.
-
-Sudo 1.5.5 released.
-
-270) Initialize group vector if we are becoming a user other than root.
-     For root, it is often more useful to hang on to our existing group
-     vector.
-
-271) Fix usage of select(2) to deal correctly with a high-numbered fd.
-
-272) Fixed a bug where sudo sometime didn't give the user a chance to
-     enter a password at the prompt.
-
-273) Use a dynamically sized buffer when reading ether interfaces.
-
-274) Fixed configure problems with identification of HP-UX > 10.x and
-     with cc being identified as a cross compiler on some platforms.
-
-275) Fixed a problem with HP-UX 10.x and alloca.  Bison does not
-     include alloca.h on HP-UX 10.x even though it uses alloca()
-     (and thus needs the #define of alloca(x) to __builtin_alloca(x)).
-     To fix this we include alloca.h ourselves if using bison and not gcc.
-
-276) Included support for the AIX 4.x authenticate() function from
-     Matt Richards <v2matt@btv.ibm.com>.
-
-277) Fixed an off by one error in the parser.  Found by
-     Piete Brooks <Piete.Brooks@cl.cam.ac.uk>
-
-278) Change NewArgv size computation to work on UNICOS.
-     From Mike Kienenberger <mkienenb@arsc.edu>
-
-279) Added --with-logfile and --with-timedir configure options.
-
-280) Use getcwd(3), not getwd(3) to avoid possible buffer overflow.
-     Use BSD getcwd(3) if system lacks one or is SunOS 4.x.
-
-281) Fix 'fprintf' argument mismatches in 'visudo.c'.
-     From ariel@oz.engr.sgi.com (Ariel Faigon)
-
-282) Use waitpid or wait3 to reap children in logging.c.
-     Pointed out by Theo de Raadt <deraadt@theos.com>
-
-283) Sudo should prompt for a password before telling the user that
-     a command could not be found.  Noted by rhodie@NAC.NET.
-
-284) Fix OTP_ONLY for opie; "Deven T. Corzine" <deven@fuse.net>.
-
-285) Include pre-yacc'd parse.yacc as sudo.tab.[ch] since more and
-     more vendors are charging for yacc (bad vendor, no cookie).
-
-286) Use MAX*, not MAX*+1
-
-287) Add support for Hitachi SR2201, from b-edgington@hpcc.hitachi-eu.co.uk
-
-288) Added RUNAS_DEFAULT option to allow one to compile sudo with a
-     default runas user other than root.
-
-289) Add options to log the hostname in the file-based log and to not
-     do word wrap in file-based log.  From Theo Van Dinter <tvd@chrysalis.com>
-
-290) RedHat Linux pam support, from Gary Calvin <GCalvin@kenwoodusa.com>.
-     pam.sudo goes in /etc/pam.d/sudo on RedHat 5.0 and above.
-
-291) With sudo -s, set command the full path of the shell, not the basename.
-     Noted by Peter W. Osel <pwo@guug.de>
-
-Sudo 1.5.6 released.
-
-292) Pam auth now runs as root; necessary for shadow passwords.
-
-293) Shadow password support is now compiled in by default.  You can disable
-     it via --disable-shadow.
-
-294) We now remove a timestamp file with a bogus date when it is detected.
-     From Steve Fobes <sfobes@uswest.com>.
-
-295) In tgetpass(), restart select if it is interrupted.  This really fixes a
-     problem where a user sometimes is not given a change to enter a password.
-
-296) All options have moved from options.h -> configure.
-
-297) visudo is now installed in /usr/local/sbin where it belongs.
-
-298) Lots of configure changes.  Instead of checking for the existence
-     of -lsocket, -lnsl, or -linet, we instead check them for the
-     functions we need only if they are not already in libc.
-
-299) Added DUNIX SIA (Security Integration Architecture) support from
-     Spider Boardman <spider@Orb.Nashua.NH.US>.
-
-300) Added test for broken Digital UNIX 4.0 prot.h.
-
-301) Better support for C2 security on Digital UNIX.
-
-302) Hacked autoconf so that you have have single quotes in
-     --with-passprompt.
-
-303) For SecureWare-style shadow passwords use getprpwnam() instead
-     of getprpwuid() since getprpwuid is broken in HP-UX 10.20 at
-     least (it sleeps for 2 minutes if the shadow files don't exist).
-
-304) We can't really trust UID_MAX or MAXUID since they may only exist for
-     backwards compatibility; spider-both@Orb.Nashua.NH.US
-
-305) Make %groups work as RunAs specifiers; Ray Bellis <rpb@community.net.uk>.
-
-306) Set USER environment variable to target user.
-     Suggested by Ray Bellis <rpb@community.net.uk>.
-
-307) Go back to printing "command not found" unless --disable-path-info
-     specified.  Also, tell user when we ignore '.' in their path and it
-     would have been used but for --with-ignore-dot.
-
-308) When using tty tickets make it user:tty not user.tty as a username
-     could have a '.' in it.
-
-309) Define BSD_COMP for svr4 to get BSD ioctl defs.  Also, if we have
-     sys/sockio.h but SIOCGIFCONF is not defined by including sys/ioctl.h
-     include sys/sockio.h directly.
-
-310) Fixed a bug that could cause "sudo -l" to segfault or complain
-     about non-existent syntax errors.
-
-Sudo 1.5.7 released.
-
-311) Fixed square bracket quoting in configure and moved check for -lnsl
-     to be before -lsocket.
-
-312) In load_interfaces(), close sock after bwe are done with it.  Leak
-     noticed by Mike Kienenberger <mkienenb@arsc.edu>.
-
-313) Missing pieces from change #308; from Mike Kienenberger.
-
-314) Real Kerberos 5 support from Frank Cusack <fcusack@iconnet.net>.
-
-315) FWTK 'authsrv' support from Kevin Kadow <kadow@MSG.NET>.
-
-316) Fixed handling and documentation of -with-umask.
-
-317) If the check for socket() or inet_addr() fails, retry, this time
-     linking with both -lsocket and -lnsl for those systems that
-     have interlibrary dependencies.
-
-Sudo 1.5.8 released.
-
-318) Add dirfd() macro for systems without it.
-
-319) Better check for socket() in -lsocket -lnsl in configure.
-
-320) Minor configure fixes.
-
-Sudo 1.5.8p1 released.
-
-321) Fixed a bug wrt quoting characters in command args.
-
-322) Make --without-sendmail work.
-
-Sudo 1.5.8p2 released.
-
-323) Fixed a segv if HOST_IN_LOG defined and gethostbyname() fails.
-     Reported by Gero Treuner <gero@faveve.uni-stuttgart.de>.
-
-324) Fixed a parse bug wrt the ! operator and runas specs.  Noted by
-     David A Beck <BKD@payserv.telekurs.com>.
-
-325) Use new emalloc/erealloc/estrdup functions (catch errors and exit).
-
-326) New PAM code that should work on both Solaris and Linux.
-
-327) Make sudo's usage info better when mutually exclusive args are given
-     and don't rely on argument order to detect this.  From Nick Andrew.
-
-328) In visudo, shift return value of system() by 8 to get the real exit value.
-
-Sudo 1.5.9 released.
-
-329) The runas user and NOPASSWD tags are now persistent across entries
-     in a command list (ie: cmnd1,cmnd2,cmnd3).  A PASSWD tag has been
-     added to reverse NOPASSWD.  The runas user and *PASSWD tags can be
-     overridden on a per-command basis at which point they become the
-     new default for the rest of the list.
-
-330) It is now possible to use the '!' operator in a runas list as
-     well as in a Cmnd_Alias, Host_Alias and User_Alias.
-
-331) In estrdup(), do the malloc ourselves so we don't need to rely on the
-     system strdup(3) which may or may not exist.  There is now no need to
-     provide strdup() for those w/o it.
-
-332) You can now specify a host list instead of just a host or alias
-     in a privilege list.  Ie: user=host1,host2,ALIAS,!host3 /bin/ls
-
-333) Stash the "safe" path to the command instead of stashing the struct
-     stat.  Should be safer.
-
-334) Now set $LOGNAME in addition to $USER.
-
-335) No longer use stdio in tgetpass()
-
-336) Don't use _PASSWD_LEN or PASS_MAX as we can't rely on them corresponding
-     to anything real.  Instead, we just use a max password size of 256
-     everywhere.
-
-337) Block keyboard-generated signals during startup and restore signal
-     mask before exec'ing the program.  We don't want the user to be
-     able to simply kill us and avoid logging.
-
-338) Rewrote timestamp handling.  For the default case, a directory is used
-     instead of a file.  For the tty-based case, the timestamp is just a
-     file in that directory (eg. /var/run/sudo/username/tty).  You now only
-     get the lecture once, even in the tty case.  The goal here is to allow
-     the tty and non-tty schemes to coexist, though it is worth noting that
-     when you update a tty file, the mtime of the dir gets updated too.
-
-339) The meaning of -k has changed to mean "invalidate the timestamp".
-     There is a new -K option to really remove the timestamp file/dir.
-
-340) New modular authentication API.  This fixes the rat's nest of
-     #ifdefs that was the old auth code.
-
-341) New logging functions.  log_error() now takes a variable number of
-     args ala printf() and log_auth() reacts to the return value of validate().
-
-342) If a user is not in the sudoers file they are still asked for a password.
-     This keeps someone who finds a user logged in to a terminal from being
-     able to tell whether or not the user is allowed to use sudo.
-
-343) New PAM code again, this time it should be correct.
-
-344) tgetpass() now has a flag to specify whether or not to turn
-     off echo while reading the password.  Used by the new PAM and
-     fwtk code.
-
-345) Fixed shadow password dectection on SCO.
-
-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.
-
-352) Fixed crypt() check in libufc.
-
-353) It is now possible to put a list of users as the first thing in a
-     user specification.  I don't suggest this but it makes the grammar
-     more uniform.
-
-354) Visudo will now warn about what it thinks are undefined aliases.
-     Since it can't be 100% sure these are just warnings, not errors.
-
-355) Add a --without-passwd option to configure that turns off
-     passwd/shadow file authentication.  Only usable with an alternate
-     authentication scheme.
-
-356) Add a --disable-authentication option to configure that causes sudo
-     to not require authentication by default.  The PASSWD tag can be
-     used to require authentication for an entry.
-
-357) Add a --with-devel option to add -Wall and uncomment yacc/lex
-     generation in Makefile.
-
-358) Zero out plaintext password after use (should do encrypted as well).
-
-359) Added real dependencies in Makefile.
-
-360) Deprecated --with-otp-only in favor of --without-passwd.
-
-361) Add --with-mail-if-no-host to send mail if a user tries to run sudo on
-     a host for which he/she is not authorized.
-
-362) Most of sudo now runs as root instead of the invoking user to
-     minimize the possibility of user control via signals or tracing.
-
-363) Now Support CIDR-style netmasks (ie: 128.138.0.0/16).
-
-364) In "sudo -l" mode, the type of the stored (expanded) alias was not
-     stored with the contents.  This could lead to incorrect output
-     if the sudoers file had different alias types with the same name.
-     Normal parsing (ie: not in '-l' mode) is unaffected.
-
-365) Now include strcasecmp() for those without it.
-
-366) Most compile-time options are now changable at runtime via
-     the 'Defaults' specification in the sudoers file.
-
-367) Added a -L flag to printout all the possible 'Defaults' parameters.
-
-368) It is now possible to escape "special" characters in usernames, hostnames,
-     etc with a backslash.
-
-369) Sudo will now accept a hostname/username/netgroupname that contains
-     almost any character in it.  It seems many people want to use '.'
-     and other non-alphanumerics in usernames.
-
-370) Fixed the root_sudo option.  Sudo was always complaining that root
-     was not allowed to run sudo if the root_sudo flag was turned off.
-
-371) tgetpass() now uses a function to read up until the end of line.
-     Fixes problems in a pipeline when a program sets the tty mode
-     to be character at a time.
-
-372) sudo now turns off core dumps via setrlimit (probably paranoia).
-
-Sudo 1.6 released.
-
-373) Better diagnostics on PAM failure.
-
-374) Killed shell_noargs option, it cannot work since the command needs to
-     be set before sudoers is parsed.
-
-375) Fixed the following Defaults options: set_home, fqdn, syslog, tty_tickets,
-     ticket_dir, insults.
-
-376) When using select() in tgetpass(), do a separate select before
-     each read to be sure we can timeout correctly.
-
-377) SecurID support compiles and works again.
-
-378) Fixed a bug parsing runas modifiers.  If a user spec contained multiple
-     runas specs, the latter ones may not be applied.
-
-379) #uid now works in a RunasAlias
-
-380) Don't ask the user for a password if the user is not allowed to run
-     the command and the authenticate flag (in sudoers) is false.
-
-381) Added configure check for initgroups(3).
-
-382) Use our own fnmatch() if there is no fnmatch.h, even if there is an
-     fnmatch() in libc.
-
-Sudo 1.6.1 released.
-
-383) Better behavior for -l and -v flags in conjunction with NOPASSWD and
-     added "verifypw" and "listpw" options.
-
-384) For HP-UX with cc, add the -Aa flag along with -D_HPUX_SOURCE.
-
-385) Fix compilation with K&R compilers.
-
-386) For netgroup host matching, match against the short version of the
-     hostname as well as the long one if they are different.
-
-387) Terminate passwd reading on '\r' in addition to '\n'
-
-388) Visudo used to loop endlessly if a user entered ^D at the whatnow
-     prompt.  EOF is now treaded as 'x' (exit w/o saving changes).
-
-389) The 'shell_noargs' runtime option is back based on a patch from
-     bguillory@email.com.
-
-390) Systems that return RLIM_INFINITY for RLIMIT_NOFILE (like AIX)
-     would loop for a very loing time during sudo startup.  A value of
-     RLIM_INFINITY is now ignored (getdtablesize/sysconf is used instead).
-
-391) Locking in visudo was broken.  We now lock the sudoers file, not the
-     sudoers temp file, which should be safe.
-
-392) PAM fixups: custom prompts now work correctly and errors are
-     dealt with more sanely.  Patches from Cloyce D. Spradling.
-
-Sudo 1.6.2 released.
-
-393) Users in the 'exempt' group shouldn't get their $PATH overridden
-     by 'secure-path'.  Patch from jmknoble@pobox.com.
-
-394) Pam now works on HP-UX 11.0, thanks to Jeff A. Earickson.
-
-395) Fixed a bug that caused an infinite loop when the password
-     timeout was disabled.
-
-396) It is now possible to set the path to the editor for visudo as well
-     as the flag that determines whether or not visudo will look at
-     $EDITOR in the sudoers file.
-
-397) configure now pulls in the values of LIBS, LDFLAGS, CPPFLAGS, etc
-     as the documentation says it ought to.
-
-398) Added rootpw, runaspw, and targetpw to prompt for the root, runas_default
-     and target user's passwords respectively (instead of the invoking user's
-     password).
-
-399) Added -S flag to force password read from stdin.
-
-400) Restore coredumpsize resource limit before exec'ing the child
-     process (sudo sets it to 0 internally).
-
-401) Truncate unencrypted password to 8 chars if encrypted password is exactly
-     13 characters (indicateing standard a DES password).  Many versions
-     of crypt() do this for you, but not all (like HP-UX's).
-
-402) Fixed a typo/thinko that broke secureware support for long passwords.
-
-403) Added a new command line switch '-c' to support BSD login classes.
-     The '-c' option can be used to sudo a command with specific resource
-     limits in the login.conf database.  This feature is optionally enabled
-     via the --with-logincap configure switch.  Based on a patch from
-     Michael D. Marchionna.
-
-404) Fixed a bug where sudo would hang around and consume CPU if we spawn
-     a long-running process.
-
-405) Deal with HP-UX password aging info tacked on to the end of the
-     encrypted password.
-
-406) Added set_logname run-time option.  When unset, sudo will not set
-     the USER and LOGNAME environment variables.
-
-407) Wildcards are now allowed in the hostnames specified in sudoers.
-     The 'fqdn' option is often required for this to be useful.
-
-408) Fixed a bug where host and user qualifiers in a Defaults entry were
-     not being used correctly and the entry was being applied globally.
-
-Sudo 1.6.3 released.
-
-409) Fixed targetpw, rootpw, and runaspw options when used with non-passwd
-     authentication (pam, etc).
-
-Sudo 1.6.3p1 released.
-
-410) When the targetpw flag is set, use the target username as part
-     of the timestamp path.
-
-Sudo 1.6.3p2 released.
-
-411) Fixed a bug that prevented the -H option from being useful.
-
-Sudo 1.6.3p3 released.
-
-412) Fixed a case where a string was used after it had been freed.
-
-Sudo 1.6.3p4 released.
-
-413) Fixed listpw and verifypw sudoers options.
-
-414) Do not write NUL when writing passwd prompt; hag@linnaean.org.
-
-Sudo 1.6.3p5 released.
-
-415) Fix word splitting bug that caused a segv for very long command line args.
-
-Sudo 1.6.3p6 released.
-
-416) Fix negation of path-type Defaults entries in a boolean context.
-
-Sudo 1.6.3p7 released.
-
-417) Visudo now checks for the existence of an editor and gives a sensible
-     error if it does not exist.
-
-418) The path to the editor for visudo is now a colon-separated list of
-     allowable editors.  If the user has $EDITOR set and it matches
-     one of the allowed editors that editor will be used.  If not,
-     the first editor that actually exists is used.
-
-419) Visudo now does its own fork/exec instead of calling system(3).
-
-420) Allow special characters (including '#') to be embedded in pathnames
-     if quoted by a '\\'.  The quoted chars will be dealt with by fnmatch().
-     Unfortunately, 'sudo -l' still prints the '\\'.
-
-421) Added the always_set_home option.
-
-422) Strip NLSPATH and PATH_LOCALE out from the environment to prevent
-     reading of protected files by a less privileged user.
-
-423) Added support for BSD authentication and associated -a flag.
-
-424) Added check for _innetgr(3) since NCR systems have this instead
-     of innetgr(3).
-
-425) Added stay_setuid option for systems that have libraries that perform
-     extra paranoia checks in system libraries for setuid programs.
-
-426) Environment munging is now done by hand.  The environment is zeroed
-     upon sudo startup and a new environment is built before the command
-     is executed.  This means we don't rely on getenv(3), putenv(3),
-     or setenv(3).
-
-427) Added a class of environment variables that are only cleared if they
-     contain '/' or '%' characters.
-
-428) Use stashed user_gid when checking against exempt gid since sudo
-     sets its gid to SUDOERS_GID, making getgid() return that, not the
-     real gid.  Fixes problem with setting exempt group == SUDOERS_GID.
-     Fix from Paul Kranenburg.
-
-429) Fixed file locking in visudo on NeXT which has a broken lockf().
-     Patch from twetzel@gwdg.de.
-
-430) Regenerated configure script with autoconf-2.52 (required some
-     tweaking of configure.in and friends).
-
-431) Added mail_badpass option to send mail when the user does not
-     authenticate successfully.
-
-432) Added env_reset Defaults option to reset the environment to
-     a clean slate.  Also implemented env_keep Defaults option
-     to specify variables to be preserved when resetting the
-     environment.
-
-433) Added env_check and env_delete Defaults options to allow the admin
-     to modify the built-in list of environment variables to remove.
-
-434) If timestamp_timeout < 0 then the timestamp never expires.  This
-     allows users to manage their own timestamps and create or delete
-     them via 'sudo -v' and 'sudo -k' respectively.
-
-435) Authentication routines that use sudo's tgetpass() now accept
-     ^C or ^Z at the password prompt and sudo will act appropriately.
-
-436) Added a check-only mode to visudo to check an existing sudoers
-     file for sanity.
-
-437) Visudo can now edit an alternate sudoers file.
-
-438) If sudo is configured with S/Key support and the system has
-     skeyaccess(3) use that to determine whether or not to allow
-     a normal Unix password or just S/Key.
-
-439) Fixed CIDR handling in sudoers.
-
-440) Fixed a segv if the local hostname is not resolvable and
-     the 'fqdn' option is set.
-
-441) "listpw=never" was not having an effect for users who did not
-     appear in sudoers--now it does.
-
-442) The --without-sendmail option now works on systems with
-     a /usr/include/paths.h file that defines _PATH_SENDMAIL.
-
-443) Removed the "secure_path" Defaults option as it does not work and
-     cannot work until the parser is overhauled.
-
-444) Added new -P flag and "preserve_groups" sudoers option to cause
-     sudo to preserve the group vector instead of setting it to that
-     of the target user.  Previously, if the target user was root
-     the group vector was not changed.  Now it is always changed unless
-     the -P flag or "preserve_groups" option was given.
-
-445) If find_path() fails as root, try again as the invoking user (useful
-     for NFS).  Idea from Chip Capelik.
-
-446) Use setpwent()/endpwent() and its shadow equivalents to be sure
-     the passwd/shadow file gets closed.
-
-447) Use getifaddrs(3) to get the list of network interfaces if it is
-     available.
-
-448) Dump list of local IP addresses and environment variables to clear
-     when 'sudo -V' is run as root.
-
-449) Reorganized the lexer a bit and added more states.  Sudo now does a
-     better job of parsing command arguments in the sudoers file.
-
-450) Wrap each call to syslog() with openlog()/closelog() since some
-     things (such as PAM) may call closelog(3) behind sudo's back.
-
-451) The LOGNAME and USER environment variables are now set if the user
-     specified a target uid and that uid exists in the password database.
-
-452) configure will no longer add the -g flag to CFLAGS by default.
-
-453) Now call pam_setcreds() to setup creds for the target user when
-     PAM is in use.  On Linux this often sets resource limits.
-
-454) If "make install" is run by non-root and the destination dir
-     is writable, install things normally but don't set owner and mode.
-
-455) The Makefile now supports installing in a shadow hierarchy
-     specified via the DESTDIR variable.
-
-456) config.h.in is now generated by autoheader.
-
-Sudo 1.6.4 released.
-
-457) Move the call to rebuild_env() until after MODE_RESET_HOME is set.
-     Otherwise, the set_home option has no effect.
-
-458) Fix use of freed memory when the "fqdn" flag is set.  This was
-     introduced by the fix for the "segv when gethostbynam() fails" bug.
-
-459) Add 'continue' statements to optimize the switch statement.
-     From Solar Designer.
-
-Sudo 1.6.4p1 released.
-
-460) Some special characters were not being escaped properly (e.g. '\,')
-     in command line arguments and would cause a syntax error instead.
-
-461) "sudo -l" would not work if the always_set_home option was set.
-
-462) Added a configure option to disable use of POSIX saved IDs for
-     operating systems where these are broken.
-
-463) The SHELL environment variable was preserved from the user's environment
-     instead of being reset based on the passwd database even when the
-     "env_reset" option was set.
-
-Sudo 1.6.4p2 released.
-
-464) Added a configure option to cause mail sent by sudo to be run as
-     the invoking user instead of root.  Some people consider this to
-     be safer.
-
-465) If the mailer is being run as root, use a hard-coded environment
-     that is not influenced in any way by the invoking user's environment.
-
-466) Fixed the call to skeyaccess().  Patch from Phillip E. Lobbes.
-
-Sudo 1.6.5 released.
-
-467) Visudo could access memory that was already freed.
-
-468) If the skey.access file denied use of plaintext passwords sudo
-     would exit instead of allowing the user to enter an S/Key.
-
-Sudo 1.6.5p1 released.
-
-469) Older versions of BSDi have getifaddrs() but no freeifaddrs().
-
-470) BSDi has a fake setreuid() as do certain versions of FreeBSD and NetBSD.
-
-471) Ignore the return value of pam_setcred().  In Linux-PAM 0.75,
-     pam_setcred() will return PAM_PERM_DENIED even if the setcred function
-     of the module succeeds when pam_authenticate() has not been called.
-
-472) Avoid giving PAM a NULL password response, use the empty string instead.
-     This avoids a log warning when the user hits ^C at the password prompt
-     when Linux-PAM is in use.  This also prevents older versions of
-     Linux-PAM from dereferencing the NULL pointer.
-
-473) The user's password was not zeroed after use when AIX authentication,
-     BSD authentication, FWTK or PAM was in use.
-
-Sudo 1.6.5p2 released.
-
-474) Fixed compilation problem on HP-UX 9.x.
-
-475) Moved call to endpwent() and added a call to endgrent().
-
-476) Fixed a warning conflicting declaration of VOID with AFS.
-
-477) Fixed a security hole in prompt rewriting found by Global InterSec.
-
-Sudo 1.6.6 released.
-
-478) Wildcards now work correctly in the env_keep Defaults directive.
-
-479) Added support for non-root timestamp dirs.  This allows the timestamp
-     dir to be shared via NFS (though this is not recommended).
-
-480) Removed double printing of bad environment variable table in -V mode.
-
-481) configure script has been regenerated with autoconf 2.5.7.
-     This required some changes to configure.in.
-
-482) Fixed a compilation problem on SunOS; thanks to Alek O. Komarnitsky.
-
-483) SecurID 5.0 API support from Michael Stroucken.
-
-484) Restore state of signal handlers to what we had upon startup.
-     Fixes a problem when using sudo with nohup; thanks to Paul Markham.
-
-485) Revamp set_perms() to use setresuid() or setreuid() when available
-     in preference to POSIX stuff since they allow us to properly
-     implement "stay_setuid" whereas POSIX does not really.
-
-486) In strict mode sudo did not throw an error for undefined User_Aliases.
-
-487) Fixed a Makefile bug on IRIX.
-
-488) Write the prompt *after* turning off echo to avoid some password
-     characters being echoed on heavily-loaded machines with fast typists.
-
-489) Added %U and %H escapes in the prompt and fixed treatment of %%.
-
-490) Visudo will now add a final newline to sudoers if the user's editor
-     not add one before EOF.
-
-491) The lexer state is now reset to its initial value on EOF. 
-     Previously, the state was not reset between parser invocations
-     which could cause problems for visudo in rare cases.
-
-492) Added support for Defaults that apply based on the RunasUser.
-
-493) Sudo now includes copies of strlc{at,py} and uses them throughout.
-
-494) Sudo is now careful to avoid interger overflow when allocating
-     memory.  This is one of those "should not happen" situations.
-
-495) Added a configure option (--with-stow) to make sudo compatible
-     with GNU stow.
-
-496) auth/kerb5.c now compiles under Heimdal.
-
-497) The volatile prefix is used in the hopes of preventing compilers
-     from optimizing away memory zeroing.  Unfortunately, this results
-     in some warnings from gcc.
-
-498) Better Kerberos IV/V support in the configure script.
-
-499) Fixed a logic thinko in the SIGCHLD handler that caused problems
-     with rlogin on HP-UX.
-
-500) configure now adds -R to LDFLAGS when it adds -L for Solaris and
-     SVR4.  There is a configure option, --with-rpath, to control this.
-
-501) On AIX, configure will pass extra directory paths to the linker
-     via the -blibpath ld option.  This is only active when additional
-     library paths are used.  It may be disabled via the
-     --without-blibpath configure option.
-
-502) The --with-skey and --with-opie configure options now take
-     an optional directory argument that should have an include and
-     lib dir for the skey/opie include file and library respectively.
-
-Sudo 1.6.7 released.
-
-503) Fixed false positives in the overflow detection of expand_prompt().
-
-Sudo 1.6.7p1 released.
-
-504) An unterminated comment broke Kerberos V authentication.
-
-505) The krb5-config script is used to determine Kerberos V CPPFLAGS
-     and LDFLAGS/LIBS if it exists.
-
-506) Backed out changes to mkinstalldirs from autoconf 2.57 that
-     caused problems on Tru64 Unix.
-
-Sudo 1.6.7p2 released.
-
-507) Kerberos V support should work on latest MIT Kerberos V and Heimdal.
-
-Sudo 1.6.7p3 released.
-
-508) Fixed remaining Kerberos V issues with MIT Kerberos V and old Heimdal.
-
-Sudo 1.6.7p4 released.
-
-509) Fixed a typo that caused a compilation error on Heimdal.
-
-510) Darwin (MacOS X) doesn't have a real setreuid() system call.
-
-511) Fixed a problem with large numbers of environment variables.
-
-Sudo 1.6.7p5 released.
-
-512) Fixed a problem on FreeBSD when the user is only listed in NIS (not
-     master.passwd) and netgroups are used in the master.passwd file.
-
-513) BSD-style warn/err functions are now used throughout.
-
-514) Fixed the --with-stow configure option
-
-515) Added a "sudo_lecture" option that points to a file containing a custom
-     lecture.
-
-516) The username in a log entry is no longer truncated at 8 characters.
-
-517) A new tag, NOEXEC, will prevent a dynamically-linked program being run
-     by sudo from executing another program (think shell escapes).
-     Because this uses LD_PRELOAD it has no effect on static binaries.
-     Idea from Reznic Valery.
-
-518) TIS fwtk authentication now supports fwtk 2.0 and higher.
-
-519) Sudo will now try to stat the command to be run as the user
-     specified by the -u flag if the stat fails as root.  Fixes
-     an NFS issue.
-
-520) Added Stan Lee / Uncle Ben quote to the lecture (from RedHat).
-
-521) Added a -i option to simulate an initial login similar to "su -".
-     Originally based on a patch from David J. MacKenzie.
-
-522) Added a -e option to edit files the with uid of the invoking user.
-     This prevents the user from editing other files or running commands
-     as the target user.  If sudo is run as "sudoedit" the -e flag is implied.
-
-523) If sudo is used to run as root shell, further sudo commands will
-     be logged as run by the user specified by the SUDO_USER environment
-     variable.  In -e mode (sudoedit), SUDO_USER is used to determine
-     what user to run the editor when the real uid is 0.
-
-524) Merged in LDAP support from Aaron Spangler.
-
-525) Added the --with-pc-insults configure to replace politically
-     incorrect insults with ones from Alek O. Komarnitsky.
-
-526) Added start_tls support from Gudleik Rasch <gudleik@rastamatra.org>.
-
-527) A uid specified in sudoers now matches the user specified by the
-     -u flag even if the -u flag specified a name, not a uid.
-
-528) /tmp/.odus is no longer used for timestamps by default.  One of
-     /var/run/sudo, /var/adm/sudo or /usr/adm/sudo is used depending
-     on what directories exist.
-
-529) Quoting globbing characters with a backslash now works as documented.
-
-530) A negated user/uid in a runas list was not treated the same as a
-     negated command (it did not override a previously allowed entry).
-     Now it does.
-
-531) Added support for Tandem NSK and other systems w/o seteuid().
-
-532) The timeout on password reading is now done via alarm(), not select().
-
-533) Fixed several issues when closing all open descriptors.  Sudo now uses
-     closefrom() if it exists, using /proc/$$/fd if possible.
-
-534) Use PATH_MAX, not MAXPATHLEN since the former is standardized.
-
-535) Added a check in visudo for runas_default being used before it
-     was set.
-
-536) If the target user == invoking user a password is no longer required.
-
-537) PAM support now uses Use pam_acct_mgmt() to check for disabled accounts
-    (from Brian Farrell).
-
-538) The sudoers file is now parsed as the runas user in all cases instead
-     of root.  This fixes some issues with running NFS-mounted commands.
-
-539) Sudo now produces a sensible error message when the targetpw
-     Defaults option is set and a non-existent uid is specified via -u.
-
-Sudo 1.6.8 released.
-
-540) Now find the command base and fill in struct stat earlier.
-
-541) sudoedit now re-opens the temp file as the invoking user.
-
-542) struct timespec is used throughout the code base.
-
-543) Added --with-ldap-conf-file option to override /etc/ldap.conf
-
-544) Added SSL tls_* certificate checking options when using LDAP.
-
-545) Sudoedit will now only attempt to edit regular files or links.
-
-546) Sudo now uses futime() or futimes() where possible.
-
-547) Updated sample.pam to a current version.
-
-548) Better detection of unchanged files in sudoedit.
-
-Sudo 1.6.8p1 released.
-
-549) Bash exported functions are now stripped from the environment passed
-     to the program to be executed.
-
-Sudo 1.6.8p2 released.
-
-550) The CDPATH variable is now stripped from the environment passed
-     to the program to be executed.
-
-551) Fix temp file generation on systems where the _PATH_VARTMP macro
-     lacks a trailing slash.
-
-Sudo 1.6.8p3 released.
-
-552) The KRB5CCNAME environment variable is preserved during sudo
-     execution for password lookups that use GSSAPI.
-
-Sudo 1.6.8p4 released.
-
-553) Added a configure check for systems with a 2-argument version of
-     timespecsub (like BSD/OS).
-
-554) Added stub struct defintions to sudo.h to quiet compiler warnings
-     on some systems.
-
-555) In sudoers Defaults lines, tuples like "lecture" may now be used
-     without a value, restoring their old boolean-like nature.
-
-556) Invalid values for a tuple are now handled correctly.
-
-Sudo 1.6.8p5 released.
-
-557) Added a set of missing braces needed for MacOS X / Darwin.
-
-558) Define LDAP_OPT_SUCCESS for those without it.
-
-Sudo 1.6.8p6 released.
-
-559) Warn if the user tries to use the -u option when not running a command.
-
-560) Better PAM error handling and messages.
-
-561) Fixed setting of $USER when env_reset is enabled.
-
-Sudo 1.6.8p7 released.
-
-562) Fixed noexec functionality on Linux.
-
-563) Fixed minor format string mismatches in some error cases.
-
-564) Fixed a bug that prevented Heimdal authentication from working.
-
-Sudo 1.6.8p8 released.
-
-565) Updated config.guess and config.sub entries for OpenBSD.
-
-566) A sudoers entry with sudo ALL no longer overwrites the value of
-     safe_cmnd.
-
-Sudo 1.6.8p9 released.
-
-567) Added PS4 and SHELLOPTS to the list of variables to remove from
-     the environment.
-
-Sudo 1.6.8p10 released.
-
-567) Added JAVA_TOOL_OPTIONS to the list of variables to remove from
-     the environment.
-
-Sudo 1.6.8p11 released.
-
-567) Added PERLLIB, PERL5LIB and PERL5OPT to the list of variables to
-     remove from the environment.
-
-Sudo 1.6.8p12 released.
-
-568) Fixed a file descriptor leak when the lecture file option is enabled.
-
-569) Added to the list of variables to remove from the environment.
-
-570) Fixed a Kerberos V security issue that could allow a
-     user to authenticate using a fake KDC.
-
-571) Pulled in updated configure and libtool from sudo 1.7.
-
-572) PAM is now the default on systems where it is supported.
-
-573) Removed POSIX saved uid use; the stay_setuid option now
-     requires the setreuid() or setresuid() functions to work.
-
-574) Regenerated configure with up to date autoconf and libtool.
-
-575) Fixed fd leak when lecture file option is enabled.
-
-576) Removed used of POSIX saved uids.  The stay_setuid
-     option now requires setreuid() or setresuid().
-
-577) PAM fixes.  If the user enters ^C at the password prompt,
-     abort instead of trying to authenticate with an empty password
-     (which causes an annoying delay).  Also Call pam_open_session()
-     and pam_close_session() to give pam_limits a chance to run.
-
-578) Security fix for Kerberos5.  If we cannot get a valid service
-     key using the default keytab it is a fatal error.  Now uses
-     krb5_verify_user() and krb5_init_secure_context() if they
-     are available.
-
-579) Fixed securid5 authentication.
-
-580) Added fcntl F_CLOSEM support to closefrom().
-
-581) Added NOEXEC support for AIX 5.3.
-
-582) Sudo now uses the supplemental group vector for matching.
-     This fixes problems with split group lines in /etc/group
-     as well as multiple group sources in nsswitch.conf.
-
-583) Added more environment variables to remove by default.
-
-584) Mail from sudo now includes an Auto-Submitted: auto-generated
-     header ala rfc 3834.
-
-585) Reworked the environment handling code.
-
-586) Remove the --with-execv option, it was not useful.
-
-587) Use TCSADRAIN instead of TCSAFLUSH in tgetpass() since
-     some OSes have issues with TCSAFLUSH.
-
-588) Use glob(3) instead of fnmatch(3) for matching pathnames
-     and stat() each result that matches the basename of the user's
-     command.  This makes "cd /usr/bin ; sudo ./blah" work when
-     sudoers allows /usr/bin/blah.
-
-589) Reworked the syslog long line splitting code based on changes
-     from Eygene Ryabinkin.
-
-590) Sudo can now with deal more than 32 network interfaces on
-     Solaris.
-
-591) Visudo will now honor command line arguments in the EDITOR or
-     VISUAL environment variables if env_editor is enabled.
-
-592) LDAP now honors rootbinddn, timelimit and bind_timelimit in
-     /etc/ldap.conf.
-
-593) For LDAP, do a sub tree search instead of a base search (one
-     level in the tree only) for sudo right objects.  This allows
-     system administrators to categorize the rights in a tree to
-     make them easier to manage.
-
-594) The env_reset option is now enabled by default.  Commands run
-     through sudo now receive a minimal environment with certain
-     variables passed through and/or checked.  The list of variables
-     allowed is configurable via the env_keep and env_check options
-     in sudoers.
-
-595) Added support for Solaris 10 resource control limits using
-     the "project" interface.
-
-596) Moved LDAP schema data into separate files.
-
-597) Sudo no longer assumes that gr_mem in struct group is non-NULL.
-
-598) Added support for setting environment variables on the command
-     line if the command has the SETENV attribute set in sudoers.
-
-599) Added a -E flag to preserve the environment if the SETENV attribute
-     has been set.
-
-600) The sudoers2ldif script now parses Runas users.
-
-601) The -- flag now behaves as documented.
-
-602) sudo -k/-K no longer cares if the timestamp is in the future.
-
-603) When searching for the command, sudo now uses the effective gid
-     of the runas user.
-
-604) Sudo no longer updates the timestamp if not validated by sudoers.
-
-605) Now rebuild environment regardless of how sudo was invoked.
-
-606) More accurate usage() when called as sudoedit.
-
-607) Command line environment variables are now treated like
-     normal environment variables unless the SETENV tag is set.
-     
-608) Better explanation of environment handling in the sudo man page.
-
-Sudo 1.6.9 released.
-
-609) Worked around a bug ins some PAM implementations that caused a crash
-     when no tty was present.
-
-610) Fixed a crash on some platforms in the error logging function.
-
-611) Documentation improvements.
-
-Sudo 1.6.9p1 released.
-
-612) Fixed updating of the saved environment when the environ pointer
-     gets changed out from underneath us.
-
-Sudo 1.6.9p2 released.
-
-613) Fixed a bug related to supplemental group matching introduced
-     in 1.6.9.
-
-Sudo 1.6.9p3 released.
-
-614) Added IPv6 support from YOSHIFUJI Hideaki.
-
-615) Fixed sudo_noexec installation path.
-
-616) Fixed a K&R compilation error.
-
-Sudo 1.6.9p4 released.
-
-617) Fixed a bug in the IP address matching introduced by the IPV6 merge.
-
-618) For "visudo -f file" we now use the permissions of the original file
-     and not the hard-coded sudoers owner/group/mode.  This makes
-     it possible to use visudo with a revision control system.
-
-619) Fixed sudoedit when used on a non-existent file.
-
-620) Regenerated configure using autoconf 2.6.1 and libtool 1.5.24.
-
-621) Groups and netgroups are now valid in an LDAP sudoRunas statement.
-
-Sudo 1.6.9p5 released.
-
-622) Worked around bugs in the session support of some PAM implementations.
-     The full tty path is now passed to PAM as well.
-
-623) Sudo now only prints the password prompt if the process is in the
-     foreground.
-
-624) inttypes.h is now included when appropriate if it is present.
-
-625) Simplified alias allocation in the parser.
-
-Sudo 1.6.9p6 released.
-
-626) Go back to using TCSAFLUSH instead of TCSADRAIN when turning
-     off echo in tgetpass().
-
-627) Fixed addition of -lutil for logincap on FreeBSD and NetBSD.
-
-628) Add configure check for struct in6_addr since some systems define
-     AF_INET6 but have no real IPv6 support.
-
-Sudo 1.6.9p7 released.
-
-629) Fixed a bug where a sudoers entry with no runas user specified
-     was treated differently from a line with the default runas
-     user specified.
-
-Sudo 1.6.9p8 released.
-
-630) The ALL command in sudoers now implies SETENV permissions.
-
-631) The command search is now performed using the target user's
-     auxiliary group vector too.
-
-632) When determining if the PAM prompt is the default "Password: ",
-     compare the localized version if possible.
-
-633) Added passprompt_override flag to sudoers to cause sudo's prompt
-     to be used in all cases.  Also set when the -p flag is used.
-
-Sudo 1.6.9p9 released.
-
-634) Moved LDAP options into a table for simplified parsing/setting.
-
-635) Fixed a problem with how some LDAP options were being applied.
-
-636) Added support for connecting directly to LDAP servers via SSL
-     in addition to the existing start_tls support.
-
-Sudo 1.6.9p10 released.
-
-637) Fixed a compilation problem on SCO related to how they
-     store the high resolution timestamps in struct stat.
-
-638) Avoid checking the passwd file group multiple times
-     in the LDAP query when the user's passwd group is also
-     listed in the supplemental group vector.
-
-639) The URI specifier can now be used in ldap.conf even when
-     the LDAP SDK doesn't support ldap_initialize().
-
-640) New %p prompt escape that expands to the user whose password
-     is being prompted, as specified by the rootpw, targetpw and
-     runaspw sudoers flags.  Based on a diff from Patrick Schoenfeld.
-
-Sudo 1.6.9p11 released.
-
-641) Added a configure check for the ber_set_option() function.
-
-642) Fixed a compilation problem with the HP-UX K&R C compiler.
-
-643) Revamped the Kerberos 5 ticket verification code.
-
-644) Added support for the checkpeer ldap.conf variable for
-     netscape-based LDAP SDKs.
-
-645) Fixed a problem where an incomplete password could be echoed
-     to the screen if there was a read timeout.
-
-Sudo 1.6.9p12 released.
-
-646) Sudo will now set the nproc resource limit to unlimited on Linux
-     systems to work around Linux's setuid() resource limit semantics.
-     On PAM systems the resource limits will be reset by pam_limits.so
-     before the command is executed.
-
-647) SELinux support that can be used to implement role based access
-     control (RBAC).  A role and (optional) type may be specified
-     in sudoers or on the command line.  These are then used in the
-     security context that the command is run as.
-
-648) Fixed a Kerberos 5 compilation problem with MIT Kerberos.
-
-Sudo 1.6.9p13 released.
-
-649) Fixed an invalid assumption in the PAM conversation function
-     introduced in version 1.6.9p9.  The conversation function may
-     be called for non-password reading purposes as well.
-
-650) Fixed freeing an uninitialized pointer in -l mode, introduced in
-     version 1.6.9p13.
-
-651) Check /etc/sudoers after LDAP even if the user was found in LDAP.
-     This allows Defaults options in /etc/sudoers to take effect.
-
-652) Add missing checks for enforcing mode in SELinux RBAC mode.
-
-Sudo 1.6.9p14 released.
-
-653) Fixed installation of sudo_noexec.so on AIX.
-
-654) Updated libtool to version 1.5.26.
-
-655) Fixed printing of default SELinux role and type in -V mode.
-
-656) The HOME environment variable is once again preserved by default,
-     as per the documentation.
-
-Sudo 1.6.9p15 released.
-
-657) There was a missing space before the ldap libraries in the Makefile
-     for some configurations.
-
-658) LDAPS_PORT may not be defined on older Solaris LDAP SDKs.
-
-659) If the LDAP server could not be contacted and the user was not present
-     in sudoers, a syntax error in sudoers was incorrectly reported.
-
-Sudo 1.6.9p16 released.
-
-660) The -i flag should imply resetting the environment, as it did in
-     sudo version prior to 1.6.9.  Also, the -i and -E flags are
-     mutually exclusive.
-
-661) Fixed the configure test for dirfd() under Linux.
-
-662) Fixed test for whether -lintl is required to link.
-
-663) Changed how sudo handles the child process when sending mail.
-     This fixes a problem on Linux with the mail_always option.
-
-664) Fixed a problem with line continuation characters inside of
-     quoted strings.
-
-Sudo 1.6.9p17 released.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..63023fc
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,19639 @@
+2008-12-14 17:40  millert
+
+       * TODO: sync
+
+2008-12-09 18:48  millert
+
+       * auth/pam.c: Return PAM_AUTH_ERR instead of PAM_CONV_ERR if user
+         enters ^C at the password prompt.
+
+2008-12-09 16:13  millert
+
+       * configure.in, configure: Don't try to build sudo_noexec.so on
+         HP-UX with the bundled compiler as it cannot generate shared
+         objects.
+
+2008-12-09 15:55  millert
+
+       * glob.c, lbuf.c, tgetpass.c, emul/charclass.h: K&R compilation
+         fixes
+
+2008-12-09 08:49  millert
+
+       * parse.c: Use tq_foreach_fwd when checking pseudo-commands to make
+         it clear that we are not short-circuiting on last match.  When
+         pwcheck is 'all', initialize nopass to TRUE and override it with
+         the first non-TRUE entry.
+
+2008-12-08 10:02  millert
+
+       * parse.c: Do not short circuit pseudo commands when we get a match
+         since, depending on the settings, we may need to examine all
+         commands for tags.
+
+2008-12-03 15:58  millert
+
+       * sudoers.cat, sudoers.man.in: regen
+
+2008-12-03 15:57  millert
+
+       * sudoers.pod: hostnames may also contain wildcards
+
+2008-12-03 15:40  millert
+
+       * Makefile.in: remove stamp-* files and linux core files in clean
+         target
+
+2008-12-02 12:30  millert
+
+       * config.h.in, configure, configure.in, auth/sudo_auth.h: Use
+         HAVE_SIA_SES_INIT instead of HAVE_SIA for Digital UNIX
+
+2008-11-26 15:10  millert
+
+       * configure, configure.in: correctly enable SIA on Digital UNIX
+
+2008-11-25 20:06  millert
+
+       * TODO: checkpoint
+
+2008-11-25 20:05  millert
+
+       * ChangeLog: sync
+
+2008-11-25 12:01  millert
+
+       * check.c, sudo.h, tgetpass.c: Even if neither stdin nor stdout are
+         ttys we may still have /dev/tty available to us.
+
+2008-11-24 10:09  millert
+
+       * sudoers.cat, sudoers.man.in: regen
+
+2008-11-24 10:08  millert
+
+       * sudoers.pod: fix typos; Markus Lude
+
+2008-11-24 07:08  millert
+
+       * ChangeLog: sync
+
+2008-11-23 19:42  millert
+
+       * toke.c: regen
+
+2008-11-23 19:41  millert
+
+       * toke.l: Fix matching of a line that only consists of a comment
+         char
+
+2008-11-22 13:17  millert
+
+       * auth/pam.c: MacOS pam will retry conversation function if it
+         fails so just treat ^C as an empty password.
+
+2008-11-22 10:12  millert
+
+       * visudo.c: When checking for alias use, also check defaults
+         bindings.
+
+2008-11-22 10:01  millert
+
+       * redblack.c: unused var
+
+2008-11-22 09:42  millert
+
+       * redblack.c: Replace my rbdelete with Emin's version (which
+         actually works ;-)
+
+2008-11-19 12:01  millert
+
+       * testsudoers.c: malloc debugging
+
+2008-11-19 07:37  millert
+
+       * visudo.c: malloc options in devel mode for visudo too
+
+2008-11-18 10:57  millert
+
+       * sudo.c: fix compilation on non-C99; from Theo
+
+2008-11-18 10:50  millert
+
+       * visudo.c: fix check_aliases
+
+2008-11-18 08:29  millert
+
+       * alias.c: when destroying an alias, free the correct data pointer
+
+2008-11-18 07:54  millert
+
+       * auth/sudo_auth.h: add proto for aixauth_cleanup; from Dale King
+
+2008-11-15 13:34  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in, visudo.cat,
+         visudo.man.in: regen
+
+2008-11-15 13:34  millert
+
+       * sudo.pod, sudoers.pod, visudo.pod: standardize on the term
+         'option' for command line options (not flag)
+
+2008-11-14 06:18  millert
+
+       * INSTALL: Add note on configuring HP-UX pam
+
+2008-11-11 13:28  millert
+
+       * check.c, sudo.c: Move tty checks into check_user() so we only do
+         them if we actually need a password.
+
+2008-11-11 12:34  millert
+
+       * sudo.c: Don't error out if no tty or askpass unless we actually
+         need to authenticate.
+
+2008-11-10 15:20  millert
+
+       * ChangeLog: regen
+
+2008-11-10 08:07  millert
+
+       * pathnames.h.in, sudo.c: s/overriden/overridden/; from Tobias
+         Stoeckmann
+
+2008-11-09 15:18  millert
+
+       * visudo.c, WHATSNEW: check sudoers owner and mode in strict mode
+
+2008-11-09 09:15  millert
+
+       * gram.c, toke.c: regen
+
+2008-11-09 09:13  millert
+
+       * alias.c, alloc.c, closefrom.c, compat.h, defaults.c, defaults.h,
+         env.c, fileops.c, gettime.c, gram.y, ins_csops.h, insults.h,
+         interfaces.c, interfaces.h, lbuf.c, license.pod, list.c,
+         logging.c, logging.h, parse.c, parse.h, pwutil.c, redblack.c,
+         redblack.h, snprintf.c, sudo.c, sudo.pod, sudo_edit.c,
+         sudo_nss.h, testsudoers.c, toke.l, tsgetgrpw.c, utimes.c,
+         version.h, visudo.c, zero_bytes.c, LICENSE, sudoers.pod,
+         visudo.pod, auth/afs.c, auth/aix_auth.c, auth/bsdauth.c,
+         auth/fwtk.c, auth/kerb4.c, auth/kerb5.c, auth/pam.c,
+         auth/securid.c, auth/securid5.c, auth/sia.c, auth/sudo_auth.h,
+         sudo.man.in, sudoers.man.in, visudo.man.in: Update copyright
+         years.
+
+2008-11-09 08:48  millert
+
+       * fnmatch.c, glob.c, emul/charclass.h: add my copyright
+
+2008-11-08 10:40  millert
+
+       * toke.c, toke.l: The loop in fill_cmnd() was going one byte too
+         far past the end, resulting in a NUL being written immediately
+         after the buffer end.
+
+2008-11-08 10:31  millert
+
+       * UPGRADE, WHATSNEW: add sections on tgetpass changes
+
+2008-11-08 10:30  millert
+
+       * tgetpass.c: Treat EOF w/o newline as an error.
+
+2008-11-07 17:42  millert
+
+       * parse.c: Fix "sudo -v" when NOPASSWD is set.
+
+2008-11-07 12:45  millert
+
+       * auth/: bsdauth.c, fwtk.c, pam.c, sudo_auth.c, sudo_auth.h: No
+         longer treat an empty password at the prompt as special.  To quit
+         out of sudo you now need to hit ^C at the password prompt.
+
+2008-11-06 21:07  millert
+
+       * sudoers.cat, sudoers.man.in: regen
+
+2008-11-06 21:06  millert
+
+       * def_data.c, def_data.h, def_data.in, sudo.c, sudoers.pod: Sudo
+         will now refuse to run if no tty is present unless the new
+         visiblepw sudoers flag is set.
+
+2008-11-05 19:42  millert
+
+       * aix.c: just use RLIM_INFINITY for RLIM_SAVED_MAX if
+         RLIM_SAVED_MAX not defined
+
+2008-11-05 19:40  millert
+
+       * aix.c: fix fallback value for RLIM_SAVED_MAX
+
+2008-11-05 19:14  millert
+
+       * auth/: aix_auth.c, sudo_auth.h: Move clearing of AUTHSTATE into
+         aixauth_cleanup.
+
+2008-11-05 19:08  millert
+
+       * env.c, auth/aix_auth.c: Unset AUTHSTATE after calling
+         authenticate() as it may not be correct for the user we are
+         running the command as.
+
+2008-11-05 19:05  millert
+
+       * isblank.c: Add isblank() function for systems without it.  Needed
+         for POSIX character class matching in fnmatch.c and glob.c.
+
+2008-11-05 11:02  millert
+
+       * TROUBLESHOOTING: expound on sudo and cd
+
+2008-11-04 15:52  millert
+
+       * ChangeLog: regen
+
+2008-11-04 15:46  millert
+
+       * sudoers.cat, sudoers.man.in: regen
+
+2008-11-04 15:45  millert
+
+       * sudoers.pod: mention defauts parse order
+
+2008-11-03 13:19  millert
+
+       * Makefile.in, aclocal.m4, compat.h, configure: Add isblank()
+         function for systems without it.  Needed for POSIX character
+         class matching in fnmatch.c and glob.c.
+
+2008-11-03 12:54  millert
+
+       * Makefile.in: add emul/charclass.h to HDRS
+
+2008-11-02 14:08  millert
+
+       * TODO: checkpoint
+
+2008-11-02 14:06  millert
+
+       * parse.c, defaults.c, testsudoers.c, visudo.c: Move
+         update_defaults into defaults.c and call it properly from visudo
+         and testsudoers.
+
+2008-11-02 09:51  millert
+
+       * defaults.c, interfaces.c, pwutil.c, sudo.c, sudo_edit.c,
+         tgetpass.c, tsgetgrpw.c: use zero_bytes() instead of memset() for
+         consistency
+
+2008-11-02 09:45  millert
+
+       * logging.c, mon_systrace.c, parse.c, sudo.c, sudo_edit.c,
+         tgetpass.c, visudo.c: Zero out sigaction_t before use in case it
+         has non-standard entries.
+
+2008-11-02 09:35  millert
+
+       * match.c: quiet gcc
+
+2008-11-02 09:28  millert
+
+       * match.c: Short circuit glob() checks if basename(pattern) !=
+         basename(command).  Refactor code that checks for a command in a
+         directory and use it in the glob case if the resolved pattern
+         ends in a '/'.
+
+2008-11-01 09:20  millert
+
+       * defaults.h, parse.c, sudo.c, testsudoers.c, visudo.c: Defer
+         setting runas defaults until after runaspw/gr is setup.
+
+2008-10-29 13:26  millert
+
+       * match.c, sudo.c, testsudoers.c: Use MAXHOSTNAMELEN+1 when
+         allocating host/domain name since some systems do not include
+         space for the NUL in the size.  Also manually NUL-terminate
+         buffer from gethostname() since POSIX is wishy-washy on this.
+
+2008-10-26 17:13  millert
+
+       * sudo.c, sudoers.pod: When setting the umask, use the union of the
+         user's umask and the default value set in sudoers so that we
+         never lower the user's umask when running a command.
+
+2008-10-26 16:43  millert
+
+       * sudo.c: Don't try to read from a zero-length sudoers file.
+         Remove the bogus Solaris work-around for EAGAIN.  Since we now
+         use fgetc() it should not be a problem.
+
+2008-10-25 09:22  millert
+
+       * parse.c: In update_defaults() check the return value of
+         user*_matches against ALLOW so we don't inadvertantly match on
+         UNSPEC.
+
+2008-10-24 09:52  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.ldap.cat,
+         sudoers.ldap.man.in, sudoers.man.in, visudo.cat, visudo.man.in:
+         regen man pages; no more hyphenation
+
+2008-10-24 09:49  millert
+
+       * sudo.c: Don't error out on a zero-length sudoers file.  With the
+         advent of #include the user could create a situation where sudo
+         is unusable.
+
+2008-10-23 12:06  millert
+
+       * config.h.in, configure, configure.in, auth/kerb5.c: Newer heimdal
+         has 2-argument krb5_get_init_creds_opt_free() like MIT krb5.
+         Really old heimdal has no krb5_get_init_creds_opt_alloc() at all.
+         Add configure tests to handle all the cases.
+
+2008-10-08 17:28  millert
+
+       * sudo.pod: resort ENVIRONMENT
+
+2008-10-08 17:09  millert
+
+       * sudoers.pod: document sudoers_locale
+
+2008-10-08 16:56  millert
+
+       * sudo.pod, sudo_edit.c: add SUDO_EDITOR variable that sudoedit
+         uses in preference to VISUAL or EDITOR
+
+2008-10-08 14:27  millert
+
+       * toke.c, toke.l: In fill_cmnd(), collapse any escaped
+         sudo-specific characters.  Allows character classes to be used in
+         pathnames.
+
+2008-10-03 16:02  millert
+
+       * lbuf.c: fix typo in non-C89 function declaration
+
+2008-10-03 15:56  millert
+
+       * sudoers.pod: Mention POSIX characters classes now that out
+         fnmatch() and glob() support them.
+
+2008-10-03 15:55  millert
+
+       * sample.sudoers, sudoers.pod: Replace [A-z] (which won't match in
+         UTF8) with [A-Za-z] which is locale agnostic.
+
+2008-10-03 10:02  millert
+
+       * parse.h: use __signed char if we are going to assign a negative
+         value since on Power, char is unsigned by default
+
+2008-10-03 09:59  millert
+
+       * configure, configure.in, config.h.in: Add tests for __signed char
+         and signed char.
+
+2008-10-03 09:19  millert
+
+       * aix.c: Fix AIX limit setting.  getuserattr() returns values in
+         disk blocks rather than bytes.  The default hard stack size in
+         newer AIX is RLIM_SAVED_MAX.  From Dale King.
+
+2008-09-26 17:13  millert
+
+       * fnmatch.c, glob.c, emul/charclass.h: Add character class support
+         to included glob(3) and fnmatch(3).
+
+2008-09-16 08:28  millert
+
+       * emul/fnmatch.h: Remove UCB advertising clause and some
+         compatibility defines.
+
+2008-09-14 16:07  millert
+
+       * sudo_edit.c: Check EDITOR/VISUAL to make sure sudoedit is not
+         re-invoking itself or sudo.  This allows one to set EDITOR to
+         sudoedit without getting into an infinite loop of sudoedit
+         running itself until the path gets too big.
+
+2008-09-13 20:45  millert
+
+       * def_data.c, def_data.h, def_data.in, defaults.c, sudo.c: Add
+         sudoers_locale Defaults option to override the default sudoers
+         locale of "C".
+
+2008-09-13 14:09  millert
+
+       * sudo.c: Set locale to system default except for during sudoers
+         parse.
+
+2008-09-12 09:34  millert
+
+       * match.c: Redo change in 1.34 to use pointer arithmetic.
+
+2008-09-11 07:06  millert
+
+       * match.c: Fix a dereference (read) of a freed pointer.  Reported
+         by Patrick Williams.
+
+2008-08-23 19:09  millert
+
+       * sudo.c: Set locale to "C" to avoid interpretation issues with
+         character ranges in sudoers.  May want to make the locale a
+         sudoers option in the future.
+
+2008-08-20 07:45  millert
+
+       * config.h.in: we no longer use setproctitle
+
+2008-08-20 07:41  millert
+
+       * sudo.h: remove #if 1
+
+2008-08-20 07:40  millert
+
+       * LICENSE, mkstemp.c: Use my replacement mkstemp() from the mktemp
+         package.
+
+2008-07-12 08:53  millert
+
+       * gram.c: regen with yacc skeleton bug fixed
+
+2008-07-12 08:48  millert
+
+       * sudoers.pod: Remove duplicate "as root".  From Martin Toft.
+
+2008-07-02 06:27  millert
+
+       * pwutil.c, sudo.c, testsudoers.c, sudo.h: Flesh out the fake
+         passwd entry used for running commands as a uid not listed in the
+         passwd database.  Fixes an issue with some PAM modules.
+
+2008-07-01 07:57  millert
+
+       * sudo.c: Error out in -i mode if the user has no shell.  This can
+         happen when running commands as a uid with no password entry.
+
+2008-06-26 07:49  millert
+
+       * toke.c, toke.l: Better fix for line continuation inside double
+         quotes.  Now accepts whitespace between the backslash and the
+         newline like the main lexer.
+
+2008-06-25 14:31  millert
+
+       * toke.c, toke.l: Fix line continuation in strings.  It was only
+         being honored if preceded by whitespace.
+
+2008-06-22 16:19  millert
+
+       * config.h.in, configure, configure.in, logging.c: Replace the
+         double fork with a fork + daemonize.
+
+2008-06-21 14:59  millert
+
+       * env.c, sudo.c: The -i flag should imply env_reset.  This got
+         broken in sudo 1.6.9.
+
+2008-06-20 20:34  millert
+
+       * logging.c, sudo.c, sudo_edit.c, visudo.c: Change how the mailer
+         is waited for.  Instead of having a SIGCHLD handler, use the
+         double fork trick to orphan the child that opens the pipe to
+         sendmail.  Fixes a problem running su on some Linux distros.
+
+2008-06-20 17:16  millert
+
+       * configure, configure.in: Fix configure test for dirfd() on Linux
+         where DIR is opaque.
+
+2008-06-17 17:42  millert
+
+       * tgetpass.c: Get rid of the QNX TCSAFLUSH -> TCSADRAIN hack.  If
+         QNX still has this problem we'll need to revisit this again.
+
+2008-06-10 21:13  millert
+
+       * logging.c: Ignore SIGPIPE instead of blocking it when piping to
+         the mailer.  If we only block the signal it may be delivered
+         later when we unblock.  Also, there is no need to block SIGCHLD
+         since we no longer do the double fork.  The normal SIGCHLD
+         handler is sufficient.
+
+2008-06-08 17:37  millert
+
+       * configure, configure.in: Add description for NO_PAM_SESSION, from
+         a redhat patch.
+
+2008-06-06 09:36  millert
+
+       * sudo.cat, sudo.man.in, sudo.pod: Fix typos in -i usage
+
+2008-05-18 13:54  millert
+
+       * configure, configure.in: Redo the test for dgettext() in a way
+         that hopefully will work around the libintl_dgettext() undefined
+         problem.
+
+2008-05-11 09:21  millert
+
+       * schema.ActiveDirectory: change filename in comment
+
+2008-05-10 09:18  millert
+
+       * Makefile.in, README.LDAP, sudoers.ldap.cat, sudoers.ldap.man.in,
+         sudoers.ldap.pod: Reference schema.ActiveDirectory
+
+2008-05-09 14:49  millert
+
+       * schema.OpenLDAP, schema.iPlanet: Mark sudoRunAs as deprecated.
+
+2008-05-09 14:48  millert
+
+       * schema.ActiveDirectory: add sudoRunAsUser and sudoRunAsGroup
+
+2008-05-09 14:01  millert
+
+       * schema.ActiveDirectory: Active Directory schema by Chantal
+         Paradis and Eric Paquet
+
+2008-05-08 17:54  millert
+
+       * parse.c: remove an XXX that was fixed
+
+2008-05-08 12:53  millert
+
+       * ChangeLog: sync
+
+2008-05-08 12:49  millert
+
+       * parse.c: Initialize tags to UNSPEC instead of def_* in "sudo -l"
+         mode.  This fixes a problem where the tag value printed was
+         influenced by defaults set in the first pass through the parser.
+
+2008-05-03 21:29  millert
+
+       * Makefile.in, sudo.psf: No point in packaging the TODO file
+
+2008-05-03 21:24  millert
+
+       * ChangeLog: sync
+
+2008-05-02 20:53  millert
+
+       * WHATSNEW, def_data.c, def_data.h, def_data.in, env.c, sudo.c,
+         sudo.h, sudoers.cat, sudoers.man.in, sudoers.pod: Add env_file
+         Defaults option that is similar to /etc/environment on some
+         systems.
+
+2008-05-02 16:38  millert
+
+       * Makefile.in, README, TODO, WHATSNEW, sudo.cat, sudo.man.in,
+         sudoers.cat, sudoers.ldap.cat, sudoers.ldap.man.in,
+         sudoers.man.in, version.h, visudo.cat, visudo.man.in: change
+         version to 1.7.0
+
+2008-05-02 16:37  millert
+
+       * UPGRADE: initial valgrind pass done
+
+2008-04-23 08:30  millert
+
+       * ldap.c: Fix typo/think in sudo_ldap_read_secret() when storing
+         the secret.
+
+2008-04-11 10:03  millert
+
+       * ldap.c: define LDAPS_PORT if the system headers do not
+
+2008-04-10 14:54  millert
+
+       * gram.c, gram.y: Fix another memory leak in init_parser().
+
+2008-04-10 12:51  millert
+
+       * configure, configure.in: There was a missing space before the
+         ldap libs in SUDO_LIBS for some configurations.
+
+2008-04-10 11:28  millert
+
+       * alias.c, gram.c, gram.y, toke.c, toke.l: Clean up some memory
+         leaks pointed out by valgrind.
+
+2008-04-07 14:39  millert
+
+       * sudo.c: fix "sudo -s" broken by mode/flags breakout
+
+2008-04-07 14:26  millert
+
+       * configure, configure.in: remove duplicate check for dgettext
+
+2008-04-05 15:54  millert
+
+       * aix.c: Fall back to default stanza if no user-specific limit is
+         found.
+
+2008-04-02 15:56  millert
+
+       * snprintf.c: include stdint.h if present
+
+2008-04-02 15:28  millert
+
+       * snprintf.c: Use LLONG_MAX, not the old QUAD_MAX
+
+2008-04-01 19:18  millert
+
+       * sudoers.ldap.pod: fix cut and pasto
+
+2008-03-31 11:24  millert
+
+       * pwutil.c: Add #ifdef PURITY
+
+2008-03-30 17:36  millert
+
+       * auth/bsdauth.c: remove useless cast
+
+2008-03-27 19:07  millert
+
+       * ChangeLog: sync
+
+2008-03-27 19:04  millert
+
+       * TODO: sync
+
+2008-03-27 19:01  millert
+
+       * sudo.h: Split MODE_* defines into primary and flags.
+
+2008-03-26 13:11  millert
+
+       * aix.c: It turns out the logic for getting AIX limits is more
+         convoluted than I realized and differs depending on whether the
+         soft and/or hard limits are defined.
+
+2008-03-23 10:18  millert
+
+       * Makefile.in, configure, configure.in: Back out AIX-specific
+         change to set the sudo_noexec path to the .a file, we do really
+         want to use the .so file.  Since libtool doesn't do that
+         correctly, just install the .so file ourselves in the Makefile.
+
+2008-03-23 10:12  millert
+
+       * install-sh: If the file given to install is a path, only use the
+         basename of the file when building the destination path.
+
+2008-03-18 16:08  millert
+
+       * sudo.c: parse_args() cleanup: Sort command line options in the
+         getopt() switch The -U option requires a parameter Normalize a
+         few ISSET calls Split mode into mode and flags and retire the
+         now-obsolete excl variable
+
+2008-03-18 16:04  millert
+
+       * WHATSNEW, check.c, sudo.c, sudo.cat, sudo.h, sudo.man.in,
+         sudo.pod, sudo_usage.h.in: Add -n (non-interactive) flag.
+
+2008-03-18 15:59  millert
+
+       * sudo.c: Move version printing, etc. into a separate function.
+
+2008-03-18 15:57  millert
+
+       * sudo.c: Don't try to cleanup nsswitch if it has not been
+         initialized.
+
+2008-03-17 11:09  millert
+
+       * logging.c: Block SIGPIPE in send_mail() so sudo is not killed by
+         a problem executing the mailer.
+
+2008-03-14 08:11  millert
+
+       * configure.in, configure: AIX shared libs end in .a, not .so.
+
+2008-03-13 07:34  millert
+
+       * env.c: Preserve HOME by default too. Matches documentation and
+         previous behavior.
+
+2008-03-12 19:42  millert
+
+       * sudo.c: Use getopt() to parse the command line.  We need to be
+         able to intersperse env variables and options yet still honor
+         "--"" which complicates things slightly.
+
+2008-03-06 14:46  millert
+
+       * ChangeLog: sync
+
+2008-03-06 14:43  millert
+
+       * acsite.m4, configure, ltmain.sh: update to libtool-1.5.26
+
+2008-03-06 14:32  millert
+
+       * config.guess, config.sub: update from libtool-1.5.26 distribution
+
+2008-03-06 13:18  millert
+
+       * aix.c, sudo.h: attempt to fix compilation errors on AIX
+
+2008-03-06 13:08  millert
+
+       * Makefile.in: fix typo in last commit
+
+2008-03-06 13:07  millert
+
+       * Makefile.in: Add WHATSNEW file to the distribution
+
+2008-03-06 12:43  millert
+
+       * visudo.c: use warningx instead of fprintf(stderr, ...)
+
+2008-03-06 12:31  millert
+
+       * list.c: add DEBUG to list2tq
+
+2008-03-06 12:28  millert
+
+       * ChangeLog, TODO: sync
+
+2008-03-06 12:21  millert
+
+       * WHATSNEW: mention mailfrom
+
+2008-03-06 12:19  millert
+
+       * Makefile.in, config.h.in, configure, configure.in, set_perms.c,
+         sudo.h, aix.c: Add aix_setlimits() to set resource limits on AIX
+         using a combination of getuserattr() and setrlimit().  Currently
+         untested.
+
+2008-03-05 16:52  millert
+
+       * def_data.c, def_data.h, def_data.in, logging.c, sudoers.cat,
+         sudoers.pod, sudoers.man.in: Add mailfrom Defaults option that
+         sets the value of the From: field in the warning/error mail.  If
+         unset the login name of the invoking user is used.
+
+2008-03-05 16:18  millert
+
+       * defaults.c: store a copy of _PATH_SUDO_ASKPASS in def_askpass
+         that is freeable
+
+2008-03-05 15:19  millert
+
+       * gram.c, gram.y: When adding a default, only call list2tq() once
+         to do the list to tq conversion.  It is not legal to call list2tq
+         multiple times on the same list since list2tq consumes and
+         modifies the list argument.
+
+2008-03-05 09:38  millert
+
+       * sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.ldap.pod: comment
+         out XXXs for now
+
+2008-03-05 09:36  millert
+
+       * WHATSNEW: mention askpass
+
+2008-03-04 17:20  millert
+
+       * sudo.c: Error out if both -A and -S are specified Error out if -A
+         is specified but no askpass is configured
+
+2008-03-04 17:16  millert
+
+       * configure, configure.in: we are not going to ship a sudo-specific
+         askpass
+
+2008-03-03 14:30  millert
+
+       * sudo.h: fix definition of TGP_ASKPASS
+
+2008-03-03 13:54  millert
+
+       * def_data.c, def_data.in: make askpass boolean-capable
+
+2008-03-03 13:53  millert
+
+       * INSTALL: document --with-askpass
+
+2008-03-02 19:27  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in,
+         sudoers.ldap.cat, visudo.cat: regen
+
+2008-03-02 17:31  millert
+
+       * sudo.pod, sudo_usage.h.in, sudoers.pod: document -A and askpass
+
+2008-03-02 09:31  millert
+
+       * check.c, configure, configure.in, def_data.c, def_data.h,
+         def_data.in, defaults.c, pathnames.h.in, sudo.c, sudo.h,
+         sudo_usage.h.in, tgetpass.c, auth/sudo_auth.c: Add support for
+         running a helper program to read the password when no tty is
+         present (or when specified with the -A flag).  TODO: docs.
+
+2008-03-02 08:38  millert
+
+       * def_data.c, def_data.in: add missing printf format to SELinux
+         role and type strings
+
+2008-02-27 09:26  millert
+
+       * INSTALL, configure, configure.in: Disable use of
+         gss_krb5_ccache_name() by default and add
+         --enable-gss-krb5-ccache-name configure option to enable it.  It
+         seems that gss_krb5_ccache_name() doesn't work properly with some
+         combinations of Heimdal and OpenLDAP.
+
+2008-02-22 15:33  millert
+
+       * selinux.c: Ignore setexeccon() failing in permissive mode.  Also
+         add a call to setkeycreatecon() (though this is probably
+         insufficient).  From Dan Walsh.
+
+2008-02-22 15:19  millert
+
+       * auth/pam.c: Only set std_prompt for the PAM_PROMPT_* cases.  The
+         conversation function may be called for non-password reading
+         purposes so we must be careful not to use def_prompt in cases
+         where it may not be set.
+
+2008-02-20 12:00  millert
+
+       * selinux.c: Don't free the new tty context, we need to keep it
+         around when we restore the tty context after the command
+         completes
+
+2008-02-19 16:04  millert
+
+       * selinux.c: s/newrole/sudo/
+
+2008-02-19 13:21  millert
+
+       * sudo.man.pl, sudo.pod: Only put login_cap(3) in SEE ALSO section
+         if we have login.conf support
+
+2008-02-18 11:05  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.ldap.cat,
+         sudoers.ldap.man.in, sudoers.man.in, visudo.cat, visudo.man.in:
+         regen
+
+2008-02-18 10:53  millert
+
+       * Makefile.in, configure, configure.in, sudo.man.pl, sudo.pod,
+         sudoers.man.pl, sudoers.pod: Substitute in comment characters for
+         lines partaining to login.conf, BSD auth and SELinux and only
+         enable them if pertinent.
+
+2008-02-18 10:42  millert
+
+       * Makefile.in, sudo.pod, sudoers.ldap.pod, sudoers.pod, visudo.pod:
+         Remove the =cut on the first line (above the copyright notice) to
+         quiet pod2man.  Also remove the hackery in the FILES section and
+         just deal with the fact that there will a newline between each
+         pathname.
+
+2008-02-17 08:19  millert
+
+       * Makefile.in: run sudo.man.pl when generating sudo.man.in
+
+2008-02-17 08:11  millert
+
+       * configure, configure.in, sudo.man.pl: comment out SELinux manual
+         bits unless --with-selinux was specified
+
+2008-02-17 08:04  millert
+
+       * sudoers.pod: document role and type defaults for SELinux
+
+2008-02-16 20:26  millert
+
+       * sudo.c, sudo.cat, sudo.man.in, sudo.pod, sudo_usage.h.in:
+         Document "sudo -ll" and make "sudo -l -l" be equivalent.
+
+2008-02-15 15:23  millert
+
+       * configure.in, configure: Treat k*bsd*-gnu like Linux, not BSD.
+         Fixes compilation problems on Debian GNU/kFreeBSD.
+
+2008-02-13 17:17  millert
+
+       * auth/kerb5.c: Avoid Heimdal'isms introduced in the rev 1.32
+         rewrite of verify_krb_v5_tgt()
+
+2008-02-13 07:28  millert
+
+       * logging.c, logging.h, sudo.c: Remove dependence on
+         VALIDATE_NOT_OK in logging functions.  Split log_auth() into
+         log_allowed() and log_denial() Replace mail_auth() with
+         should_mail() and a call to send_mail()
+
+2008-02-10 18:06  millert
+
+       * ldap.c: Add debugging so we can tell if the krb5 ccache is
+         accessible
+
+2008-02-10 17:34  millert
+
+       * INSTALL: mention --with-selinux
+
+2008-02-09 09:48  millert
+
+       * configure: regen
+
+2008-02-09 09:43  millert
+
+       * selinux.c: add Sudo tag
+
+2008-02-09 09:30  millert
+
+       * Makefile.in, config.h.in, configure.in, def_data.c, def_data.h,
+         def_data.in, gram.c, gram.h, gram.y, ldap.c, parse.c, parse.h,
+         pathnames.h.in, selinux.c, sesh.c, sudo.c, sudo.cat, sudo.h,
+         sudo.man.in, sudo.pod, sudo_usage.h.in, sudoers.ldap.cat,
+         sudoers.ldap.man.in, sudoers.ldap.pod, testsudoers.c, toke.c,
+         toke.l: Add support for SELinux RBAC.  Sudoers entries may
+         specify a role and type.  There are also role and type defaults
+         that may be used.  To make sure a transition occurs, when using
+         RBAC commands are executed via the new sesh binary.  Based on
+         initial changes from Dan Walsh.
+
+2008-02-08 08:18  millert
+
+       * lbuf.c, ldap.c, parse.c, sudo.c, sudo.h, sudo_nss.c: Add long
+         list (sudo -ll) support for printing verbose LDAP and sudoers
+         file entries.  Still need to update manual.
+
+2008-02-03 10:43  millert
+
+       * ldap.c, parse.c, sudo.h, sudo_nss.c, sudo_nss.h: Unify the -l
+         output for file and ldap based sudoers and use lbufs for both.
+         The ldap output does not currently include options that cannot be
+         represented as tags.  This will be remedied in a long list output
+         mode to come.
+
+2008-01-27 16:37  millert
+
+       * set_perms.c: Use a specific error message for errno == EAGAIN
+         when setuid() et al fails.  On Linux systems setuid() will fail
+         with errno set to EAGAIN if changing to the new uid would result
+         in a resource limit violation.
+
+2008-01-27 16:34  millert
+
+       * sudo.c: Unlimit nproc on Linux systems where calling the setuid()
+         family of syscalls causes the nroc resource limit to be checked.
+         The limits will be reset by pam_limits.so when PAM is used.  In
+         the non-PAM case the nproc limit will remain unlimited but there
+         doesn't seem to be a way around that other than having sudo parse
+         /etc/security/limits.conf directly.
+
+2008-01-27 16:31  millert
+
+       * env.c, sudo.c, sudo.pod: Only read /etc/environment on Linux and
+         AIX
+
+2008-01-23 06:33  millert
+
+       * configure, configure.in: Use SUDO_DEFINE_UNQUOTED instead of
+         AC_DEFINE_UNQUOTED to prevent ldap.conf and ldap.secret paths
+         from going into config.h.  Avoid single quotes in variable
+         expansion when using SUDO_DEFINE_UNQUOTED since in some versions
+         of bash they will end up literally in the resulting define.
+
+2008-01-21 13:22  millert
+
+       * README.LDAP: mention --with-nsswitch=no
+
+2008-01-21 11:43  millert
+
+       * configure, configure.in: ldap_ssl.h depends on ldap.h being
+         included first
+
+2008-01-21 11:07  millert
+
+       * configure, configure.in, ldap.c, config.h.in: Include ldap_ssl.h
+         if we can find it.  Needed for the ldapssl_set_strength defines
+         on HP-UX at least.
+
+2008-01-21 10:02  millert
+
+       * TODO, sudoers.ldap.pod: sync
+
+2008-01-21 10:01  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.ldap.cat,
+         sudoers.ldap.man.in, sudoers.man.in, visudo.cat, visudo.man.in:
+         regen
+
+2008-01-21 10:00  millert
+
+       * Makefile.in: Use 78n line length when formatting cat pages.
+
+2008-01-21 09:50  millert
+
+       * README.LDAP: Remove redundant info that is now in
+         sudoers.ldap.pod
+
+2008-01-20 16:18  millert
+
+       * sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.ldap.pod:
+         Reorganize the first section a bit.  Substitute the proper path
+         for /etc/sudoers.
+
+2008-01-20 10:17  millert
+
+       * sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.ldap.pod:
+         Substitute values for ldap.conf, ldap.secret and nsswitch.conf
+         Move schema into EXAMPLES
+
+2008-01-20 10:15  millert
+
+       * configure.in, configure: Substitute values for ldap.conf,
+         ldap.secret and nsswitch.conf into sudoers.ldap.man.
+
+2008-01-19 20:35  millert
+
+       * configure, configure.in: substitute for sudoers.ldap.man
+
+2008-01-19 20:34  millert
+
+       * Makefile.in: Fix cut & pasto introduced when adding sudoers.ldap
+         man page.
+
+2008-01-19 20:25  millert
+
+       * sudoers.ldap.pod, sudoers.ldap.cat, sudoers.ldap.man.in: Fill in
+         some of the missing pieces.  Still needs some reorganization and
+         editing.
+
+2008-01-19 15:06  millert
+
+       * Makefile.in, sudoers.ldap.cat, sudoers.ldap.man.in,
+         sudoers.ldap.pod: Beginnings of a sudoers.ldap man page.
+         Currently, much of the information is adapted from README.LDAP.
+
+2008-01-18 17:32  millert
+
+       * pwutil.c: When copying gr_mem we must guarantee that the storage
+         space for gr_mem is properly aligned.  The simplest way to do
+         this is to simply store gr_mem directly after struct group.  This
+         is not a problem for gr_passwd or gr_name as they are simple
+         strings.
+
+2008-01-18 16:47  millert
+
+       * ldap.c: Fix a typo/thinko in one of the calls to
+         sudo_ldap_check_user_netgroup().  From Marco van Wieringen.
+
+2008-01-17 15:44  millert
+
+       * config.h.in, configure, configure.in, ldap.c: include
+         <mps/ldap_ssl.h> in ldap.c if available
+
+2008-01-16 18:20  millert
+
+       * gram.c, gram.y: Make sure we define SIZE_MAX for yacc's
+         skeleton.c
+
+2008-01-16 13:03  millert
+
+       * tgetpass.c: Use TCSAFLUSH when restoring terminal settings (and
+         echo) to guarantee that any pending output is discarded
+
+2008-01-15 17:18  millert
+
+       * sudoers: no longer need to specify SETENV when user has sudo ALL
+
+2008-01-15 09:40  millert
+
+       * testsudoers.c: sync user_args size calculation with sudo.c Add -g
+         group option, renaming old -g to -G Add set_runasgr() and
+         set_runaspw() and use them
+
+2008-01-15 09:23  millert
+
+       * sudo.h, sudo.c: Make set_runaspw static void
+
+2008-01-15 09:17  millert
+
+       * testsudoers.c, visudo.c: g/c set_runaspw stub
+
+2008-01-15 07:28  millert
+
+       * configure, configure.in: Don't add -llber twice.
+
+2008-01-14 06:40  millert
+
+       * ldap.c: fix typo
+
+2008-01-13 15:39  millert
+
+       * gram.c: regen
+
+2008-01-13 14:57  millert
+
+       * configure, configure.in: Fix check that determines whether -llber
+         is required.
+
+2008-01-13 14:22  millert
+
+       * config.h.in, configure, configure.in, README.LDAP, ldap.c: For
+         netscape-based LDAP, use ldapssl_set_strength() to implement the
+         checkpeer ldap.conf option.
+
+2008-01-13 09:49  millert
+
+       * auth/kerb5.c: Delay krb5_cc_initialize() until we actually need
+         to use the cred cache, which is what krb5_verify_user() does.
+         Better cleanup on failure.
+
+2008-01-12 12:40  millert
+
+       * auth/kerb5.c: Rewrite verify_krb_v5_tgt() based on what heimdal's
+         krb5_verify_user() does.
+
+2008-01-09 14:58  millert
+
+       * gram.c: The U suffix on constants is an ANSI feature
+
+2008-01-09 12:08  millert
+
+       * configure.in, configure: Add check for ber_set_option() in -llber
+
+2008-01-06 19:02  millert
+
+       * README.LDAP: default if no nsswitch.conf is files only
+
+2008-01-06 17:28  millert
+
+       * README.LDAP: don't tell people to mail aaron about LDAP stuff
+
+2008-01-06 12:32  millert
+
+       * README.LDAP: timelimit and bind_timelimit
+
+2008-01-06 08:54  millert
+
+       * ChangeLog: sync
+
+2008-01-06 07:56  millert
+
+       * ldap.c: Move ldap.secret reading into a separate function.
+
+2008-01-05 19:09  millert
+
+       * check.c: user_runas -> runas_pw
+
+2008-01-05 18:59  millert
+
+       * TODO: sync
+
+2008-01-05 18:59  millert
+
+       * check.c, sudo.pod, sudoers.pod: Add and document the %p escape in
+         the password prompt.  Based on a patch from Patrick Schoenfeld.
+
+2008-01-05 18:25  millert
+
+       * ldap.c: Check strlcpy() return values.
+
+2008-01-05 18:12  millert
+
+       * ldap.c: refactor ldap binding code into sudo_ldap_bind_s()
+
+2008-01-05 16:35  millert
+
+       * README.LDAP: Make it clear that host and uri can take multiple
+         parameters.  URI is now supported for more than just openldap
+         nsswitch.conf does't accept "compat"
+
+2008-01-05 16:27  millert
+
+       * sudo.c: comment cleanup and update (c) year
+
+2008-01-05 16:25  millert
+
+       * parse.c, sudo_nss.c: Move display_privs() and display_cmnd() from
+         parse.c to sudo_nss.c.  This should make it possible to build an
+         LDAP-only sudo binary.
+
+2008-01-05 13:27  millert
+
+       * ldap.c, parse.c, sudo.c, sudo.h, sudo_nss.h: Improve chaining of
+         multiple sudoers sources by passing in the previous return value
+         to the next in the chain
+
+2008-01-05 13:26  millert
+
+       * gram.y: Free up parser data structures in sudo_file_close().
+
+2008-01-05 08:13  millert
+
+       * gram.c, parse.c: Free up parser data structures in
+         sudo_file_close().
+
+2008-01-05 07:59  millert
+
+       * ldap.c: Parse uri ourself if no ldap_initialize() is present Use
+         ldap_create() instead of deprecated ldap_init() Use
+         ldap_sasl_bind_s() instead of deprecated ldap_simple_bind_s()
+
+2008-01-05 07:56  millert
+
+       * config.h.in, configure, configure.in: Add check for
+         ldap_sasl_bind_s() Remove -DLDAP_DEPRECATED from CFLAGS
+
+2008-01-04 09:56  millert
+
+       * configure.in, configure, config.h.in: add check for ldap_create
+
+2008-01-03 16:11  millert
+
+       * config.h.in, configure, configure.in, ldap.c: Add
+         sudo_ldap_get_first_rdn() to return the first rdn of an entry's
+         dn using the mechanism appropriate for the LDAP SDK in use.  Use
+         ldap_unbind_ext_s() instead of deprecated ldap_unbind_s().
+         Emulate ldap_unbind_ext_s() and ldap_search_ext_s() for SDK's
+         without them.
+
+2008-01-03 16:02  millert
+
+       * lbuf.c: include unistd.h
+
+2008-01-03 11:05  millert
+
+       * config.h.in, configure.in: fix typo in mtim_getnsec
+
+2008-01-02 15:29  millert
+
+       * config.h.in, configure.in, configure: add check for st__tim in
+         struct stat as used by SCO
+
+2008-01-02 11:05  millert
+
+       * ldap.c: use ldap_search_ext_s instead of deprecated ldap_search_s
+
+2008-01-02 10:09  millert
+
+       * Makefile.in, TODO, sudo.cat, sudo.man.in: add sudo_nss.h to HDRS
+
+2008-01-01 19:04  millert
+
+       * ldap.c: Replace deprecated ldap_explode_dn() with calls to
+         ldap_str2dn() and ldap_rdn2str().
+
+2008-01-01 18:37  millert
+
+       * ldap.c: Use ldap_get_values_len()/ldap_value_free_len() instead
+         of the deprecated ldap_get_values()/ldap_value_free().
+
+2008-01-01 17:07  millert
+
+       * TODO, ChangeLog: sync
+
+2008-01-01 17:06  millert
+
+       * gettime.c, sudo.c: Remove some already fixed XXXs
+
+2008-01-01 17:03  millert
+
+       * ldap.c: Same return value as non-existent sudoers if LDAP was
+         unable to connect.
+
+2008-01-01 16:52  millert
+
+       * sudo.pod: mention /etc/environment
+
+2008-01-01 16:42  millert
+
+       * UPGRADE, WHATSNEW, README.LDAP: Update to reflect recent
+         developments.
+
+2008-01-01 16:42  millert
+
+       * sudo.c: Print nsswitch.conf, ldap.conf and ldap.secret paths in
+         -V output.
+
+2008-01-01 16:25  millert
+
+       * ldap.c: When building up a query don't list groups in the aux
+         group vector that are the same as the passwd file group.  On most
+         systems the first gid in the group vector is the same as the
+         passwd entry gid.
+
+2008-01-01 14:01  millert
+
+       * env.c, ldap.c: Define LDAPNOINIT before calling ldap_init(), etc.
+         to disable user ldaprc and system defaults that could affect how
+         LDAP works.
+
+2008-01-01 13:21  millert
+
+       * INSTALL, configure, configure.in, pathnames.h.in, sudo.c,
+         sudo_nss.c, sudo_nss.h: Rename read_nss -> sudo_read_nss Add
+         --with-nsswitch to allow users to specify nsswitch.conf path or
+         disable it.  If --with-nsswitch=no but --with-ldap, order is
+         LDAP, then sudoers.  Fix --with-ldap-conf-file and
+         --with-ldap-secret-file
+
+2008-01-01 13:12  millert
+
+       * parse.c: Honor def_ignore_local_sudoers
+
+2007-12-31 16:44  millert
+
+       * ldap.c: no longer need to check def_ignore_local_sudoers here
+
+2007-12-31 16:36  millert
+
+       * parse.c: Refactor group vector resetting into a function and also
+         call it from display_cmnd.  Stop after the first sucessful match
+         in display_cmnd.  Print a newline between each display_privs
+         method.
+
+2007-12-31 16:23  millert
+
+       * parse.c: fix double free introduced in rev 1.218
+
+2007-12-31 16:10  millert
+
+       * ldap.c: belt and suspenders; zero out result after freeing it
+
+2007-12-31 15:04  millert
+
+       * env.c, fileops.c, ldap.c, sudo.h, sudo_nss.c: Refactor line
+         reading into a separate function, sudo_parseln(), which removes
+         comments, leading/trailing whitespace and newlines.  May want to
+         rethink the use of sudo_parseln() for /etc/ldap.secret
+
+2007-12-31 14:26  millert
+
+       * parse.c, sudo.c: Make the inability to read the sudoers file a
+         non-fatal error if there are other sudoers sources available.
+         sudoers_file_lookup now returns "not OK" if sudoers was not
+         present
+
+2007-12-31 14:24  millert
+
+       * ldap.c: make it clear that the global options are from LDAP
+
+2007-12-31 14:13  millert
+
+       * logging.c: allocate proper amount of space for error string
+
+2007-12-31 10:24  millert
+
+       * sudo_nss.c, sudo_nss.h: actual sudo nss code
+
+2007-12-31 10:08  millert
+
+       * ldap.c, parse.c, sudo.c, sudo.h: nss-ify display_privs and
+         display_cmnd.
+
+2007-12-31 07:54  millert
+
+       * defaults.c, parse.c, testsudoers.c, visudo.c: move
+         update_defaults() to parse.c
+
+2007-12-31 07:39  millert
+
+       * Makefile.in, ldap.c, list.c, parse.c, parse.h, sudo.c, sudo.h:
+         Use nsswitch to hide some sudoers vs. ldap implementation details
+         and reduce the number of #ifdef LDAP TODO: fix display routines
+         and error handling
+
+2007-12-28 11:20  millert
+
+       * Makefile.in, README.LDAP, ldap.c, pathnames.h.in, sudo.c, sudo.h:
+         First cut at nsswitch.conf support.  Further reorganizaton and
+         related changes are forthcoming.
+
+2007-12-21 16:53  millert
+
+       * env.c, pathnames.h.in, sudo.c, sudo.h: Add support for reading
+         and /etc/environment file.  Still needs to be documented and
+         should probably only applies to OSes that have it (AIX and Linux,
+         maybe others).
+
+2007-12-21 16:20  millert
+
+       * ldap.c: include limits.h
+
+2007-12-20 10:02  millert
+
+       * WHATSNEW: reword LDAP SASL
+
+2007-12-19 16:40  millert
+
+       * TODO: sync
+
+2007-12-19 16:39  millert
+
+       * README.LDAP: Add an example sudoRole, clarify netscape vs.
+         openldap a bit more
+
+2007-12-19 14:42  millert
+
+       * README.LDAP: Be clear on what is OpenLDAP vs. Netscape-derived
+
+2007-12-19 14:28  millert
+
+       * config.h.in, configure, configure.in, ldap.c: Use ldapssl_init()
+         for ldaps support instead of trying to do it manually with
+         ldap_init() + ldapssl_install_routines().  Use tls_cert and
+         tls_key for cert7.db and key3.db respectively.  Don't print
+         debugging info for options that are not set.  Add warning if
+         start_tls specified when not supported.
+
+2007-12-19 14:25  millert
+
+       * ldap.c: fix compilation on solaris
+
+2007-12-19 14:23  millert
+
+       * Makefile.in: add missing .h and .c files for missing lib objs
+
+2007-12-18 09:54  millert
+
+       * ldap.c: fix LDAP_OPT_NETWORK_TIMEOUT setting
+
+2007-12-17 20:10  millert
+
+       * ldap.c: fix compilation on Solaris
+
+2007-12-17 10:14  millert
+
+       * configure, configure.in: fix typo
+
+2007-12-17 08:08  millert
+
+       * README.LDAP: try to clear up which variables are for OpenLDAP and
+         which are for netscape-derived SDKs
+
+2007-12-17 07:31  millert
+
+       * config.h.in, configure, configure.in, ldap.c: Add support for
+         "ssl on" in both netscape and openldap flavors.  Only the
+         OpenLDAP flavor has been tested.
+
+2007-12-17 07:28  millert
+
+       * logging.c, sudo.c, sudo.h: Call cleanup() before exit in
+         log_error() instead of calling sudo_ldap_close() directly.
+         ldap_conn can now be static to sudo.c
+
+2007-12-16 20:02  millert
+
+       * sudo.c: ld -> ldap_conn
+
+2007-12-16 14:42  millert
+
+       * logging.c, sudo.c, sudo.h: Better ldap cleanup.
+
+2007-12-16 14:08  millert
+
+       * ldap.c: Distinguish between LDAP conf settings that are
+         connection-specific (which take an ld pointer) and those that are
+         default settings (which do not).
+
+2007-12-14 16:46  millert
+
+       * ldap.c: Improved warnings on error.
+
+2007-12-14 15:59  millert
+
+       * ldap.c: Make ldap config table driven and set the config *after*
+         we open the connection.
+
+2007-12-13 16:41  millert
+
+       * ldap.c: fix LDAP_OPT_X_CONNECT_TIMEOUT compat define
+
+2007-12-13 09:13  millert
+
+       * configure, configure.in: some operating systems need to link with
+         -lkrb5support when using krb5
+
+2007-12-10 17:12  millert
+
+       * WHATSNEW: minor update
+
+2007-12-10 10:56  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in: regen
+
+2007-12-07 19:17  millert
+
+       * TODO, ChangeLog: sync
+
+2007-12-07 19:09  millert
+
+       * ldap.c, schema.OpenLDAP, schema.iPlanet, sudoers2ldif: add -g
+         support for LDAP
+
+2007-12-03 11:36  millert
+
+       * WHATSNEW, sudo.c, sudo.pod, sudo_usage.h.in: The -i and -s flags
+         can now take an optional command.
+
+2007-12-02 12:13  millert
+
+       * def_data.c, def_data.h, def_data.in, sudo.c, sudo.pod,
+         sudoers.pod, auth/pam.c: Add passprompt_override flag to sudoers
+         that will cause the prompt to be overridden in all cases.  This
+         flag is also set when the user specifies the -p flag.
+
+2007-12-01 19:51  millert
+
+       * sudo.c: Move setting of login class until after sudoers has been
+         parsed.  Set NewArgv[0] for -i after runas_pw has been set.
+
+2007-12-01 19:34  millert
+
+       * configure, configure.in: Move the dgettext check.
+
+2007-12-01 11:22  millert
+
+       * config.h.in, configure, configure.in, auth/pam.c: Add basic
+         support for looking up the string "Password: " in the PAM
+         localized text db.  This allows us to determine whether the PAM
+         prompt is the default "Password: " one even if it has been
+         localized.
+
+         TODO: concatenate non-std PAM prompts and user-specified sudo
+         prompts.
+
+2007-11-27 18:40  millert
+
+       * Makefile.in, config.h.in, configure.in, parse.c, set_perms.c,
+         sudo.c, configure, sudo.h: Use AC_FUNC_GETGROUPS instead of a
+         home-grown attempt that was insufficient.
+
+2007-11-27 12:13  millert
+
+       * configure, acsite.m4, interfaces.c, memrchr.c: Fix typos;
+         Martynas Venckus
+
+2007-11-25 19:26  millert
+
+       * set_perms.c: Don't assume runas_pw is set; it may not be in the
+         -g case.
+
+2007-11-25 08:07  millert
+
+       * logging.c, set_perms.c: Set aux group vector for PERM_RUNAS and
+         restore group vector for PERM_ROOT if we previously changed it.
+         Stash the runas group vector so we don't have to call initgroups
+         more than once. Also add no-op check to check_perms.
+
+2007-11-21 15:11  millert
+
+       * WHATSNEW, check.c, def_data.in, defaults.c, gram.c, gram.h,
+         gram.y, ldap.c, logging.c, match.c, mon_systrace.c, parse.c,
+         parse.h, pwutil.c, set_perms.c, sudo.c, sudo.cat, sudo.h,
+         sudo.man.in, sudo.pod, sudo_usage.h.in, sudoers.cat,
+         sudoers.man.in, sudoers.pod, testsudoers.c, toke.c, visudo.c,
+         visudo.cat, visudo.man.in: Add support for runas groups.  This
+         allows the user to run a command with a different effective
+         group.  If the -g option is specified without -u the command will
+         be run as the current user (only the group will change).  the -g
+         and -u options may be used together.  TODO: implement runas group
+         for ldap       improve runas group documentation       add
+         testsudoers support
+
+2007-11-21 15:02  millert
+
+       * configure, configure.in: fix setting of mandir
+
+2007-11-21 14:26  millert
+
+       * sudo.pod, sudoers.pod: document that ALL implies SETENV
+
+2007-11-21 13:50  millert
+
+       * ldap.c: s/setenv_ok/setenv_implied/g
+
+2007-11-21 13:44  millert
+
+       * ldap.c: hostname_matches() returns TRUE on match in sudo 1.7.
+
+2007-11-21 13:26  millert
+
+       * ldap.c: use strcmp, not strcasecmp when comparing ALL
+
+2007-11-21 11:41  millert
+
+       * ldap.c: Make sudo ALL imply setenv.  Note that unlike with
+         file-based sudoers this does affect all the commands in the
+         sudoRole.
+
+2007-11-21 11:05  millert
+
+       * gram.c, gram.y, parse.c, parse.h: sudo "ALL" now implies the
+         SETENV tag but, unlike an explicit tag, it is not passed on to
+         other commands in the list.
+
+2007-11-21 11:02  millert
+
+       * visudo.c: Add missing sudo_setpwent() and sudo_setgrent() calls.
+         Also use sudo_getpwuid() instead of getpwuid().
+
+2007-11-15 11:16  millert
+
+       * sudoers: Expand on the dangers of not using visudo to edit
+         sudoers.
+
+2007-11-08 07:24  millert
+
+       * parse.c: Don't quote *?[]! on output since the lexer does not
+         strip off the backslash when reading those in.
+
+2007-11-07 13:16  millert
+
+       * glob.c: expand "u_foo" types to "unsigned foo" to avoid
+         compatibility issues.
+
+2007-11-04 08:33  millert
+
+       * logging.c: Refactor log line generation in to new_logline().
+
+2007-10-25 09:23  millert
+
+       * TROUBLESHOOTING: fix typo
+
+2007-10-24 12:41  millert
+
+       * config.h.in, configure, configure.in, interfaces.c, interfaces.h,
+         match.c: Add configure check for struct in6_addr instead of
+         relying on AF_INET6 since some systems define AF_INET6 but do not
+         include IPv6 support.
+
+2007-10-21 09:29  millert
+
+       * configure, configure.in: Fix block to add -lutil for FreeBSD and
+         NetBSD when logincap is in use.
+
+2007-10-19 22:28  millert
+
+       * configure, configure.in: POSIX states that struct timespec be
+         declared in time.h so check there regardless of the value of
+         TIME_WITH_SYS_TIME.
+
+2007-10-17 11:37  millert
+
+       * tgetpass.c: Instead of defining a macro to call the appropriate
+         method for turning on/off echo, just define tc[gs]etattr() and
+         the related defines that use the correct terminal ioctls if
+         needed.  Also go back to using TCSAFLUSH instead of TCSADRAIN on
+         all but QNX.
+
+2007-10-08 20:18  millert
+
+       * Makefile.in: g/c @ALLOCA@
+
+2007-10-08 20:07  millert
+
+       * configure: regen
+
+2007-10-08 20:04  millert
+
+       * INSTALL, config.h.in, configure.in, auth/pam.c: Add
+         --disable-pam-session configure option to disable calling
+         pam_{open,close}_session.  May work around bugs in some PAM
+         implementations.
+
+2007-10-08 12:00  millert
+
+       * tgetpass.c: quiet gcc warnings
+
+2007-10-08 08:41  millert
+
+       * tgetpass.c: Avoid printing the prompt if we are already
+         backgrounded.  E.g. if the user runs "sudo foo &" from the shell.
+         In this case, the call to tcsetattr() will cause SIGTTOU to be
+         delivered.
+
+2007-09-15 16:07  millert
+
+       * def_data.c, def_data.h, def_data.in: Reorder things such that the
+         definition of env_reset come right before the env variable lists.
+
+2007-09-15 07:50  millert
+
+       * parse.h: Shrink type and seqno in struct alias from int to
+         u_short
+
+2007-09-15 07:24  millert
+
+       * alias.c, match.c, parse.c, parse.h: Add a sequence number in the
+         aliases for loop detection.  If we find an alias with the seqno
+         already set to the current (global) value we know we've visited
+         it before so ignore it.
+
+2007-09-13 19:05  millert
+
+       * TODO, sudo.c, sudo.h, auth/pam.c: PAM wants the full tty path so
+         add user_ttypath which holds the full path to the tty or is NULL
+         if no tty was present.
+
+2007-09-13 18:42  millert
+
+       * auth/pam.c: Set PAM_RHOST to work around a bug in Solaris 7 and
+         lower that results in a segv.
+
+2007-09-11 15:43  millert
+
+       * gram.c: regen
+
+2007-09-11 15:42  millert
+
+       * alias.c, defaults.c, gram.y, list.c, list.h, match.c, parse.c,
+         parse.h, testsudoers.c, visudo.c: rename lh_ -> tq_
+
+2007-09-10 17:33  millert
+
+       * alloc.c: remove some useless casts
+
+2007-09-10 17:32  millert
+
+       * alloc.c: pull in inttypes.h for SIZE_MAX; we avoid stdint.h since
+         inttypes.h predates the final C99 spec and the standard specifies
+         that it shall include stdint.h anyway
+
+2007-09-06 12:39  millert
+
+       * Makefile.in, alloca.c, configure.in: Since we ship with a
+         pre-generated parser there is no need to ship a bogus alloca
+         implementation.
+
+2007-09-06 12:22  millert
+
+       * configure: regen
+
+2007-09-06 12:19  millert
+
+       * configure.in: remove initial setting of CHECKSIA, we require that
+         it be unset if not used
+
+2007-09-06 11:55  millert
+
+       * Makefile.in: add list.c to SRCS
+
+2007-09-06 07:18  millert
+
+       * configure: regen
+
+2007-09-06 07:17  millert
+
+       * configure.in: only do SIA checks on Digital Unix
+
+2007-09-05 18:50  millert
+
+       * sudoers.cat, sudoers.man.in: regen
+
+2007-09-05 18:48  millert
+
+       * ChangeLog, TODO: sync
+
+2007-09-05 18:39  millert
+
+       * auth/kerb5.c: Remove call to krb5_cc_register() as it is not
+         needed for modern kerb5.
+
+2007-09-05 18:16  millert
+
+       * configure: regen
+
+2007-09-05 18:16  millert
+
+       * configure.in, aclocal.m4: New method for setting the default
+         authentication type and avoiding conflicts in auth types.
+
+2007-09-05 14:45  millert
+
+       * match.c, parse.c, testsudoers.c: Each entry in a cmndlist now has
+         an associated runaslist so no need to keep track of the most
+         recent non-NULL one.
+
+2007-09-04 18:51  millert
+
+       * ldap.c: back out partial ldaps support mistakenly committed
+
+2007-09-04 10:57  millert
+
+       * ldap.c: Add support for unix groups and netgroups in sudoRunas
+
+2007-09-03 16:28  millert
+
+       * sudo_edit.c: Fix sudoedit of a non-existent file.  From Tilo
+         Stritzky.
+
+2007-09-02 17:05  millert
+
+       * configure: regen
+
+2007-09-02 17:05  millert
+
+       * INSTALL: update --passprompt escape info
+
+2007-09-02 17:03  millert
+
+       * configure.in: remove now-bogus comment and update copyright date
+
+2007-09-02 16:35  millert
+
+       * configure.in: Fix up use of with_passwd
+
+2007-09-02 16:25  millert
+
+       * acsite.m4, config.guess, config.sub, configure.in, ltmain.sh:
+         Update to autoconf-2.61 andf libtool-1.5.24
+
+2007-09-02 16:17  millert
+
+       * Makefile.in: "cmp -s" not just cmp Add @datarootdir@ to quiet
+         autoconf-2.61
+
+2007-09-01 17:39  millert
+
+       * gram.c: regen
+
+2007-09-01 17:39  millert
+
+       * gram.y: move tags and runaslist propagation to be earlier
+
+2007-09-01 09:34  millert
+
+       * visudo.c: If -f flag given use the permissions of the original
+         file as a template
+
+2007-09-01 08:45  millert
+
+       * gram.y: prevent a double free() when re-initing the parser
+
+2007-08-31 19:30  millert
+
+       * configure: regen
+
+2007-08-31 19:30  millert
+
+       * aclocal.m4, alias.c, alloc.c, config.h.in, configure.in, env.c,
+         ldap.c, list.c, list.h, memrchr.c, parse.c, parse.h, pwutil.c,
+         redblack.c, redblack.h, snprintf.c, sudo.c, sudo.h,
+         testsudoers.c, visudo.c, zero_bytes.c, auth/API, auth/afs.c,
+         auth/bsdauth.c, auth/kerb4.c, auth/kerb5.c, auth/pam.c,
+         auth/securid.c, auth/securid5.c, auth/sia.c, auth/sudo_auth.h:
+         Remove support for compilers that don't support void *
+
+2007-08-31 19:14  millert
+
+       * gram.c: regen
+
+2007-08-31 19:13  millert
+
+       * Makefile.in, alias.c, defaults.c, gram.y, list.c, list.h,
+         match.c, parse.c, parse.h, testsudoers.c, visudo.c: Move list
+         manipulation macros to list.h and create C versions of the more
+         complex ones in list.c.  The names have been down-cased so they
+         appear more like normal functions.
+
+2007-08-31 17:21  millert
+
+       * Makefile.in: Fix cmp command when regenerating parser.  Make
+         gram.o the first dependency for all programs so gram.h will be
+         generated before anything that needs it.
+
+2007-08-31 13:56  millert
+
+       * parse.h, gram.y: Convert NEW_DEFAULT anf NEW_MEMBER into static
+         functions.
+
+2007-08-30 21:21  millert
+
+       * match.c, parse.c, testsudoers.c: Use LH_FOREACH_REV when checking
+         permission and short-circuit on the first non-UNSPEC hit we get
+         for the command.  This means that instead of cycling through the
+         all the parsed sudoers entries we start at the end and work
+         backwards and quit after the first positive or negative match.
+
+2007-08-30 21:13  millert
+
+       * gram.c: regen
+
+2007-08-30 21:12  millert
+
+       * defaults.c, gram.y, parse.c, parse.h, testsudoers.c, visudo.c:
+         Change list head macros to take a pointer, not a struct.
+
+2007-08-30 20:46  millert
+
+       * gram.c: regen
+
+2007-08-30 20:46  millert
+
+       * gram.y: Propagate the runasspec from one command to the next in a
+         cmndspec.
+
+2007-08-30 16:15  millert
+
+       * match.c: Replace has_meta() with a macro that calls strpbrk().
+
+2007-08-30 16:04  millert
+
+       * gram.c: regen
+
+2007-08-30 13:26  millert
+
+       * alias.c, defaults.c, gram.y, match.c, parse.c, parse.h,
+         testsudoers.c, visudo.c: Use a list head struct when storing the
+         semi-circular lists and convert to tail queues in the process.
+         This will allow us to reverse foreach loops more easily and it
+         makes it clearer which functions expect a list as opposed to a
+         single member.
+
+         Add macros for manipulating lists.  Some of these should become
+         functions.
+
+         When freeing up a list, just pop off the last item in the queue
+         instead of going from head to tail.  This is simpler since we
+         don't have to stash a pointer to the next member, we always just
+         use the last one in the queue until the queue is empty.
+
+         Rename match functions that take a list to have list in the name.
+          Break cmnd_matches() into cmnd_matches() and cmndlist_matches.
+
+2007-08-30 13:12  millert
+
+       * parse.c: Fix pasto, append "!" not negated (which is an int) for
+         sudo -l output.
+
+2007-08-30 12:45  millert
+
+       * Makefile.in: Remove the dependency of gram .h on gram.y, the .c
+         dependency is enough.  Only move y.tab.h to gram.h if it is
+         different; avoids needless rebuilding.
+
+2007-08-27 15:51  millert
+
+       * sudoers.pod: Defaults lines may be associated with lists of
+         users, hosts, commands and runas users, not just single entries.
+
+2007-08-26 17:42  millert
+
+       * Makefile.in: Revert the "cmp" portion of the last diff, it
+         doesn't make sense.
+
+2007-08-26 17:10  millert
+
+       * Makefile.in: Remove *.lo for clean: When generating the parser,
+         only move the generated files into place if they differ from the
+         existing ones.
+
+2007-08-24 22:47  millert
+
+       * toke.c, toke.l: Replace IPV6 regexp with a much simpler
+         (readable) one and add an extra check when it matches to make
+         sure we have a valid address.
+
+2007-08-24 22:36  millert
+
+       * match.c: Fix thinko introduced when merging IPV6 support.
+
+2007-08-24 14:23  millert
+
+       * HISTORY, LICENSE: regen
+
+2007-08-24 14:23  millert
+
+       * license.pod: add 2007
+
+2007-08-24 14:19  millert
+
+       * UPGRADE: mention #uid vs. comment pitfall
+
+2007-08-24 09:50  millert
+
+       * acsite.m4: Merge in a patch from the libtool cvs that fixes a
+         problem with the latest autoconf.  From Stepan Kasal.
+
+2007-08-23 20:28  millert
+
+       * parse.h: Back out he XOR swap trick, it is slower than a temp
+         variable on modern CPUs.
+
+2007-08-23 20:14  millert
+
+       * gram.c: regen
+
+2007-08-23 20:14  millert
+
+       * gram.y, parse.h: Convert the tail queue to a semi-circle queue
+         and use the XOR swap trick to swap the prev pointers during
+         append.
+
+2007-08-23 15:31  millert
+
+       * parse.h: remove useless statement
+
+2007-08-23 07:47  millert
+
+       * toke.c, toke.l: Refactor #include parsing into a separate
+         function and return unparsed chars (such as newline or comment)
+         back to the lexer.
+
+2007-08-22 18:56  millert
+
+       * WHATSNEW: mention better uid support
+
+2007-08-22 18:55  millert
+
+       * sudoers.pod: Users may now consist of a uid.
+
+2007-08-22 18:39  millert
+
+       * gram.c, gram.h, toke.c: regen
+
+2007-08-22 18:32  millert
+
+       * parse.c: Use lbuf_append_quoted() for sudo -l output to quote
+         characters that would require quoting in sudoers.
+
+2007-08-22 18:31  millert
+
+       * lbuf.c, lbuf.h: Add lbuf_append_quoted() which takes a set of
+         characters which should be quoted with a backslash when
+         displayed.
+
+2007-08-22 18:28  millert
+
+       * toke.l: Require that the first character after a comment not be a
+         digit or a dash.  This allows us to remove the GOTRUNAS state and
+         treat uid/gids similar to other words.  It also means that we can
+         now specify uids in User_Lists and a User_Spec may now contain a
+         uid.
+
+2007-08-22 18:23  millert
+
+       * gram.y, toke.l: Replace RUNAS token with '(' and ')' tokens to
+         make the runas portion of the grammar more natural.
+
+2007-08-22 06:35  millert
+
+       * Makefile.in, README, BUGS: The BUGS file is history
+
+2007-08-21 09:19  millert
+
+       * toke.c, toke.l: Allow comments after a RunasAlias as long as the
+         character after the pound sign isn't a digit or a dash.
+
+2007-08-20 20:43  millert
+
+       * WHATSNEW: Glob support was back-ported to 1.6.9
+
+2007-08-20 19:59  millert
+
+       * Makefile.in: remove sudo_usage.h in distclean
+
+2007-08-20 19:24  millert
+
+       * parse.c: If a Defaults value contains a blank, double-quote the
+         string.
+
+2007-08-20 19:19  millert
+
+       * toke.c, toke.l: Properly deal with Defaults double-quoted strings
+         that span multiple lines using the line continuation char.
+         Previously, the entire thing, including the continuation char,
+         newline, and spaces was stored as-is.
+
+2007-08-20 10:46  millert
+
+       * sudo.c: Be consistent when using single quotes and backticks.
+
+2007-08-19 16:48  millert
+
+       * Makefile.in, configure, configure.in, lbuf.c, lbuf.h, parse.c,
+         sudo.c, sudo_usage.h.in: Add new linebuf code to do appends of
+         dynamically allocated strings and word-wrapped output.  Currently
+         used for sudo's usage() and sudo -l output.  Sudo usage strings
+         are now in sudo_usage.h which is generated at configure time.
+
+2007-08-18 08:22  millert
+
+       * sudo.h, parse.c, sudo.c: Fix line wrapping in usage() and use the
+         actual tty width instead of assuming 80.
+
+2007-08-17 18:32  millert
+
+       * history.pod: some more info
+
+2007-08-17 17:28  millert
+
+       * history.pod: Mentioned Chris Jepeway's parser and also the new
+         one that is in sudo 1.7.
+
+2007-08-16 09:38  millert
+
+       * sudo.pod, visudo.pod: For the options list, add flag args where
+         appropriate and increase the indent level so there is room for
+         them.
+
+2007-08-15 13:49  millert
+
+       * parse.c: Fix some spacing in "sudo -l" and add a comment about
+         some bogosity in the line wrapping.
+
+2007-08-15 11:21  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in,
+         visudo.man.in, visudo.cat: regen
+
+2007-08-15 11:20  millert
+
+       * INSTALL, Makefile.in, WHATSNEW, config.h.in, configure.in,
+         def_data.c, def_data.h, def_data.in, gram.c, gram.h, gram.y,
+         parse.c, parse.h, pathnames.h.in, sudo.c, sudo.h, sudoers.pod,
+         testsudoers.c, toke.c, toke.l: Remove monitor support until there
+         is a versino of systrace that uses a lookaside buffer (or we have
+         a better mechanism to use).
+
+2007-08-15 09:22  millert
+
+       * configure.in, configure, config.h.in, sudo.c: use getaddrinfo()
+         instead of gethostbyname() if it is available
+
+2007-08-14 15:27  millert
+
+       * parse.c, sudo.c: Deal with OSes where sizeof(gid_t) <
+         sizeof(int).
+
+2007-08-14 11:19  millert
+
+       * interfaces.c: repair non-getifaddrs() code after ipv6 integration
+
+2007-08-14 10:04  millert
+
+       * sudo.c: If we can open sudoers but fail to read the first byte,
+         close the file stream before trying again.
+
+2007-08-13 12:34  millert
+
+       * gram.c, toke.c: regen
+
+2007-08-13 12:29  millert
+
+       * gram.y, interfaces.c, interfaces.h, match.c, sudoers.pod, toke.l:
+         Add IPv6 support; adapted from patches by YOSHIFUJI Hideaki
+
+2007-08-13 12:23  millert
+
+       * sudo.pod, sudoers.pod, visudo.pod: Add some missing markup Update
+         copyright
+
+2007-08-12 18:55  millert
+
+       * configure, configure.in: fix sudo_noexec extension which got
+         broken in the libtool update
+
+2007-08-10 10:41  millert
+
+       * Makefile.in: explicitly specify -Tascii to nroff
+
+2007-08-08 16:07  millert
+
+       * logging.c: remove an ANSI-ism that crept in
+
+2007-08-06 20:37  millert
+
+       * sudo.pod: Adjust list indents Prevent -- from being turned into
+         an em dash Use a list for the environment instead of a literal
+         paragraph
+
+2007-08-06 20:36  millert
+
+       * visudo.pod: Use a list for the environment instead of an indented
+         literal paragraph.
+
+2007-08-06 20:33  millert
+
+       * sudoers.pod: Adjust list indentation
+
+2007-08-06 20:31  millert
+
+       * license.pod: add =head3
+
+2007-08-06 10:24  millert
+
+       * sudo.pod: mention that when specifying a uid for the -u option
+         the shell may require that the # be escaped
+
+2007-08-01 22:08  millert
+
+       * match.c: Fix off by one in group matching.
+
+2007-07-31 14:04  millert
+
+       * env.c: Fix typo: PYTHONINSPEC should be PYTHONINSPECT.  From
+         David Krause.
+
+2007-07-30 10:45  millert
+
+       * configure, configure.in: Add missing define of
+         HAVE_GSS_KRB5_CCACHE_NAME for the -lgssapi_krb5 case.
+
+2007-07-30 09:29  millert
+
+       * aclocal.m4, configure.in, configure: Fix link tests such that new
+         gcc doesn't optimize away the test.
+
+2007-07-29 19:21  millert
+
+       * sudo.pod, sudoers.pod, visudo.pod: add missing over/back
+
+2007-07-29 19:09  millert
+
+       * sudo.pod, sudoers.pod, visudo.pod: Change FILES section to use
+         =item
+
+2007-07-29 18:32  millert
+
+       * env.c: Add back allocation of the env struct in rebuild_env but
+         save a copy of the old pointer and free it before returning.
+
+2007-07-29 16:09  millert
+
+       * env.c: Don't init the private environment in rebuild_env() since
+         it may have already been done implicitly
+         sudo_setenv/sudo_unsetenv.
+
+         Multiply length by sizeof(char *) in memcpy/memmove when copying
+         the environment so we copy the full thing.
+
+         Add missing set of parens so we deref the right pointer in
+         sudo_unsetenv when searching for a matching variable.
+
+2007-07-26 16:35  millert
+
+       * sudo.pod, sudoers.pod, visudo.pod: Use  file markup for paths in
+         the FILES section
+
+2007-07-26 10:04  millert
+
+       * sudo.pod, sudoers.pod, visudo.pod: Don't capitalize sudo/visudo
+
+2007-07-26 07:28  millert
+
+       * sudoers.pod: Sort sudoers options; based on a diff from Igor
+         Sobrado.
+
+2007-07-25 16:19  millert
+
+       * sudo.pod, sudoers.pod, visudo.pod: Use 8 and 5 instead of
+         @mansectsu@ and @mansectform@ since the latter confuses pod2man.
+         The Makefile rules for the .man.in file will add @mansectsu@ and
+         @mansectform@ back in after pod2man is done anyway.
+
+2007-07-22 19:09  millert
+
+       * LICENSE, Makefile.in, license.pod: Move license info to pod
+         format
+
+2007-07-22 18:43  millert
+
+       * configure, configure.in, sudoers.pod: Substitute value of
+         path_info into sudoers man page.
+
+2007-07-22 16:40  millert
+
+       * WHATSNEW: remove features that were back-ported to 1.6.9
+
+2007-07-22 15:20  millert
+
+       * sudo.c, sudo.pod, visudo.c, visudo.pod: Sort SYNOPSIS and sync
+         usage.  From Igor Sobrado.
+
+2007-07-22 15:19  millert
+
+       * env.c: Only need sudo_setenv/sudo_unsetenv if we are going to use
+         ldap_sasl_interactive_bind_s() but don't have
+         gss_krb5_ccache_name().
+
+2007-07-22 08:23  millert
+
+       * ChangeLog: rebuild without branch info
+
+2007-07-22 08:23  millert
+
+       * Makefile.in: Add ChangeLog target
+
+2007-07-22 08:14  millert
+
+       * auth/pam.c: Run cleanup code if the user hits ^C at the password
+         prompt.
+
+2007-07-22 08:13  millert
+
+       * auth/pam.c: Some versions of pam_lastlog have a bug that will
+         cause a crash if PAM_TTY is not set so if there is no tty, set
+         PAM_TTY to the empty string.
+
+2007-07-20 09:32  millert
+
+       * Makefile.in: ChageLog not Changelog
+
+2007-07-20 09:31  millert
+
+       * ChangeLog: sync
+
+2007-07-20 09:29  millert
+
+       * Makefile.in: CHANGE -> Changelog
+
+2007-07-19 20:23  millert
+
+       * TODO: sync
+
+2007-07-19 19:53  millert
+
+       * config.h.in, configure.in, configure, ldap.c: Add configure hooks
+         for gss_krb5_ccache_name() and the gssapi headers.
+
+2007-07-18 12:57  millert
+
+       * env.c, sudo.c: rebuild_env() and insert_env_vars() no longer
+         return environment pointer, they set environ directly.
+
+         No longer need to pass around an envp pointer since we just
+         operate on environ now.
+
+         Add dosync argument to insert_env() that indicates whether it
+         should reset environ when realloc()ing env.envp.
+
+         Use an initial size of 128 for the environment.
+
+2007-07-18 12:41  millert
+
+       * env.c: Split sudo_setenv() into an external version and a version
+         only for use by rebuild_env().
+
+2007-07-16 19:40  millert
+
+       * ldap.c: Add support for using gss_krb5_ccache_name() instead of
+         setting KRB5CCNAME.  Also use sudo_unsetenv() in the
+         non-gss_krb5_ccache_name() case if there was no KRB5CCNAME in the
+         original environment.  TODO: configure setup for
+         gss_krb5_ccache_name()
+
+2007-07-16 18:44  millert
+
+       * README.LDAP: add krb5_ccname
+
+2007-07-16 18:44  millert
+
+       * README.LDAP, ldap.c: Add support for sasl_secprops in ldap.conf
+
+2007-07-16 18:39  millert
+
+       * env.c, sudo.h: Add sudo_unsetenv() and refactor private env
+         syncing code into sync_env().
+
+2007-07-16 07:27  millert
+
+       * README.LDAP, ldap.c: The ldap.conf variable is sasl_auth_id not
+         sasl_authid.
+
+2007-07-15 15:44  millert
+
+       * ldap.c, sudo.c, sudo.h: Add support for krb5_ccname in ldap.conf.
+         If specified, it will override the default value of KRB5CCNAME
+         in the environment for the duration of the call to
+         ldap_sasl_interactive_bind_s().
+
+2007-07-15 15:41  millert
+
+       * env.c, sudo.h: Remove format_env() Add sudo_setenv() to replace
+         most format_env() + insert_env() combinations.  insert_env() no
+         longer takes a struct environment *
+
+2007-07-15 12:47  millert
+
+       * ldap.c: Fix use_sasl vs. rootuse_sasl logic.
+
+2007-07-15 09:23  millert
+
+       * README.LDAP, config.h.in, configure, configure.in, ldap.c: Add
+         support for SASL auth when connecting to an LDAP server.  Adapted
+         from a diff by Tom McLaughlin.
+
+2007-07-14 16:32  millert
+
+       * configure, configure.in: Only enable AIX or BSD auth if no other
+         exclusive auth method has been chosen.  Allows people to e.g.,
+         use PAM on AIX without adding --without-aixauth.  A better
+         solution is needed to deal with default authentication since if a
+         non-exclusive method is chosen we will still get an error.
+
+2007-07-11 11:23  millert
+
+       * HISTORY, Makefile.in, history.pod: Generate HISTORY from
+         history.pod (which is also used for web pages)
+
+2007-07-09 19:40  millert
+
+       * sudo.man.in, sudoers.man.in: regen
+
+2007-07-09 19:25  millert
+
+       * sudo.pod: Better explanation of environment handling in the sudo
+         man page.
+
+2007-07-09 15:13  millert
+
+       * env.c, sudo.c: Defer setting user-specified env vars until after
+         authentication.
+
+2007-07-09 13:25  millert
+
+       * env.c: honor def_default_path for PATH set on the command line
+
+2007-07-09 13:22  millert
+
+       * sudo.c, env.c, sudo.pod, sudoers.pod: Allow user to set
+         environment variables on the command line as long as they are
+         allowed by env_keep and env_check.  Ie: apply the same
+         restrictions as normal environment variables.  TODO: deal with
+         secure_path
+
+2007-07-08 14:44  millert
+
+       * sudo.c, sudo_edit.c: Call rebuild_env() in call cases.  Pass
+         original envp to sudo_edit().  Don't allow -E or env var setting
+         in sudoedit mode.  More accurate usage() when called as sudoedit.
+
+2007-07-08 14:41  millert
+
+       * ldap.c: warn -> warning
+
+2007-07-08 14:11  millert
+
+       * sudo.pod: add -c option to sudoedit synopsis
+
+2007-07-08 10:27  millert
+
+       * TODO: udpate to reality
+
+2007-07-08 09:43  millert
+
+       * parse.c: Use ALLOW/DENY instead of TRUE/FALSE when dealing with
+         the return value from {user,host,runas,cmnd}_matches().  Rename
+         *matches variables -> *match.  Purely cosmetic.
+
+2007-07-08 09:30  millert
+
+       * parse.c: Move setting of FLAG_NO_CHECK into the if(pwflag) block.
+         No change in behavior.
+
+2007-07-08 09:17  millert
+
+       * sudoers: add SETENV tag
+
+2007-07-06 15:51  millert
+
+       * parse.c: Make pwcheck local to the pwflag block.  Use pwcheck
+         even if user didn't match since Defaults options may still apply.
+
+2007-07-06 14:51  millert
+
+       * check.c, sudo.c: Do not update timestamp if user not validated by
+         sudoers.
+
+2007-07-06 10:14  millert
+
+       * set_perms.c: for PERM_RUNAS, set the egid to the runas user's gid
+         and restore to the user's original in PERM_ROOT
+
+2007-07-06 10:04  millert
+
+       * logging.c, mon_systrace.c, set_perms.c, sudo.h: PERM_FULL_ROOT is
+         now no different than PERM_ROOT so remove PERM_FULL_ROOT
+
+2007-07-06 09:49  millert
+
+       * check.c: don't check timestamp mtime if we are just going to
+         remove it
+
+2007-07-06 09:33  millert
+
+       * sudoers.pod: Move sudoers defaults parameters into their own
+         section.
+
+2007-07-05 20:21  millert
+
+       * testsudoers.c: Reduce a level of indent by a few placed continue
+         statements.
+
+2007-07-05 20:20  millert
+
+       * parse.c: Make matching but negated commands/hosts/runas entries
+         override a previous match as expected.  Also reduce some levels
+         of indent by a few placed continue statements.
+
+2007-07-05 16:34  millert
+
+       * parse.c: Print default runas in "sudo -l" if sudoers don't
+         specify one.
+
+2007-07-05 15:46  millert
+
+       * match.c: Less hacky way of testing whether the domain was set.
+
+2007-07-04 15:50  millert
+
+       * INSTALL: Mention pam-devel and openldap-devel for Linux
+
+2007-07-03 19:38  millert
+
+       * README.LDAP: or vs. are
+
+2007-07-01 16:55  millert
+
+       * sudo.c: fix typo in Solaris project support
+
+2007-07-01 09:40  millert
+
+       * HISTORY: update
+
+2007-07-01 09:07  millert
+
+       * sudo.c: Make -- on the command line match the manual page.  The
+         implied shell case has been simplified as a result.
+
+2007-06-28 10:44  millert
+
+       * sudoers2ldif: add simplistic support for sudoRunas; note that if
+         a sudoers entry contains multiple Runas users, all will apply to
+         the sudoRole
+
+2007-06-28 10:42  millert
+
+       * sudoers2ldif: honor SETENV and NOSETENV tags
+
+2007-06-24 09:25  millert
+
+       * mon_systrace.c: Redo setting of user_args.  We now build up a
+         private copy of argv first and then replace the NULs with spaces.
+
+2007-06-24 09:19  millert
+
+       * mon_systrace.c: getcwd() returns NULL on failure, not 0 on
+         success
+
+2007-06-24 07:39  millert
+
+       * mon_systrace.c: allow chunksiz to reach 1 before erroring out
+
+2007-06-23 20:00  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in, visudo.cat,
+         visudo.man.in: regen
+
+2007-06-23 19:58  millert
+
+       * def_data.c, def_data.h, def_data.in, env.c, gram.c, gram.h,
+         gram.y, logging.c, parse.c, parse.h, sudo.c, sudo.h, sudo.pod,
+         sudoers.pod, toke.c, toke.l: Add support for setting environment
+         variables on the command line.  This is only allowed if the
+         setenv sudoers options is enabled or if the command is prefixed
+         with the SETENV tag.
+
+2007-06-23 19:57  millert
+
+       * README.LDAP: replace Aaron's email address with the sudo-workers
+         list
+
+2007-06-23 19:55  millert
+
+       * configure: regen
+
+2007-06-21 20:35  millert
+
+       * Makefile.in, README.LDAP, schema.OpenLDAP, schema.iPlanet: Break
+         schema out into separate files.
+
+2007-06-21 18:28  millert
+
+       * auth/aix_auth.c: free message if set by authenticate()
+
+2007-06-21 13:03  millert
+
+       * match.c: deal with NULL gr_mem
+
+2007-06-20 15:04  millert
+
+       * config.h.in: regen
+
+2007-06-20 15:04  millert
+
+       * configure.in: add template for HAVE_PROJECT_H
+
+2007-06-20 07:06  millert
+
+       * closefrom.c: include fcntl.h
+
+2007-06-19 19:37  millert
+
+       * INSTALL: mention --with-project
+
+2007-06-19 18:24  millert
+
+       * config.h.in, configure.in, sudo.c: Add Solaris 10 "project"
+         support.  From Michael Brantley.
+
+2007-06-19 17:27  millert
+
+       * sudoers.pod: fix typo
+
+2007-06-19 17:22  millert
+
+       * configure: regen
+
+2007-06-19 17:21  millert
+
+       * configure.in: Fix preservation of LDFLAGS in the LDAP case.
+
+2007-06-19 17:00  millert
+
+       * memrchr.c: Remove dependecy on NULL
+
+2007-06-19 15:37  millert
+
+       * configure: regen
+
+2007-06-19 15:37  millert
+
+       * aclocal.m4, configure.in: Can't use the regular autoconf
+         fnmatch() check since we need FNM_CASEFOLD so go back to our
+         custom one.
+
+2007-06-19 12:52  millert
+
+       * env.c: Fix preserving of variables in env_keep.
+
+2007-06-19 07:10  millert
+
+       * env.c: add XAUTHORIZATION
+
+2007-06-18 20:41  millert
+
+       * UPGRADE: expand upon env resetting and mention that it began in
+         1.6.9 not 1.7.
+
+2007-06-18 20:33  millert
+
+       * sudoers.pod: Update descriptions of env_keep and env_check to
+         match current reality.
+
+2007-06-18 17:33  millert
+
+       * env.c: Add LINGUAS to initial_checkenv_table.  Add COLORS,
+         HOSTNAME, LS_COLORS, MAIL, PS1, PS2, XAUTHORITY to
+         intial_keepenv_table.
+
+2007-06-18 17:23  millert
+
+       * env.c, logging.c: Treat USERNAME environemnt variable like
+         LOGNAME/USER
+
+2007-06-18 17:21  millert
+
+       * env.c: Don't need to populate keepenv table with the contents of
+         the checkenv table.
+
+2007-06-18 08:57  millert
+
+       * sudo.c: Don't force sudo into the C locale.
+
+2007-06-18 08:56  millert
+
+       * env.c: Make env_check apply when env_reset it true.  Environment
+         variables are passed through unless they contain '/' or '%'.
+         There is no need to have a variable in both env_check and
+         env_keep.
+
+2007-06-16 07:31  millert
+
+       * visudo.c: Remove an duplicate lock_file() call and add a comment.
+
+2007-06-15 21:16  millert
+
+       * UPGRADE: Add sudo 1.6.9 upgrade note.
+
+2007-06-14 12:23  millert
+
+       * interfaces.c: Solaris will return EINVAL if the buffer used in
+         SIOCGIFCONF is too small.  From Klaus Wagner.
+
+2007-06-14 12:03  millert
+
+       * Makefile.in, config.h.in, configure, configure.in, memrchr.c,
+         logging.c, sudo.h: Redo the long syslog line splitting based on a
+         patch from Eygene Ryabinkin.  Include memrchr() for systems
+         without it.
+
+2007-06-14 07:09  millert
+
+       * configure.in: Since we need to be able to convert timespec to
+         timeval for utimes() the last 3 digits in the tv_nsec are not
+         significant.  This makes the sudoedit file date comparison work
+         again.
+
+2007-06-13 13:41  millert
+
+       * aclocal.m4, configure, configure.in: Add SUDO_ADD_AUTH macro to
+         deal with adding things to AUTH_OBJS.  This deals with exclusive
+         authentication methods in a simple way.
+
+2007-06-12 13:08  millert
+
+       * LICENSE: mkstemp.c is BSD code too.
+
+2007-06-12 09:21  millert
+
+       * sudo.pod, sudoers.pod, visudo.pod: No commercial support for now.
+
+2007-06-11 18:27  millert
+
+       * sudo.c: cleanenv() is no more.
+
+2007-06-10 18:37  millert
+
+       * ChangeLog: Display branch info in Changelog
+
+2007-06-10 18:18  millert
+
+       * utimes.c: Include config.h early so we have it for
+         TIME_WITH_SYS_TIME
+
+2007-06-10 18:00  millert
+
+       * ChangeLog: Fix Changelog generation and update.
+
+2007-06-09 07:26  millert
+
+       * closefrom.c: Use /proc/self/fd instead of /proc/$$/fd
+
+         Move old-style fd closing into closefrom_fallback() and call that
+         if /proc/self/fd doesn't exist or the F_CLOSEM fcntl() fails
+
+2007-06-09 07:24  millert
+
+       * config.h.in, configure.in, auth/kerb5.c:  o use
+         krb5_verify_user() if available instead of doing it by hand
+          o use krb5_init_secure_context() if we have it
+          o pass an encryption type of 0 to krb5_kt_read_service_key()
+         instead of
+            ENCTYPE_DES_CBC_MD5 to let kerberos choose.
+
+2007-06-09 07:20  millert
+
+       * env.c: Check TERM and COLORTERM for '%' and '/' characters.  From
+         Debian.
+
+2007-06-09 07:17  millert
+
+       * configure.in: Fix closefrom() substitution in the Makefile
+
+2007-06-09 07:15  millert
+
+       * TROUBLESHOOTING: Mention alternate sudo pronunciation.
+
+2007-06-07 07:52  millert
+
+       * env.c: Remove KRB5_KTNAME from environment.  Allow COLORTERM.
+
+2007-06-07 07:22  millert
+
+       * auth/kerb5.c: If we cannot get a valid service key using the
+         default keytab it is a fatal error.  Fixes a bug where sudo could
+         be tricked into allowing access when it should not by a fake KDC.
+         From Thor Lancelot Simon.
+
+2007-05-12 08:56  millert
+
+       * aclocal.m4, configure, configure.in: Update long long checks to
+         use AC_CHECK_TYPES and to cache values.
+
+2007-05-12 08:07  millert
+
+       * aclocal.m4, configure.in: Use AC_FUNC_FNMATCH instead of a
+         homebrew fnmatch checker.  We can't use AC_REPLACE_FNMATCH since
+         that assumes replacing with GNU fnmatch.
+
+2007-05-11 17:05  millert
+
+       * configure, configure.in: Add closefrom() to LIB_OBJS not
+         SUDO_OBJS if it is missing since we need it for visudo now too.
+
+2007-04-24 14:44  millert
+
+       * sudoers.pod: Attempt to clarify the bit talking about network
+         numbers w/o netmasks.
+
+2007-04-24 14:25  millert
+
+       * sudo.pod: Clarify timestamp dir ownership sentence.
+
+2007-04-20 12:40  millert
+
+       * auth/pam.c: Linux PAM now defines __LINUX_PAM__, not
+         __LIBPAM_VERSION.  From Dmitry V. Levin.
+
+2007-04-16 12:13  millert
+
+       * sudo.c: -i is also one of the mutually exclusive options to list
+         it in the warning message.  Noted by Chris Pepper.
+
+2007-04-12 11:18  millert
+
+       * visudo.pod: The sudoers variable is env_editor, not enveditor.
+         From Jean-Francois Saucier.
+
+2007-03-29 13:30  millert
+
+       * redblack.c: I tracked down the original author so credit him and
+         include his license info.
+
+2007-02-06 13:25  millert
+
+       * sudo.cat, sudo.man.in, sudo.pod, sudoers.cat, sudoers.man.in,
+         sudoers.pod: Fix typos; from Jason McIntyre.
+
+2007-02-06 13:23  millert
+
+       * logging.c: Restore signal mask before calling reapchild().  Fixes
+         a possible race condition that could prevent sudo from properly
+         waiting for the child.
+
+2007-01-31 10:02  millert
+
+       * pwutil.c: Don't declare pw_free() if we are not going to use it.
+
+2007-01-31 10:00  millert
+
+       * env.c: Add NOEXEC support for AIX 5.3 which supports LDR_PRELOAD
+         and LDR_PRELOAD64.  The 64-bit version is not currently
+         supported.  Remove zero_env() prototype as it no longer exists.
+
+2006-12-11 13:21  millert
+
+       * logging.c: Add "Auto-Submitted: auto-generated" line to sudo mail
+         for rfc 3834.
+
+2006-09-29 10:53  millert
+
+       * auth/pam.c: If the user enters ^C at the password prompt, abort
+         instead of trying to authenticate with an empty password (which
+         causes an annoying delay).
+
+2006-08-17 11:26  millert
+
+       * closefrom.c, config.h.in, configure, configure.in: Add fcntl
+         F_CLOSEM support to closefrom(); adapted from a diff by Darren
+         Tucker.
+
+2006-08-17 11:25  millert
+
+       * pwutil.c: pw_free() is only used by sudo_freepwcache() so ifdef
+         it out too.
+
+2006-08-04 11:34  millert
+
+       * config.sub, config.guess: Update to latest versions from
+         cvs.savannah.gnu.org
+
+2006-07-31 13:51  millert
+
+       * pwutil.c, sudo_edit.c: Move password/group cache cleaning out of
+         sudo_end{pw,grp}ent() so we can close the passwd/group files
+         early.
+
+2006-07-31 13:50  millert
+
+       * config.h.in, configure, configure.in, set_perms.c: Add seteuid()
+         flavor of set_perms() for systems without setreuid() or
+         setresuid() that have a working seteuid().  Tested on Darwin.
+
+2006-07-30 15:56  millert
+
+       * mon_systrace.c: systrace_read() returns ssize_t
+
+2006-07-30 15:53  millert
+
+       * configure, configure.in: Fix typo, -lldap vs. -ldap; from Tim
+         Knox.
+
+2006-07-28 13:12  millert
+
+       * HISTORY: Fix typo; Matt Ackeret
+
+2006-07-17 08:25  millert
+
+       * sudo.c: Print sudoers path in -V mode for root.
+
+2006-06-15 14:44  millert
+
+       * ldap.c: Do a sub tree search instead of a base search (one level
+         in the tree only) for sudo right objects.  This allows system
+         administrators to categorize the rights in a tree to make them
+         easier to manage.
+
+2005-12-28 13:52  millert
+
+       * sudo.pod: fix typo
+
+2005-12-04 12:16  millert
+
+       * ldap.c: Convert GET_OPT and GET_OPTI to use just 2 args.  Add
+         timelimit and bind_timelimit support; adapted from gentoo.
+
+2005-11-23 18:57  millert
+
+       * ldap.c: Support comments that start in the middle of a line
+
+2005-11-23 18:56  millert
+
+       * configure.in, configure: Define LDAP_DEPRECATED until we start
+         using ldap_get_values_len()
+
+2005-11-18 09:55  millert
+
+       * closefrom.c: Silence gcc -Wsign-compare; djm@openbsd.org
+
+2005-11-17 20:39  millert
+
+       * error.c, sudo.c, sudo.h, testsudoers.c, visudo.c: cleanup() now
+         takes an int as an arg so it can be used as a signal handler too.
+
+2005-11-17 20:38  millert
+
+       * sudo.c: Make a copy of the shell field in the passwd struct for
+         NewArgv to avoid a use after free situation after sudo_endpwent()
+         is called.
+
+2005-11-16 20:36  millert
+
+       * Makefile.in, mkstemp.c, config.h.in, configure, configure.in: Add
+         mkstemp() for those poor souls without it.
+
+2005-11-15 09:25  millert
+
+       * env.c: Add PERL5DB to list of environment variables to remove.
+
+2005-11-13 15:49  millert
+
+       * mon_systrace.c, mon_systrace.h: Instead of calling the check
+         function twice with a state cookie use separate check/log
+         functions.
+
+         Check more ioctl() calls for failure.
+
+         systrace_{read,write} now return the number of bytes read/written
+         or -1 on error.
+
+2005-11-13 14:51  millert
+
+       * env.c: Add more environment variables to remove; from gentoo
+         linux Add some comments about what bad env variables go to what
+         (more to do)
+
+2005-11-11 17:23  millert
+
+       * sudo.c, sudo_edit.c: Move sudo_end{gr,pw}ent() until just before
+         the exec since they free up our cached copy of the passwd
+         structs, including sudo_user and sudo_runas.  Fixes a
+         use-after-free bug.
+
+2005-11-11 17:19  millert
+
+       * visudo.c: Close all fd's before executing editor.
+
+2005-11-11 17:17  millert
+
+       * sudo.c: Enable malloc debugging on OpenBSD when SUDO_DEVEL is
+         set.
+
+2005-11-11 11:22  millert
+
+       * check.c: Fix fd leak when lecture file option is enabled.  From
+         Jerry Brown
+
+2005-11-07 11:02  millert
+
+       * env.c: Add PERLLIB, PERL5LIB and PERL5OPT to the default list of
+         environment variables to remove.  From Charles Morris
+
+2005-11-01 13:24  millert
+
+       * env.c: add JAVA_TOOL_OPTIONS to initial_badenv_table for java 5
+
+2005-10-27 20:35  millert
+
+       * env.c: add PS4 and SHELLOPTS to initial_badenv_table for bash
+
+2005-08-14 20:32  millert
+
+       * sudoers.pod: Fix typo; Toby Peterson
+
+2005-08-02 09:57  millert
+
+       * tsgetgrpw.c: Make return buffers static so they don't get
+         clobbered
+
+2005-07-27 21:14  millert
+
+       * auth/securid5.c: Fix securid5 authentication, was not checking
+         for ACM_OK.  Also add default cases for the two switch()es.
+         Problem noted by ccon at worldbank
+
+2005-06-26 20:10  millert
+
+       * ldap.c: Remove ncat() in favor of just counting bytes and
+         pre-allocating what is needed.
+
+2005-06-26 19:44  millert
+
+       * ldap.c: Fix up some comments Add missing fclose() for the
+         rootbinddn case
+
+2005-06-26 19:38  millert
+
+       * ldap.c: align struct ldap_config
+
+2005-06-26 19:37  millert
+
+       * ldap.c: use LINE_MAX for max conf file line size
+
+2005-06-26 18:36  millert
+
+       * pathnames.h.in: add _PATH_LDAP_SECRET
+
+2005-06-26 18:36  millert
+
+       * README.LDAP: Mention rootbinddn Give example ou=SUDOers container
+
+2005-06-25 18:03  millert
+
+       * configure, INSTALL, configure.in, ldap.c: Support rootbinddn in
+         ldap.conf
+
+2005-06-25 17:46  millert
+
+       * env.c, sudo.pod, sudoers.pod: Preserve DISPLAY environment
+         variable by default.
+
+2005-06-25 16:39  millert
+
+       * acsite.m4, configure: set need_lib_prefix=no for all cases; this
+         is safe for LD_PRELOAD
+
+2005-06-25 16:15  millert
+
+       * acsite.m4, configure: set need_version=no for all cases; this is
+         safe for LD_PRELOAD
+
+2005-06-25 14:45  millert
+
+       * aclocal.m4: typo
+
+2005-06-25 14:33  millert
+
+       * configure, configure.in: Add dragonfly
+
+2005-06-25 14:29  millert
+
+       * auth/pam.c: Fix call to pam_end() when pam_open_session() fails.
+
+2005-06-25 14:21  millert
+
+       * configure: regen
+
+2005-06-25 14:20  millert
+
+       * acsite.m4: rebuild acsite.m4 from libtool 1.9f  libtool.m4
+         ltoptions.m4 ltsugar.m4 ltversion.m4
+
+2005-06-25 14:08  millert
+
+       * config.guess, config.sub, ltmain.sh: merge in local changes:
+         config.guess:  o better openbsd support config.sub:  o hiuxmpp
+         support ltmain.sh  o remove requirement that libs must begin with
+         "lib"  o don't print a bunch of crap about library installs  o
+         don't run ldconfig
+
+2005-06-25 14:05  millert
+
+       * config.guess, config.sub, ltmain.sh: libtool 1.9f
+
+2005-06-25 14:04  millert
+
+       * configure.in: Update with autoupdate and make minor changes for
+         libtool 1.9f
+
+2005-06-22 23:19  millert
+
+       * parse.c: don't call sudo_ldap_display_cmnd if ldap not setup
+
+2005-06-22 23:04  millert
+
+       * check.c, compat.h, fileops.c, gettime.c, sudo_edit.c, visudo.c,
+         emul/timespec.h: Move declatation of struct timespec to its own
+         include files for systems without it since it needs time_t
+         defined.
+
+2005-06-22 22:57  millert
+
+       * ldap.c: Don't set safe_cmnd for the "sudo ALL" case.
+
+2005-05-27 01:59  millert
+
+       * auth/pam.c: Call pam_open_session() and pam_close_session() to
+         give pam_limits a chance to run.  Idea from Karel Zak.
+
+2005-04-24 19:24  millert
+
+       * check.c, sudo.c: Add explicit cast from mode_t -> u_int in printf
+         to silence warnings on Solaris
+
+2005-04-24 19:22  millert
+
+       * parse.c: include grp.h to silence a warning on Solaris
+
+2005-04-23 15:10  millert
+
+       * parse.c: Fix printing of += and -= defaults.
+
+2005-04-17 01:21  millert
+
+       * mon_systrace.c: Sanity check number of syscall args with argsize.
+         Not really needed but a little paranoia never hurts.
+
+2005-04-17 01:18  millert
+
+       * mon_systrace.c, mon_systrace.h: Don't do pointer arithmetic on
+         void * Use int, not size_t/ssize_t for systrace lengths (since it
+         uses int)
+
+2005-04-16 03:14  millert
+
+       * mon_systrace.c: Add some memsets for paranoia Fix namespace
+         collsion w/ error Check rval of decode_args() and update_env()
+         Remove improper setting of validated variable
+
+2005-04-11 21:37  millert
+
+       * parse.c, sudo.c, sudo.h: In -l mode, only check local sudoers
+         file if def_ignore_sudoers is not set and call LDAP versions from
+         display_privs() and display_cmnd() instead of directly from
+         main().  Because of this we need to defer closing the ldap
+         connection until after -l processing has ocurred and we must pass
+         in the ldap pointer to display_privs() and display_cmnd().
+
+2005-04-11 21:33  millert
+
+       * ldap.c: Reorganize LDAP code to better match normal sudoers
+         parsing.  Instead of storing strings for later printing in -l
+         mode we do another query since the authenticating user and the
+         user being listed may not be the same (the new -U flag).  Also
+         add support for "sudo -l command".
+
+         There is still a fair bit if duplicated code that can probably be
+         refactored.
+
+2005-04-11 00:37  millert
+
+       * ldap.c: Replace pass variable with do_netgr for better
+         readability.
+
+2005-04-10 23:49  millert
+
+       * ldap.c: use DPRINTF macro
+
+2005-04-10 23:18  millert
+
+       * ldap.c: estrdup, not strdup
+
+2005-04-10 17:44  millert
+
+       * parse.c: Add macro to test if the tag changed to improve
+         readability.
+
+2005-04-10 17:40  millert
+
+       * parse.c: Avoid printing defaults header if there are no defaults
+         to print...
+
+2005-04-10 15:29  millert
+
+       * glob.c: Fix a warning on systems without strlcpy().
+
+2005-04-10 13:32  millert
+
+       * pwutil.c: Use macros where possible for sudo_grdup() like
+         sudo_pwdup().
+
+2005-04-08 17:04  millert
+
+       * utimes.c: It is possible for tv_usec to hold >= 1000000 usecs so
+         add in tv_usec / 1000000.
+
+2005-03-29 23:38  millert
+
+       * auth/kerb5.c: The component in krb5_principal_get_comp_string()
+         should be 1, not 0 for Heimdal.  From Alex Plotnick.
+
+2005-03-29 09:29  millert
+
+       * alias.c, alloc.c, check.c, defaults.c, find_path.c, gram.c,
+         gram.y, interfaces.c, ldap.c, logging.c, match.c, mon_systrace.c,
+         pwutil.c, redblack.c, sudo.c, sudo.h, toke.c, toke.l, visudo.c:
+         Add efree() for consistency with emalloc() et al.  Allows us to
+         rely on C89 behavior (free(NULL) is valid) even on K&R.
+
+2005-03-28 22:33  millert
+
+       * parse.c, sudo.c: Move initgroups() for -U option into
+         display_privs() so group matching in sudoers works correctly.
+
+2005-03-26 21:34  millert
+
+       * ldap.c: Removed duplicate call to ldap_unbind_s introduced along
+         with sudo_ldap_close.
+
+2005-03-26 20:01  millert
+
+       * parse.c: Add missing space in Defaults printing
+
+2005-03-25 12:36  millert
+
+       * pwutil.c: Sync sudo_pwdup with OpenBSD changes: use macros for
+         size computaton and string copies.
+
+2005-03-18 22:08  millert
+
+       * pwutil.c: Zero old pw_passwd before replacing with version from
+         shadow file.
+
+2005-03-18 22:07  millert
+
+       * configure, configure.in: Only attempt shadow password detection
+         if PAM is not being used Add shadow_* variables to make shadow
+         password detection more generic.
+
+2005-03-18 21:46  millert
+
+       * configure.in: Use OSDEFS for os-specific -D_FOO_BAR stuff rather
+         than CPPFLAGS
+
+2005-03-12 19:27  millert
+
+       * sudoers.pod: use a non-breaking space to avoid a double space
+         after e.g.
+
+2005-03-12 19:26  millert
+
+       * sudo.pod: commna, not colon after e.g.
+
+2005-03-12 18:43  millert
+
+       * sudo_noexec.c: Add __ variants of the exec functions.  GNU libc
+         at least uses __execve() internally.
+
+2005-03-12 12:29  millert
+
+       * indent.pro: Match reality a bit more.
+
+2005-03-12 12:27  millert
+
+       * pwutil.c: Missed piece from rev. 1.6, fix sudo_getpwnam() too.
+
+2005-03-11 23:42  millert
+
+       * pwutil.c: Store shadow password after making a local copy of
+         struct passwd in case normal and shadow routines use the same
+         internal buffer in libc.
+
+2005-03-10 20:57  millert
+
+       * alloc.c, logging.c: Make varargs usage consistent with the rest
+         of the code.
+
+2005-03-10 10:09  millert
+
+       * sudo_noexec.c: Wrap more of the exec family since on Linux the
+         others do not appear to go through the normal execve() path.
+
+2005-03-10 09:57  millert
+
+       * visudo.c: make print_unused static like proto says
+
+2005-03-10 09:55  millert
+
+       * glob.c: silence a warning on K&R systems
+
+2005-03-10 09:51  millert
+
+       * parse.c, alias.c, error.c: make this build in K&R land
+
+2005-03-07 22:21  millert
+
+       * toke.c: regen
+
+2005-03-05 22:46  millert
+
+       * ldap.c: return(foo) not return foo optimize _atobool() slightly
+
+2005-03-05 22:40  millert
+
+       * ldap.c: Use TRUE/FALSE
+
+2005-03-05 22:31  millert
+
+       * ldap.c: Reformat to match the rest of sudo's code.
+
+2005-03-05 19:33  millert
+
+       * sudo.pod: I am the primary author
+
+2005-02-22 22:28  millert
+
+       * README, RUNSON, Makefile.in: The RUNSON file is toast--it
+         confused too many people and really isn't needed in a
+         configure-oriented world.
+
+2005-02-22 22:28  millert
+
+       * INSTALL: alternate -> alternative
+
+2005-02-22 22:26  millert
+
+       * tgetpass.c: Use TCSADRAIN instead of TCSAFLUSH since some OSes
+         have issues with TCSAFLUSH.
+
+2005-02-22 22:16  millert
+
+       * toke.l: Allow leading blanks before Defaults and Foo_Alias
+         definitions
+
+2005-02-22 22:14  millert
+
+       * Makefile.in: fix rules to build toke.o and gram.o in devel mode
+
+2005-02-20 13:00  millert
+
+       * sudoers.pod: env_keep overrides set_logname
+
+2005-02-20 12:57  millert
+
+       * env.c: Fix disabling set_logname and make env_keep override
+         set_logname.
+
+2005-02-20 12:28  millert
+
+       * compat.h, config.h.in, configure, configure.in: No longer need
+         memmove()
+
+2005-02-20 11:48  millert
+
+       * env.c, sudo.c: Just clean the environment once.  This assumes
+         that any further setenv/putenv will be able to handle the fact
+         that we replaced environ with our own malloc'd copy but all the
+         implementations I've checked do.
+
+2005-02-15 23:16  millert
+
+       * env.c, sudo.c: In -i mode, base the value of insert_env()'s
+         dupcheck flag on DID_FOO flags.  Move checks for $HOME resetting
+         into rebuild_env()
+
+2005-02-13 00:33  millert
+
+       * env.c, sudo.c: Move setting of user_path, user_shell, user_prompt
+         and prev_user into init_vars() since user_shell at least is
+         needed there.
+
+2005-02-12 18:51  millert
+
+       * Makefile.in: fix devel builds
+
+2005-02-12 18:46  millert
+
+       * check.c, sudo.c: Fix some printf format mismatches on error.
+
+2005-02-12 18:33  millert
+
+       * configure, gram.c, toke.c: regen
+
+2005-02-12 17:56  millert
+
+       * LICENSE, Makefile.binary.in, Makefile.in, aclocal.m4, alias.c,
+         alloc.c, check.c, closefrom.c, compat.h, configure.in,
+         defaults.c, defaults.h, env.c, error.c, fileops.c, find_path.c,
+         getprogname.c, getspwuid.c, gettime.c, goodpath.c, gram.y,
+         interfaces.c, interfaces.h, ldap.c, logging.c, logging.h,
+         match.c, mon_systrace.c, parse.c, redblack.c, redblack.h,
+         set_perms.c, sigaction.c, snprintf.c, strcasecmp.c, strerror.c,
+         strlcat.c, strlcpy.c, sudo.c, sudo.h, sudo.pod, sudo_edit.c,
+         sudo_noexec.c, sudoers.pod, testsudoers.c, tgetpass.c, toke.l,
+         utimes.c, version.h, visudo.c, visudo.pod, zero_bytes.c,
+         auth/afs.c, auth/aix_auth.c, auth/bsdauth.c, auth/dce.c,
+         auth/fwtk.c, auth/kerb4.c, auth/kerb5.c, auth/pam.c,
+         auth/passwd.c, auth/rfc1938.c, auth/secureware.c, auth/securid.c,
+         auth/securid5.c, auth/sia.c, auth/sudo_auth.c, auth/sudo_auth.h,
+         emul/utime.h: Update copyright years.
+
+2005-02-12 16:46  millert
+
+       * BUGS, INSTALL, INSTALL.binary, Makefile.in, README, configure.in:
+         version 1.7
+
+2005-02-12 16:16  millert
+
+       * WHATSNEW: What's new in sudo 1.7, based on the 1.7 CHANGES
+         entries.
+
+2005-02-11 18:06  millert
+
+       * compat.h, logging.h, sudo.h: Add __printflike and use it with gcc
+         to warn about printf-like format mismatches
+
+2005-02-10 00:16  millert
+
+       * CHANGES, ChangeLog: Replaced CHANGES file with ChangeLog
+         generated from cvs logs
+
+2005-02-10 00:03  millert
+
+       * set_perms.c: Use warning/error instead of perror/fatal.
+
+2005-02-09 23:13  millert
+
+       * config.guess: Update OpenBSD section
+
+2005-02-09 23:10  millert
+
+       * UPGRADE: Add upgrading noted for 1.7
+
+2005-02-09 23:00  millert
+
+       * env.c, sudo.c, sudoers.pod: Instead of zeroing out the
+         environment, just prune out entries based on the env_delete and
+         env_check lists.  Base building up the new environment on the
+         current environment and the variables we removed initially.
+
+2005-02-09 22:23  millert
+
+       * configure, configure.in, sudo.c, config.h.in: Set locale to "C"
+         if locales are supported, just to be safe.
+
+2005-02-09 22:19  millert
+
+       * toke.c, toke.l: Cast argument to ctype functions to unsigned
+         char.
+
+2005-02-07 22:56  millert
+
+       * env.c: correct value for DID_USER
+
+2005-02-07 22:55  millert
+
+       * error.c, fnmatch.c, getcwd.c, glob.c, snprintf.c: #include
+         <compat.h> not "compat.h"
+
+2005-02-07 22:51  millert
+
+       * defaults.c: Reset the environment by default.
+
+2005-02-07 22:50  millert
+
+       * sudo.c: Alloc an extra slot in NewArgv.  Removes the need to
+         malloc an new vector if execve() fails.
+
+2005-02-06 23:16  millert
+
+       * INSTALL, config.h.in, configure, configure.in, sudo.c: Use
+         execve(2) and wrap the command in sh if we get ENOEXEC.
+
+2005-02-05 23:01  millert
+
+       * sudo_noexec.c: Only include time.h on systems that lack struct
+         timespec which gets defind in compat.h (using time_t).
+
+2005-02-05 22:59  millert
+
+       * sudo_noexec.c: Include time.h for time_t in compat.h for systems
+         w/o struct timespec.
+
+2005-02-05 22:56  millert
+
+       * configure, compat.h, config.h.in, configure.in: use bcopy on
+         systems w/o memmove
+
+2005-02-05 22:31  millert
+
+       * compat.h: __attribute__((__unused__)) doesn't work in gcc 2.7.2.1
+         so limit its use to gcc >= 2.8.
+
+2005-02-05 21:21  millert
+
+       * Makefile.in: Add explicit rule to build sudo_noexec.lo
+
+2005-02-05 17:56  millert
+
+       * INSTALL.configure, Makefile.in: No longer depend on VPATH;
+         pointed out a bunch of missed dependencies.
+
+2005-02-05 13:18  millert
+
+       * TROUBLESHOOTING: Help for PAM when account section is missing
+
+2005-02-05 13:01  millert
+
+       * auth/pam.c: Give user a clue when there is a missing "account"
+         section in the PAM config.
+
+2005-02-05 10:22  millert
+
+       * auth/pam.c: Better error handling.
+
+2005-02-05 09:57  millert
+
+       * configure, config.h.in, configure.in: Move _FOO_SOURCE to
+         CPPFLAGS so it takes effect as early as possible.  Silences a
+         warning about isblank() on linux.
+
+2005-02-04 21:49  millert
+
+       * auth/pam.c: Fix typo (missing comma) that caused an incorrect
+         number of args to be passed to log_error().
+
+2005-01-31 23:03  millert
+
+       * pwutil.c: Don't try to destroy a tree we didn't create.
+
+2005-01-27 10:42  millert
+
+       * alias.c, alloc.c, check.c, closefrom.c, compat.h, defaults.c,
+         env.c, error.c, fileops.c, find_path.c, fnmatch.c, getcwd.c,
+         getprogname.c, getspwuid.c, gettime.c, goodpath.c, gram.c,
+         gram.y, interfaces.c, ldap.c, logging.c, match.c, mon_systrace.c,
+         parse.c, pwutil.c, set_perms.c, sigaction.c, snprintf.c,
+         strcasecmp.c, strerror.c, strlcat.c, strlcpy.c, sudo.c,
+         sudo_edit.c, sudo_noexec.c, testsudoers.c, tgetpass.c, toke.c,
+         toke.l, utimes.c, visudo.c, zero_bytes.c, auth/afs.c,
+         auth/aix_auth.c, auth/bsdauth.c, auth/dce.c, auth/fwtk.c,
+         auth/kerb4.c, auth/kerb5.c, auth/pam.c, auth/passwd.c,
+         auth/rfc1938.c, auth/secureware.c, auth/securid.c,
+         auth/securid5.c, auth/sia.c, auth/sudo_auth.c: Add __unused to
+         rcsids
+
+2005-01-21 10:34  millert
+
+       * configure, configure.in: Fix error message when mixing invalid
+         auth types
+
+2005-01-21 10:32  millert
+
+       * INSTALL: PAM, AIX auth, BSD auth and login_cap are now on by
+         default if the OS supports them.
+
+2005-01-21 10:29  millert
+
+       * config.h.in, auth/sudo_auth.h: s/HAVE_AUTHENTICATE/HAVE_AIXAUTH/g
+
+2005-01-21 10:29  millert
+
+       * configure.in: Better checking for conflicting authentication
+         methods Display the authentication methods used at the end of
+         configure Rename --with-authenticate -> --with-aixauth Use
+         --with-aixauth, --with-bsdauth, --with-pam, --with-logincap by
+         default on systems that support them unless disabled.  Add
+         OSMAJOR variable that replaces old OSREV; now OSREV has full
+         version number
+
+2005-01-17 19:40  millert
+
+       * def_data.c, def_data.in, sudo.c, sudoers.pod: s/-O/-C/
+
+2005-01-14 13:35  millert
+
+       * configure.in: Replace:     test -n "$FOO" || FOO="bar"
+
+         With:     : ${FOO='bar'}
+
+2005-01-09 18:58  millert
+
+       * pwutil.c, testsudoers.c, tsgetgrpw.c: Use function pointers to
+         only call private passwd/group routines when using a nonstandard
+         passwd/group file.
+
+2005-01-06 10:34  millert
+
+       * CHANGES: sync
+
+2005-01-05 22:16  millert
+
+       * tsgetgrpw.c: Can't use strtok() since it doesn't handle empty
+         fields so add getpwent()/getgrent() functions and call those.
+
+2005-01-05 17:29  millert
+
+       * Makefile.in: Fix dummied out toke.c and gram.c dependencies.
+
+2005-01-05 17:18  millert
+
+       * Makefile.in: Rename PARSESRCS -> GENERATED since it is only used
+         in the clean target Add devdir variable and use it to specify the
+         path to parser sources
+
+2005-01-05 17:17  millert
+
+       * configure: regen
+
+2005-01-05 17:17  millert
+
+       * configure.in: Add a devdir variables that defaults to $(srcdir)
+         and is set to . if --devel was specified.  Allows for proper
+         dependecies building the parser.
+
+2005-01-05 14:50  millert
+
+       * testsudoers.c: Add support for custom passwd/group files.
+
+2005-01-05 14:47  millert
+
+       * Makefile.in: Build private copy of pwutil.o for testsudoers with
+         MYPW defined so it uses our own passwd/group routines.
+
+2005-01-05 14:46  millert
+
+       * visudo.c: Remove sudo_*{pw,gr}* stubs and add
+         sudo_setspent/sudo_endspent stubs instead.  We can now just use
+         the caching sudo_*{pw,gr}* functions in pwutil.c Add comment
+         about wanting to call sudo_endpwent/sudo_endgrent in cleanup()
+
+2005-01-05 14:44  millert
+
+       * tsgetgrpw.c: Remove caching; we will just use what is in pwutil.c
+         Use global buffers for passwd/group structs Rename functions from
+         sudo_* to my_*
+
+2005-01-05 14:43  millert
+
+       * logging.c, sudo.c: g/c pwcache_init/pwcache_destroy
+
+2005-01-05 14:42  millert
+
+       * sudo.h: Undo last commit and add sudo_setspent and sudo_endspent
+         instead.
+
+2005-01-05 14:41  millert
+
+       * getspwuid.c, pwutil.c: Move all but the shadow stuff from
+         getspwuid.c to pwutil.c and pwcache_get and pwcache_put as they
+         are no longer needed.  Also add preprocessor magic to use private
+         versions of the passwd and group routines if MYPW is defined (for
+         use by testsudoers).
+
+2005-01-04 22:40  millert
+
+       * tsgetgrpw.c: zero out struct passwd/group before filling it in so
+         if there are fields we don't handle they end up as 0.
+
+2005-01-04 20:10  millert
+
+       * logging.c, sudo.c, sudo.h, testsudoers.c, visudo.c: Adapt to
+         pwutil.c
+
+2005-01-04 20:09  millert
+
+       * Makefile.in: Add tsgetgrpw.c and pwutil.c Rename the *OBJ
+         variables for better readability.
+
+2005-01-04 20:08  millert
+
+       * tsgetgrpw.c: Passwd and group lookup routines for testsudoers
+         that support alternate passwd and group files.
+
+2005-01-04 20:07  millert
+
+       * getspwuid.c, pwutil.c: Split off pw/gr cache and dup code into
+         its own file.  This allows visudo and testsudoers to use the
+         pw/gr cache too.
+
+2005-01-01 19:31  millert
+
+       * parse.c: Print Defaults info in "sudo -l" output and wrap lines
+         based on the terminal width.
+
+2005-01-01 12:41  millert
+
+       * match.c, visudo.c, testsudoers.c: Only check group vector in
+         usergr_matches() if we are matching the invoking or list user.
+         Always check the group members, even if there was a group vector.
+
+2004-12-17 17:24  millert
+
+       * LICENSE, Makefile.in, fnmatch.3: No longer bundle fnmatch.3
+
+2004-12-17 13:12  millert
+
+       * CHANGES, TODO: checkpoint
+
+2004-12-16 14:20  millert
+
+       * sudo.c: sort usage
+
+2004-12-16 14:20  millert
+
+       * sudo.pod: Sort command line options
+
+2004-12-16 13:33  millert
+
+       * def_data.c, def_data.h, def_data.in, defaults.c, logging.c,
+         sudo.c, sudo.pod, sudoers.pod: Add closefrom sudoers option to
+         start closing at a point other than 3.  Add closefrom_override
+         sudoers option and -C sudo flag to allow the user to specify a
+         different closefrom starting point.
+
+2004-12-16 13:25  millert
+
+       * pathnames.h.in: Add _PATH_DEVNULL for those without it.
+
+2004-12-15 22:55  millert
+
+       * LICENSE: no more UCB strcasecmp
+
+2004-12-15 22:54  millert
+
+       * strcasecmp.c: replace BSD licensed one with version derived from
+         pdksh
+
+2004-12-09 21:07  millert
+
+       * sudo.c: Fix last commit.
+
+2004-12-09 19:26  millert
+
+       * sudo.c: Make sure stdin, stdout and stderr are open and dup them
+         to /dev/null if not.
+
+2004-12-03 13:57  millert
+
+       * ldap.c, mon_systrace.c, sudo.c, sudo.h: add sudo_ldap_close
+
+2004-12-03 13:52  millert
+
+       * fileops.c, gettime.c, sudo.c, sudo_edit.c, utimes.c, visudo.c:
+         Use TIME_WITH_SYS_TIME
+
+2004-12-03 13:48  millert
+
+       * configure, configure.in, config.h.in: Add TIME_WITH_SYS_TIME_H
+
+2004-12-02 11:18  millert
+
+       * env.c: Add missing braces to avoid DYLD_FORCE_FLAT_NAMESPACE
+         being set unconditionally on darwin.  From Toby Peterson.
+
+2004-12-02 10:40  millert
+
+       * getspwuid.c: Check rbinsert() return value.  In the case of faked
+         up entries there is usually a negative response cached that we
+         need to overwrite.
+
+         In pwfree() don't try to zero out a NULL pw_passwd pointer.
+
+2004-12-02 09:53  millert
+
+       * mon_systrace.c: Use the double fork trick to avoid the monitor
+         process being waited for by the main program run through sudo.
+
+2004-11-29 12:52  millert
+
+       * sudo.c: Call initgroups() in -U mode so group matches work
+         normally.
+
+2004-11-29 12:34  millert
+
+       * def_data.h, mkdefaults: Don't print a trailing comma for the last
+         entry in enum def_tupple
+
+2004-11-28 16:08  millert
+
+       * sudoers.cat, sudoers.man.in, sudoers.pod: Mention values when
+         lecture, listpw and verifypw are used in boolean context.
+
+2004-11-28 16:05  millert
+
+       * def_data.c, def_data.in: verifypw when used in a boolean TRUE
+         context should be "all", not "any".
+
+2004-11-26 14:21  millert
+
+       * def_data.in, defaults.c: Allow tuples that can be used as
+         booleans to be used as boolean TRUE.  In this case the 2nd
+         possible value of the tuple is used for TRUE.
+
+2004-11-25 12:23  millert
+
+       * configure, configure.in: Correct the test for 2-parameter
+         timespecsub
+
+2004-11-25 12:20  millert
+
+       * sudo.h: Add strub struct definitions for passwd, timeval and
+         timespec
+
+2004-11-25 12:09  millert
+
+       * configure, configure.in, config.h.in, sudo_edit.c, visudo.c: Add
+         check for 2-argument form of timespecsub (FreeBSD and BSD/OS) and
+         fix a typo in the gettimeofday check.
+
+2004-11-24 16:44  millert
+
+       * match.c, testsudoers.c: Deal with user_stat being NULL as it is
+         for visudo and testsudoers.
+
+2004-11-24 16:31  millert
+
+       * parse.c, sudo.c, sudo.cat, sudo.h, sudo.man.in, sudo.pod: Add -U
+         option to use in conjunction with -l instead of -u.  Add support
+         for "sudo -l command" to test a specific command.
+
+2004-11-24 16:28  millert
+
+       * gram.c, gram.y, sudo.c: Set safe_cmnd after sudoers_lookup() if
+         it has not been set.  Previously it was set by sudo "ALL" in the
+         parser but at that point the fully-qualified pathname has not yet
+         been found.
+
+2004-11-23 18:18  millert
+
+       * parse.c, testsudoers.c: Correctly handle multiple privileges per
+         userspec and runas inheritence.
+
+2004-11-21 14:09  millert
+
+       * defaults.c: Zero out sd_un for each entry in sudo_defs_table in
+         init_defaults.
+
+2004-11-19 18:04  millert
+
+       * toke.c, toke.l: make per-command defaults work with sudoedit
+
+2004-11-19 18:00  millert
+
+       * ldap.c, parse.c, sudo.c, sudo.h: Remove the FLAG_NOPASS,
+         FLAG_NOEXEC and FLAG_MONITOR flags.  Instead, we just set the
+         approriate defaults variable.
+
+2004-11-19 17:09  millert
+
+       * sample.sudoers, sudoers.cat, sudoers.man.in, sudoers.pod:
+         Document per-command Defaults.
+
+2004-11-19 16:35  millert
+
+       * defaults.c, defaults.h, gram.c, gram.h, gram.y, mon_systrace.c,
+         sudo.c, testsudoers.c, toke.c, toke.l, visudo.c: Add support for
+         command-specific Defaults entries.  E.g.
+         Defaults!/usr/bin/vi noexec
+
+2004-11-19 15:03  millert
+
+       * defaults.c, match.c, parse.c, parse.h, testsudoers.c: Change an
+         occurence of user_matches() -> runas_matches() missed previously
+         runas_matches(), host_matches() and cmnd_matches() only really
+         need to pass in a list of members.  user_matches() still needs to
+         pass in a passwd struct because of "sudo -l"
+
+2004-11-19 14:46  millert
+
+       * parse.c: Check def_authenticate, def_noexec and def_monitor when
+         setting return flags.  XXX May be better to just set the defaults
+         directly and get rid of those flags.
+
+2004-11-19 13:39  millert
+
+       * alias.c, alloc.c, check.c, closefrom.c, defaults.c, env.c,
+         error.c, fileops.c, find_path.c, fnmatch.c, getcwd.c,
+         getprogname.c, getspwuid.c, gettime.c, glob.c, goodpath.c,
+         gram.c, gram.y, interfaces.c, ldap.c, logging.c, match.c,
+         mon_systrace.c, parse.c, redblack.c, set_perms.c, snprintf.c,
+         strcasecmp.c, strerror.c, strlcat.c, strlcpy.c, sudo.c,
+         sudo_edit.c, sudo_noexec.c, testsudoers.c, tgetpass.c, toke.c,
+         toke.l, utimes.c, visudo.c, zero_bytes.c, auth/afs.c,
+         auth/aix_auth.c, auth/bsdauth.c, auth/dce.c, auth/fwtk.c,
+         auth/kerb4.c, auth/kerb5.c, auth/pam.c, auth/passwd.c,
+         auth/rfc1938.c, auth/secureware.c, auth/securid.c,
+         auth/securid5.c, auth/sia.c, auth/sudo_auth.c: Use: #include
+         <config.h> Not: #include "config.h" That way we get the correct
+         config.h when build dir != src dir
+
+2004-11-19 13:30  millert
+
+       * Makefile.in: Back out part of rev 1.263; fix -I order
+
+2004-11-19 13:12  millert
+
+       * toke.c, toke.l: More robust parsing if #include; could be much
+         better still.
+
+2004-11-19 12:55  millert
+
+       * sudo_edit.c, visudo.c: Make arg splitting in visudo and sudoedit
+         consistent.
+
+2004-11-19 12:35  millert
+
+       * Makefile.in, alias.c, gram.c, gram.y, parse.h: Split alias
+         routines out into their own file.
+
+2004-11-19 12:32  millert
+
+       * error.h: __attribute__ is already defined in compat.h
+
+2004-11-19 12:30  millert
+
+       * visudo.c: quit() should not be __noreturn__ as it is non-void on
+         some platforms.
+
+2004-11-19 12:24  millert
+
+       * auth/: fwtk.c, rfc1938.c, securid.c, securid5.c: Add local
+         error/warning functions like err/warn but that call an additional
+         cleanup routine in the error case.  This means we no longer need
+         to compile a special version of alloc.o for visudo.
+
+2004-11-19 11:54  millert
+
+       * parse.h: Clarify comments about the data structures
+
+2004-11-18 15:28  millert
+
+       * visudo.c: Add support for VISUAL and EDITOR containing command
+         line args.  If env_editor is not set any args in VISUAL and
+         EDITOR are ignored.  Arguments are also now supported in
+         def_editor.
+
+2004-11-17 14:25  millert
+
+       * parse.h: alias_matches() is no more
+
+2004-11-17 14:09  millert
+
+       * CHANGES, TODO: sync
+
+2004-11-17 13:19  millert
+
+       * Makefile.in: When regenerating the parser, don't replace gram.h
+         unless it has changed.
+
+2004-11-17 11:56  millert
+
+       * Makefile.in: remove Makefile.binary for distclean
+
+2004-11-17 11:18  millert
+
+       * env.c: Preserve KRB5CCNAME in zero_env() and add a paranoia check
+         to make sure we can't overflow new_env.
+
+2004-11-17 10:33  millert
+
+       * sudo_edit.c: paranoia when stripping trailing slashes from
+         tempdir.
+
+2004-11-16 19:00  millert
+
+       * sudo.c: Set user_ngroups to 0 if getgroups() returns an error.
+
+2004-11-16 18:59  millert
+
+       * configure, configure.in, config.h.in, sudo.c: Add configure check
+         for getgroups()
+
+2004-11-16 18:55  millert
+
+       * ldap.c: Use supplementary group vector in struct sudo_user.
+
+2004-11-16 18:40  millert
+
+       * match.c: Only do string comparisons on the group members if there
+         is no supplemental group list.
+
+2004-11-16 16:10  millert
+
+       * CHANGES, TODO: sync
+
+2004-11-16 15:54  millert
+
+       * sudo_edit.c: On Digital UNIX _PATH_VAR_TMP doesn't end with a
+         trailing slash so chop off any trailing slashes we see and add an
+         explicit one.
+
+2004-11-16 12:02  millert
+
+       * match.c: remove bogus XXX comment
+
+2004-11-16 11:10  millert
+
+       * match.c: Get rid of alias_matches and correctly fall through to
+         the non-alias cases when there is no alias with the specified
+         name.
+
+2004-11-16 10:47  millert
+
+       * getspwuid.c: Cache non-existent passwd/group entries too.
+
+2004-11-16 10:45  millert
+
+       * gram.c: regen
+
+2004-11-15 23:32  millert
+
+       * getspwuid.c: fix typo
+
+2004-11-15 23:24  millert
+
+       * check.c, getspwuid.c, glob.c, ldap.c, logging.c, match.c,
+         mon_systrace.h, sudo.c, sudo.h, testsudoers.c, visudo.c:
+         Implement group caching and use the passwd and group caches
+         throughout.
+
+2004-11-15 14:43  millert
+
+       * match.c: Properly negate the return value of alias_matches() when
+         appropriate.
+
+2004-11-15 14:38  millert
+
+       * match.c: Make hostname_matches() return TRUE for a match, else
+         FALSE like the caller expects.
+
+2004-11-15 13:24  millert
+
+       * Makefile.in: Add missing dependencies on gram.h
+
+2004-11-15 13:06  millert
+
+       * match.c: Use runas_matches in alias_matches() now that we have
+         it.
+
+2004-11-15 13:00  millert
+
+       * parse.c, parse.h: Expand aliases in "sudo -l" mode
+
+2004-11-15 12:33  millert
+
+       * gram.y, match.c: Use ALIAS for the member type when storing an
+         alias instead of HOSTALIAS/RUNASALIAS/CMNDALIAS/USERALIAS since
+         match.c relies on the more generic type.  Expand runas_matches
+         instead of calling user_matches() inside of it since
+         user_matches() looks up USERALIASes, not RUNASALIASes.
+
+2004-11-15 12:05  millert
+
+       * CHANGES, getspwuid.c: Paranoia; zero out pw_passwd before freeing
+         passwd entry.
+
+2004-11-15 10:53  millert
+
+       * LICENSE, Makefile.in, alloc.c, check.c, config.h.in, configure,
+         configure.in, err.c, error.c, error.h, defaults.c, env.c,
+         find_path.c, interfaces.c, logging.c, mon_systrace.c, sudo.c,
+         sudo.h, sudo_edit.c, testsudoers.c, visudo.c, emul/err.h: Add
+         local error/warning functions like err/warn but that call an
+         additional cleanup routine in the error case.  This means we no
+         longer need to compile a special version of alloc.o for visudo.
+
+2004-11-15 09:59  millert
+
+       * match.c: Use userpw_matches() to compare usernames, not strcmp(),
+         since the latter checks for "#uid".
+
+2004-11-15 09:53  millert
+
+       * getspwuid.c, mon_systrace.c, mon_systrace.h, sudo.c: Cache passwd
+         db entries in 2 reb-black trees; one indexed by uid, the other by
+         user name.  The data returned from the cache should be considered
+         read-only and is destroyed by sudo_endpwent().
+
+2004-11-15 09:50  millert
+
+       * match.c: add cast to uid_t
+
+2004-11-15 09:49  millert
+
+       * gram.y: missing free in alias_destroy
+
+2004-11-15 09:49  millert
+
+       * redblack.c: Can't use rbapply() for rbdestroy since the
+         destructor is passed a data pointer, not a node pointer.
+
+2004-11-14 23:06  millert
+
+       * getspwuid.c, logging.c, sudo.c, sudo.h: Create and use private
+         versions of setpwent() and endpwent() that set/end the shadow
+         password file too.
+
+2004-11-14 22:55  millert
+
+       * gram.c, gram.h, gram.y, match.c, parse.h, testsudoers.c,
+         visudo.c: Store aliases in a red-black tree.
+
+2004-11-14 22:52  millert
+
+       * Makefile.in, redblack.c, redblack.h: red-black tree
+         implementation
+
+2004-11-14 22:37  millert
+
+       * visudo.c: Edit all sudoers file if there were unused or undefined
+         aliases and we are in strict mode.
+
+2004-11-12 11:19  millert
+
+       * CHANGES, def_data.c, def_data.h, def_data.in, defaults.c, env.c,
+         find_path.c, sudoers.cat, sudoers.man.in, sudoers.pod, visudo.c:
+         Bring back the "secure_path" Defaults option now that Defaults
+         take effect before the path is searched.
+
+2004-11-11 12:22  millert
+
+       * logging.c, parse.c: A user can always list their own entries,
+         even with -u.  Better error message when failing to list another
+         user's entries.
+
+2004-11-11 12:12  millert
+
+       * parse.c, sudo.c, sudo.h: The syntax to list another user's
+         entries is now "-u otheruser -l".  Only root or users with sudo
+         "ALL" may list other user's entries.
+
+2004-11-11 11:30  millert
+
+       * sudo.cat, sudo.man.in, sudo.pod: Update env variable info in
+         SECURITY NOTES
+
+2004-11-11 11:25  millert
+
+       * env.c: strip CDPATH too
+
+2004-11-11 11:20  millert
+
+       * env.c: strip exported bash functions from the environment.
+
+2004-10-27 12:16  millert
+
+       * sudo.c: Only reset sudo_user.pw based on SUDO_USER environment
+         variables for real commands and sudoedit.  This avoids a
+         confusing message when a user tries "sudo -l" or "sudo -v" and is
+         denied.
+
+2004-10-27 12:06  millert
+
+       * gram.c, gram.y, parse.h: Extend LIST_APPEND to deal with
+         appending lists too
+
+2004-10-26 18:39  millert
+
+       * logging.c: Convert some bitwise AND to ISSET
+
+2004-10-26 18:29  millert
+
+       * lex.yy.c, toke.c: toke.c replaces lex.yy.c
+
+2004-10-26 18:29  millert
+
+       * CHANGES, TODO: sync
+
+2004-10-26 18:28  millert
+
+       * BUGS: new parser fixes most of the outstanding bugs
+
+2004-10-26 18:27  millert
+
+       * configure: regen
+
+2004-10-26 18:26  millert
+
+       * visudo.c: Rework for the new parser.  Now checks for unused
+         aliases in sudoers.
+
+2004-10-26 18:25  millert
+
+       * testsudoers.c: Rewrite for the new parser.  Now supports a -d
+         flag (dump) and adds a -h flag (host).  It now defaults to the
+         local hostname unless otherwise specified.
+
+2004-10-26 18:23  millert
+
+       * sudo.h: Add new prototypes.  Remove NOMATCH/UNSPEC (now in
+         parse.h)
+
+2004-10-26 18:22  millert
+
+       * sudo.c: Update for new parse.  We now call find_path() *after* we
+         have updated the global defaults based on sudoers.  Also adds
+         support for listing other user's privs if you are root.
+
+2004-10-26 18:21  millert
+
+       * mon_systrace.c: Working LDAP support; also remove a now-unneeded
+         rewind().
+
+2004-10-26 18:20  millert
+
+       * logging.c, logging.h: Add NO_STDERR flag.
+
+2004-10-26 18:19  millert
+
+       * ldap.c: Split sudo_ldap_check() into three pieces:
+         sudo_ldap_open(), udo_ldap_update_defaults() and
+         sudo_ldap_check().  This allows us to connecto to LDAP, apply the
+         default options, find the command in the user's path, and then
+         check whether the user is allowed to run it.  The important thing
+         here is that the default runas user may be specified as a default
+         option and that needs to be set before we search for the command.
+
+2004-10-26 18:17  millert
+
+       * ldap.c: Add casts to unsigned char for isspace() to quiet a gcc
+         warning.
+
+2004-10-26 18:16  millert
+
+       * defaults.h: Add prototype for update_defaults()
+
+2004-10-26 18:16  millert
+
+       * defaults.c: Don't warn about line numbers now that we operate on
+         a set of data structures (or LDAP) and not a file.
+
+2004-10-26 18:15  millert
+
+       * config.h.in: No long use lsearch()
+
+2004-10-26 18:14  millert
+
+       * Makefile.in: Update for new and changed file names.
+
+2004-10-26 18:14  millert
+
+       * LICENSE: no more BSD lsearch.c
+
+2004-10-26 18:14  millert
+
+       * match.c: foo_matches() routines now live in match.c Added
+         user_matches(), runas_matches(), host_matches(), cmnd_matches()
+         and alias_matches() that operate on the parsed sudoers file.
+
+2004-10-26 18:12  millert
+
+       * parse.lex, toke.l: Move parse.lex -> toke.l Rename buffer_frob()
+         -> switch_buffer() WORD no longer needs to exclude '@' kill
+         yywrap()
+
+2004-10-26 18:10  millert
+
+       * gram.c, gram.h, gram.y, parse.c, parse.h, parse.yacc, sudo.tab.h:
+         Rewritten parser that converts sudoers into a set of data
+         structures.  This eliminates ordering issues and makes it
+         possible to apply sudoers Defaults entries before searching for
+         the command.
+
+2004-10-26 18:09  millert
+
+       * configure.in, lsearch.c, emul/search.h: We won't be using
+         lsearch() any longer.
+
+2004-10-26 18:07  millert
+
+       * ldap.c: sudo should not send mail if someone who runs 'sudo -l'
+         has no entry.
+
+2004-10-26 16:09  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in, visudo.cat,
+         visudo.man.in: regen
+
+2004-10-26 16:09  millert
+
+       * visudo.pod: Update warnings to match new visudo
+
+2004-10-26 16:08  millert
+
+       * sudoers.pod: The new parser doesn't have the old ordering
+         constraints.
+
+2004-10-26 16:08  millert
+
+       * sudo.pod: Document that -l now takes an optional username
+         argument
+
+2004-10-25 13:44  millert
+
+       * RUNSON: AIX 5.2.0.0 works
+
+2004-10-25 13:38  millert
+
+       * ldap.c: If LDAP_OPT_SUCCESS is not defined, use LDAP_SUCCESS
+         instead.  Fixes a compilation problem with Solaris 9's native
+         LDAP.
+
+         Set FLAG_MONITOR when needed.
+
+2004-10-23 13:32  millert
+
+       * mon_systrace.c: Call sudo_goodpath() *after* changing the cwd to
+         match the traced process.  Fixes relative paths.
+
+2004-10-21 12:31  millert
+
+       * testsudoers.c: Kill set_perms() stub--it is no longer needed.
+
+2004-10-13 12:52  millert
+
+       * sudoers.cat, sudoers.man.in, sudoers.pod: stay_setuid now
+         requires set_reuid() or setresuid()
+
+2004-10-13 12:46  millert
+
+       * INSTALL, PORTING, TROUBLESHOOTING, config.h.in, configure,
+         configure.in, set_perms.c, sudo.c, sudo.h: Kill use of POSIX
+         saved uids; they aren't worth bothering with.
+
+2004-10-07 16:23  millert
+
+       * glob.c: remove call to issetugid()
+
+2004-10-07 14:57  millert
+
+       * sudoers.cat, sudoers.man.in, sudoers.pod: Remove warning about
+         wildcards.  Now that we use glob() the bug is fixed.
+
+2004-10-07 14:52  millert
+
+       * parse.c: Use glob(3) instead of fnmatch(3) for matching pathnames
+         and stat each result that matches the basename of the user's
+         command.  This makes "cd /usr/bin ; sudo ./blah" work when
+         sudoers allows /usr/bin/blah.  Fixes bug #143.
+
+2004-10-07 14:27  millert
+
+       * configure, configure.in, config.h.in: Define HAVE_EXTENDED_GLOB
+         for extended glob (GLOB_TILDE and GLOB_BRACE)
+
+2004-10-07 12:59  millert
+
+       * config.h.in, configure, configure.in: Check for a glob() that
+         supports GLOB_BRACE and GLOB_TILDE
+
+2004-10-07 12:51  millert
+
+       * LICENSE: reference glob
+
+2004-10-07 12:50  millert
+
+       * glob.c, emul/glob.h: 4.4BSD glob(3) with fixes from OpenBSD and
+         some unneeded extensions removed.
+
+2004-10-05 17:26  millert
+
+       * mon_systrace.c: Just return if STRIOCINJECT or STRIOCREPLACE
+         fail.  It probably means we are out of space in the stack gap...
+
+2004-10-05 17:20  millert
+
+       * CHANGES: sync
+
+2004-10-05 16:53  millert
+
+       * mon_systrace.c: Take a stab at ldap sudoers support here.
+
+2004-10-05 15:13  millert
+
+       * mon_systrace.c, mon_systrace.h: Detach from tracee on SIGHUP,
+         SIGINT and SIGTERM.  Now "sudo reboot" doesn't cause reboot to
+         inadvertanly kill itself.
+
+2004-10-05 14:21  millert
+
+       * mon_systrace.c: put "monitor" in the proctitle, not "systrace"
+
+2004-10-05 14:15  millert
+
+       * mon_systrace.c: When modifying the environment, don't replace
+         envp when we can get away with just rewriting pointers in the
+         traced process.
+
+2004-10-05 13:46  millert
+
+       * mon_systrace.c, mon_systrace.h: Add environment updating via
+         STRIOCINJECT (if available).
+
+2004-10-05 10:22  millert
+
+       * sudoers.cat, sudoers.man.in: regen
+
+2004-10-04 16:15  millert
+
+       * lex.yy.c: regen
+
+2004-10-04 16:15  millert
+
+       * parse.lex: Fix bug introduced in unput() removal; want yyless(0)
+         not yyless(1)
+
+2004-10-04 12:09  millert
+
+       * mon_systrace.c: Include file is now mon_systrace.h
+
+2004-10-04 12:07  millert
+
+       * Makefile.in, configure, configure.in, def_data.c, def_data.h,
+         def_data.in, lex.yy.c, parse.c, parse.h, parse.lex, parse.yacc,
+         sudo.c, sudo.h, sudo.tab.h, sudoers.pod: No longer call it
+         tracing, it is now "monitoring" which should be more a obvious
+         name to non-hackers.
+
+2004-10-01 15:06  millert
+
+       * mon_systrace.c, mon_systrace.h: Fix some XXX
+
+2004-10-01 14:30  millert
+
+       * mon_systrace.c, mon_systrace.h: No need to include syscall.h, use
+         1024 as the max # of entries (the max that systrace(4) allows).
+
+         Only need to use SYSTR_POLICY_ASSIGN once
+
+         Change check_syscall() -> find_handler() and have it return the
+         handler instead of just running it.  We need this since handler
+         now have two parts: one part that generates and answer and
+         another that gets called after the answer is accepted (to do
+         logging).
+
+         Add some missing check_exec for emul execv
+
+2004-10-01 10:58  millert
+
+       * sample.pam, sample.sudoers, sample.syslog.conf, sudoers: Add
+         $Sudo: ChangeLog,v 1.19 2008/12/19 17:40:39 millert Exp $ tags.
+
+2004-10-01 10:47  millert
+
+       * config.h.in: Add missing HAVE_LINUX_SYSTRACE_H
+
+2004-09-30 20:46  millert
+
+       * Makefile.in: add trace_systrace.o dependency
+
+2004-09-30 19:00  millert
+
+       * configure, configure.in: Also look for systrace.h in
+         /usr/include/linux
+
+2004-09-30 18:27  millert
+
+       * mon_systrace.c, mon_systrace.h: Move all struct defs and
+         prototypes into trace_systrace.h and mark all but
+         systace_attach() static.
+
+2004-09-30 18:14  millert
+
+       * mon_systrace.c, mon_systrace.h: Add support for tracing
+         emulations.  At the moment, all emulations are compiled in.  It
+         might make sense to #ifdef them in the future, though this
+         impeeds readability.
+
+2004-09-30 17:07  millert
+
+       * Makefile.in, configure.in, configure: rename systrace.c ->
+         trace_systrace.c
+
+2004-09-30 15:58  millert
+
+       * parse.yacc: Allow this to build with a K&R compiler again
+
+2004-09-30 13:58  millert
+
+       * TODO: sync
+
+2004-09-30 13:55  millert
+
+       * sudo.c, compat.h, visudo.c: Use __attribute__((__noreturn__))
+
+2004-09-30 13:44  millert
+
+       * visudo.c: Exit() takes a negative value to indicate it was not
+         called via signal.
+
+2004-09-30 13:25  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in, visudo.cat,
+         visudo.man.in: regen
+
+2004-09-30 13:22  millert
+
+       * Makefile.in, visudo.c: Define Err() and Errx() that are like
+         err() and errx() but call Exit() instead of exit().  Build
+         private copy of alloc.o for visudo that calls Err() and Errx().
+
+2004-09-29 15:22  millert
+
+       * lex.yy.c: regen
+
+2004-09-29 15:22  millert
+
+       * CHANGES: sync
+
+2004-09-29 14:41  millert
+
+       * visudo.c: Overhaul visudo for editing multiple files:  o visudo
+         has been broken out into functions (more work needed here)  o
+         each file is now edited before sudoers is re-parsed  o if a
+         #include line is added that file will be edited too
+
+         TODO:  o cleanup temp files when exiting via err() or errx()  o
+         continue breaking things out into separate functions
+
+2004-09-29 14:36  millert
+
+       * parse.lex, sudo.c, sudo.h, testsudoers.c, visudo.c: Add keepopen
+         arg to open_sudoers that open_sudoers can use to indicate to the
+         caller that the fd should not be closed when it is done with it.
+         To be used by visudo to keep locked fds from being closed
+         prematurely (and thus losing the lock).
+
+2004-09-29 14:33  millert
+
+       * parse.yacc, sudo.c: Add errorfile global that contains the name
+         of the file that caused the error.
+
+2004-09-29 14:30  millert
+
+       * parse.lex: return COMMENT to yacc grammar for a #include line
+
+2004-09-29 14:29  millert
+
+       * parse.lex: Remove us of unput() in favor of yyless() which is
+         cheaper.
+
+2004-09-29 14:28  millert
+
+       * parse.yacc: Allow an empty sudoers file.
+
+2004-09-28 16:50  millert
+
+       * mon_systrace.c: Rewind sudoers_fp now that sudoers_lookup()
+         doesn't do it for us.
+
+2004-09-28 14:37  millert
+
+       * lex.yy.c: regen
+
+2004-09-28 14:36  millert
+
+       * visudo.c: Do signal setup before calling edit_sudoers().  Don't
+         shadow the "quiet" global.
+
+2004-09-28 14:33  millert
+
+       * visudo.c: If a sudoers file includes other files, edit those too.
+         Does not yes deal with creating the new includes files itself.
+
+2004-09-28 14:31  millert
+
+       * testsudoers.c: init_parser now takes a path
+
+2004-09-28 14:31  millert
+
+       * parse.c, parse.h, parse.lex, parse.yacc: More scaffolding for
+         dealing with multiple sudoers files:  o init_parser() now takes a
+         path used to populate the sudoers global  o the sudoers global is
+         used to print the correct file in yyerror()  o when switching to
+         a new sudoers file, perserve old file name and line number
+
+2004-09-28 14:29  millert
+
+       * Makefile.in, pathnames.h.in: Kill _PATH_SUDOERS_TMP; it is not
+         meaningful now that we can have multiple sudoers files.
+
+2004-09-28 13:52  millert
+
+       * parse.c, sudo.c: Rewind sudoers_fp in open_sudoers() instead of
+         sudoers_lookup() so we start at the right file position when
+         reading include files.
+
+2004-09-27 21:04  millert
+
+       * sudoers.pod: document #include
+
+2004-09-27 20:47  millert
+
+       * lex.yy.c: regen
+
+2004-09-27 20:47  millert
+
+       * parse.lex: Add max depth of 128 for the include stack to avoid
+         loops.
+
+         Since yyerror() doesn't stop parsing, pass return values back to
+         yylex and call yyterminate() on error.
+
+2004-09-27 14:06  millert
+
+       * sudoers.pod: document tracing
+
+2004-09-27 14:05  millert
+
+       * sudo.pod: Mention PREVENTING SHELL ESCAPES section of sudoers man
+         page
+
+2004-09-27 12:08  millert
+
+       * lex.yy.c: regen
+
+2004-09-27 12:03  millert
+
+       * parse.lex: Add support for #include in sudoers (visudo support
+         TBD)
+
+2004-09-27 12:02  millert
+
+       * parse.yacc: make yyerror()'s argument const
+
+2004-09-27 12:02  millert
+
+       * testsudoers.c, visudo.c: Add open_sudoers() stubs.
+
+2004-09-27 12:01  millert
+
+       * sudo.c, sudo.h: Rename check_sudoers() open_sudoers() and make it
+         return a FILE *
+
+2004-09-26 12:35  millert
+
+       * BUGS, INSTALL, INSTALL.binary, Makefile.in, README, configure.in,
+         version.h: Crank version
+
+2004-09-26 12:33  millert
+
+       * Makefile.in, sudo.psf: Better HP-UX depot construction
+
+2004-09-25 17:08  millert
+
+       * mon_systrace.c: o Made children global so check_exec() can lookup
+         a child.  o Replaced uid in struct childinfo with struct passwd *
+         (for runas) o new_child() now takes a parent pid so the runas
+         info can be inherited o Added find_child() to lookup a child by
+         its pid o update_child() now fills in a struct passwd o Converted
+         the big if/else mess in set_policy to a switch o Syscalls that
+         change uid are now "ask" so we get SYSTR_MSG_UGID events
+
+2004-09-25 17:01  millert
+
+       * getspwuid.c: Add flag to sudo_pwdup that indicates whether or not
+         to lookup the shadow password.  Will be used to a struct passwd
+         that has the shadow password already filled in.
+
+2004-09-25 16:58  millert
+
+       * mon_systrace.c: add missing increment of addr in read_string()
+
+2004-09-25 16:15  millert
+
+       * mon_systrace.c: Remove bogus call to update_child() and some
+         cosmetic fixes
+
+2004-09-25 16:11  millert
+
+       * mon_systrace.c: Don't leak /dev/systrace fd to tracee Make
+         initialized global for simplicity If STRIOCATTACH returns EBUSY
+         we are already being traced Check for user_args == NULL in
+         setproctitle() call Add missing calls to STRIOCANSWER
+
+2004-09-25 13:15  millert
+
+       * sudo.c: g/c sudo_pwdup proto
+
+2004-09-24 20:21  millert
+
+       * Makefile.in, sudo.psf: Add target for building a depot file
+
+2004-09-24 20:07  millert
+
+       * mon_systrace.c: trim includes
+
+2004-09-24 14:11  millert
+
+       * lex.yy.c, sudo.tab.h: regen
+
+2004-09-24 14:10  millert
+
+       * INSTALL: document --with-systrace
+
+2004-09-24 14:10  millert
+
+       * config.h.in, configure, configure.in: Add check for setproctitle
+
+2004-09-24 14:09  millert
+
+       * mon_systrace.c: pass struct str_msg_ask in to syscall checker so
+         it can set the error code
+
+2004-09-24 13:30  millert
+
+       * mon_systrace.c: systrace(4) support for sudo.  On systems with
+         the systrace(4) kernel facility (OpenBSD, NetBSD, Linux w/
+         patches) sudo can intercept exec calls and check the exec args
+         against the sudoers file.  In other words, sudo can now control
+         subcommands and shell escapes.
+
+2004-09-24 13:17  millert
+
+       * sudo.c, sudo.h: Call systrace_attach() if FLAG_TRACE is set.
+
+2004-09-24 13:15  millert
+
+       * parse.c, parse.h, parse.lex, parse.yacc, sudo.h: Add trace
+         Defaults option and TRACE/NOTRACE tags and set FLAG_TRACE
+
+2004-09-24 13:13  millert
+
+       * parse.c, sudo.c: Don't close sudoers_fp, keep it open and set
+         close on exec flag instead.
+
+2004-09-24 13:11  millert
+
+       * def_data.c, def_data.h, def_data.in: Add trace option
+
+2004-09-23 20:24  millert
+
+       * Makefile.in: Add systrace
+
+2004-09-23 20:23  millert
+
+       * INSTALL: SunOS /bin/sh blows up with configure
+
+2004-09-23 20:23  millert
+
+       * configure, configure.in: Include sys/param.h before systrace.h
+
+2004-09-23 20:15  millert
+
+       * configure: regen
+
+2004-09-23 20:15  millert
+
+       * pathnames.h.in: _PATH_DEV_SYSTRACE
+
+2004-09-23 20:14  millert
+
+       * configure.in: line up options in --help
+
+2004-09-23 20:11  millert
+
+       * config.h.in, configure.in: Add --with-systrace
+
+2004-09-23 13:35  millert
+
+       * configure: regen
+
+2004-09-23 13:35  millert
+
+       * aclocal.m4, configure.in: make this work with autoconf-2.59
+
+2004-09-16 12:58  millert
+
+       * sudo_edit.c: Simplify logic around open & stat of files and do
+         sanity on edited file even if we lack fstat (still racable but
+         worth doing).
+
+2004-09-15 18:47  millert
+
+       * HISTORY: Add support url
+
+2004-09-15 16:11  millert
+
+       * Makefile.in: versino 1.6.8p1
+
+2004-09-15 15:20  millert
+
+       * CHANGES: more changes for 1.6.8p1
+
+2004-09-15 15:18  millert
+
+       * version.h: 1.6.8p1
+
+2004-09-15 12:16  millert
+
+       * CHANGES, sudo_edit.c: Add sanity check so we don't try to edit
+         something other than a regular file.
+
+2004-09-14 20:55  aaron
+
+       * CHANGES: sync
+
+2004-09-14 20:21  aaron
+
+       * INSTALL: document --with-ldap-conf-file
+
+2004-09-14 17:43  millert
+
+       * CHANGES, ins_csops.h: political correctness strikes again
+
+2004-09-14 15:09  millert
+
+       * RUNSON: sync
+
+2004-09-12 19:50  millert
+
+       * Makefile.binary.in, Makefile.in: Install sudoedit man link
+
+2004-09-12 14:25  millert
+
+       * INSTALL: Update PAM note and mention where HP-UX users can
+         download gcc binaries.
+
+2004-09-12 12:08  millert
+
+       * Makefile.in: libtool wants to install stuff from .libs so fake
+         one up for binary installations.
+
+2004-09-12 11:53  millert
+
+       * Makefile.binary.in: rm -f old sudoedit link instead of using ln
+         -f set LIBTOOL correctly
+
+2004-09-12 11:53  millert
+
+       * Makefile.in: Deal with "uname -m" having slashes in it rm -f old
+         sudoedit link instead of using ln -f
+
+2004-09-12 10:22  millert
+
+       * Makefile.binary, Makefile.binary.in: Makefile.binary ->
+         Makefile.binary.in for config.status substitution Add support for
+         installing noexec bits
+
+2004-09-12 10:21  millert
+
+       * Makefile.in: Copy noexec bits into binary dists too No longer use
+         my old arch script for making binary dists
+
+2004-09-12 09:36  millert
+
+       * Makefile.binary: Install sudoedit link.
+
+2004-09-11 12:25  millert
+
+       * emul/utime.h: avoid __P so there is no need for compat.h to be
+         included
+
+2004-09-11 12:24  millert
+
+       * utimes.c: Don't use HAVE_UTIME_H before including config.h.
+
+2004-09-10 12:31  millert
+
+       * compat.h: Fix Solatis futimes macro
+
+2004-09-09 11:02  millert
+
+       * sudo_edit.c: Rename ots -> omtim for improved readability.
+
+2004-09-08 14:38  millert
+
+       * sudo_edit.c: Redo changes in revision 1.7.  Don't really need to
+         keep the temp file open; re-opening it with the invoking user's
+         euid is sufficient.
+
+2004-09-08 14:36  millert
+
+       * CHANGES: sync
+
+2004-09-08 14:35  millert
+
+       * sudo.cat, sudo.man.in: regen
+
+2004-09-08 14:34  millert
+
+       * sudo.pod: back out revision 1.70; it is no long applicable
+
+2004-09-08 11:57  millert
+
+       * env.c: Let the loader initialize nep
+
+2004-09-08 11:49  millert
+
+       * configure, configure.in, config.h.in: Removed unneed check for
+         fchown Add check for gettimeofday Move autoheader template stuff
+         into separate AH_TEMPLATE lines
+
+2004-09-08 11:48  millert
+
+       * check.c, compat.h, fileops.c, sudo.h, sudo_edit.c, visudo.c: Use
+         timespec throughout.
+
+2004-09-08 11:47  millert
+
+       * Makefile.in: gettime.[co]
+
+2004-09-08 11:47  millert
+
+       * gettime.c: function to return the current time in a struct
+         timespec
+
+2004-09-08 10:51  millert
+
+       * utimes.c: Not a darpa-sponsored file.
+
+2004-09-07 16:36  millert
+
+       * compat.h, config.h.in, configure, configure.in: Add a check for
+         struct timespec and provide it for those without.
+
+2004-09-07 15:56  millert
+
+       * config.h.in, configure, configure.in, sudo_edit.c: Add checks for
+         st_mtim and st_mtimespec and add macros for pulling the mtime sec
+         and nsec out of struct stat.  These are used in sudo_edit() to
+         better tell whether or not the file has changed.
+
+2004-09-07 15:55  millert
+
+       * check.c, fileops.c, sudo.h, sudo_edit.c, visudo.c: Add an extra
+         param to touch() for nsec
+
+2004-09-07 14:06  millert
+
+       * sudo_edit.c: Call mkstemp() as the in invoking user so we don't
+         have to chown the file later.  Only touch() the temp file if we
+         can do it via the file descriptor.  Don't check for modification
+         of the temp file if we lack fstat().  Catch errors read()ing the
+         temp file.
+
+2004-09-07 14:04  millert
+
+       * fileops.c: If path is NULL and fd == -1 return -1.
+
+2004-09-07 13:31  millert
+
+       * sudo_edit.c: closefrom() is overkill, the only extra fds are the
+         ones we opened so just close those in the child.
+
+2004-09-07 13:14  millert
+
+       * Makefile.in, aclocal.m4, check.c, compat.h, config.h.in,
+         configure, configure.in, fileops.c, sudo.h, sudo_edit.c, utime.c,
+         utimes.c, visudo.c: Use utimes() and futimes() instead of utime()
+         in touch(), emulating as needed.  Not all systems are able to
+         support setting the times of an fd so touch() takes both an fd
+         and a file name as arguments.
+
+2004-09-06 21:12  aaron
+
+       * env.c: Rare SEGV
+
+2004-09-06 16:46  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in, visudo.cat,
+         visudo.man.in: regen
+
+2004-09-06 16:45  millert
+
+       * sudo.pod, sudoers.pod, visudo.pod: Add SUPPORT section and
+         re-order some of the sections to match the order we use in
+         OpenBSD.
+
+2004-09-06 15:05  aaron
+
+       * env.c: Openldap ~/.ldaprc fix
+
+2004-09-06 12:18  millert
+
+       * sudo.pod: Talk about how the editor must write its changes to the
+         original file and not just use rename(2).
+
+2004-09-06 12:12  millert
+
+       * CHANGES: sync
+
+2004-09-06 12:11  millert
+
+       * sudo_edit.c: Keep the temp file open instead of re-opening after
+         the editor has exited.
+
+2004-09-06 12:10  millert
+
+       * sample.pam: Update for current redhat/fedora core.
+
+2004-09-02 21:56  aaron
+
+       * README.LDAP: tls_ examples
+
+2004-09-02 00:03  aaron
+
+       * ldap.c: config tls_* options
+
+2004-08-29 11:39  millert
+
+       * configure, configure.in: No need for -lcrypt when using pam.
+
+2004-08-26 23:57  millert
+
+       * configure: regen
+
+2004-08-26 23:44  aaron
+
+       * configure.in, ldap.c, pathnames.h.in: Allow --with-ldap-conf-file
+         option to override LDAP_CONF
+
+2004-08-26 22:08  aaron
+
+       * ldap.c: cleanup debug message
+
+2004-08-26 19:29  aaron
+
+       * README.LDAP: more config info
+
+2004-08-24 14:01  millert
+
+       * TODO, find_path.c, goodpath.c, parse.c, sudo.c, sudo.h, visudo.c:
+         Add cmnd_base to struct sudo_user and set it in init_vars().  Add
+         cmnd_stat to struct sudo_user and set it in sudo_goodpath().  No
+         longer use gross statics in command_matches().  Also rename some
+         variables for improved clarity.
+
+2004-08-21 14:33  millert
+
+       * INSTALL: document HP's crippled compiler deficiency.
+
+2004-08-21 14:25  millert
+
+       * INSTALL: Fix some thinkos in --with-editor and --with-env-editor
+         descriptions.  Noticed by Norihiko Murase.
+
+2004-08-21 14:20  millert
+
+       * configure, configure.in: --with-noexec takes an optional PATH
+         argument.
+
+2004-08-21 14:20  millert
+
+       * INSTALL: document --with-noexec
+
+2004-08-17 16:21  millert
+
+       * RUNSON, TODO: sync
+
+2004-08-17 15:11  millert
+
+       * sudo_edit.c: Better warning message when sudoedit is unable to
+         write to the destination file.
+
+2004-08-17 14:53  millert
+
+       * sudo.cat, sudo.man.in: regen
+
+2004-08-17 14:53  millert
+
+       * sudo.pod: Don't italicize the string "sudoedit"
+
+2004-08-16 18:45  millert
+
+       * HISTORY: Mention GratiSoft.
+
+2004-08-11 14:29  millert
+
+       * parse.yacc: Reset used_runas to FALSE when re-intializing the
+         parser.
+
+2004-08-09 19:04  millert
+
+       * config.guess: Correct OpenBSD mips support
+
+2004-08-09 17:28  millert
+
+       * config.guess: Add OpenBSD/mips
+
+2004-08-06 23:43  aaron
+
+       * README.LDAP: More behavior notes
+
+2004-08-06 23:36  aaron
+
+       * README.LDAP: Updates on current behavior
+
+2004-08-06 19:56  millert
+
+       * sudo.pod, sudoers.pod: =back does not take an indentlevel (makes
+         no difference to formatted files).
+
+2004-08-06 19:48  millert
+
+       * CHANGES: new
+
+2004-08-06 19:42  millert
+
+       * sudo.c: Consistency.  Use same error for bad -u #uid when
+         targetpw is set as we do when a bad -u username is specified.
+
+2004-08-06 19:33  millert
+
+       * TODO: Add checksum idea from Steve Mancini
+
+2004-08-06 19:32  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in: regen
+
+2004-08-06 19:31  millert
+
+       * sudo.pod, sudoers.pod: Document the restriction on uids specified
+         via -u when targetpw is set.
+
+2004-08-06 19:24  millert
+
+       * sudo.c: Error out when targetpw is enabled and sudo is run with
+         -u #uid but #uid does not exist in the passwd database.  We can't
+         do target authentication when the target is not in passwd!
+
+2004-08-05 21:16  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in: regen
+
+2004-08-05 21:14  millert
+
+       * TODO: Some more todo for the next release.
+
+2004-08-05 21:13  millert
+
+       * INSTALL: Make it clear that PAM should be used for DCE support
+         when possible.
+
+2004-08-05 21:13  millert
+
+       * sudoers.pod: o Document problems with wildcards and relative
+         paths.  o Make the order requirements more prominent.  o Change a
+         "set" to "reset" for clarity.
+
+2004-08-05 14:29  millert
+
+       * sudo.pod: Mention --with-secure-path, not SECURE_PATH.
+
+2004-08-02 22:34  aaron
+
+       * ldap.c: reflect changes to parse.c
+
+2004-08-02 14:44  millert
+
+       * parse.c, parse.h, parse.yacc, testsudoers.c, visudo.c: Don't pass
+         user_cmnd and user_args to command_matches(), just use the
+         globals there.  Since we keep state with statics anyway it is
+         misleading to pretend that passing in different cmnd and
+         cmnd_args will work.
+
+2004-08-02 14:40  millert
+
+       * parse.c: Fix a bug introduced in rev. 1.149.  When checking for
+         pseudo-commands check for a '/' anywhere in cmnd, not just the
+         first character.
+
+2004-07-30 23:07  aaron
+
+       * sudo.man.in, sudo.pod: Clarification thanks to Olivier Blin
+         <oblin@mandrakesoft.com>
+
+2004-07-30 22:41  aaron
+
+       * sudoers.man.in, sudoers.pod: Add ignore_local_sudoers
+
+2004-07-30 22:06  aaron
+
+       * README.LDAP: Sun One schema definition by
+         Andreas.Bussjaeger@t-systems.com and janth@moldung.no
+
+2004-07-29 11:57  millert
+
+       * CHANGES: typo
+
+2004-07-23 16:44  millert
+
+       * CHANGES: sync
+
+2004-07-23 16:43  millert
+
+       * parse.c: Parse sudoers file as PERM_RUNAS not PERM_ROOT and
+         remove a useless PERM_SUDOERS.  Restore to PERM_ROOT upon exit of
+         the parse.
+
+2004-07-08 10:20  millert
+
+       * CHANGES: PAM change
+
+2004-07-07 21:04  aaron
+
+       * ldap.c: Better debugging of ALL command
+
+2004-07-07 20:15  millert
+
+       * parse.c: When matching for "sudoedit" in sudoers check both the
+         command the user typed *and* the command that is listed in the
+         sudoers entry.
+
+2004-07-04 19:59  aaron
+
+       * ldap.c: Added !command feature
+
+2004-06-28 10:51  millert
+
+       * auth/pam.c: Use pam_acct_mgmt() to check for disabled accounts;
+         Brian Farrell
+
+2004-06-10 23:11  millert
+
+       * LICENSE: License is ISC-style, not BSD-style
+
+2004-06-10 20:58  millert
+
+       * CHANGES: sync
+
+2004-06-10 16:54  millert
+
+       * sudo.man.in, sudo.cat: regen
+
+2004-06-10 16:53  millert
+
+       * sudo.pod: o Update some out of date bits to reality o Change the
+         shell promt in examples to bourne-shell style o Clarify some
+         details o Add a CAVEAT about "sudo cd /foo"
+
+2004-06-10 16:19  millert
+
+       * check.c: Don't ask for a password if invoking user == target
+         user.
+
+2004-06-10 12:32  millert
+
+       * sudo.c: typo in comment
+
+2004-06-08 19:20  millert
+
+       * sudoers.man.in, sudoers.cat: regen
+
+2004-06-08 19:19  millert
+
+       * sudoers.pod: Expand on NOEXEC a little.
+
+2004-06-08 16:20  millert
+
+       * TODO: sync
+
+2004-06-08 15:58  millert
+
+       * visudo.man.in, visudo.cat: regen
+
+2004-06-08 15:55  millert
+
+       * CHANGES, parse.yacc, visudo.c, visudo.pod: Add a check in visudo
+         for runas_default being set after it has already been used.
+
+2004-06-08 13:53  millert
+
+       * parse.yacc: Add a MATCHED macro for testing whether foo_matches
+         has been set to TRUE or FALSE.  This is more readable than
+         checking for >=0 or < 0.  Doesn't change the actual code
+         generated.
+
+2004-06-06 20:11  millert
+
+       * sudoers.man.in, sudoers.cat: regen
+
+2004-06-06 20:07  millert
+
+       * sudoers, sudoers.pod: Correct description of where Defaults specs
+         should go.
+
+2004-06-06 20:02  millert
+
+       * find_path.c, ldap.c, logging.h, testsudoers.c, visudo.c,
+         auth/bsdauth.c, auth/kerb5.c, auth/pam.c: update (c) year
+
+2004-06-06 19:58  millert
+
+       * check.c, compat.h, defaults.c, env.c, find_path.c, getcwd.c,
+         ldap.c, logging.h, parse.c, parse.yacc, sudo.c, testsudoers.c,
+         tgetpass.c, visudo.c, auth/bsdauth.c, auth/kerb5.c, auth/pam.c:
+         Remove trailing spaces, no actual code changes.
+
+2004-06-06 16:22  millert
+
+       * parse.yacc: Fix a >=0 that should be <0 that was improperly
+         converted when UNSPEC was added.
+
+2004-06-06 15:54  millert
+
+       * parse.yacc: Add do {} while(0) around pop macro Set cmnd_matches
+         to UNSPEC, not NOMATCH when resetting it.
+
+2004-06-06 15:39  millert
+
+       * parse.yacc: Fix pastos introduced in SETNMATCH addition.
+
+2004-06-05 13:55  millert
+
+       * README.LDAP: Update for configure changes
+
+2004-06-05 13:42  millert
+
+       * parse.yacc, sudo.h: Add NOMATCH and UNSPEC defines (-1 and -2
+         respectively) and use these in parse.yacc.  Also in parse.yacc
+         initialize the *_matches vars to UNSPEC and add two macros,
+         SETMATCH and SETNMATCH for use when setting *_matches to a value
+         that may be NOMATCH/UNSPEC/TRUE/FALSE.
+
+2004-06-05 11:17  millert
+
+       * parse.yacc: Initialize runas to -2, not -1 since we need to be
+         able to distinguish between the initialized value and the value
+         of a non-match when passing along the runas value to multiple
+         commands.
+
+         The result of this is that an unmatched runas is now set to -1,
+         not 0.  This is required now that parse.c treats a FALSE value
+         for runas as being explicitly denied.
+
+2004-06-03 16:21  millert
+
+       * getprogname.c, sudo.c, visudo.c: Error out if argc < 1.
+
+2004-06-03 12:37  millert
+
+       * configure, configure.in: Add tests for what libs we need to link
+         with for ldap and for whether or not lber.h needs to be
+         explicitly included.
+
+2004-06-02 20:30  aaron
+
+       * ldap.c: Solaris native LDAP build fix
+
+2004-06-01 16:56  millert
+
+       * ldap.c: Set edn to NULL is ldap_get_dn() fails to avoid potential
+         use of an unset variable.
+
+2004-06-01 16:56  millert
+
+       * sudo.h: Add prototype for sudo_ldap_list_matches
+
+2004-06-01 16:53  millert
+
+       * compat.h, config.h.in, configure, configure.in: Better check for
+         dirfd macro--we now set HAVE_DIRFD for the macro version too.
+         Added check for dd_fd in `DIR' if no dirfd is found; this is now
+         used to confitionally define the dirfd macro in compat.h.
+
+2004-06-01 16:51  millert
+
+       * closefrom.c: Only check /proc/$$/fd if we have the dirfd
+         function/macro.
+
+2004-06-01 15:13  millert
+
+       * compat.h, config.h.in, configure, configure.in: Add a check for a
+         dirfd() function (like Linux) and add a dirfd macro in compat.h
+         if there is no dirfd() function or macro.
+
+2004-06-01 14:59  millert
+
+       * closefrom.c, getcwd.c: dirfd() is now defined in compat.h as
+         needed.
+
+2004-06-01 14:30  millert
+
+       * CHANGES: Clarify closefrom() note.
+
+2004-06-01 12:51  millert
+
+       * parse.c: When checking for a command in the directory, only copy
+         the base dir once.
+
+2004-06-01 12:44  millert
+
+       * closefrom.c: If there is a /proc/$$/fd directory, behave like the
+         Solaris closefrom() and only close the descriptors listed
+         therein.
+
+2004-06-01 12:23  millert
+
+       * alloc.c: compat.h guarantees INT_MAX is defined.
+
+2004-06-01 12:23  millert
+
+       * compat.h: Add definitions of OPEN_MAX and INT_MAX for those
+         without it and remove definition of RLIM_INFINITY (now unused).
+
+2004-05-31 21:22  millert
+
+       * CHANGES, alloc.c, check.c, compat.h, find_path.c, getcwd.c,
+         parse.c, sudo.c, sudo.h, visudo.c: Use PATH_MAX, not MAXPATHLEN
+         since the former is standardized.
+
+2004-05-31 19:18  millert
+
+       * CHANGES: sync
+
+2004-05-31 19:10  millert
+
+       * RUNSON: Add some entries that were mailed in a while ago
+
+2004-05-31 14:16  millert
+
+       * closefrom.c: o sysconf returns a long, not an int.  o check for
+         negative return value from sysconf/getdtablesize and use
+         OPEN_MAX in this case.  o define OPEN_MAX to 256 for those
+         without it (a fair guess...)
+
+2004-05-30 12:25  millert
+
+       * UPGRADE: Mention change in parse order for RunAs entries.
+
+2004-05-30 12:15  millert
+
+       * configure: regen
+
+2004-05-29 18:29  millert
+
+       * config.h.in, configure.in, INSTALL, README.LDAP:  o --with-ldap
+         now takes an optional dir as a parameter
+          o added check for ldap_initialize() and start_tls_s()
+
+2004-05-29 14:54  millert
+
+       * README.LDAP: Fix some typos, word choice and formatting issues.
+
+2004-05-28 18:06  millert
+
+       * tgetpass.c: Use SA_INTERRUPT so SunOS works correctly, avoid
+         stdio and just use read/write as it is simpler.
+
+2004-05-28 16:27  millert
+
+       * configure, configure.in: Remove hack overriding cross-compiler
+         check.  It should no longer be needed.
+
+2004-05-28 16:26  millert
+
+       * compat.h: Remove select() compat bits since we no longer use
+         select().
+
+2004-05-28 16:24  millert
+
+       * CHANGES, tgetpass.c: Use alarm() instead of select() for the
+         timeout for systems that don't fully/properly implement select().
+
+2004-05-27 19:14  millert
+
+       * CHANGES: synbc
+
+2004-05-27 19:12  millert
+
+       * RUNSON: update
+
+2004-05-27 19:12  millert
+
+       * set_perms.c: Deal with systems that have no way of setting the
+         effective uid such as nsr-tandem-nsk.
+
+2004-05-27 19:01  millert
+
+       * configure, configure.in: Define NO_SAVED_IDS if we don't find
+         seteuid()
+
+2004-05-27 18:21  millert
+
+       * config.h.in, configure, configure.in: Add back check for
+         setreuid() since NSK doesn't have it.
+
+2004-05-27 15:57  millert
+
+       * sudoers.cat, sudoers.man.in: regen
+
+2004-05-27 15:56  millert
+
+       * BUGS, CHANGES: sync
+
+2004-05-27 15:55  millert
+
+       * parse.c: In sudoers_lookup() return VALIDATE_NOT_OK if the runas
+         user was explicitly denied and the command matched.  This fixes a
+         long-standing bug and makes:     foo machine = (ALL)
+         /usr/bin/blah     foo machine = (!bar) /usr/bin/blah
+
+         equivalent to:     foo machine = (ALL, !bar) /usr/bin/blah
+
+2004-05-27 15:52  millert
+
+       * sudoers.pod: Clarify mail_noperm
+
+2004-05-19 21:25  aaron
+
+       * Makefile.in: Missing DESTDIR in make install for sudo_noexec.la
+
+2004-05-17 18:32  millert
+
+       * sudo.man.in, sudoers.man.in, visudo.man.in, sudo.cat,
+         sudoers.cat, visudo.cat: regen
+
+2004-05-17 18:31  millert
+
+       * TODO: sync
+
+2004-05-17 18:31  millert
+
+       * sample.sudoers, sudoers.pod: Remove fastboot/fasthalt (who still
+         remembers these?) and add a minimal sudoedit example.
+
+2004-05-17 18:21  millert
+
+       * CHANGES, INSTALL, TROUBLESHOOTING, UPGRADE, sudo.c, visudo.c:
+         filesystem -> file system
+
+2004-05-17 18:19  millert
+
+       * sudo.pod, sudoers.pod: Fix some minor typos and formatting goofs
+
+2004-05-17 18:10  millert
+
+       * lex.yy.c: regen
+
+2004-05-17 17:57  millert
+
+       * visudo.pod: remove my email addr
+
+2004-05-17 17:55  millert
+
+       * sudo.pod, sudoers.pod, visudo.pod: Use @mansectform@ and
+         @mansectsu@ everywhere Make man page references links with L<>
+
+2004-05-17 16:51  millert
+
+       * parse.lex: Accept quoted globbing characters and pass them
+         verbatim for fnmatch()
+
+2004-05-17 16:50  millert
+
+       * UPGRADE: Document that /tmp/.odus is gone.
+
+2004-05-17 16:28  millert
+
+       * CHANGES, aclocal.m4, configure, pathnames.h.in: No longer use
+         /tmp/.odus as a possible timestamp dir unless specifically
+         configured to do so.  Instead, if no /var/run exists, use
+         /var/adm/sudo or /usr/adm/sudo.
+
+2004-05-17 16:08  millert
+
+       * check.c, compat.h, logging.c, set_perms.c, sudo.c, tgetpass.c,
+         visudo.c: Preliminary changes to support nsr-tandem-nsk.  Based
+         on patches from Tom Bates.
+
+2004-05-16 18:47  millert
+
+       * CHANGES: There was no 1.6.7p6.
+
+2004-05-16 16:38  millert
+
+       * BUGS, CHANGES: sync
+
+2004-05-16 16:36  millert
+
+       * Makefile.in: add missing files to DISTFILES
+
+2004-05-16 16:23  millert
+
+       * sudoers.man.in, sudo.cat, sudoers.cat, visudo.cat: regen
+
+2004-05-16 16:20  millert
+
+       * Makefile.in: Fix some line wrap and update (c) year
+
+2004-04-28 15:05  aaron
+
+       * README.LDAP: Build Note
+
+2004-04-06 22:03  aaron
+
+       * Makefile.in: Fix install-dirs
+
+2004-04-04 20:27  millert
+
+       * visudo.c: In Exit() when used as a signal handler, emsg is a
+         pointer so sizeof() is wrong so make it a #define instead.  Also
+         avoid using a negative exit value.  Found by Aaron Campbell
+
+2004-03-24 18:23  millert
+
+       * sudoers.pod: Remove bogus sentence about uids in a User_List.
+         Document usernames vs. uid parsing in a Runas_List.
+
+2004-03-24 18:06  millert
+
+       * parse.c, parse.h, parse.yacc, sudo.c, testsudoers.c, visudo.c: If
+         the user specified a uid with the -u flag and the uid exists in
+         the passwd file, set runas_user to the name, not the uid.
+
+         When comparing usernames in sudoers, if a name is really a uid
+         (starts with '#') compare it numerically to pw_uid.
+
+2004-03-22 13:35  millert
+
+       * auth/kerb5.c: krb5_mcc_ops should be const; Johnny C. Lam
+
+2004-02-28 18:54  aaron
+
+       * CHANGES, config.h.in, ldap.c: Added start_tls support
+
+2004-02-14 18:04  millert
+
+       * Makefile.in: Clean up libtool stuff for 'make distclean' and add
+         def_data.c, def_data.h to PARSESRCS.
+
+2004-02-14 10:13  aaron
+
+       * strlcat.c, strlcpy.c: Un-Fix last license munge
+
+2004-02-13 16:37  millert
+
+       * CHANGES, RUNSON, TODO: checkpoint
+
+2004-02-13 16:37  millert
+
+       * lex.yy.c, configure: regen
+
+2004-02-13 16:36  millert
+
+       * LICENSE, Makefile.binary, Makefile.in, alloc.c, check.c,
+         closefrom.c, compat.h, defaults.c, defaults.h, env.c, fileops.c,
+         find_path.c, getprogname.c, getspwuid.c, goodpath.c, ins_2001.h,
+         ins_classic.h, ins_csops.h, ins_goons.h, insults.h, interfaces.c,
+         interfaces.h, ldap.c, logging.c, logging.h, parse.c, parse.h,
+         parse.lex, parse.yacc, pathnames.h.in, set_perms.c, sigaction.c,
+         strerror.c, strlcat.c, strlcpy.c, sudo.c, sudo.h, sudo.man.in,
+         sudo.pod, sudo_edit.c, sudo_noexec.c, sudoers.man.in,
+         sudoers.pod, testsudoers.c, tgetpass.c, utime.c, version.h,
+         visudo.c, visudo.man.in, visudo.pod, zero_bytes.c, auth/afs.c,
+         auth/aix_auth.c, auth/bsdauth.c, auth/dce.c, auth/fwtk.c,
+         auth/kerb4.c, auth/kerb5.c, auth/pam.c, auth/passwd.c,
+         auth/rfc1938.c, auth/secureware.c, auth/securid.c,
+         auth/securid5.c, auth/sia.c, auth/sudo_auth.c, auth/sudo_auth.h,
+         emul/search.h, emul/utime.h: More to a less restrictive,
+         ISC-style license.
+
+2004-02-12 21:08  aaron
+
+       * CHANGES, Makefile.in, README.LDAP, config.h.in, configure.in,
+         def_data.c, def_data.h, def_data.in, ldap.c, sudo.c, sudo.h,
+         sudoers2ldif: Merged in LDAP Support
+
+2004-02-08 15:53  millert
+
+       * sudo.h, sudo_noexec.c: Only do "extern int errno" if errno is not
+         a macro.
+
+2004-02-06 18:08  millert
+
+       * set_perms.c: setreuid(0, 0) fails on QNX if the euid is not
+         already 0 so set the euid first, then just call setuid(0) to set
+         the real uid too.
+
+2004-02-06 14:52  millert
+
+       * set_perms.c: Use setresuid() and setreuid() for PERM_RUNAS when
+         appropriate instead of seteuid() which may not exist.
+
+2004-02-04 14:58  millert
+
+       * LICENSE: 2004
+
+2004-02-03 23:38  millert
+
+       * INSTALL, config.h.in, configure, configure.in, ins_classic.h: Add
+         --with-pc-insults configure option
+
+2004-02-03 23:32  millert
+
+       * visudo.man.in: Prefer VISUAL over EDITOR like old vipw did.
+
+2004-02-01 15:45  millert
+
+       * sudo.man.in, sudoers.man.in: regen
+
+2004-02-01 15:44  millert
+
+       * sudoers.pod: Add a note that noexec is not a cure-all.
+
+2004-02-01 15:20  millert
+
+       * sudoers.pod: Mention that disabling "root_sudo" is pretty
+         pointless.
+
+2004-02-01 15:20  millert
+
+       * configure, configure.in: Substitute for root_sudo in sudoers.pod
+
+2004-02-01 15:03  millert
+
+       * sudo.pod: Add sudoedit to the NAME section
+
+2004-02-01 15:00  millert
+
+       * sudoers.pod: Document that fact that setting ignore_dot in
+         sudoers has no effect due to the fact that find_path() is called
+         *before* sudoers is read.
+
+2004-01-29 19:50  millert
+
+       * sudo_edit.c: Do not require _PATH_USRTMP to be set.
+
+2004-01-29 19:42  millert
+
+       * BUGS, CHANGES, TODO: sync
+
+2004-01-29 19:42  millert
+
+       * sudo.man.in: regen
+
+2004-01-29 19:41  millert
+
+       * sudo.pod: Clarify that when sudo is run by root with the
+         SUDO_USER variable set, the sudoers lookup happens for root and
+         not the SUDO_USER user.
+
+2004-01-29 17:33  millert
+
+       * defaults.c, env.c, fnmatch.c, interfaces.c, logging.c, parse.c,
+         set_perms.c, sigaction.c, sudo.c, tgetpass.c, auth/pam.c,
+         auth/sudo_auth.c: Use the SET, CLR and ISSET macros.
+
+2004-01-29 16:22  millert
+
+       * interfaces.h: MAIN was replaced with _SUDO_MAIN some time ago.
+
+2004-01-29 16:15  millert
+
+       * sudo.c: Don't look at prev_user until after we've parsed sudoers
+         and done the password check.  That way, if sudo/sudoedit is run
+         from a root process that was invoked by sudo, we check sudoers
+         for root, not the previous user.  This makes sudoedit much more
+         useful and means that for the sudo case, we get correct logging
+         on who actually ran the command.
+
+2004-01-22 19:22  millert
+
+       * sudo_edit.c: Add a comment describing why we need to be notified
+         about our child stopping.
+
+2004-01-22 16:06  millert
+
+       * def_data.c, def_data.in: Update the noexec variable descriptions
+
+2004-01-22 14:18  millert
+
+       * sudoers.man.in, sudoers.pod: noexec now replaces more than just
+         execve()
+
+2004-01-22 12:14  millert
+
+       * sudo_noexec.c: Alas, all the world does not go through execve(2).
+         Many systems still have an execv(2) system call, Linux 2.6
+         provides fexecve(2) and it is not uncommon for libc to have
+         underscore ('_') versions of the functions to be used internally
+         by the library.  Instead of stubbing all these out by hand,
+         define a macro and let it do the work.  Extra exec functions
+         pointed out by Reznic Valery.
+
+2004-01-21 21:57  millert
+
+       * sudo.c, sudo_edit.c: Fix suspending the editor in -e mode.
+         Because we do a fork() first we need to be notified when the
+         child has been stopped and then send that same signal to ourself
+         so the shell can do its job control thing.
+
+2004-01-21 21:44  millert
+
+       * visudo.c: Use WIFEXITED and WEXITSTATUS macros.  If there are
+         systems out there that want to run sudo that still don't support
+         these we can try to deal with that later.
+
+2004-01-21 20:03  millert
+
+       * lex.yy.c: regen
+
+2004-01-21 20:00  millert
+
+       * sudo.man.in, sudo.pod, sudoers.man.in, sudoers.pod: Document sudo
+         -e / sudoedit
+
+2004-01-21 19:08  millert
+
+       * configure, configure.in: fix typo
+
+2004-01-21 19:02  millert
+
+       * config.h.in, configure.in: Add SET/CLR/ISSET
+
+2004-01-21 18:55  millert
+
+       * sudo.c: Allow non-exclusive flags when invoked as sudoedit.
+         Pretty print the long usage() line to not wrap (assumes 80 char
+         display)
+
+2004-01-21 18:01  millert
+
+       * Makefile.in, sudo.c: If sudo is invoked as "sudoedit" the -e flag
+         is implied and no other flags are permitted.
+
+2004-01-21 18:00  millert
+
+       * sudo.h: Add a new flag, -e, that makes it possible to give users
+         the ability to edit files with the editor of their choice as the
+         invoking user, not the runas user.  Temporary files are used for
+         the actual edit and the temp file is copied over the original
+         after the editor is done.
+
+2004-01-21 17:25  millert
+
+       * Makefile.in, parse.c, parse.lex, sudo.c, sudo_edit.c: Add a new
+         flag, -e, that makes it possible to give users the ability to
+         edit files with the editor of their choice as the invoking user,
+         not the runas user.  Temporary files are used for the actual edit
+         and the temp file is copied over the original after the editor is
+         done.
+
+2004-01-21 17:06  millert
+
+       * sudo.c, env.c: If real uid == 0 and the SUDO_USER environment
+         variables is set, use that to determine the invoking user's true
+         identity.  That way the proper info gets logged by someone who
+         has done "sudo su" but still uses sudo to as root.  We can't do
+         this for non-root users since that would open up a security hole,
+         though perhaps it would be acceptable to use getlogin(2) on OSes
+         where this a system call (and doesn't just look in the utmp
+         file).
+
+2004-01-21 16:58  millert
+
+       * pathnames.h.in: Add _PATH_TMP, _PATH_VARTMP and _PATH_USRTMP
+
+2004-01-21 16:57  millert
+
+       * configure, config.h.in, configure.in: Add check for fchown(2)
+
+2004-01-20 14:22  millert
+
+       * sudo.c: Back out portions of the -i commit that set NewArgv[0] in
+         set_runaspw.  It is far to late to set NewArgv[0] there and will
+         have no effect anyway as cmnd and safe_cmnd have already been
+         set.
+
+2004-01-20 14:18  millert
+
+       * visudo.c, visudo.pod: Prefer VISUAL over EDITOR like old vipw
+         did.
+
+2004-01-18 20:17  millert
+
+       * env.c, sudo.c: In -i mode always set new environment based on the
+         runas user's passwd entry.
+
+2004-01-18 17:56  millert
+
+       * sudo.man.in, sudo.pod: Document the new -i flag and sync SYNOPSIS
+         section with usage() in sudo.c.  Also sort the flags in the
+         OPTIONS section.
+
+2004-01-18 17:55  millert
+
+       * sudo.c, sudo.h: o Add -i that acts similar to "su -", based on
+         patches from David J. MacKenzie o Sort the flags in the usage
+         message
+
+2004-01-18 17:22  millert
+
+       * sudoers.man.in, sudoers.pod: Add a missing @runas_default@
+         substitution.
+
+2004-01-17 16:34  millert
+
+       * sudo.c: Change euid to runas user before calling find_path().
+         Unfortunately, though runas_user can be modified in sudoers we
+         haven't parsed sudoers yet.
+
+2004-01-17 16:25  millert
+
+       * sudoers.man.in, sudoers.pod: Add missing defintion of
+         Parameter_List and use single pipes in the Defaults EBNF
+         definition.
+
+2004-01-17 13:49  millert
+
+       * sudo.c: Fix a bug when set_runaspw() is used as a callback.  We
+         don't want to reset the contents of runas_pw if the user
+         specified a user via the -u flag.
+
+         Avoid unnecessary passwd lookups in set_authpw().  In most cases
+         we already have the info in runas_pw.
+
+2004-01-16 18:16  millert
+
+       * check.c: Add Stan Lee / Uncle Ben quote to the lecture from
+         RedHat
+
+2004-01-16 18:12  millert
+
+       * sudo.h: Update sudo_getepw() proto and add one for set_runaspw()
+
+2004-01-16 18:10  millert
+
+       * parse.c: If we can't stat the command as root, try as the runas
+         user instead.
+
+2004-01-16 18:09  millert
+
+       * testsudoers.c, visudo.c: Add stub set_runaspw() function
+
+2004-01-16 18:09  millert
+
+       * sudo.c: Add set_runaspw() function to fill in runas_pw.  This
+         will be used as a callback to update runas_pw when the runas user
+         changes.
+
+2004-01-16 18:07  millert
+
+       * env.c, sudo.c: PERM_RUNAS -> PERM_FULL_RUNAS
+
+2004-01-16 18:05  millert
+
+       * set_perms.c, sudo.h: Rename PERM_RUNAS -> PERM_FULL_RUNAS and add
+         a PERM_RUNAS that just changes the euid.
+
+2004-01-16 18:04  millert
+
+       * getspwuid.c: Make sudo_pwdup() act like OpenBSD pw_dup() and
+         allocate memory in one chunk for easy free()ing.  Also change it
+         from static to extern.
+
+2004-01-16 18:03  millert
+
+       * defaults.c, defaults.h: Add callback support
+
+2004-01-16 18:02  millert
+
+       * def_data.c, def_data.in, mkdefaults: Add a callback field and use
+         it for runas_default
+
+2004-01-15 15:13  millert
+
+       * auth/fwtk.c: Add support for chalnecho and display server
+         responses used by fwtk >= 2.0
+
+2004-01-12 18:39  millert
+
+       * sudoers.man.in, sudoers.pod: ld.so is ld.so.1 on solaris
+
+2004-01-12 14:03  millert
+
+       * Makefile.in, config.h.in, configure, configure.in, sudo.c,
+         sudo.h: Use closefrom() instead of doing the equivalent inline.
+
+2004-01-12 13:55  millert
+
+       * closefrom.c: closefrom(3) for systems w/o it
+
+2004-01-09 16:29  millert
+
+       * sudoers.man.in: Update from .pod file.
+
+2004-01-09 16:26  millert
+
+       * configure, configure.in: Substitute noexec_file for the sudoers
+         man page
+
+2004-01-09 16:24  millert
+
+       * sudo.man.in, sudo.pod: Mention noexec
+
+2004-01-09 16:16  millert
+
+       * sudoers.man.in, sudoers.pod: Document noexec
+
+2004-01-09 14:38  millert
+
+       * config.h.in, configure.in, auth/pam.c: Move PAM_CONST macro
+         definition from config.h to pam.c where it belongs.  We can't
+         have this in config.h since that gets included too early.
+
+2004-01-09 14:35  millert
+
+       * config.h.in, configure, configure.in, auth/pam.c: Some PAM
+         implementations put their headers in /usr/include/pam instead of
+         /usr/include/security.
+
+2004-01-09 14:32  millert
+
+       * configure.in: I missed changing the EXEC macro -> EXECV here when
+         I changed this in config.h.in and sudo.c a while ago.
+
+2004-01-09 13:15  millert
+
+       * acsite.m4: OpenBSD vax/m88k/hppa don't do shared libs
+
+2004-01-09 03:29  millert
+
+       * configure, configure.in: o merge the hpux case entries into a
+         single entry w/ its own sub-case statement.  o HP-UX >= 11
+         support getspnam(), use it in preference to getprpwuid()
+
+2004-01-09 02:58  millert
+
+       * configure, configure.in: eval $shrext so that it expands nicely
+         on MacOS X
+
+2004-01-09 02:50  millert
+
+       * Makefile.in: Don't lie about making a module, it does the wrong
+         thing on mach
+
+2004-01-09 02:49  millert
+
+       * ltmain.sh: Remove requirement that libs must begin with "lib".
+         They don't when we point directly at the lib using LD_PRELOAD or
+         its equivalent.
+
+2004-01-09 02:01  millert
+
+       * acsite.m4: Disable support for c++, f77 and java.  We don't need
+         it, it takes a lot of time, and it hosed our check for shared lib
+         support.
+
+2004-01-09 02:00  millert
+
+       * configure: regen
+
+2004-01-09 02:00  millert
+
+       * configure.in: Call AC_ENABLE_SHARED and check the status of
+         enable_shared to know when shared libs are available.
+
+2004-01-09 01:37  millert
+
+       * acsite.m4: Duh, OpenBSD suports shared libs too
+
+2004-01-09 01:18  millert
+
+       * configure.in, config.h.in: Only OpenPAM and Linux PAM use const
+         qualifiers.
+
+2004-01-09 01:15  millert
+
+       * configure, configure.in: o No need to check for sed, libtool
+         config does that for us o move check for --with-noexec until
+         after libtool magic is run so we   can use $can_build_shared and
+         $shrext
+
+2004-01-09 01:14  millert
+
+       * ltmain.sh: Don't print a bunch of crap about library installs
+         since we are not really installing a library.
+
+2004-01-09 00:38  millert
+
+       * env.c: Make format_env() varargs Add noexec support for Darwin,
+         MacOS X, Irix, and Tru64
+
+2004-01-09 00:32  millert
+
+       * acsite.m4, ltconfig, ltmain.sh: Update to libtool 1.5 with local
+         changes:  o no ldconfig in the finish step  o assume no libprefix
+         or version is needed
+
+2004-01-09 00:15  millert
+
+       * sudo_noexec.c: Fix compilation under K&R
+
+2004-01-06 09:31  millert
+
+       * CHANGES: checkpoint
+
+2004-01-06 09:28  millert
+
+       * sudo_noexec.c: stub execve() that just returns EACCES; used for
+         noexec functionality
+
+2004-01-06 01:42  millert
+
+       * sudo.tab.h: Regen w/ updated byacc from OpenBSD; fixes a gcc 3.2
+         issue with generated code.
+
+2004-01-05 16:10  millert
+
+       * def_data.c, def_data.h, def_data.in: Move the environment
+         defaults to the end and shorten a few of the descriptions.
+
+2004-01-05 15:05  millert
+
+       * configure.in, configure: no shared libs on ultris or convexos
+
+2004-01-05 15:03  millert
+
+       * Makefile.in, configure, configure.in: Build sudo_noexec shared
+         object using libtool; could use some cleanup.
+
+2004-01-05 14:59  millert
+
+       * acsite.m4, ltconfig, ltmain.sh: libtool scaffolding
+
+2004-01-05 14:56  millert
+
+       * parse.yacc: Merge the NOPASSWD/PASSWD and NOEXEC/EXEC rules so
+         that order is not important.
+
+2004-01-05 12:15  millert
+
+       * defaults.c, env.c, parse.c, parse.h, parse.lex, parse.yacc,
+         pathnames.h.in, sudo.c, sudo.h, lex.yy.c: update copyright year
+
+2004-01-04 22:58  millert
+
+       * configure, configure.in, defaults.c, env.c, pathnames.h.in: Add
+         _PATH_SUDO_NOEXEC and corresponding --with-noexec configure
+         option.  The default value of noexec_file is set to this.
+
+2004-01-04 21:48  millert
+
+       * def_data.c, def_data.h, def_data.in, env.c, lex.yy.c, parse.c,
+         parse.h, parse.lex, parse.yacc, sudo.c, sudo.h, sudo.tab.h: Add
+         support for preloading a shared object containing a dummy
+         execve() function that just sets error and returns -1.  This adds
+         a "noexec_file" option to load the filename as well as a "noexec"
+         flag to enable it unconditionally.  There is also a NOEXEC tag
+         that can be attached to specific commands and an EXEC tag to
+         disable it.
+
+2004-01-04 21:40  millert
+
+       * mkdefaults: add missing newline to usage statement
+
+2004-01-04 20:39  millert
+
+       * config.h.in, sudo.c: Rename EXEC macro -> EXECV
+
+2004-01-04 20:16  millert
+
+       * logging.c: Don't truncate usernames to 8 characters in the log
+         message.
+
+2004-01-04 20:13  millert
+
+       * check.c, sudoers.man.in, sudoers.pod: Update copyright year
+
+2004-01-04 20:12  millert
+
+       * check.c, def_data.c, def_data.h, def_data.in, sudoers.man.in,
+         sudoers.pod: Add a new option, lecture_file, that can be used to
+         point to a custom sudo lecture.
+
+2003-12-31 17:46  millert
+
+       * Makefile.in, sudo.h, zero_bytes.c, auth/aix_auth.c,
+         auth/bsdauth.c, auth/fwtk.c, auth/pam.c, auth/sudo_auth.c: Add a
+         zero_bytes() function to do the equivalent of bzero in such a way
+         that will heopfully not be optimized away by sneaky compilers.
+
+2003-12-31 13:35  millert
+
+       * err.c: Use #ifdef __STDC__, not #if __STDC__.
+
+2003-12-30 17:41  millert
+
+       * mkdefaults: Always put at least one space between the def_* macro
+         name and its definition.
+
+2003-12-30 17:34  millert
+
+       * configure, configure.in: Adjust code for --without-lecture to
+         match new values.
+
+2003-12-30 17:33  millert
+
+       * visudo.man.in: regen after pasto fix
+
+2003-12-30 17:31  millert
+
+       * sudoers.man.in, sudoers.pod: Document that "lecture" has changed
+         from a flag to a tuple.
+
+2003-12-30 17:31  millert
+
+       * check.c, def_data.c, def_data.h, def_data.in, defaults.c,
+         defaults.h, logging.c, mkdefaults, parse.c, sudo.c, sudo.h: Add
+         support for tuples in def_data.in; these are implemented as an
+         enum type.  Currently there is only a single tuple enum but in
+         the future we may have one tuple enum per T_TUPLE entry in
+         def_data.in.  Currently listpw, verifypw and lecture are tuples.
+         This avoids the need to have two entries (one ival, one str) for
+         pwflags and syslog values.
+
+         lecture is now a tuple with the following values: never, once,
+         always
+
+         We no longer use both an int and string entry for syslog
+         facilities and priorities.  Instead, there are logfac2str() and
+         logpri2str() functions that get used when we need to print the
+         string values.
+
+2003-12-30 17:20  millert
+
+       * check.c, def_data.h, defaults.c, defaults.h, env.c, find_path.c,
+         logging.c, mkdefaults, parse.c, parse.yacc, set_perms.c, sudo.c,
+         visudo.c, auth/aix_auth.c, auth/bsdauth.c, auth/fwtk.c,
+         auth/pam.c, auth/rfc1938.c, auth/securid5.c, auth/sia.c,
+         auth/sudo_auth.c: Create def_* macros for each defaults value so
+         we no longer need the def_{flag,ival,str,list,mode} macros (which
+         have been removed).  This is a step toward more flexible data
+         types in def_data.in.
+
+2003-12-30 15:55  millert
+
+       * TODO: checkpoint
+
+2003-12-22 21:18  millert
+
+       * sudo.c: If we are in -k/-K mode, just spew to stderr.  It is not
+         unusual for users to place "sudo -k" in a .logout file which can
+         cause sudo to be run during reboot after the YP/NIS/NIS+/LDAP/etc
+         daemon has died.  Previously, this would result in useless mail
+         and logging.
+
+2003-12-16 13:51  millert
+
+       * visudo.pod: fix pasto in VISUAL description
+
+2003-12-09 22:09  millert
+
+       * configure: regen
+
+2003-12-09 22:08  millert
+
+       * CHANGES: checkpoint
+
+2003-12-09 22:02  millert
+
+       * TROUBLESHOOTING: Some OSes (like Solaris) allow export w/ nosuid
+         too
+
+2003-08-12 16:45  millert
+
+       * compat.h: We don't use FD_ZERO anymore so just define FD_SET (if
+         not already there).
+
+2003-06-28 21:31  millert
+
+       * auth/pam.c: Fix a core dump on Solaris by preserving the
+         pam_handle_t we used during authentication for pam_prep_user().
+         If we didn't authenticate (ie: ticket still valid), we call
+         pam_init() from pam_prep_user().  This is something of a hack; it
+         may be better to change the auth API and add an auth_final()
+         function that acts like pam_prep_user().
+
+2003-06-21 12:50  millert
+
+       * set_perms.c: Add explicit declaration of printerr variable in
+         function header (was defaulting to int which is OK but oh so K&R
+         :-).  From Theo.
+
+2003-06-09 19:00  millert
+
+       * config.h.in, configure.in: s/HAVE_STOW/USE_STOW/
+
+2003-06-09 16:07  millert
+
+       * logging.c: Also exit waitpid() loop when pid == 0.  Fixes a
+         problem where the sudo process would spin eating up CPU until
+         sendmail finished when it has to send mail.
+
+2003-05-30 16:22  millert
+
+       * fnmatch.3, fnmatch.c: Remove advertising clause, UCB has
+         disavowed it
+
+2003-05-21 21:53  millert
+
+       * parse.c: Don't assume that getgrnam() calls don't modify contents
+         of struct passwd returned by getpwnam().  On FreeBSD w/ NIS this
+         can happen.  Based on a patch from Kirk Webb.
+
+2003-05-06 11:25  millert
+
+       * configure.in: missing ;;
+
+2003-05-06 00:53  millert
+
+       * configure.in: darwin has a broken setreuid() in at least some
+         versions
+
+2003-05-06 00:31  millert
+
+       * env.c: Fix an off by one error when reallocating the environment;
+         Kevin Pye
+
+2003-04-30 14:04  millert
+
+       * sudoers.pod: Fix User_Spec definition; SEKINE Tatsuo
+
+2003-04-28 19:30  millert
+
+       * HISTORY: More info on the early days from Coggs.
+
+2003-04-21 14:47  millert
+
+       * auth/kerb5.c: remove errant semicolon that prevented compilation
+         under heimdal
+
+2003-04-15 20:42  millert
+
+       * Makefile.in, alloc.c, check.c, compat.h, defaults.c, defaults.h,
+         env.c, fileops.c, find_path.c, getprogname.c, getspwuid.c,
+         goodpath.c, interfaces.c, interfaces.h, logging.c, parse.c,
+         parse.lex, parse.yacc, pathnames.h.in, set_perms.c, sigaction.c,
+         strerror.c, sudo.c, sudo.h, sudo.man.in, sudo.pod,
+         sudoers.man.in, sudoers.pod, testsudoers.c, tgetpass.c, utime.c,
+         version.h, visudo.c, visudo.man.in, visudo.pod, auth/afs.c,
+         auth/aix_auth.c, auth/bsdauth.c, auth/dce.c, auth/fwtk.c,
+         auth/kerb4.c, auth/kerb5.c, auth/pam.c, auth/passwd.c,
+         auth/rfc1938.c, auth/secureware.c, auth/securid.c,
+         auth/securid5.c, auth/sia.c, auth/sudo_auth.c: add DARPA credit
+         on affected files
+
+2003-04-15 20:25  millert
+
+       * LICENSE: slightly different wording for the darpa credit
+
+2003-04-15 14:37  millert
+
+       * LICENSE: Add DARPA credit
+
+2003-04-14 16:49  millert
+
+       * auth/kerb5.c: Use krb5_princ_component() instead of
+         krb5_princ_realm() for MIT Kerberos like we did before I messed
+         things up ;-)
+
+         Use krb5_principal_get_comp_string() to do the same thing w/
+         Heimdal.  I'm not sure if the component should be 0 or 1 in this
+         case.
+
+         #define ENCTYPE_DES_CBC_MD5 ETYPE_DES_CBC_MD5 for Heimdal since
+         older versions lack ENCTYPE_DES_CBC_MD5.  This is gross and there
+         should be a configure check for this I guess.
+
+2003-04-13 15:48  millert
+
+       * TROUBLESHOOTING, config.h.in, configure, configure.in,
+         sample.sudoers: builtin -> built-in; Jason McIntyre
+
+2003-04-13 15:45  millert
+
+       * sudoers.pod: built in -> built-in; Jason McIntyre
+
+2003-04-09 16:14  millert
+
+       * CHANGES: checkpoint for 1.6.7p3
+
+2003-04-09 16:14  millert
+
+       * HISTORY: Update info on the early years @ SUNY-Buffalo from Cliff
+         Spencer.  Amazingly, sudo source from 1985 is available via
+         groups.google.com
+
+2003-04-09 16:13  millert
+
+       * sudo.c: Don't change rl.rlim_max for RLIMIT_CORE.  We need only
+         set rl.rlim_cur to 0 to turn off core dumps.  This may be needed
+         for the RLIMIT_CORE restoration on some OSes.
+
+2003-04-04 12:46  millert
+
+       * auth/kerb5.c: Make this compile on Heimdal and MIT Kerberos 5
+
+2003-04-04 12:45  millert
+
+       * config.h.in, configure, configure.in: Check for heimdal even if
+         we found krb5-config and define HAVE_HEIMDAL.
+
+2003-04-03 22:04  millert
+
+       * auth/kerb5.c: Replace ETYPE_DES_CBC_MD5 with ENCTYPE_DES_CBC_MD5.
+         The former is no longer defined by MIT kerb5 (though it used to
+         be and indeed remains so in Heimdal).
+
+2003-04-03 10:16  millert
+
+       * mkinstalldirs: Remove newer stuff that passes multiple (possibly
+         duplicate) directories to "mkdir -p" since that seems to break on
+         Tru64 Unix at least.  This basically brings back what shipped
+         with sudo 1.6.6.
+
+2003-04-02 13:57  millert
+
+       * auth/kerb5.c: Correct number of args to
+         krb5_principal_get_realm() and fix an unclosed comment that hid
+         the bug.
+
+2003-04-02 13:45  millert
+
+       * configure: regen
+
+2003-04-02 13:45  millert
+
+       * BUGS, CHANGES, INSTALL, INSTALL.binary, Makefile.in, README,
+         configure.in, version.h: ++version
+
+2003-04-02 13:44  millert
+
+       * configure.in: use krb5-config to determine Kerberos V details if
+         it exists
+
+2003-04-02 13:25  millert
+
+       * alloc.c, check.c, compat.h, defaults.c, env.c, find_path.c,
+         interfaces.c, logging.c, parse.c, sudo.c, sudo.h, testsudoers.c,
+         visudo.c, auth/fwtk.c, auth/rfc1938.c, auth/securid.c,
+         auth/securid5.c, auth/sia.c: Use warn/err and getprogname()
+         throughout.  The main exception is openlog().  Since the admin
+         may be filtering logs based on the program name in the log files,
+         hard code this to "sudo".
+
+2003-04-02 13:16  millert
+
+       * Makefile.in: Add getprogname.c and err.c
+
+2003-04-02 13:15  millert
+
+       * configure: regen
+
+2003-04-02 13:15  millert
+
+       * configure.in, config.h.in: Add checks for getprognam(),
+         __progname and err.h
+
+2003-04-02 13:14  millert
+
+       * err.c, emul/err.h: For systems withour err/warn functions.
+
+2003-04-02 13:14  millert
+
+       * getprogname.c: For systems neither getprogname() nor __progname;
+         uses Argv[0].
+
+2003-04-01 10:09  millert
+
+       * CHANGES: checkpoint for 1.6.7p1
+
+2003-04-01 10:02  millert
+
+       * sudo.c, testsudoers.c: fix strlcpy() rval check (innocuous)
+
+2003-04-01 09:58  millert
+
+       * check.c: oflow detection in expand_prompt() was faulty (false
+         positives).  The count was based on strlcat() return value which
+         includes the length of the entire string.
+
+2003-03-30 19:02  millert
+
+       * CHANGES, RUNSON, TODO: checkpoint for the sudo 1.6.7 release
+
+2003-03-24 16:09  millert
+
+       * logging.c: g/c unused variable
+
+2003-03-24 11:06  millert
+
+       * configure: regen
+
+2003-03-24 11:05  millert
+
+       * configure.in: use man sections 8 and 5 for csops
+
+2003-03-21 18:11  millert
+
+       * configure: regen
+
+2003-03-21 15:10  millert
+
+       * configure.in: Add -lskey or -lopie directly to SUDO_LIBS instead
+         of having AC_CHECK_LIB() add them to LIBS.  Fixes visudo linkage.
+
+2003-03-21 14:02  millert
+
+       * configure: regen
+
+2003-03-21 14:01  millert
+
+       * INSTALL, aclocal.m4, configure.in: Add --with-blibpath for AIX.
+         An alternate libpath may be specified or -blibpath support can be
+         disabled.  Also change conifgure such that -blibpath is not
+         specified if no -L libpaths were added to SUDO_LDFLAGS.
+
+2003-03-20 22:05  millert
+
+       * configure.in: add AIX blibpath support
+
+2003-03-20 20:28  millert
+
+       * INSTALL, configure.in: --with-skey and --with-opie now take an
+         option directory argument This obsoletes a --with-csops hack
+         (/tools/cs/skey)
+
+         Also remove the remaining direct uses of "echo"
+
+2003-03-20 17:44  millert
+
+       * configure.in: Detect KTH Kerberos IV and deal with it.  Also make
+         -lroken optional for KTH Kerberos IV and V.
+
+2003-03-20 14:42  millert
+
+       * aclocal.m4: Add SUDO_APPEND_LIBPATH function that add
+         -L/path/to/dir (and -R/path/to/dir if $with_rpath) to the
+         specified variable.
+
+2003-03-20 14:40  millert
+
+       * INSTALL, configure.in: Add -R/path/to/libs for Solaris and SVR4.
+         There is a new configure option, --with-rpath to control this
+         behavior.
+
+2003-03-19 23:50  millert
+
+       * configure.in: for kerb4 put libdes after libkrb on the link line
+
+2003-03-19 23:49  millert
+
+       * auth/kerb4.c: typo
+
+2003-03-19 23:33  millert
+
+       * configure.in: fix kerberos lib check when a path is specified
+
+2003-03-19 21:04  millert
+
+       * logging.c: Fix boolean thinko in SIGCHLD reaper and call
+         reapchild after sending mail instead of doing a conditional
+         sudo_waitpid.
+
+2003-03-19 16:20  millert
+
+       * configure: regen
+
+2003-03-19 16:19  millert
+
+       * configure.in: replace =DIR with [=DIR] where sensible
+
+2003-03-19 16:16  millert
+
+       * configure.in: o Use AC_MSG_* instead of "echo" o New Kerberos
+         include/lib detection based on openssh's configure.in
+
+2003-03-19 15:58  millert
+
+       * INSTALL: --with-kerb4 and --with-kerb5 now take an optional
+         argument.
+
+2003-03-15 22:03  millert
+
+       * auth/securid.c: Kill remaining strcpy(), the programmer's guide
+         says username is 32 bytes.
+
+2003-03-15 21:18  millert
+
+       * auth/kerb4.c: trat uid_t as unsigned long for printf and use
+         snprintf, not sprintf
+
+2003-03-15 21:18  millert
+
+       * auth/rfc1938.c: use snprintf
+
+2003-03-15 15:37  millert
+
+       * auth/: afs.c, aix_auth.c, bsdauth.c, dce.c, fwtk.c, kerb4.c,
+         kerb5.c, pam.c, passwd.c, rfc1938.c, sudo_auth.c: update
+         copyright year
+
+2003-03-15 15:31  millert
+
+       * LICENSE, alloc.c, check.c, configure.in, env.c, sudo.c,
+         Makefile.in, aclocal.m4, compat.h, find_path.c, interfaces.c,
+         logging.c, parse.c, parse.lex, parse.yacc, set_perms.c, sudo.h,
+         sudo.pod, sudoers.pod, testsudoers.c, version.h, visudo.c,
+         visudo.pod, sudo.man.in, sudoers.man.in, visudo.man.in: update
+         copyright year
+
+2003-03-15 15:19  millert
+
+       * check.c, env.c, sudo.c: Cast [ug]ids to unsigned long and printf
+         with %lu
+
+2003-03-15 15:17  millert
+
+       * configure: regen
+
+2003-03-15 15:16  millert
+
+       * configure.in: correct error messages for
+         --with-sudoers-{mode,uid,gid}
+
+2003-03-15 15:10  millert
+
+       * alloc.c: make the malloc(0) error specific to each function to
+         aid tracking down bugs.
+
+2003-03-15 14:49  millert
+
+       * alloc.c: deal with platforms where size_t is signed and there is
+         no SIZE_MAX or SIZE_T_MAX
+
+2003-03-15 14:10  millert
+
+       * auth/kerb5.c: Make this compile w/ Heimdal and fix some gcc
+         warnings.
+
+2003-03-15 13:02  millert
+
+       * sudo.c: Use stat_sudoers macro so --with-stow can work
+
+2003-03-15 13:01  millert
+
+       * INSTALL, config.h.in, configure, configure.in: Add support for
+         --with-stow based on patches from Robert Uhl
+
+2003-03-15 12:51  millert
+
+       * env.c: fix indentation
+
+2003-03-15 00:21  millert
+
+       * configure.in: back out rev 1.352
+
+2003-03-14 20:11  millert
+
+       * lex.yy.c: regen
+
+2003-03-14 20:11  millert
+
+       * parse.lex: use strlcpy, not strncpy
+
+2003-03-14 19:48  millert
+
+       * set_perms.c: Fix typo; check pw_uid, not pw_gid after
+         setusercontext() failure.
+
+2003-03-14 19:43  millert
+
+       * logging.c: use pid_t
+
+2003-03-14 10:43  millert
+
+       * strlcat.c, strlcpy.c: Make gcc shutup about unused rcsid
+
+2003-03-14 10:35  millert
+
+       * interfaces.c: Move the n == 0 check for the non-getifaddrs cas
+
+2003-03-13 21:47  millert
+
+       * auth/rfc1938.c: skeychallenge() on NetBSD take a size parameter
+
+2003-03-13 21:38  millert
+
+       * configure: regen
+
+2003-03-13 21:38  millert
+
+       * configure.in: put -ldl after -lpam, not before; fixes static
+         linking on Linux
+
+2003-03-13 21:17  millert
+
+       * interfaces.c: Avoid malloc(0) and fix the loop invariant for the
+         getifaddrs() case.
+
+2003-03-13 20:24  millert
+
+       * sudo.man.in, sudoers.man.in, visudo.man.in, sudo.cat,
+         sudoers.cat, visudo.cat: regen
+
+2003-03-13 20:23  millert
+
+       * Makefile.in: Preserve copyright notice from .pod file in .man.in
+         file
+
+2003-03-13 20:01  millert
+
+       * visudo.pod: Add sudoers(5) to SEE ALSO
+
+2003-03-13 15:27  millert
+
+       * lex.yy.c: regen
+
+2003-03-13 15:27  millert
+
+       * parse.lex: Don't assume libc can realloc() a NULL string.  If
+         malloc/realloc fails, make sure we just return; yyerror() is not
+         terminal.
+
+2003-03-13 15:17  millert
+
+       * lex.yy.c: regen
+
+2003-03-13 15:17  millert
+
+       * parse.lex: simplify fill_args a little and use strlcpy for
+         paranoia
+
+2003-03-13 15:00  millert
+
+       * check.c, env.c, find_path.c, parse.c, parse.yacc, sudo.c,
+         testsudoers.c: Use strlc{at,py} for paranoia's sake and exit on
+         overflow.  In all cases the strings were either pre-allocated to
+         the correct size of length checks were done before the copy but a
+         little paranoia can go a long way.
+
+2003-03-13 12:54  millert
+
+       * sudo.h: Add strlc{at,py} protos
+
+2003-03-13 12:03  millert
+
+       * env.c, interfaces.c: Use erealloc3()
+
+2003-03-13 12:00  millert
+
+       * configure: regen
+
+2003-03-13 12:00  millert
+
+       * alloc.c: Oflow test of nmemb > SIZE_MAX / size is fine (don't
+         need >=).  Use memcpy() instead of strcpy() in estrdup() so this
+         is strcpy()-free.
+
+2003-03-13 11:58  millert
+
+       * sudo.c: snprintf() a uid as %lu, not %ld to match the
+         MAX_UID_T_LEN test in configure.
+
+2003-03-13 11:56  millert
+
+       * aclocal.m4: In MAX_UID_T_LEN test cast uid_t to unsigned long,
+         just unsigned.
+
+2003-03-12 18:46  millert
+
+       * sudo.c: Use snprintf() for paranoia
+
+2003-03-12 17:16  millert
+
+       * parse.yacc: Use emalloc2 and erealloc3
+
+2003-03-12 17:08  millert
+
+       * Makefile.in: strlc{at,py} for those w/o it
+
+2003-03-12 17:07  millert
+
+       * strlcat.c, strlcpy.c: stlc{at,py} for those w/o it.
+
+2003-03-12 17:07  millert
+
+       * config.h.in, configure, configure.in: Add stlc{at,py} for those
+         w/o it.
+
+2003-03-12 16:51  millert
+
+       * alloc.c, sudo.h: Add erealloc3(), a realloc() version of
+         emalloc2().
+
+2003-03-12 16:45  millert
+
+       * interfaces.c, sudo.c: Use emalloc2() to allocate N things of a
+         certain size.
+
+2003-03-12 16:41  millert
+
+       * alloc.c, sudo.h: Add emalloc2() -- like calloc() but w/o the
+         bzero and with error/oflow checking.
+
+2003-03-12 16:23  millert
+
+       * alloc.c: Error out on malloc(0); suggested by theo
+
+2003-03-09 19:34  millert
+
+       * configure, configure.in: fix a typo; David Krause
+
+2003-03-07 10:46  millert
+
+       * sudo.pod: fix typo
+
+2003-03-03 21:47  millert
+
+       * env.c: Remove DYLD_ from the environment for MacOS X; from bbraun
+
+2003-03-01 13:20  millert
+
+       * configure.in, config.h.in: not not; Anil Madhavapeddy
+
+2003-01-23 03:03  millert
+
+       * sudo.pod, sudoers.pod, visudo.pod: typos; jmc@openbsd.org
+
+2003-01-20 16:13  millert
+
+       * parse.yacc: Add some missing ';' rule terminators that bison
+         warns about.
+
+2003-01-20 16:07  millert
+
+       * config.sub: fix typo I introduced in last merge
+
+2003-01-20 15:59  millert
+
+       * configure: regenerate with autoconf 2.57
+
+2003-01-20 15:58  millert
+
+       * config.h.in: Add missing "$HOME"
+
+2003-01-20 15:57  millert
+
+       * configure.in: Add some more square backets to make autoconf 2.57
+         happy
+
+2003-01-20 14:39  millert
+
+       * config.guess, config.sub, mkinstalldirs: Updates from
+         autoconf-2.57
+
+2003-01-17 18:10  millert
+
+       * lex.yy.c, sudo.tab.h: regen
+
+2003-01-17 18:09  millert
+
+       * parse.lex, parse.yacc, sudoers.pod: Add support for
+         Defaults>RunasUser
+
+2003-01-06 19:10  millert
+
+       * visudo.c: fclose() yyin after each yyparse() is done and use
+         fopen() instead of using freopen().
+
+2003-01-06 19:02  millert
+
+       * parse.lex: Better fix for sudoers files w/o a newline before EOF.
+         It looks like the issue is that yyrestart() does not reset the
+         start condition to INITIAL which is an issue since we parse
+         sudoers multiple times.
+
+2003-01-06 18:47  millert
+
+       * parse.lex: Work around what appears to be a flex bug when dealing
+         with files that lack a final newline before EOF.  This adds a
+         rule to match EOF in the non-initial states which resets the
+         state to INITIAL and throws an error.
+
+2003-01-06 15:06  millert
+
+       * visudo.c: o The parser needs sudoers to end with a newline but
+         some editors (emacs) may   not add one.  Check for a missing
+         newline at EOF and add one if needed.  o Set quiet flag during
+         initial sudoers parse (to get options) o Move yyrestart() call
+         and always use freopen() to open yyin after   initial sudoers
+         parse.
+
+2002-12-15 11:24  millert
+
+       * set_perms.c: Fix pasto/thinko in setresgid()/setregid() usage.
+         Want to set effective gid, not real gid, when reading sudoers.
+
+2002-12-15 11:08  millert
+
+       * set_perms.c: don't compile set_perms_posix if we have setreuid or
+         setresuid
+
+2002-12-14 14:21  millert
+
+       * sudo.pod, sudoers.pod: document new prompt escapes
+
+2002-12-14 14:15  millert
+
+       * check.c: Add %U and %H escapes and redo prompt rewriting.  "%%"
+         now gets collapsed to "%" as was originally intended.  This also
+         gets rid of lastchar (does lookahead instead of lookback) which
+         should simplify the logic slightly.
+
+2002-12-13 13:20  millert
+
+       * tgetpass.c: Write the prompt *after* turning off echo to avoid
+         some password characters being echoed on heavily-loaded machines
+         with fast typists.
+
+2002-12-13 13:09  millert
+
+       * config.sub: Add support for mipseb; wiz@danbala.tuwien.ac.at
+
+2002-12-13 12:48  millert
+
+       * configure.in: Fix IRIX fallout from name changes in man dir/sect
+         Makefile variables.  Patch from erici AT motown DOT cc DOT utexas
+         DOT edu
+
+2002-12-13 11:33  millert
+
+       * auth/pam.c: Keep a local copy of tgetpass_flags so we don't add
+         in TGP_ECHO to the global copy.  Problem noted by Peter Pentchev.
+
+2002-11-28 18:43  millert
+
+       * parse.yacc: Add missing yyerror() calls; YYERROR does not seem to
+         call this for us.
+
+2002-11-26 12:09  millert
+
+       * sudo.c: fix typo in comment; Pedro Bastos
+
+2002-11-22 14:41  millert
+
+       * INSTALL: document --disable-setresuid
+
+2002-11-22 14:41  millert
+
+       * auth/: aix_auth.c, bsdauth.c, fwtk.c, pam.c, sudo_auth.c:
+         Sprinkle some volatile qualifiers to prevent over-enthusiastic
+         optimizers from removing memset() calls.
+
+2002-11-22 14:11  millert
+
+       * logging.c, parse.yacc: minor sign fixes pointed out by gcc
+         -Wsign-compare
+
+2002-11-22 14:09  millert
+
+       * set_perms.c, sudo.c, sudo.h: Revamp set_perms.  We now use a
+         version based on setresuid() or setreuid() when possible since
+         that allows us to support the stay_setuid option and we always
+         know exactly what the semantics will be (various Linux kernels
+         have broken POSIX saved uid support).
+
+2002-11-22 14:08  millert
+
+       * config.h.in, configure: regen from configure.in
+
+2002-11-22 14:07  millert
+
+       * configure.in: Add checks for setresuid() and a way to disable
+         using it
+
+2002-11-22 14:05  millert
+
+       * compat.h: No long need to emulate set*[ug]id() via setres[ug]id()
+         or setre[ug]id().  The new set_perms stuff only uses things it
+         knows are there.
+
+2002-11-22 13:33  millert
+
+       * sudo.c: Before exec, restore state of signal handlers to be the
+         same as when we were initialy invoked instead of just reseting to
+         SIG_DFL.  Fixes a problem when using sudo with nohup.  Based on a
+         patch from Paul Markham.
+
+2002-11-22 13:23  millert
+
+       * sudo.c: o timestamp_uid should be uid_t, not int o clarify error
+         message when sudo is run by root and no_root_sudo is set
+
+2002-09-19 17:27  millert
+
+       * README: update ftp link for bison
+
+2002-07-20 08:30  millert
+
+       * set_perms.c: Error out if setusercontext() fails and the runas
+         user is not root.
+
+2002-05-20 16:51  millert
+
+       * auth/securid5.c: Fix rcsid
+
+2002-05-20 16:50  millert
+
+       * configure.in: Fix SecurID API test
+
+2002-05-17 13:20  millert
+
+       * env.c: typo in comment
+
+2002-05-17 13:20  millert
+
+       * configure.in: securid5 stuff needs pthreads.  Just adding
+         -lpthread is suboptimal but I don't see a better way at the
+         moment.
+
+2002-05-17 13:04  millert
+
+       * Makefile.in, auth/securid5.c: SecurID API version 5 support from
+         Michael Stroucken
+
+2002-05-17 13:02  millert
+
+       * configure.in: Add check for SecurID 5.0 API
+
+2002-05-08 16:46  millert
+
+       * strerror.c: We actually do still need config.h to get the 'const'
+         definition for K&R C.
+
+2002-05-05 16:43  millert
+
+       * configure: regen with autoconf 2.5.3
+
+2002-05-05 16:25  millert
+
+       * configure.in: Don't set sysconfdir to '/etc' if the user has
+         specified a --prefix.
+
+2002-05-05 16:14  millert
+
+       * configure.in: Some fixes for autoconf 2.53 from Robert Uhl  o
+         don't AC_SUBST LIBOBJS  o force a 4th arg for AC_CHECK_HEADER()
+         to workaround a bug
+
+2002-05-05 15:58  millert
+
+       * env.c, sudo.c, sudo.h: No need for dump_badenv() now that
+         dump_defaults() knows how to dump lists.
+
+2002-05-04 21:31  millert
+
+       * BUGS, INSTALL, Makefile.in, configure.in, version.h,
+         INSTALL.binary, README: ++version
+
+2002-05-04 20:57  millert
+
+       * sudoers.pod: document timestampowner
+
+2002-05-04 20:45  millert
+
+       * check.c: Don't call set_perms() when doing timestamp stuff unless
+         timestamp_uid != 0.
+
+2002-05-04 20:43  millert
+
+       * check.c, logging.c, parse.c, set_perms.c, sudo.c, sudo.h,
+         testsudoers.c, auth/sudo_auth.c: g/c second arg to set_perms--it
+         is no longer used
+
+2002-05-03 18:48  millert
+
+       * check.c, set_perms.c, sudo.c, sudo.h: Add support for non-root
+         timestamp dirs.  This allows the timestamp dir to be shared via
+         NFS (though this is not recommended).
+
+2002-05-03 18:47  millert
+
+       * def_data.c, def_data.h, def_data.in: Add timestampowner, "Owner
+         of the authentication timestamp dir"
+
+2002-05-02 15:40  millert
+
+       * env.c: Don't try to pre-compute the size of the new envp, just
+         allocate space up front and realloc as needed.  Changes to the
+         new env pointer must all be made through insert_env() which now
+         keeps track of spaced used and allocates as needed.
+
+2002-04-26 15:12  millert
+
+       * configure: regen
+
+2002-04-26 15:12  millert
+
+       * configure.in: Fix two typo/pastos; from jrj@purdue.edu
+
+2002-04-25 11:36  millert
+
+       * INSTALL.binary, README: ++version
+
+2002-04-25 11:35  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in, visudo.cat,
+         visudo.man.in, configure: regen
+
+2002-04-25 11:31  millert
+
+       * CHANGES, RUNSON, TODO: Sync with 1.6.6
+
+2002-04-25 11:30  millert
+
+       * check.c: The the loop used to expand %h and %u, the lastchar
+         variable was not being initialized.  This means that if the last
+         char in the prompt is '%' and the first char is 'h' or 'u' a
+         extra copy of the host or user name would be copied, for which
+         space had not been allocated.
+
+2002-04-18 11:41  millert
+
+       * BUGS, INSTALL, Makefile.in, configure.in, version.h: crank
+         version to 1.6.6
+
+2002-04-18 11:39  millert
+
+       * auth/afs.c: #undef VOID to get rid of an AFS warning
+
+2002-04-18 11:38  millert
+
+       * env.c: Use easprintf instead of emalloc + sprintf for some
+         things.
+
+2002-03-15 19:45  millert
+
+       * lex.yy.c: regen
+
+2002-03-15 19:44  millert
+
+       * parse.c, parse.lex, parse.yacc, testsudoers.c: Remove Chris
+         Jepeway's email address so people don't bug him ;-)
+
+2002-03-11 22:19  millert
+
+       * sudo.c: Move endpwent() to be after set_perms(PERM_RUNAS, ...)
+         and also call endgrent() at the same time.
+
+2002-02-21 22:23  millert
+
+       * INSTALL: Make it clear which configure options take arguments.
+
+2002-01-25 13:38  millert
+
+       * compat.h: HP-UX 9.x has RLIMIT_* but no RLIM_INFINITY.  If there
+         is no RLIM_INFINITY, just pretend it is -1.  This works because
+         we only check for RLIM_INFINITY and do not set anything to that
+         value.
+
+2002-01-22 11:43  millert
+
+       * auth/pam.c: Zero and free allocated memory when there is a
+         conversation error.
+
+2002-01-21 22:37  millert
+
+       * auth/bsdauth.c: Use sigaction() not signal()
+
+2002-01-21 22:26  millert
+
+       * INSTALL: Mention that some linux kernels have broken POSIX saved
+         ID support
+
+2002-01-21 21:03  millert
+
+       * CHANGES: checkpoint for 1.6.5p2
+
+2002-01-21 21:01  millert
+
+       * configure: regen
+
+2002-01-21 21:01  millert
+
+       * configure.in: Add --disable-setreuid flag
+
+2002-01-21 21:00  millert
+
+       * INSTALL: Document new --disable-setreuid option and change
+         description for --disable-saved-ids to match new error message.
+
+2002-01-21 21:00  millert
+
+       * set_perms.c: fatal() now takes an argument that determines
+         whether or not to call perror().
+
+2002-01-21 20:58  millert
+
+       * PORTING, TROUBLESHOOTING: Update for new error messages from
+         set_perms()
+
+2002-01-21 17:46  millert
+
+       * auth/pam.c: Make this compile w/o warnings
+
+2002-01-21 17:36  millert
+
+       * auth/pam.c: Mention that we can't use pam_acct_mgmt()
+
+2002-01-21 17:25  millert
+
+       * auth/: aix_auth.c, bsdauth.c, fwtk.c, pam.c: The user's password
+         was not zeroed after use when AIX authentication, BSD
+         authentication, FWTK or PAM was in use.
+
+2002-01-20 14:21  millert
+
+       * auth/pam.c: Avoid giving PAM a NULL password response, use the
+         empty string instead.  This avoids a log warning when the user
+         hits ^C at the password prompt when PAM is in use.
+
+2002-01-19 19:46  millert
+
+       * auth/pam.c: Don't check the return value of pam_setcred().  In
+         Linux-PAM 0.75 pam_setcred() returns the last saved return code,
+         not the return code for the setcred module.  Because we haven't
+         called pam_authenticate(), this is not set and so pam_setcred()
+         returns PAM_PERM_DENIED.
+
+2002-01-19 19:43  millert
+
+       * Makefile.binary, Makefile.in: Don't need a '/' between $(DESTDIR)
+         and a directory.
+
+2002-01-18 14:18  millert
+
+       * configure: regen
+
+2002-01-18 14:18  millert
+
+       * configure.in: o BSDi also has a bogus setreuid() o Old FreeBSD
+         has a bogus setreuid() o new NetBSD has a real setreuid() o add
+         check for freeifaddrs() if getifaddrs() exists.
+
+2002-01-18 14:17  millert
+
+       * config.h.in, interfaces.c: Older BSDi releases lack freeifaddrs()
+         so add a test for that and if it is not present just use free().
+
+2002-01-17 11:30  millert
+
+       * CHANGES, RUNSON: Checkpoint for 1.6.5p1
+
+2002-01-17 10:56  millert
+
+       * auth/passwd.c: Return AUTH_FAILURE in passwd_init() if
+         skeyaccess() denies access to normal passwords, not AUTH_FATAL
+         (which just causes an exit).
+
+2002-01-17 10:35  millert
+
+       * visudo.c: Don't use memory after it has been freed.
+
+2002-01-17 00:24  millert
+
+       * auth/passwd.c: skeyaccess() wants a struct passwd * not a char *;
+         Patch from Phillip E. Lobbes
+
+2002-01-16 20:00  millert
+
+       * BUGS: ++version
+
+2002-01-16 19:53  millert
+
+       * CHANGES, RUNSON, TODO: checkpoint for sudo 1.6.5
+
+2002-01-16 18:37  millert
+
+       * configure: regen
+
+2002-01-16 18:37  millert
+
+       * INSTALL, INSTALL.binary, Makefile.in, README, configure.in:
+         version 1.6.5
+
+2002-01-16 18:37  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in, visudo.cat,
+         visudo.man.in: sudo version 1.6.5
+
+2002-01-16 16:28  millert
+
+       * logging.c: o when invoking the mailer as root use a hard-coded
+         environment that   doesn't include any info from the user's
+         environment.  Basically   paranoia.
+
+         o Add support for the NO_ROOT_MAILER compile-time option and run
+         the   mailer as the user and not root if NO_ROOT_MAILER is
+         defined.
+
+2002-01-16 16:27  millert
+
+       * set_perms.c, sudo.h: Bring back PERM_FULL_USER
+
+2002-01-16 16:26  millert
+
+       * configure: regen
+
+2002-01-16 16:26  millert
+
+       * version.h: version 1.6.5
+
+2002-01-16 16:26  millert
+
+       * INSTALL, config.h.in, configure.in: Add --disable-root-mailer
+         option to run the mailer as the user and not root.
+
+2002-01-16 12:44  millert
+
+       * CHANGES: checkpoint for 1.6.4p2
+
+2002-01-15 19:22  millert
+
+       * PORTING: Mention the "seteuid(0): Operation not permitted"
+         problem here too just for good measure.
+
+2002-01-15 18:43  millert
+
+       * env.c, getspwuid.c, sudo.c: The SHELL environment variable was
+         preserved from the user's environment instead of being reset
+         based on the passwd database when the "env_reset" option was
+         used.  Now it is reset as it should be.
+
+2002-01-15 17:47  millert
+
+       * configure: regen
+
+2002-01-15 17:47  millert
+
+       * INSTALL, TROUBLESHOOTING, config.h.in, configure.in, set_perms.c,
+         sudo.c: Add a configure option to turn off use of POSIX saved IDs
+
+2002-01-15 15:48  millert
+
+       * configure: regen
+
+2002-01-15 15:48  millert
+
+       * configure.in: add --with-efence option
+
+2002-01-15 15:39  millert
+
+       * sudo.c: Only OR in MODE_RESET_HOME if MODE_RUN is set.  Fixes a
+         problem where "sudo -l" would not work if always_set_home was
+         set.
+
+2002-01-15 13:16  millert
+
+       * lex.yy.c: regen
+
+2002-01-15 13:16  millert
+
+       * parse.lex: Quoted commas were not being treated correctly in
+         command line arguments.
+
+2002-01-14 20:53  millert
+
+       * sudo.c: o Move the call to rebuild_env() until after
+         MODE_RESET_HOME is set.    Otherwise, the set_home option has no
+         effect.
+
+         o Fix use of freed memory when the "fqdn" flag is set.  This was
+          introduced by the fix for the "segv when gethostbynam() fails"
+         bug.    Also, we no longer call set_fqdn() if the "fqdn" flag is
+         not set so    there is no need to check the "fqdn" flag in
+         set_fqdn() itself.
+
+2002-01-14 20:45  millert
+
+       * env.c: Add 'continue' statements to optimize the switch
+         statement.  From Solar.
+
+2002-01-13 13:42  millert
+
+       * sudoers.cat, sudoers.man.in: Regen from new sudoers.pod
+
+2002-01-13 13:36  millert
+
+       * sudoers.pod: Add caveat about stay_setuid flag
+
+2002-01-13 13:29  millert
+
+       * sudo.c: If set_perms == set_perms_posix and the stay_setuid flag
+         is not set, set all uids to 0 and use set_perms_fallback().
+
+2002-01-13 13:28  millert
+
+       * set_perms.c, sudo.h: Remove PERM_FULL_USER (which is no longer
+         used) and add PERM_FULL_ROOT (used when exec'ing the mailer).
+
+2002-01-13 13:27  millert
+
+       * logging.c: Use set_perms(PERM_FULL_ROOT, 0) before exec'ing the
+         mailer since we never want to run the mailer setuid.
+
+2002-01-12 17:55  millert
+
+       * sudo.cat, sudo.man.in, sudo.pod, visudo.cat, visudo.man.in,
+         visudo.pod: Use sudo.ws instead of courtesan.com in URLs
+
+2002-01-12 14:00  millert
+
+       * Makefile.in, Makefile.binary: Fix mansect substitution
+
+2002-01-12 13:15  millert
+
+       * Makefile.in: Substitute man sections in Makefile.binary
+
+2002-01-12 13:15  millert
+
+       * Makefile.binary: Sync install targets with Makefile.in and
+         substitute in man sections.
+
+2002-01-12 13:09  millert
+
+       * INSTALL, INSTALL.binary: version is 1.6.4
+
+2002-01-12 12:59  millert
+
+       * Makefile.in: Repair bindist target
+
+2002-01-12 11:43  millert
+
+       * CHANGES: sync for 1.6.4
+
+2002-01-10 13:00  millert
+
+       * install-sh: Fix case where neither whoami nor id are found
+
+2002-01-09 12:35  millert
+
+       * install-sh: If neither whoami nor id exists, just assume we are
+         root.
+
+2002-01-09 11:56  millert
+
+       * alloc.c: Add explicit cast to (VOID *) on malloc/realloc.  Seems
+         to be needed on AIX which for some reason isn't pulling in the
+         malloc prototype.
+
+2002-01-08 10:00  millert
+
+       * Makefile.in, aclocal.m4, compat.h, parse.c, sudo.c: (c) 2002
+
+2002-01-08 09:21  millert
+
+       * CHANGES: checkpoint
+
+2002-01-08 09:20  millert
+
+       * sudo.c: Defer assigning new environment until right before the
+         exec.
+
+2002-01-08 09:08  millert
+
+       * parse.c: kill extra blank line
+
+2002-01-07 13:59  millert
+
+       * configure: regen
+
+2002-01-07 13:59  millert
+
+       * configure.in: Use -O not -O2 for m88k-motorola-sysv* since
+         motorola gcc-derived compiler doesn't recognise -O2.
+
+2002-01-06 23:02  millert
+
+       * HISTORY: Clarify origins of Root Group sudo a bit based on info
+         from billp@rootgroup.com
+
+2002-01-02 22:41  millert
+
+       * LICENSE: 2002
+
+2002-01-02 22:26  millert
+
+       * CHANGES: checkpoint for 1.6.4rc1
+
+2002-01-02 17:40  millert
+
+       * config.h.in: now generated via autoheader
+
+2002-01-02 17:40  millert
+
+       * configure: regen
+
+2002-01-02 17:37  millert
+
+       * compat.h: Move in some stuff that was previously in config.h.
+
+2002-01-02 17:36  millert
+
+       * configure.in, aclocal.m4: Add info for autoheader.
+
+2002-01-01 16:53  millert
+
+       * Makefile.in:  o Add DESTDIR support
+          o Use -M, -O, and -G instead of -m, -o, and -g to facilitate
+         non-root installs
+
+2002-01-01 16:48  millert
+
+       * install-sh: Add -M option (like -m but only for root) If we can't
+         find "whoami", use "id" w/ some sed.
+
+2002-01-01 14:01  millert
+
+       * configure: regen
+
+2002-01-01 14:00  millert
+
+       * configure.in: allow user to always override mansectsu and
+         mansectform
+
+2001-12-31 17:05  millert
+
+       * mkinstalldirs: update from autoconf 2.52
+
+2001-12-31 17:03  millert
+
+       * config.guess, config.sub: Update from autoconf 2.52
+
+2001-12-31 16:57  millert
+
+       * configure: regen with autoconf 2.52
+
+2001-12-31 16:57  millert
+
+       * configure.in:  o Call AC_PROG_CC_STDC to find out how to run the
+         compiler in ANSI mode
+          o Remove compiler-specific checks for HP-UX now that we use
+         AC_PROG_CC_STDC
+
+2001-12-31 12:19  millert
+
+       * RUNSON: Checkpoint
+
+2001-12-31 12:18  millert
+
+       * auth/pam.c: o Add pam_prep_user function to call pam_setcred()
+         for the target user;   on Linux this often sets resource limits.
+         o When calling pam_end(), try to convert the auth->result to a
+         PAM_FOO   value.  This is a hack--we really need to stash the
+         last PAM_FOO   value received and use that instead.
+
+2001-12-31 12:18  millert
+
+       * set_perms.c, sudo.h: o Add pam_prep_user function to call
+         pam_setcred() for the target user;   on Linux this often sets
+         resource limits.
+
+2001-12-31 00:53  millert
+
+       * env.c: Fix off by one error in number of bytes allocated via
+         malloc (does not affected any released version of sudo).
+
+2001-12-30 17:12  millert
+
+       * lex.yy.c: regen
+
+2001-12-30 17:12  millert
+
+       * parse.lex: Allow '@', '(', ')', ':' in arguments to a defaults
+         variable w/o requiring that they be quoted.
+
+2001-12-30 14:26  millert
+
+       * sudoers.cat, sudoers.man.in, sudoers.pod: Mention that no double
+         quotes are needed when adding/deleting/assigning a single value
+         to a list.
+
+2001-12-30 13:58  millert
+
+       * Makefile.in: Don't rely on mkdefaults being executable, call perl
+         explicitly.
+
+2001-12-30 13:41  millert
+
+       * parse.yacc: Remove some XXX that are no longer relevant.
+
+2001-12-30 13:40  millert
+
+       * defaults.c: o Roll our own loop instead of using strpbrk() for
+         better grokability o When adding to a list we must malloc() and
+         use memcpy(), not strdup()   since we must only copy len bytes
+         from str.
+
+2001-12-21 16:49  millert
+
+       * parse.yacc: typo in comment
+
+2001-12-19 11:50  millert
+
+       * CHANGES: checkpoint
+
+2001-12-19 10:56  millert
+
+       * configure: regen
+
+2001-12-19 10:56  millert
+
+       * configure.in: avoid the -g flag unless --with-devel was specified
+
+2001-12-19 10:04  millert
+
+       * Makefile.in: mkdefaults, def_data.in and sigaction.c were missing
+         from the tarball
+
+2001-12-19 09:46  millert
+
+       * Makefile.in: def_data.c was missing
+
+2001-12-18 12:42  millert
+
+       * env.c: Fix setting of $USER and $LOGNAME in the non-reset_env
+         case.  Also allow HOME, SHELL, LOGNAME, and USER to be specified
+         in keep_env
+
+2001-12-17 20:48  millert
+
+       * TODO: Another TODO item
+
+2001-12-17 19:50  millert
+
+       * sudoers: Add comment for Default section so folks know where it
+         should go.
+
+2001-12-17 18:56  millert
+
+       * tgetpass.c: Use TCSETAF, not TCSETA to set terminal in termio
+         case
+
+2001-12-17 18:35  millert
+
+       * sudoers.man.in, sudoers.cat: regen from sudoers.pod
+
+2001-12-17 18:33  millert
+
+       * sudoers.pod:  o Typo, Runas_User_List should be Runas_List
+          o a User_List can not contain a uid
+          o mention that the Defaults section should come after Alias
+            definitions but before the user specifications
+
+2001-12-15 11:51  millert
+
+       * sudoers.cat, sudoers.man.in: regen
+
+2001-12-15 11:51  millert
+
+       * sudoers.pod: Fix listpw and verifypw sections, they were not
+         being formatted properly.
+
+2001-12-15 11:39  millert
+
+       * sudoers.cat, sudoers.man.in: regen
+
+2001-12-15 11:38  millert
+
+       * sudoers.pod: fix typos
+
+2001-12-15 10:57  millert
+
+       * configure: regen
+
+2001-12-15 10:57  millert
+
+       * configure.in, config.h.in: use AC_SYS_POSIX_TERMIOS instead of
+         rolling our own
+
+2001-12-15 10:33  millert
+
+       * README: Reference sudo.ws not courtesan.com
+
+2001-12-15 10:29  millert
+
+       * PORTING: Add notes on shadow passwords
+
+2001-12-15 00:48  millert
+
+       * BUGS: In list mode (sudo -l), characters escaped with a backslash
+         are shown verbatim with the backslash.
+
+2001-12-15 00:44  millert
+
+       * sudoers: Add simple examples from OpenBSD (Marc Espie)
+
+2001-12-15 00:40  millert
+
+       * tgetpass.c: Catch SIGTTIN and SIGTTOU too and treat them like
+         SIGTSTP.
+
+2001-12-14 21:53  millert
+
+       * CHANGES: minor prettyification
+
+2001-12-14 21:43  millert
+
+       * CHANGES: Updated change log
+
+2001-12-14 21:27  millert
+
+       * testsudoers.c: Fix CIDR handling here too.
+
+2001-12-14 21:21  millert
+
+       * auth/pam.c: Apparently a NULL response is OK
+
+2001-12-14 21:19  millert
+
+       * TODO: Checkpoint for upcoming beta release
+
+2001-12-14 21:17  millert
+
+       * TROUBLESHOOTING: Many people believe that adding a runas spec
+         should obviate the need for the -u flag.  It does not.
+
+2001-12-14 21:11  millert
+
+       * RUNSON: checkpoint update for upcoming 1.6.4 beta
+
+2001-12-14 20:44  millert
+
+       * config.h.in: o Add HAVE_STDLIB_H and HAVE_MEMORY_H o Define
+         HAVE_STRINGS_H even if HAVE_STRING_H is defined -- this is safe
+         now
+
+2001-12-14 20:07  millert
+
+       * PORTING: Add signals section
+
+2001-12-14 20:00  millert
+
+       * configure: regen
+
+2001-12-14 20:00  millert
+
+       * configure.in: Fix check for sigaction_t
+
+2001-12-14 19:45  millert
+
+       * sudo.c: XXX - should call find_path() as runas user, not root.
+         Can't do that until the parser changes though.
+
+2001-12-14 19:38  millert
+
+       * sudo.c: If find_path() fails as root, try again as the invoking
+         user (useful for NFS).  Idea from Chip Capelik.
+
+2001-12-14 19:28  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in: Regenerate
+         after pod file changes
+
+2001-12-14 19:24  millert
+
+       * def_data.c, def_data.h, def_data.in, set_perms.c, sudo.c, sudo.h,
+         sudo.pod, sudoers.pod: Add new sudoers option "preserve_groups".
+         Previously sudo would not call initgroups() if the target user
+         was root.  Now it always calls initgroups() unless the -P command
+         line option or the "preserve_groups" sudoers option is set.  Idea
+         from TJ Saunders.
+
+2001-12-14 18:38  millert
+
+       * compat.h, config.h.in: Use new HAVE_SIGACTION_T define
+
+2001-12-14 18:33  millert
+
+       * logging.c: Fix compilation on K&C
+
+2001-12-14 18:14  millert
+
+       * configure: regen
+
+2001-12-14 18:14  millert
+
+       * configure.in: Add check for sigaction_t -- IRIX already defines
+         this so don't redefine it.
+
+2001-12-14 17:15  millert
+
+       * snprintf.c: fix typo
+
+2001-12-14 17:12  millert
+
+       * interfaces.c: need stdlib.h here too
+
+2001-12-14 15:31  millert
+
+       * configure: regen
+
+2001-12-14 15:31  millert
+
+       * configure.in: Remove redundant checks for string.h, strings.h and
+         unistd.h
+
+2001-12-14 15:29  millert
+
+       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in, visudo.cat,
+         visudo.man.in: Regen from pod files
+
+2001-12-14 15:03  millert
+
+       * BUGS: Update for 1.6.4
+
+2001-12-14 14:59  millert
+
+       * configure, lex.yy.c: regen
+
+2001-12-14 14:56  millert
+
+       * strerror.c: Return EINVAL if errnum > sys_nerr
+
+2001-12-14 14:54  millert
+
+       * LICENSE, Makefile.binary, Makefile.in, aclocal.m4, compat.h,
+         config.h.in, defaults.h, interfaces.h, pathnames.h.in, sudo.h,
+         sudo.pod, auth/sudo_auth.h: o Update copyright year
+
+2001-12-14 14:54  millert
+
+       * configure.in: o Don't define STDC_HEADERS unconditionally for
+         IRIX o Update copyright year
+
+2001-12-14 14:53  millert
+
+       * README: update version
+
+2001-12-14 14:52  millert
+
+       * alloc.c, check.c, defaults.c, env.c, fileops.c, find_path.c,
+         fnmatch.c, getcwd.c, getspwuid.c, goodpath.c, interfaces.c,
+         logging.c, lsearch.c, parse.c, parse.lex, parse.yacc,
+         set_perms.c, snprintf.c, sudo.c, testsudoers.c, tgetpass.c,
+         utime.c, visudo.c, auth/afs.c, auth/aix_auth.c, auth/bsdauth.c,
+         auth/dce.c, auth/fwtk.c, auth/kerb4.c, auth/kerb5.c, auth/pam.c,
+         auth/passwd.c, auth/rfc1938.c, auth/secureware.c, auth/securid.c,
+         auth/sia.c, auth/sudo_auth.c: o Reorder some headers and use
+         STDC_HEADERS define properly o Update copyright year
+
+2001-12-14 01:53  millert
+
+       * configure: regen
+
+2001-12-14 01:53  millert
+
+       * tgetpass.c: flags set in signal handlers should be volatile
+         sig_atomic_t
+
+2001-12-14 01:52  millert
+
+       * config.h.in, configure.in: Add checks for volatile and
+         sig_atomic_t
+
+2001-12-14 01:42  millert
+
+       * lex.yy.c, configure: regen
+
+2001-12-14 01:40  millert
+
+       * def_data.c, def_data.h, def_data.in, defaults.c, env.c,
+         find_path.c, sudo.c, sudoers.pod: Remove "secure_path" Defaults
+         option since it cannot work with the existing parser.
+
+2001-12-14 01:26  millert
+
+       * find_path.c, sudo.c: Unset "secure_path" if user_is_exempt()
+
+2001-12-14 01:24  millert
+
+       * env.c, pathnames.h.in: o Remove assumption that PATH and TERM are
+         not listed in env_keep o If no PATH is in the environment use a
+         default value o If TERM is not set in the non-reset case also
+         give it a default   value.
+
+2001-12-14 01:17  millert
+
+       * aclocal.m4, configure.in, defaults.c, pathnames.h.in:
+         _PATH_SENDMAIL -> _PATH_SUDO_SENDMAIL so --without-sendmail works
+         on systems that define  in paths.h
+
+2001-12-14 01:15  millert
+
+       * auth/: passwd.c, sudo_auth.c, sudo_auth.h: Add support for
+         skeyaccess(3) if it is present in libskey.
+
+2001-12-12 21:42  millert
+
+       * sudo.c: Only need to do 'lc = login_getclass(NULL)' if lc == NULL
+
+2001-12-12 21:24  millert
+
+       * parse.lex: '\\' is a perfectly legal character to have in a
+         command line argument.
+
+2001-12-12 20:24  millert
+
+       * sudo.c: o Defer call to set_fqdn() until it is safe to use
+         log_error() o Don't print errno string value if gethostbyname
+         fails, it is not relevant
+
+2001-12-12 20:07  millert
+
+       * parse.c: Fix CIDR -> in_addr_t conversion.
+
+2001-12-12 16:21  millert
+
+       * sudoers.pod: Remove an extra "User_List" in the User_Spec
+         definition From ybertrand AT snoopymail.com
+
+2001-12-12 16:00  millert
+
+       * parse.c: Make 'listpw=never' work for users who are not
+         explicitly mentioned in sudoers.
+
+2001-12-12 15:40  millert
+
+       * sudoers.pod: Remove gratuitous '=' in EBNF grammar; era AT iki.fi
+
+2001-12-12 15:34  millert
+
+       * sudoers.pod: Document new list Defaults type and convert env_keep
+         and env_delete to lists.  Document new env_check option.
+
+2001-12-12 15:11  millert
+
+       * lex.yy.c, sudo.tab.h: regen parser
+
+2001-12-12 14:56  millert
+
+       * parse.lex: Don't let '#' appear in a {WORD} and restrict #foo in
+         a Runas spec to #[0-9-]+.
+
+2001-12-12 14:55  millert
+
+       * configure: regen
+
+2001-12-12 14:55  millert
+
+       * aclocal.m4: Simpler SUDO_FUNC_ISBLANK that uses AC_TRY_LINK
+
+2001-12-12 14:43  millert
+
+       * config.h.in, configure.in: Add check for skeyaccess(3)
+
+2001-12-11 19:47  millert
+
+       * visudo.pod: Document new -c, -f, and -q options
+
+2001-12-11 19:41  millert
+
+       * visudo.c: o Add -f option (alternate sudoers file) o Convert to
+         use getopt(3)
+
+2001-12-11 19:31  millert
+
+       * configure: regen
+
+2001-12-11 19:31  millert
+
+       * aclocal.m4, config.h.in, configure.in: Add check for isblank and
+         a replacement macro if it doesn't exist.
+
+2001-12-11 18:22  millert
+
+       * visudo.c: In check-only mode, don't create sudoers if it does not
+         already exist.
+
+2001-12-11 18:06  millert
+
+       * parse.yacc:  o Add a new token, DEFVAR, to indicate a Defaults
+         variable name
+          o Add support for "+=" and "-=" list operators
+          o replace some 1 and 0 with TRUE and FALSE for greater
+         legibility.
+
+2001-12-11 18:05  millert
+
+       * parse.lex:  o Use exclusive start conditions to remove some
+         ambiguity in the
+            lexer.  Also reorder some things for clarity.
+          o Add support for "+=" and "-=" list operators.
+          o Use the new DEFVAR token to denote a Defaults variable name.
+
+2001-12-11 18:03  millert
+
+       * sudo.h: Prototype init_envtables()
+
+2001-12-11 18:02  millert
+
+       * env.c:  o Convert environment handling to use lists instead of
+         strings.
+            This greatly simplifies routines that need to do "foreach"
+         type
+            operations.
+          o Add new init_envtables() function to set env_check and
+         env_delete
+            defaults based on initial_badenv_table and
+         initial_checkenv_table
+            (formerly sudo_badenv_table).
+
+2001-12-11 18:00  millert
+
+       * defaults.c, defaults.h:  o Add a new LIST type and functions to
+         manipulate it.
+          o This is for use with environment handling variables.
+          o Call new init_envtables() routine inside init_defaults() to
+            initialize the environment lists.
+
+2001-12-11 17:57  millert
+
+       * def_data.c, def_data.h, def_data.in: Convert environment options
+         to use the new LIST type and add a new one, env_check that only
+         deletes if the sanity check fails.
+
+2001-12-11 17:55  millert
+
+       * testsudoers.c: Add dummy version of init_envtables()
+
+2001-12-11 17:53  millert
+
+       * parse.yacc: honor quiet mode
+
+2001-12-11 17:51  millert
+
+       * visudo.c: Add check-only mode
+
+2001-12-10 20:27  millert
+
+       * mkdefaults: Fix generation of entries with NULL descriptions.
+
+2001-12-09 00:27  millert
+
+       * tgetpass.c: Use sigaction_t and quiet a gcc warning.
+
+2001-12-09 00:20  millert
+
+       * sudo.c: Must reset signal handlers before we exec
+
+2001-12-09 00:16  millert
+
+       * auth/: aix_auth.c, bsdauth.c, fwtk.c, pam.c, sudo_auth.c: Be
+         carefule now that tgetpass() can return NULL (user hit ^C).  PAM
+         version needs testing.  Set SIGTSTP to SIG_DFL during password
+         entry so user can suspend us.
+
+2001-12-09 00:14  millert
+
+       * tgetpass.c: Add support for interrupting/suspending tgetpass via
+         keyboard input.  If you suspend sudo from the password prompt and
+         resume it will re-prompt you.
+
+2001-12-09 00:09  millert
+
+       * sudo.c: Don't block keyboard interrupt signals, just set them to
+         SIG_IGN.
+
+2001-12-08 14:48  millert
+
+       * config.h.in: add back HAVE_SIGACTION
+
+2001-12-08 14:44  millert
+
+       * configure: regen
+
+2001-12-08 14:44  millert
+
+       * config.h.in, configure.in, logging.c, sudo.c, visudo.c: Kill
+         POSIX_SIGNALS define and old signal support now that we emulate
+         POSIX ones Also be sure to correctly initialize struct sigaction.
+
+2001-12-08 14:42  millert
+
+       * strerror.c: Don't need config.h or "#ifndef HAVE_STRERROR"
+         wrapper.
+
+2001-12-08 14:39  millert
+
+       * compat.h: Add scaffolding for POSIX signal emulation
+
+2001-12-08 14:36  millert
+
+       * sigaction.c: o Add missing ';' so this compiles o Can't use NULL
+         since we don't include stdio.h
+
+2001-12-08 14:23  millert
+
+       * sigaction.c: Emulate sigaction() using sigvec()
+
+2001-11-12 19:32  millert
+
+       * sudoers.pod: Document new behavior of negative values of
+         timestamp_timeout Fix a typo
+
+2001-11-12 19:31  millert
+
+       * sudo.pod: Add security note about command not being logged after
+         'sudo su' and friends.
+
+2001-11-12 19:19  millert
+
+       * sudo.pod: Mention that -V prints default values when run as root,
+         including the list of environment variables to clear.
+
+2001-11-12 19:14  millert
+
+       * Makefile.in: Run pod2man with --quotes=none to avoid stupid
+         quoting of C<> entries.
+
+2001-11-12 13:12  millert
+
+       * def_data.c, def_data.h, def_data.in, sudoers.pod,
+         auth/sudo_auth.c: Add mail_badpass option Also modify mail_always
+         behavior to also send mail when the password is wrong
+
+2001-11-12 13:08  millert
+
+       * env.c, sudo.c, sudo.h: Dump default bad env table when 'sudo -V'
+         is run by root.
+
+2001-11-11 23:52  millert
+
+       * sudoers.pod: document env_delete
+
+2001-11-11 23:51  millert
+
+       * env.c: Add support for '*' in env_keep when not resetting the
+         environment (ie: the normal case).
+
+2001-11-11 23:47  millert
+
+       * env.c: Add env_delete variable that lets the user replace/add to
+         the bad_env_table.  Allow '*' wildcard in env_keep entries.
+
+2001-11-06 13:59  millert
+
+       * mkinstalldirs: Force umask to 022 to guarantee sane directory
+         permissions.
+
+2001-11-02 18:09  millert
+
+       * Makefile.in: add sudo.tab.h and sudo.tab.c to sudo.tab.o
+         dependency
+
+2001-11-02 17:25  millert
+
+       * mkdefaults: fix breakage in last commit
+
+2001-11-02 17:18  millert
+
+       * Makefile.in: acsite.m4 -> aclocal.m4
+
+2001-11-02 15:59  millert
+
+       * check.c: fix I_TS_TIMEOUT vs. I_TIMESTAMP_TIMEOUT pasto in
+         previous commit
+
+2001-11-02 15:57  millert
+
+       * def_data.c: regenerated from def_data.in
+
+2001-11-02 15:56  millert
+
+       * check.c, defaults.c, defaults.h: Add new T_UINT type that most
+         things use instead of T_INT If timestamp_timeout is < 0 then
+         treat the ticket as never expiring (to be expired manually by the
+         user).
+
+2001-11-02 15:51  millert
+
+       * def_data.in: change most T_INT -> T_UINT
+
+2001-11-02 15:51  millert
+
+       * mkdefaults: fix warning when no args
+
+2001-11-02 12:52  millert
+
+       * visudo.c: Change 2 Exit() -> exit() Avoid stdio in Exit() and
+         call _exit() if we are a signal handler.  We no longer print the
+         signal number but the user can just check the exit value for
+         that.
+
+2001-10-16 01:35  millert
+
+       * logging.c: when setting up pipes in child process check for case
+         where stdin == pipe fd 0
+
+2001-10-11 13:20  millert
+
+       * visudo.c: Ignore editor exit value since XPG4 says vi's exit
+         value is the count of editing errors made (failed searches, etc).
+
+2001-10-05 16:39  millert
+
+       * configure: regen
+
+2001-10-05 16:39  millert
+
+       * configure.in: sco now is identified by config.guess as *-sco-*
+
+2001-10-05 16:24  millert
+
+       * configure.in: Check for getspnam() in -lgen if not in -lc for
+         UnixWare.
+
+2001-09-17 21:48  millert
+
+       * sudoers.pod, visudo.pod: "upper case" -> "uppercase"
+
+2001-09-17 21:32  millert
+
+       * sudoers.pod: fix typos and grammar; pjanzen@foatdi.harvard.edu
+
+2001-08-28 10:26  millert
+
+       * sudoers.pod: Missing word (specify); krapht@secureops.com
+
+2001-08-23 17:43  millert
+
+       * sudo.c: If we fail to lookup a login class, apply the default
+         one.
+
+2001-08-23 17:42  millert
+
+       * logging.c: In log_error() free message, not logline
+         unconditionally, then free logline if it is not the same as
+         message.  No function change but this mirrors how they are
+         allocated.
+
+2001-07-16 23:33  millert
+
+       * configure: regenerate
+
+2001-07-16 23:33  millert
+
+       * configure.in: remove some backslash quotes that are unneeded
+
+2001-07-16 23:30  millert
+
+       * configure.in: o Tweaks to make this work with autoconf-2.50 o Use
+         AC_LIBOBJ instead of changing LIBOBJS directly o Use
+         AC_REPLACE_FUNCS where we can o Use AC_CHECK_FUNCS instead of
+         AC_CHECK_FUNC so we don't have to   AC_DEFINE things manually.
+
+2001-07-16 23:28  millert
+
+       * config.guess, config.sub: Updated from autoconf-2.50
+
+2001-05-22 19:11  millert
+
+       * README: Update mailing list section.  We use mailman now, not
+         majordomo.
+
+2001-05-10 14:55  millert
+
+       * getspwuid.c, logging.c, sudo.c: Use setpwent()/endpwent() + all
+         the shadow variants to make sure we don't inadvertantly leak an
+         fd to the child.  Apparently Linux's shadow routines leave the fd
+         open even if you don't call setspent().  Reported by
+         mike@gistnet.com; different patch used.
+
+2001-04-12 21:43  millert
+
+       * sudoers.pod: s/eg./e.g./
+
+2001-04-12 21:42  millert
+
+       * tgetpass.c: select() may return EAGAIN.  If so, continue like we
+         do for EINTR.
+
+2001-04-12 21:41  millert
+
+       * logging.c: Fix a non-exploitable buffer overflow in the word
+         splitting code.  This should really be rewritten.
+
+2001-04-12 21:41  millert
+
+       * Makefile.in: FAQ link goes away
+
+2001-04-12 21:40  millert
+
+       * INSTALL: Tell people to look in sample.syslog.conf for examples,
+         not FAQ
+
+2001-04-12 21:40  millert
+
+       * TROUBLESHOOTING: Update list of env vars that are cleared
+
+2001-04-12 21:36  millert
+
+       * sudo.c: remove struct env_table decl since that stuff has all
+         moved to env.c
+
+2001-04-04 13:17  millert
+
+       * fileops.c: Fix a pasto in flock-style unlocking and include
+         <sys/file.h> for flock on older systems; twetzel@gwdg.de
+
+2001-04-04 13:14  millert
+
+       * configure: regen to get NeXT lockf/flock fix
+
+2001-04-04 13:14  millert
+
+       * configure.in: force NeXT to use flock since lockf is broken
+
+2001-03-30 08:54  millert
+
+       * check.c: Use stashed user_gid when checking against exempt gid
+         since sudo sets its gid to a a value that makes sudoers readable.
+         Previously if you used gid 0 as the exempt group everyone would
+         be exempt.  From Paul Kranenburg <pk@cs.few.eur.nl>
+
+2001-03-29 13:14  millert
+
+       * configure: regen
+
+2001-03-29 13:08  millert
+
+       * aclocal.m4: #include stdio.h in SUDO_CHECK_TYPE since IRIX 6
+         aparently defines some types (such as ssize_t) therein.
+
+2001-03-02 09:09  millert
+
+       * defaults.c: Fix negation of paths in a boolean context.  Problem
+         found by apt@UH.EDU
+
+2001-02-23 13:03  millert
+
+       * visudo.c: pasto
+
+2001-02-17 16:11  millert
+
+       * visudo.c: SA_RESETHAND means the opposite of what I was
+         thinking--oops To block all signals in old-style signals use ~0,
+         not 0xffffffff
+
+2001-02-04 11:16  millert
+
+       * defaults.c: coerce difference of pointers to int when used in a
+         string length printf format; deraadt@openbsd.org
+
+2001-01-17 11:34  millert
+
+       * visudo.c: Block all signals in Exit() to avoid a signal race.
+         There is still a tiny window but I'm not going to worry about it.
+
+2001-01-07 13:57  millert
+
+       * env.c: glibc uses the LANGUAGE env var so clear that too; Solar
+         Designer
+
+2001-01-07 13:55  millert
+
+       * lex.yy.c: Regenerate with a fix to flex.skl that preserves errno
+         from clobbering by isatty().
+
+2000-12-30 20:39  millert
+
+       * auth/: aix_auth.c, bsdauth.c, fwtk.c, pam.c, sia.c, sudo_auth.c:
+         Some defaults I_ defines got renamed.
+
+2000-12-30 20:38  millert
+
+       * Makefile.in, check.c, def_data.c, def_data.h, def_data.in,
+         defaults.c, defaults.h, env.c, logging.c, mkdefaults, parse.yacc,
+         set_perms.c, sudo.c: Move defaults info into its own files from
+         which we generate .h and .c files.  This makes adding or
+         rearranging variables much simpler.
+
+2000-12-30 16:58  millert
+
+       * configure, configure.in: fix typo in last commit
+
+2000-12-30 16:55  millert
+
+       * compat.h, config.h.in, configure, configure.in: Add check +
+         emulation for setegid (like seteuid).
+
+2000-12-30 16:22  millert
+
+       * env.c: Make env_keep override badenv_table as documented Fix
+         traversal of badenv_table (broken in last commit)
+
+2000-12-29 22:59  millert
+
+       * set_perms.c, sudo.c, sudo.h: Don't try and build saved uid
+         version of set_perms on systems w/o them.  Rename
+         set_perms_saved_uid() -> set_perms_posix() Make
+         set_perms_setreuid simply be set_perms_fallback() and simply
+         include   the appropriate function at compile time (setreuid()
+         vs. setuid()).
+
+2000-12-29 22:45  millert
+
+       * sudoers.pod, sudoers.cat, sudoers.man.in: PATH is also preserved
+         when env_reset is in effect
+
+2000-12-29 22:29  millert
+
+       * CHANGES, env.c, Makefile.in, check.c, compat.h, config.h.in,
+         configure, configure.in, defaults.c, defaults.h, find_path.c,
+         getspwuid.c, set_perms.c, sudo.c, sudo.cat, sudo.h, sudo.man.in,
+         sudo.pod, sudoers.cat, sudoers.man.in, sudoers.pod,
+         testsudoers.c, visudo.c, visudo.cat, visudo.man.in: New Defaults
+         options:  o stay_setuid - sudo will remain setuid if system has
+         saved uids or setreuid(2)  o env_reset - reset the environment to
+         a sane default  o env_keep - preserve environment variables that
+         would otherwise be cleared
+
+         No longer use getenv/putenv/setenv functions--do environment
+         munging by hand.  Potentially dangerous environment variables can
+         be cleared only if they contain '/' pr '%' characters to protect
+         buggy programs.  Moved environment routines into env.c (new file)
+
+2000-12-29 22:17  millert
+
+       * INSTALL: Clear up --without-passwd description
+
+2000-12-29 19:39  millert
+
+       * sudo_setenv.c, putenv.c: We now build up a new environment from
+         scratch and assign it to "environ".
+
+2000-12-18 22:35  millert
+
+       * sudo.pod, visudo.pod: Grammatical fixes from Paul Janzen
+
+2000-12-14 23:19  millert
+
+       * visudo.c: If there was a syntax error and the user just wants to
+         quit, unlink sudoers if it is zero length.
+
+2000-12-14 23:10  millert
+
+       * visudo.c: 'Q' means ignore parse error, not 'q'
+
+2000-12-14 22:57  millert
+
+       * visudo.c: Open sudoers for writing with mode SUDOERS_MODE From
+         Dimitry Andric <dim@xs4all.nl>
+
+2000-12-13 12:23  millert
+
+       * set_perms.c: Add missing #ifdef HAVE_LOGIN_CAP_H;
+         ayamura@ayamura.org
+
+2000-12-09 11:46  millert
+
+       * config.guess, config.sub: Darwin / Mac OS X support from Wilfredo
+         Sanchez <wsanchez@apple.com>
+
+2000-11-03 09:36  millert
+
+       * sudo.c, visudo.c: Use exit(127), not exit(-1)
+
+2000-11-03 00:37  millert
+
+       * defaults.h, set_perms.c, sudo.c, Makefile.in, defaults.c: Move
+         set_perms() to its own file and use POSIX saved uid or setreuid()
+         if available.
+
+         Added stay_setuid option for systems that have libraries that
+         perform extra paranoia checks in system libraries for setuid
+         programs (ie: anything with issetugid(2)).
+
+2000-11-02 20:28  millert
+
+       * sudo.c: strip more bits from the environment and add a facility
+         for stripping things only if they contain '/' or '%' to address
+         printf format string vulnerabilities in other programs.
+
+2000-11-02 12:55  millert
+
+       * configure: regen
+
+2000-11-02 12:55  millert
+
+       * configure.in: For NCR, add -lc89 to LIBS, not SUDO_LIBS and cache
+         the existence of strcasecmp().
+
+2000-11-02 12:46  millert
+
+       * configure: regen
+
+2000-11-02 12:46  millert
+
+       * configure.in: Check for strcasecmp(3) in -lc89 for NCR Unix
+
+2000-11-01 10:22  millert
+
+       * config.h.in: Define HAVE_INNETGR #ifdef HAVE__INNETGR
+
+2000-11-01 10:17  millert
+
+       * configure: regen
+
+2000-11-01 10:17  millert
+
+       * compat.h, config.h.in, configure.in: Add check for _innetgr(3)
+         since NCR systems have that instead of innetgr(3).
+
+2000-10-31 14:16  millert
+
+       * auth/securid.c: check return value of creadcfg() call sd_close()
+         after sd_auth() store username in sd->username so we don't rely
+         on the USER env variable
+
+2000-10-29 23:00  millert
+
+       * INSTALL: document --with-bsdauth
+
+2000-10-29 22:57  millert
+
+       * configure: regen
+
+2000-10-29 22:56  millert
+
+       * configure.in: --with-bsdauth assumes --with-logincap
+
+2000-10-29 22:45  millert
+
+       * auth/: bsdauth.c, fwtk.c: When prompting for a response to a
+         challenge, if the user just hits return then reprompt with echo
+         turned on.
+
+2000-10-29 17:31  millert
+
+       * sudo.c: Remove debugging code that should not have been
+         committed, oops.
+
+2000-10-29 17:31  millert
+
+       * auth/bsdauth.c: Use lower-level routines and get the password
+         ourselves.  Checks for a challenge and if there is one echo is
+         not turned off.
+
+2000-10-29 17:30  millert
+
+       * auth/: pam.c, sudo_auth.h: minor housekeeping, no real code
+         changes
+
+2000-10-27 18:41  millert
+
+       * sudo.c: Fix a coredump in the logging functions if gethostname(2)
+         fails by deferring the call to log_error() until things are
+         better setup.
+
+         Fix return value of set_loginclass() in non-BSD-auth case.
+
+         Hard-code 'sudo' in the usage message so we can fit more options
+         on a line
+
+2000-10-27 18:35  millert
+
+       * logging.c: Fix errant ';' (typo) that broken MSG_ONLY
+
+2000-10-26 13:03  millert
+
+       * sudo.cat, sudo.man.in: regen
+
+2000-10-26 13:01  millert
+
+       * sudo.pod: Document -a flag
+
+2000-10-26 12:42  millert
+
+       * Makefile.in, config.h.in, configure, configure.in, getspwuid.c,
+         sudo.c, auth/sudo_auth.h, auth/bsdauth.c: Add support for BSD
+         authentication.
+
+2000-10-19 10:09  millert
+
+       * sudoers.pod: Fix typo; from sato@complex.eng.hokudai.ac.jp
+
+2000-10-12 09:49  millert
+
+       * sudoers.pod: Mention negating umask
+
+2000-10-12 01:30  millert
+
+       * defaults.c: Allow user to specify umask of 0777 (same as !umask)
+
+2000-10-08 21:46  millert
+
+       * sudo.pod, visudo.pod: Fix a typo and give a URL for the sudo
+         history.
+
+2000-10-08 12:25  millert
+
+       * defaults.c, sudo.pod: fix typos; pepper@reppep.com
+
+2000-09-14 16:48  millert
+
+       * sudo.c, sudo.h, sudo_setenv.c: sudo_setenv() now exits on memory
+         alloc failure instead of returning -1.
+
+2000-09-07 17:41  millert
+
+       * sudo.c: Strip out NLSPATH and PATH_LOCALE from the environment
+         for FreeBSD and possibly others.
+
+2000-09-07 10:43  millert
+
+       * logging.c: Don't use vsyslog(3) since HP-UX (and others?) lack
+         it.  This means that "%m" won't be expanded but we don't use that
+         anyway since the logging routines may splat to stderr as well.
+
+2000-09-06 21:35  millert
+
+       * defaults.c, defaults.h, sudo.c, sudoers.cat, sudoers.man.in,
+         sudoers.pod: Add always_set_home variable
+
+2000-09-06 21:24  millert
+
+       * configure, configure.in: Have to hard code default values in help
+         since the defaults are set _after_ the help stuff.
+
+2000-08-31 13:08  millert
+
+       * lex.yy.c, parse.lex: Allow special characters (including '#') to
+         be embedded in pathnames if quoted by a '\\'.  The quoted chars
+         will be dealt with by fnmatch().  Unfortunately, 'sudo -l' still
+         prints the '\\'.
+
+2000-08-13 17:10  millert
+
+       * install-sh: Better path searching for programs we need.
+
+2000-08-13 17:10  millert
+
+       * TROUBLESHOOTING: Add section on "C compiler cannot create
+         executables" errors.
+
+2000-08-13 17:10  millert
+
+       * Makefile.binary, Makefile.in, version.h: Crank version
+
+2000-08-13 17:09  millert
+
+       * aclocal.m4, configure, configure.in, sudo.cat, sudo.man.in,
+         sudo.pod, sudoers.cat, sudoers.man.in, sudoers.pod, visudo.cat,
+         visudo.man.in, visudo.pod: Substitute values from configure into
+         man pages.
+
+2000-08-12 16:48  millert
+
+       * parse.c, sudo.c: The listpw and verifypw sudoers options would
+         not take effect because the value of the default was checked
+         *before* sudoers was parsed.  Instead of passing in the value of
+         PWCHECK_* to sudoers_lookup(), pass in the arg for def_ival() so
+         the check can be deferred until after sudoers is parsed.
+
+2000-08-11 15:41  millert
+
+       * tgetpass.c: When writing prompt, no need to write the NUL as
+         well; hag@linnaean.org
+
+2000-06-09 12:25  millert
+
+       * install-sh: When looking for chown, check in /sbin too
+
+2000-06-04 22:57  millert
+
+       * visudo.c: Remove extraneous call to init_defaults() and set
+         runas_user to NULL betweem parses so init_defaults will reset it
+         each time, thus avoiding a reference to free()d data.
+
+2000-06-04 19:57  millert
+
+       * config.h.in, interfaces.c, interfaces.h, sudo.c: Add support for
+         using getifaddrs() to get the list of ip addr / netmask pairs.
+         Currently IPv4-only.
+
+2000-06-04 19:51  millert
+
+       * visudo.c: Add a missing check for UserEditor == NULL Add missing
+         '+' before line number when invoking editor to fix a syntax error
+
+2000-05-12 16:55  millert
+
+       * sudo.c: Call clean_env very early in main() for paranoia's sake.
+         Idea from Marc Esipovich.
+
+2000-05-10 01:11  millert
+
+       * sudo.h: Update proto for evasprintf and easprintf
+
+2000-05-10 01:10  millert
+
+       * alloc.c: Make easprintf() and evasprintf() return an int.
+
+2000-05-10 00:56  millert
+
+       * check.c: If the targetpw flag is set, use target username as part
+         of the timestamp path.  If tty tickets are in effect cat the tty
+         and the target username with a ':' as the separator.
+
+2000-05-09 12:05  millert
+
+       * auth/pam.c: Backout part of last change; setting PAM_USER to the
+         invoking user breaks things like targetpw.
+
+2000-05-09 11:52  millert
+
+       * auth/pam.c: set tty and username via pam_set_item
+
+2000-05-09 11:42  millert
+
+       * check.c, getspwuid.c, sudo.c, sudo.h, auth/sudo_auth.c: Fix root,
+         runas, and target authentication for non-passwd file auth
+         methods.
+
+2000-04-22 14:15  millert
+
+       * sudo.pod, sudo.man.in, sudoers.man.in, sudoers.pod, visudo.pod,
+         sudo.cat, sudoers.cat, visudo.man.in, visudo.cat: Use B<-Z> not
+         C<-Z> for command line flags in all places.  This is more
+         consistent and works around a bug in Pod::Man.
+
+2000-04-22 13:59  millert
+
+       * sudoers.cat, sudoers.man.in, sudoers.pod: Fix an occurence of
+         'semicolon' that should be 'colon'
+
+2000-04-19 15:30  millert
+
+       * configure, configure.in: Fix --with-badpri help line
+
+2000-04-17 14:01  millert
+
+       * defaults.c, logging.c, sudo.c: Bracket calls to syslog with an
+         openlog() and closelog() since some authentication methods (like
+         PAM) may do their own logging via syslog.  Since we don't use
+         syslog much (usually just once per session) this doesn't really
+         incur a performance penalty.  It also Fixes a SEGV with pam_kafs.
+
+2000-04-15 16:32  millert
+
+       * sudo.c: Fix -H flag.  runas_homedir is only valid after
+         set_perms(PERM_RUNAS, mode)
+
+2000-04-12 18:56  millert
+
+       * INSTALL: Clarify the fact that insults are not enabled just by
+         including them in the binary.
+
+2000-04-07 10:39  millert
+
+       * sudo.man.in, sudoers.man.in, visudo.man.in, sudo.cat,
+         sudoers.cat, visudo.cat: Regenerated with perl 5.6.0 pod2man
+
+2000-04-07 10:38  millert
+
+       * Makefile.in: Give date string to pod2man since its default is
+         ugly and it ain't got no alibi.
+
+2000-04-07 10:27  millert
+
+       * Makefile.in: Do section substitution on the output of pod2man and
+         remove hack needed for old pod2man.
+
+2000-04-07 10:26  millert
+
+       * sudo.pod, sudoers.pod, visudo.pod: Put back real man sections, we
+         will do the substitution later.
+
+2000-04-02 11:44  millert
+
+       * configure, configure.in: Don't bother checking for the path to vi
+         if user specified --with-editor
+
+2000-04-01 17:25  millert
+
+       * CHANGES, visudo.c: Visudo now does its own fork/exec instead of
+         calling system(3).
+
+2000-04-01 16:23  millert
+
+       * CHANGES, INSTALL, Makefile.in, sudoers.cat, sudoers.man.in,
+         sudoers.pod, visudo.c: Visudo now checks for the existence of an
+         editor and gives a sensible error if it does not exist.
+
+         The path to the editor for visudo is now a colon-separated list
+         of allowable editors.  If the user has $EDITOR set and it matches
+         one of the allowed editors that editor will be used.  If not, the
+         first editor in the list that actually exists is used.
+
+2000-04-01 16:22  millert
+
+       * sudo.pod, sudo.cat, sudo.man.in: Clear up confusion wrt sudo's
+         return value.
+
+2000-03-27 12:08  millert
+
+       * Makefile.in: Strip sudo and visudo for bindist target
+
+2000-03-26 22:26  millert
+
+       * sudo.cat, sudo.man.in, sudo.pod, sudoers.cat, sudoers.man.in,
+         sudoers.pod, visudo.cat, visudo.man.in, visudo.pod: Use
+         @mansectsu@ and @mansectform@ in the man page bodies as well.
+
+2000-03-26 22:07  millert
+
+       * visudo.cat, visudo.man.in, visudo.pod: Typo: @sysconf@ ->
+         @sysconfdir@
+
+2000-03-26 21:57  millert
+
+       * Makefile.in: 'make dist' should not cause any files to be
+         modified so remove its dependencies.
+
+2000-03-26 21:43  millert
+
+       * CHANGES: Whoops, forgot to add release marker
+
+2000-03-26 11:57  millert
+
+       * CHANGES: Final change for 1.6.3 (or so I hope)
+
+2000-03-26 11:57  millert
+
+       * sudo.cat, sudoers.cat, visudo.cat: Use SYSV man sections since
+         BSD systems will have nroff...
+
+2000-03-24 18:58  millert
+
+       * parse.yacc: When checking to see if the host/user matches in a
+         defaults spec, check against TRUE, not just non-zero since it
+         might be -1.
+
+2000-03-24 15:14  millert
+
+       * configure.in, configure: OSF/1 puts file formats in section 4,
+         not 5.
+
+2000-03-24 15:13  millert
+
+       * CHANGES, INSTALL, sudo.c: Make login class support work on BSD/OS
+
+2000-03-23 20:24  millert
+
+       * RUNSON: Update for 1.6.3
+
+2000-03-23 20:23  millert
+
+       * configure, configure.in: If there is no inet_addr but there *is*
+         an __inet_addr that's ok since inet_addr is probably just a macro
+         then.  The better thing to do would be to look for the macro, but
+         this is fine for now.
+
+2000-03-23 19:50  millert
+
+       * configure, configure.in: Don't use shlicc for BSD/OS 4.x
+
+2000-03-23 19:40  millert
+
+       * Makefile.in, configure, configure.in: *.man lives in cwd, *.cat
+         lives in $(srcdir), add a @mansrcdir@ configure variable so we
+         can deal with this.  Also, only remove *.man for 'distclean' not
+         'clean'.
+
+2000-03-23 19:16  millert
+
+       * sudo.c: set_loginclass() should be static like the proto says
+
+2000-03-23 14:14  millert
+
+       * fnmatch.c: Add #ifdef __STDC__ around the rangematch function
+         header to avoid promotion of test to int, thus violating the
+         prototype.  Gcc handles this gracefully but more std ANSI
+         compilers will complain.
+
+2000-03-23 10:11  millert
+
+       * emul/fnmatch.h: Pull in newer fnmatch(3) that supports
+         FNM_CASEFOLD
+
+2000-03-23 10:11  millert
+
+       * aclocal.m4, configure, fnmatch.3, fnmatch.c: Pull in newer
+         fnmatch(3) that supports FNM_CASEFOLD Check for FNM_CASEFOLD in
+         configure
+
+2000-03-22 23:41  millert
+
+       * CHANGES, TODO: update for 1.6.3
+
+2000-03-22 23:38  millert
+
+       * lex.yy.c, parse.c, parse.h, parse.lex, parse.yacc, sudo.tab.h,
+         testsudoers.c, visudo.c: Fully qualified hosts w/ wildcards were
+         not matching the FQHOST token type.  There's really no need for a
+         separate token for fully-qualified vs.  unqualified anymore so
+         FQHOST is now history and hostname_matches now decides which
+         hostname (short or long) to check based on whether or not the
+         pattern contains a '.'.
+
+2000-03-22 23:09  millert
+
+       * parse.c, parse.h, parse.yacc, sudoers.pod, testsudoers.c,
+         visudo.c, sudoers.cat, sudoers.man.in: Add support for wildcards
+         in the hostname.
+
+2000-03-22 22:50  millert
+
+       * Makefile.in: Add targets for *.man.in, using config.status to
+         generate *.man from *.man.in
+
+2000-03-22 22:20  millert
+
+       * sudoers.cat, sudoers.man.in, sudoers.pod: Document set_logname
+         option and enbolden refs to sudo and visudo.
+
+2000-03-22 19:35  millert
+
+       * INSTALL, Makefile.in, aclocal.m4, configure, configure.in,
+         sudo.cat, sudo.pod, sudo.man.in, sudoers.cat, sudoers.pod,
+         visudo.cat, visudo.pod, sudoers.man.in, visudo.man.in: Add
+         FreeBSD login.conf support (untested on BSD/OS) based on a patch
+         from Michael D. Marchionna.  configure now does substitution on
+         the man pages, allowing us to fix up the paths and set the
+         section correctly.  Based on an idea from Michael D. Marchionna.
+
+2000-03-22 19:27  millert
+
+       * auth/passwd.c: Better fix for handling HP-UX aging info.
+
+2000-03-22 19:20  millert
+
+       * sudo.c: Add support for set_logname run-time default
+
+2000-03-22 19:17  millert
+
+       * sudo.man.in, sudoers.man.in, visudo.man.in: configure does
+         substitution on these to produce *.man
+
+2000-03-22 19:16  millert
+
+       * sudo.man, sudoers.man, visudo.man: These files now get generated
+         from *.man.in at configure time.
+
+2000-03-22 18:40  millert
+
+       * defaults.c, defaults.h: Add set_logname option so users can turn
+         off setting of LOGNAME/USER environment variables.
+
+2000-03-22 10:53  millert
+
+       * testsudoers.c, lsearch.c, parse.c: kill register
+
+2000-03-13 15:52  millert
+
+       * auth/passwd.c: HP-UX adds extra info at the end for password
+         aging so when comparing the result of crypt to pw_passwd we only
+         compare the first len(epass) bytes *unless* the user entered an
+         empty string for a password.
+
+2000-03-13 11:05  millert
+
+       * logging.c: Get rid of grandchild hack, it was causing problems
+         and there is really no need for it.  This fixes a bug where we
+         spin eating up CPU when the user runs a long-running process like
+         a shell.
+
+2000-03-07 14:26  millert
+
+       * sudo.c: User can always specify a login class if he/she is
+         already root.
+
+2000-03-06 23:29  millert
+
+       * config.h.in, configure, configure.in, defaults.c, defaults.h,
+         sudo.c, sudo.h: FreeBSD login class (login.conf) support.
+
+2000-03-06 14:42  millert
+
+       * auth/sudo_auth.c: HAVE_SECUREWARE -> HAVE_GETPRPWNAM; fixes
+         secureware support
+
+2000-03-03 18:04  millert
+
+       * auth/passwd.c: Truncate unencrypted password to 8 chars if
+         encrypted password is exactly 13 characters (indicateing standard
+         a DES password).  Many versions of crypt() do this for you, but
+         not all (like HP-UX's).
+
+2000-03-01 21:01  millert
+
+       * INSTALL, RUNSON: Mention that gcc on dynix may have problems
+
+2000-02-29 17:46  millert
+
+       * Makefile.in: Link visudo with NET_LIBS since we now call syslog
+         via defaults.c
+
+2000-02-29 17:41  millert
+
+       * defaults.c: Use Argv[0] as the first arg to openlog() since
+         visudo uses this too.
+
+2000-02-28 18:58  millert
+
+       * sudo.c: Stash coredumpsize resource limit and retsore it before
+         the exec() Otherwise the child ends up with a coredumpsize of 0.
+
+2000-02-26 22:56  millert
+
+       * sudo.cat, sudo.man, sudo.pod: document -S flag
+
+2000-02-26 22:54  millert
+
+       * sudo.c: fix usage string
+
+2000-02-26 22:48  millert
+
+       * CHANGES, RUNSON, TODO, sudo.c, sudo.h, tgetpass.c,
+         auth/aix_auth.c, auth/fwtk.c, auth/pam.c, auth/sudo_auth.c: Added
+         -S flag (read passwd from stdin) and tgetpass_flags global that
+         holds flags to be passed in to tgetpass().  Change echo_off param
+         to tgetpass() into a flags field.  There are currently 2 possible
+         flags for tgetpass(): TGP_ECHO and TGP_STDIN.  In tgetpass(),
+         abstract the echo set/clear via macros and if (flags & TGP_ECHO)
+         but echo is not set on the terminal, but sure to set it.
+
+2000-02-26 22:11  millert
+
+       * tgetpass.c: Fixed a bug that caused an infinite loop when the
+         password timeout was disabled.
+
+2000-02-18 12:56  millert
+
+       * CHANGES, defaults.c, defaults.h, getspwuid.c, sudo.c, sudo.h,
+         sudoers.cat, sudoers.man, sudoers.pod, visudo.c: Add rootpw,
+         runaspw, and targetpw options.
+
+2000-02-18 12:11  millert
+
+       * CHANGES, defaults.c, sudoers.cat, sudoers.man, sudoers.pod,
+         visudo.c: enveditor -> env_editor
+
+2000-02-15 19:07  millert
+
+       * BUGS, INSTALL, Makefile.in, README, configure, configure.in,
+         sudo.cat, sudo.man, sudoers.cat, sudoers.man, version.h,
+         visudo.cat, visudo.man: crank versino to 1.6.3
+
+2000-02-15 19:03  millert
+
+       * INSTALL, TODO, defaults.c, defaults.h, sudoers.cat, sudoers.man,
+         sudoers.pod, visudo.c: Add 'editor' and 'enveditor' sudoers
+         defaults and make visudo honor them.  This means that visudo will
+         now parse the sudoers file *before* it is edited so a bogus
+         sudoers file will cause a warning to go to stderr.  Also, visudo
+         checks the variables once--it does not check them after each
+         editor run since that could be confusing.
+
+2000-02-15 18:49  millert
+
+       * RUNSON: 1.6.2 -> 1.6.2p1
+
+2000-02-15 18:36  millert
+
+       * check.c, sudo.c, sudo.h: Move user_is_exempt prototype into
+         sudo.h
+
+2000-02-13 13:38  millert
+
+       * configure, configure.in: Fix thinko, some && should have been ||
+         in the last commit
+
+2000-02-13 13:28  millert
+
+       * configure, configure.in: Don't initialized Makefile variables to
+         be NULL since the user may want to import variables from their
+         environment.
+
+2000-02-03 21:09  millert
+
+       * configure, configure.in: typo
+
+2000-01-27 15:01  millert
+
+       * INSTALL, RUNSON, configure, configure.in: Make pam work on HP-UX
+         11.0;jaearick@colby.edu
+
+2000-01-27 15:01  millert
+
+       * CHANGES: recent changes; prepare for 1.6.2p1
+
+2000-01-26 23:31  millert
+
+       * find_path.c: Don't apply SECURE_PATH if user is example;
+         jmknoble@pobox.com
+
+2000-01-26 16:21  millert
+
+       * sudoers.cat, sudoers.man, sudoers.pod: Expanded docs on sudoers
+         'defaults' options based on INSTALL file info.
+
+2000-01-26 16:21  millert
+
+       * INSTALL: Fix some while lies
+
+2000-01-24 10:48  millert
+
+       * Makefile.in: When making a bindist, link FAQ to TROUBLESHOOTING
+         instead of copying.
+
+2000-01-23 22:57  millert
+
+       * sudoers.cat, sudoers.man, sudoers.pod: Add netgroup caveat
+
+2000-01-23 22:42  millert
+
+       * RUNSON: Last minute updates
+
+2000-01-23 22:26  millert
+
+       * TROUBLESHOOTING: PAM entry
+
+2000-01-23 22:23  millert
+
+       * auth/pam.c: correct a comment
+
+2000-01-23 22:03  millert
+
+       * CHANGES, RUNSON: update for 1.6.2
+
+2000-01-23 21:59  millert
+
+       * auth/pam.c: Better detection of PAM errors and fix custom prompts
+         with PAM.  Based on patches from "Cloyce D. Spradling"
+         <cloyce@headgear.org>
+
+2000-01-20 11:15  millert
+
+       * snprintf.c: Cast ULONG_MAX to unsigned long long when comparing
+         to an unsigned long long value.
+
+2000-01-19 14:07  millert
+
+       * CHANGES, config.h.in, configure, configure.in, visudo.c: Fix
+         sudoers locking in visudo.  We now lock the sudoers file itself,
+         not the temp file (since locking the temp file can foul up
+         editors).  The previous locking scheme didn't work because the fd
+         was closed too early.
+
+2000-01-19 13:37  millert
+
+       * configure, config.h.in, configure.in: Don't need test for
+         ftruncate() any more.
+
+2000-01-18 21:23  millert
+
+       * configure, configure.in: Add a test for the -Aa flag w/ HP-UX's
+         cc.  Fixes compilation with the unbundled HP-UX cc.
+
+2000-01-18 17:00  millert
+
+       * sudoers.cat, sudoers.man, sudoers.pod: "a a" -> "a"; Aaron
+         Campbell <aaron@cs.dal.ca>
+
+2000-01-17 18:46  millert
+
+       * LICENSE, Makefile.in, defaults.c, defaults.h, parse.c, parse.h,
+         parse.yacc, sudo.c, sudo.h, sudoers.pod, testsudoers.c,
+         tgetpass.c, version.h, visudo.c: update copyright year on changed
+         files
+
+2000-01-17 18:45  millert
+
+       * RUNSON: updates
+
+2000-01-17 18:45  millert
+
+       * CHANGES: aix fix
+
+2000-01-17 18:42  millert
+
+       * INSTALL: Crank version to 1.6.2
+
+2000-01-17 18:11  millert
+
+       * configure: Crank version to 1.6.2
+
+2000-01-17 17:46  millert
+
+       * sudo.c: When using rlimit check for RLIM_INFINITY When computing
+         the value of maxfd, use min(getdtablesize(), RLIMIT_NOFILE)
+
+2000-01-17 12:32  millert
+
+       * CHANGES: recent changes
+
+2000-01-17 12:28  millert
+
+       * BUGS, Makefile.in, README, configure.in, sudo.cat, sudo.man,
+         sudoers.cat, sudoers.man, version.h, visudo.cat, visudo.man:
+         Crank version to 1.6.2
+
+2000-01-17 12:25  millert
+
+       * INSTALL, defaults.c, defaults.h, sudo.c, sudo.h, sudoers.pod: Add
+         'shell_noargs' runtime option back in.  We have to defer checking
+         until after the sudoers file has been parsed but since there are
+         now other options that operate that way this one can too.  Based
+         on a patch from bguillory@email.com.
+
+2000-01-16 23:05  millert
+
+       * defaults.c, defaults.h, parse.c, sudo.c, sudo.h: Add "listpw" and
+         "verifypw" options.
+
+2000-01-16 22:57  millert
+
+       * sudoers.cat, sudoers.man, sudoers.pod: o Fix some typos/omissions
+         o Add section on verifypw and listpw o Define how NOPASSWD
+         interacts with the -v and -l flags
+
+2000-01-14 12:39  millert
+
+       * configure, configure.in: For HP-UX cc, add -Aa to CPPFLAGS.  For
+         HP-UX always add -D_HPUX_SOURCE to CPPFLAGS.
+
+2000-01-14 12:29  millert
+
+       * defaults.c, defaults.h: In struct sudo_defs_types, move the union
+         to the end and don't initialize the union member since that only
+         works with an ANSI compiler.  We set the value of the union by
+         hand in init_defaults() anyway.  This allows sudo to compile on a
+         K&R compiler again.
+
+2000-01-11 13:20  millert
+
+       * parse.c, parse.h, parse.yacc, testsudoers.c, visudo.c:
+         netgr_matches needs to check shost as well as host since they may
+         be different.
+
+2000-01-11 13:17  millert
+
+       * tgetpass.c: End on \r as well as \n
+
+2000-01-02 23:53  millert
+
+       * sudo.c: Update statbuf.st_mode based on SUDOERS_MODE when we are
+         chaning from 0400 to whatever SUDOERS_MODE is (converting from
+         the old sudoers mode).  Assumes that SUDOERS_MODE is less
+         restrictive than 0400 which should always be the case.
+
+2000-01-02 23:43  millert
+
+       * parse.c, parse.yacc, sudo.c, sudo.h: Make treatment of -l and -v
+         sane wrt NOPASSWD flags.  Now allow -l w/o a passwd if there is
+         *any* entry for the user on the host with a NOPASSWD flag.  For
+         -v, only allow w/o a passwd if *all* entries for the user on the
+         host w/ the specified runas user have the NOPASSWD flag set.
+
+2000-01-02 23:26  millert
+
+       * Makefile.in: add check target
+
+1999-12-16 13:02  millert
+
+       * visudo.c: Treat EOF at whatnow prompt like 'x' instead of
+         looping.
+
+1999-12-10 00:09  millert
+
+       * CHANGES: recent changes
+
+1999-12-08 23:04  millert
+
+       * config.h.in, configure, configure.in, sudo.c: Add check for
+         initgroups() since old SYSV lacks this.
+
+1999-12-08 22:54  millert
+
+       * CHANGES, RUNSON, aclocal.m4, config.h.in, configure,
+         configure.in, parse.c, testsudoers.c: o Kill HAVE_FNMATCH_H o
+         Only define HAVE_FNMATCH if <fnmatch.h> exists.
+
+1999-12-06 01:47  millert
+
+       * CHANGES, RUNSON, insults.h, auth/sudo_auth.c: Don't allow insults
+         to be enabled if the insults[] array is empty.  Otherwise there
+         would be division by zero.
+
+1999-12-06 01:25  millert
+
+       * insults.h: Don't care about USE_INSULTS #define since the insult
+         stuff may be overridden at runtime.
+
+1999-12-06 01:23  millert
+
+       * auth/sudo_auth.c: Honor insults flag.
+
+1999-12-05 19:14  millert
+
+       * CHANGES, parse.c: Don't ask the user for a password if the user
+         is not allowed to run the command and the authenticate flag (in
+         sudoers) is false.
+
+1999-12-05 19:05  millert
+
+       * CHANGES, RUNSON, lex.yy.c, parse.lex: o Whenever we get a bare
+         newline we change to the INITIAL state.  o Enter GOTRUNAS when we
+         see Runas_Alias
+
+         This allows #uid to work in a RunasAlias.
+
+1999-12-05 14:06  millert
+
+       * CHANGES, parse.yacc: fix parsing of runas lists: o oprunasuser
+         and runaslist now return a value o in a runasspec, if a runaslist
+         does not return TRUE, set runas_matches to   FALSE.  Normally, a
+         runaslist only returns FALSE for explicitly denied   users.  o
+         since runaslist does not modify the stack there is no need for a
+         push/pop   in runasalias.
+
+1999-12-04 21:54  millert
+
+       * check.c, sudo.c: Don't kill the user's tickets until after
+         sudoers has been parsed since tty_tickets and ticket_dir could be
+         set in sudoers.
+
+1999-12-04 21:18  millert
+
+       * BUGS, CHANGES, Makefile.binary, Makefile.in, README, RUNSON,
+         configure, configure.in, sudo.cat, sudo.man, sudoers.cat,
+         sudoers.man, tgetpass.c, version.h, visudo.cat, visudo.man: crank
+         version to 1.6
+
+1999-12-04 21:18  millert
+
+       * testsudoers.c: add set_fqdn() stub
+
+1999-12-02 15:31  millert
+
+       * INSTALL, defaults.c, defaults.h, sudo.c, sudo.h, sudoers.cat,
+         sudoers.man, sudoers.pod, visudo.c: o Kill shell_noargs option,
+         it cannot work since the command needs to   be set before sudoers
+         is parsed.  o Fix the "set_home" sudoers option (only worked at
+         compile time).  o Fix "fqdn" sudoers option.  We now set
+         host/shost via set_fqdn which   gets called when the "fqdn"
+         option is set in sudoers.  o Move the openlog() to
+         store_syslogfac() so this gets overridden   correctly from the
+         sudoers file.
+
+1999-12-02 15:21  millert
+
+       * auth/securid.c: SecurID support should compile now.
+
+1999-11-28 20:56  millert
+
+       * sudo.pod, visudo.pod, sudo.cat, sudo.man, sudoers.man,
+         visudo.man, sudoers.cat, visudo.cat: fix some syntactic goofs
+
+1999-11-28 18:51  millert
+
+       * sudo.html, sudoers.html, Makefile.in, visudo.html: No longer need
+         the .html files as they are generated automatically on the web
+         site.
+
+1999-11-28 18:49  millert
+
+       * CHANGES, LICENSE: kill characters that made wml unhappy
+
+1999-11-28 18:34  millert
+
+       * HISTORY: typo
+
+1999-11-25 12:05  millert
+
+       * README: majordomo@cs.colorado.edu -> majordomo@courtesan.com
+
+1999-11-24 19:43  millert
+
+       * Makefile.in, configure: Wrap script execution w/ /bin/sh for the
+         benefit of ctm
+
+1999-11-23 22:52  millert
+
+       * sudo.c: Make the -s flag be exclusive too.  Also reorder the
+         flags in the exclusive usage message so they are alphabetical.
+
+1999-11-23 13:27  millert
+
+       * auth/pam.c: make pam errors other than PAM_PERM_DENIED fatal
+
+1999-11-23 13:07  millert
+
+       * auth/API: fix typo
+
+1999-11-23 13:07  millert
+
+       * INSTALL: make it clear that /etc/pam.d/sudo is required on linux
+
+1999-11-23 13:06  millert
+
+       * auth/pam.c: fix a warning on redhat and spew an error if
+         pam_authenticate() returns an error other than AUTH_SUCCESS or
+         PAM_PERM_DENIED
+
+1999-11-23 00:43  millert
+
+       * sudo.cat, sudo.html, sudo.man, sudo.pod: Be very clear that the
+         password required is the user's not root's
+
+1999-11-19 21:04  millert
+
+       * Makefile.in: add sample.syslog.conf to DISTFILES and BINFILES
+
+1999-11-18 19:13  millert
+
+       * RUNSON: updates from Brian Jackson + some formatting
+
+1999-11-17 21:39  millert
+
+       * INSTALL.binary, Makefile.binary, README, RUNSON: o One RUNSon
+         update o Changes for automating real binary releases
+
+1999-11-17 21:38  millert
+
+       * Makefile.in: Add bindist target
+
+1999-11-16 16:26  millert
+
+       * TROUBLESHOOTING: talk about run-time options in addition to
+         compile-time options
+
+1999-11-16 01:16  millert
+
+       * CHANGES: fix typos
+
+1999-11-16 01:09  millert
+
+       * sudo.c: need sys/time.h if HAVE_SETRLIMIT
+
+1999-11-16 00:42  millert
+
+       * PORTING, README, RUNSON, sudo.c, sudo.cat, sudo.html, sudo.man,
+         sudo.pod, visudo.cat, visudo.html, visudo.man, visudo.pod: get
+         rid of references to sudo-bugs.  Now mention the web site or the
+         sudo@ alias
+
+1999-11-16 00:35  millert
+
+       * sudoers.html: repair pod2html damage
+
+1999-11-16 00:28  millert
+
+       * RUNSON, TODO: Update for 1.6 release
+
+1999-11-16 00:23  millert
+
+       * sudoers.cat, sudoers.html, sudoers.man, sudoers.pod: Add warning
+         about using ALL in a command context.
+
+1999-11-09 15:12  millert
+
+       * visudo.c: Call yyrestart() on a parse error to reset the lexer
+         state.
+
+1999-11-09 15:06  millert
+
+       * parse.lex, lex.yy.c: Don't need YY_FLUSH_BUFFER after all Move
+         yyrestart() into visudo.c since it might not get called in yywrap
+         if we get a parse error (and we only reread the file on error
+         anyway).
+
+1999-11-09 14:32  millert
+
+       * parse.lex, lex.yy.c: Call YY_FLUSH_BUFFER macro in yywrap() to
+         clean up any buffers that might still exist.  Call yyrestart()
+         instead of using the deprecated YY_NEW_FILE macro.
+
+1999-11-09 12:13  millert
+
+       * lex.yy.c, parse.lex: flex doesn't need %N table size declarations
+
+1999-11-08 19:00  millert
+
+       * sudoers.cat, sudoers.html, sudoers.man, sudoers.pod: Mention what
+         characters need to be escaped in names.
+
+1999-11-08 18:59  millert
+
+       * configure: regen
+
+1999-11-08 18:59  millert
+
+       * INSTALL: clarify Mac OS X entry
+
+1999-11-08 18:59  millert
+
+       * RUNSON: update
+
+1999-11-08 17:45  millert
+
+       * configure.in: o Use AC_MSG_ERROR throughout o Check syslog
+         configure options for danity
+
+1999-11-05 17:11  millert
+
+       * defaults.c: Fix printing of type T_MODE in dump_defaults()
+
+1999-11-05 12:00  millert
+
+       * strcasecmp.c: missing sys/types.h
+
+1999-11-05 00:42  millert
+
+       * INSTALL: Break out options that may be overridden at run time
+         into their own section.  Add a not about Max OS X and correct
+         some lies.
+
+1999-11-04 14:01  millert
+
+       * CHANGES, config.h.in, configure, configure.in, sudo.c: o Now use
+         getrlimit to find the highest fd when closing all non-std fd's o
+         Turn off core dumps via setrlimit for the sake of paranoia
+
+1999-11-04 13:57  millert
+
+       * RUNSON: updates
+
+1999-11-01 10:59  millert
+
+       * CHANGES: updates
+
+1999-11-01 10:58  millert
+
+       * tgetpass.c: When read()'ing, do a single character at a time to
+         be sure we don't go oast the newline.
+
+1999-11-01 10:43  millert
+
+       * sudo.c: For the sudo_root option, check against user_uid, not
+         getuid() since at this point, ruid == euid == 0.
+
+1999-10-31 23:14  millert
+
+       * RUNSON: some updates
+
+1999-10-31 23:14  millert
+
+       * logging.h: Fix compilation problem when --with-logging=file was
+         specified.  This means that syslog is now required to build sudo
+         but that should not be a problem.  If it is it can be fixed
+         trivially with a configure check for syslog() or syslog.h.
+
+1999-10-31 23:00  millert
+
+       * tgetpass.c: Make this work again for things like "sudo echo hi |
+         more" where the tty gets put into character at a time mode.  We
+         read until we read end of line or we run out of space (similar to
+         fgets(3)).
+
+1999-10-20 11:23  millert
+
+       * sudoers.cat, sudoers.html, sudoers.man, sudoers.pod: change ital
+         to bold
+
+1999-10-20 11:23  millert
+
+       * RUNSON: update
+
+1999-10-16 13:56  millert
+
+       * defaults.c: Error out if syslog parameters are given without a
+         value.  For Ultrix or 4.2BSD "syslog" is allowed without a value
+         since there are no facilities in the 4.2BSD syslog.
+
+1999-10-15 16:37  millert
+
+       * defaults.c: Ignore the syslog facility for systems w/ old syslog
+         like Ultrix.
+
+1999-10-15 12:51  millert
+
+       * TROUBLESHOOTING: people with "." early in their path can have
+         problems running sudo from the build dir ;-)
+
+1999-10-13 00:18  millert
+
+       * sudo.man, sudo.pod, sudo.cat, sudo.html: Remove -r realm option
+
+1999-10-12 22:34  millert
+
+       * configure, configure.in, sudo.c, auth/kerb5.c, auth/sudo_auth.c,
+         auth/sudo_auth.h: New krb5 code from Frank Cusack
+         <fcusack@iconnet.net>.
+
+1999-10-12 22:33  millert
+
+       * CHANGES: update to reality
+
+1999-10-11 20:53  millert
+
+       * auth/fwtk.c: include <auth.h> to get function prototypes.
+
+1999-10-11 20:05  millert
+
+       * sudo.cat, sudo.html, sudo.man, sudo.pod: document -L flag
+
+1999-10-11 19:42  millert
+
+       * sudo.c: in set_perms(), always call setuid(0) before changing the
+         ruid/euid so we always know it will succeed.
+
+1999-10-11 12:24  millert
+
+       * defaults.h: #undef T_FOO to avoid conflicts with system defines
+         (like on ULTRIX).
+
+1999-10-11 11:55  millert
+
+       * TODO, sample.sudoers, sudoers.cat, sudoers.html, sudoers.man,
+         sudoers.pod: Docuement "Defaults" lines in /etc/sudoers.  Still
+         needs some fleshing out but this is a start.
+
+1999-10-10 17:21  millert
+
+       * defaults.c: use strtol, not strtoul since not everyone has not
+         strtoul
+
+1999-10-10 15:01  millert
+
+       * lex.yy.c, parse.lex: last {WORD} rule should only apply in the
+         INITIAL state
+
+1999-10-10 14:38  millert
+
+       * lex.yy.c, parse.lex: o Add support for escaped characters in the
+         WORD macro o Modify fill() to squash escape chars
+
+1999-10-10 13:56  millert
+
+       * defaults.c, defaults.h: o Add T_PATH flag to allow simple sanity
+         checks for default values that   are supposed to be pathnames.  o
+         Fix a duplicate free when visudo finds an error.
+
+1999-10-09 01:01  millert
+
+       * defaults.c, defaults.h, logging.c: mail_if_foo -> mail_foo
+
+1999-10-07 21:12  millert
+
+       * compat.h, defaults.c, defaults.h, sudo.c, tgetpass.c: o Add
+         requiretty option o Move O_NOCTTY to compat.h
+
+1999-10-07 21:12  millert
+
+       * logging.c: The exit() in log_error() was mistakenly removed in a
+         previous version.  Put it back...
+
+1999-10-07 17:20  millert
+
+       * INSTALL, TODO, check.c, config.h.in, configure, configure.in,
+         defaults.c, defaults.h, find_path.c, getspwuid.c, lex.yy.c,
+         logging.c, parse.yacc, sudo.c, auth/aix_auth.c, auth/fwtk.c,
+         auth/pam.c, auth/rfc1938.c, auth/sia.c, auth/sudo_auth.c: o
+         Change defaults stuff to put the value right in the struct.  o
+         Implement mailer_flags o Store syslog stuff both in int and
+         string form.  Setting the string   form magically updates the int
+         version.  o Add boolean attribute to strings where it makes sense
+         to say !foo
+
+1999-10-07 17:13  millert
+
+       * tgetpass.c: add O_NOCTTY when opening /dev/tty just in case
+
+1999-10-06 00:48  millert
+
+       * auth/API: cleanup function no longer takes a status arg
+
+1999-10-06 00:48  millert
+
+       * INSTALL: the the
+
+1999-09-15 05:15  millert
+
+       * TODO, config.h.in, configure, configure.in, logging.c: Use
+         strftime() instead of ctime() if it is available.
+
+1999-09-14 12:58  millert
+
+       * defaults.c: fix copyright date
+
+1999-09-14 12:57  millert
+
+       * RUNSON: update ReliantUNIX entry
+
+1999-09-14 12:56  millert
+
+       * defaults.c, defaults.h, logging.c: add log_year option
+
+1999-09-14 04:01  millert
+
+       * configure, configure.in: add --without-sendmail to help output
+
+1999-09-14 03:42  millert
+
+       * configure, configure.in: enforce an otctal arg for
+         --with-suoders-mode
+
+1999-09-08 04:06  millert
+
+       * BUGS, INSTALL, Makefile.in, TODO, aclocal.m4, check.c,
+         config.h.in, configure, configure.in, defaults.c, defaults.h,
+         find_path.c, lex.yy.c, logging.c, parse.h, parse.lex, parse.yacc,
+         sudo.c, sudo.h, sudo.tab.h, testsudoers.c, version.c, visudo.c,
+         auth/aix_auth.c, auth/fwtk.c, auth/kerb5.c, auth/pam.c,
+         auth/rfc1938.c, auth/sia.c, auth/sudo_auth.c: Add support for
+         "Defaults" line in sudoers to make configuration variables
+         changable at runtime (and on a global, per-host and per-user
+         basis).  Both the names and the internal representation are still
+         subject to change.  It was necessary to make sudo_user.runas but
+         a char ** instead of a char * since this value can be changed by
+         a Defaults line.  There is a similar (but more complicated) issue
+         with sudo_user.prompt but it is handled differently at the
+         moment.
+
+         Add a "-L" flag to list the name of options with their
+         descriptions.  This may only be temporary.
+
+         Move some prototypes to parse.h
+
+         Be much less restrictive on what is allowed for a username.
+
+1999-09-08 04:01  millert
+
+       * sample.syslog.conf: Add more info
+
+1999-09-04 03:09  millert
+
+       * fnmatch.3, fnmatch.c, getcwd.c, lsearch.c, snprintf.c,
+         strcasecmp.c, LICENSE: UCB has dropped the advertising clause
+         from their license.
+
+1999-08-31 05:39  millert
+
+       * auth/sudo_auth.h: move dce_verofy proto to correct section
+
+1999-08-31 05:39  millert
+
+       * auth/dce.c: remove XXX
+
+1999-08-28 06:00  millert
+
+       * emul/fnmatch.h: Add fnmatch() prototype
+
+1999-08-28 06:00  millert
+
+       * fnmatch.c, parse.c, testsudoers.c: Move inclusion of
+         emul/fnmatch.h to be after sudo.h for __P
+
+1999-08-28 05:59  millert
+
+       * sudo.h: add strcasecmp proto
+
+1999-08-28 05:50  millert
+
+       * auth/sudo_auth.c: add check for case where there are no auth
+         methods
+
+1999-08-28 05:36  millert
+
+       * configure, configure.in: Define _XOPEN_EXTENDED_SOURCE on AIX and
+         __USE_FIXED_PROTOTYPES__ on SunOS4 w/ gcc
+
+1999-08-28 05:24  millert
+
+       * getspwuid.c, lex.yy.c, parse.lex, parse.yacc: include strings.h
+         everywhere we include string.h
+
+1999-08-28 05:22  millert
+
+       * version.c: nicer output when showing auth methods
+
+1999-08-28 05:00  millert
+
+       * version.c: Add support for SEND_MAIL_WHEN_NO_HOST
+
+1999-08-28 04:49  millert
+
+       * config.h.in, configure.in, configure: Add _GNU_SOURCE for Linux
+
+1999-08-28 04:22  millert
+
+       * parse.lex, lex.yy.c: fix definition of OCTECT
+
+1999-08-28 04:10  millert
+
+       * configure, configure.in: aix_auth.o not authenticate.o
+
+1999-08-27 17:02  millert
+
+       * sudo.c: Only block SIGINT, SIGQUIT, SIGTSTP (which can be
+         generated from the keyboard).  Since we run with ruid/euid == 0
+         the user can't really signal us in nasty ways.
+
+1999-08-27 17:01  millert
+
+       * visudo.c: Don't need to worry about catching too many signals
+         since we do locking on the tmp file.  If a lockfile is really
+         stale, it will be detected and overwritten.
+
+1999-08-27 16:09  millert
+
+       * INSTALL, Makefile.in: include auth/API in tarball
+
+1999-08-27 16:09  millert
+
+       * auth/sudo_auth.c: move memset() of plaintext pw outside of verify
+         loop and only do the memset if we are *not* in standalone mode.
+
+1999-08-27 13:46  millert
+
+       * auth/: sudo_auth.c, sudo_auth.h: DCE is not a standalone method
+
+1999-08-27 11:53  millert
+
+       * sudo.c: fix --enable-noargs-shell
+
+1999-08-27 11:06  millert
+
+       * snprintf.c: "#ifdef __STDC__" not "#if __STDC__" (I missed one)
+
+1999-08-27 10:54  millert
+
+       * auth/: fwtk.c, sia.c: _cleanup() function returns an int.
+
+1999-08-27 10:50  millert
+
+       * auth/dce.c: there were still some return(0)'s hanging around,
+         make them AUTH_FAILURE
+
+1999-08-27 10:39  millert
+
+       * parse.c: typo in comment
+
+1999-08-27 10:03  millert
+
+       * version.c: add missing semicolon
+
+1999-08-27 08:31  millert
+
+       * auth/sudo_auth.h: missing backslash
+
+1999-08-26 17:24  millert
+
+       * CHANGES, config.h.in, configure, configure.in: Kill
+         _XOPEN_EXTENDED_SOURCE -- causes problems on some OSes
+
+1999-08-26 09:21  millert
+
+       * Makefile.in: add parse.h to HDRS
+
+1999-08-26 09:16  millert
+
+       * Makefile.in, configure, configure.in: Kill VISUDO_LIBS and
+         VISUDO_LDFLAGS.  Add LIBS, NET_LIBS, and LDFLAGS.  Common libs go
+         in LIBS, commong ld flags go in LDFLAGS and network libs like
+         -lsocket, -lnsl go in NET_LIBS.  This allows testsudoers to build
+         on Solaris and is a bit cleaner in general.
+
+1999-08-26 06:56  millert
+
+       * UPGRADE: mention ptmp -> sudoers.tmp
+
+1999-08-26 06:12  millert
+
+       * configure.in, configure, config.h.in: Define
+         _XOPEN_SOURCE_EXTENDED not _XOPEN_SOURCE
+
+1999-08-26 05:37  millert
+
+       * RUNSON: add 2 reports
+
+1999-08-26 05:20  millert
+
+       * auth/kerb5.c: Minor changes, mostly cosmetic.
+         verify_krb_v5_tgt() changed to return a value  more like a system
+         function
+
+1999-08-26 05:19  millert
+
+       * auth/dce.c: Add an XXX
+
+1999-08-26 05:19  millert
+
+       * TODO: more things todo!
+
+1999-08-26 05:18  millert
+
+       * sample.sudoers: update based on what is in the man page
+
+1999-08-26 05:10  millert
+
+       * parse.yacc: minor change to first line printed in -l mode
+
+1999-08-26 05:10  millert
+
+       * sudo.cat, sudo.html, sudo.man, sudo.pod: rename "ENVIRONMENT
+         VARIABLES" section to "ENVIRONMENT" to be more standard and add
+         "EXAMPLES" section
+
+1999-08-26 05:08  millert
+
+       * visudo.cat, visudo.html, visudo.man, visudo.pod: rename
+         "ENVIRONMENT VARIABLES" section to "ENVIRONMENT" to be more
+         standard
+
+1999-08-26 05:06  millert
+
+       * logging.c, parse.c, sudo.h: add FLAG_NO_CHECK
+
+1999-08-26 05:05  millert
+
+       * parse.lex, lex.yy.c: make an OCTET really be limited to 0-255
+
+1999-08-26 05:04  millert
+
+       * UPGRADE: mention timestamp changes
+
+1999-08-26 05:04  millert
+
+       * PORTING: cosmetic cleanup
+
+1999-08-26 05:00  millert
+
+       * sudoers.cat, sudoers.html, sudoers.man, sudoers.pod: new
+         sudoers(8) man page
+
+1999-08-24 13:45  millert
+
+       * version.c: Update comments about syslog name tables
+
+1999-08-24 13:37  millert
+
+       * CHANGES, LICENSE, Makefile.in, configure, strcasecmp.c,
+         configure.in, parse.yacc: include strcasecmp() for those without
+         it
+
+1999-08-24 12:43  millert
+
+       * sample.sudoers: Use the : operator some more and fix a typo
+
+1999-08-24 12:43  millert
+
+       * HISTORY: update the history of sudo
+
+1999-08-24 12:42  millert
+
+       * parse.c, parse.lex, testsudoers.c: CIDR-style netmask support
+
+1999-08-24 12:41  millert
+
+       * CHANGES: recent changes
+
+1999-08-24 12:40  millert
+
+       * sudo.tab.h: these should be generated with byacc, not bison
+
+1999-08-24 12:40  millert
+
+       * lex.yy.c: regen
+
+1999-08-24 11:58  millert
+
+       * parse.h, parse.yacc, sudo.tab.h: In "sudo -l" mode, the type of
+         the stored (expanded) alias was not stored with the contents.
+         This could lead to incorrect output if the sudoers file had
+         different alias types with the same name.  Normal parsing (ie:
+         not in '-l' mode) is unaffected.
+
+1999-08-23 12:47  millert
+
+       * configure, configure.in: define _XOPEN_SOURCE to get at crypt()
+         proto on some systems
+
+1999-08-22 13:10  millert
+
+       * snprintf.c: fix comment
+
+1999-08-22 13:09  millert
+
+       * tgetpass.c: don't need limits.h
+
+1999-08-22 07:36  millert
+
+       * snprintf.c: kill bogus reference to vfprintf
+
+1999-08-22 07:26  millert
+
+       * sample.sudoers, sudoers: better examples
+
+1999-08-22 07:23  millert
+
+       * snprintf.c: Add some const in the K&R defs.  This is safe since
+         we define const away if the compiler doesn't grok it.
+
+1999-08-22 07:22  millert
+
+       * aclocal.m4, configure: Better test for working long long support.
+         Ultrix compiler supports basic long long but not all operations
+         on them.
+
+1999-08-22 05:59  millert
+
+       * aclocal.m4, config.h.in, configure, getspwuid.c, snprintf.c,
+         sudo.c, auth/secureware.c: Add check for LONG_IS_QUAD #undef
+         MAXINT before including hpsecurity.h to silence an HP-UX warning
+         Check for U?LONG_LONG_MAX in snprintf.c and use LONG_IS_QUAD
+
+1999-08-21 15:00  millert
+
+       * LICENSE, aclocal.m4, config.h.in, configure, configure.in,
+         snprintf.c: UCB-derived snprintf + asprintf support.  Supports
+         quads if the compiler does.  No floating point yet, perhaps
+         later...
+
+1999-08-20 16:37  millert
+
+       * check.c, find_path.c, goodpath.c, logging.c, parse.c, sudo.c,
+         auth/API, auth/sudo_auth.c, auth/sudo_auth.h: Run most of the
+         code as root, not the invoking user.  It doesn't really gain us
+         anything to run as the user since an attacker can just have an
+         setuid(0) in their egg.  Running as root solves potential
+         problems wrt signalling.
+
+1999-08-19 13:45  millert
+
+       * logging.c, sudo.c: Don't wait for child to finish in log_error(),
+         let the signal handler get it if we are still running, else let
+         init reap it for us.  The extra time it takes to wait lets the
+         user know that mail is being sent.
+
+         Install SIGCHLD handler in main() and for POSIX signals, block
+         everything *except* SIGCHLD.
+
+1999-08-19 12:30  millert
+
+       * logging.c, parse.c, parse.yacc, sudo.c, configure, sudo.h,
+         INSTALL, config.h.in, configure.in: sudoers_lookup() now returns
+         a bitmap instead of an int.  This makes it possible to express
+         things like "failed to validate because user not listed for this
+         host".  Some thigns that were previously VALIDATE_FOO are now
+         FLAG_FOO.  This may change later on.
+
+         Reorganized code in log_auth() and sudo.c to deal with above
+         changes.
+
+         Safer versions of push/pushcp with in the do { ... } while (0)
+         style
+
+         parse.yacc now saves info on the stack to allow parse.c to
+         determine if a user was listed, but not for the host he/she tried
+         to run on.
+
+         Added --with-mail-if-no-host option
+
+1999-08-17 11:29  millert
+
+       * parse.yacc, sudo.h, visudo.c, visudo.cat, visudo.html,
+         visudo.man, visudo.pod: o NewArgv and NewArgc don't need to be
+         externally visible.  o If pedantic > 1, it is a parse error.  o
+         Add -s (strict) option to visudo which sets pedantic to 2.
+
+1999-08-17 11:26  millert
+
+       * HISTORY, INSTALL: Just have sudo-bugs contact info in one place
+
+1999-08-17 11:20  millert
+
+       * sudo.cat, sudo.html, sudo.man, sudo.pod: Add BUGS section
+
+1999-08-17 10:29  millert
+
+       * configure, configure.in, Makefile.in: Add testsudoers to default
+         build target if --with-devel Don't clean generated parser files
+         unless "distclean".
+
+1999-08-17 08:47  millert
+
+       * parse.yacc: In pedantic mode we need to save *all* the aliases,
+         not just those that match, or we get spurious warnings.
+
+1999-08-17 05:32  millert
+
+       * TROUBLESHOOTING: reference samples.sylog.conf
+
+1999-08-14 11:50  millert
+
+       * sample.syslog.conf: Sample entries for syslog.conf
+
+1999-08-14 11:40  millert
+
+       * CHANGES: recent changes
+
+1999-08-14 11:36  millert
+
+       * auth/: API, afs.c, aix_auth.c, dce.c, fwtk.c, kerb4.c, kerb5.c,
+         pam.c, passwd.c, rfc1938.c, secureware.c, securid.c, sia.c,
+         sudo_auth.c, sudo_auth.h: In struct sudo_auth, turn need_root and
+         configured into flags and add a flag to specify an auth method is
+         running alone (the only one).  Pass auth methods their sudo_auth
+         pointer, not the data pointer.  This allows us to get at the
+         flags and tell if we are the only auth method.  That, in turn,
+         allows the method to be able to decide what should/should not be
+         a fatal error.  Currently only rfc1938 uses it this way, which
+         allows us to kill the OTP_ONLY define and te hackery that went
+         with it.  With access to the sudo_auth struct, methods can also
+         get at a string holding their cannonical name (useful in error
+         messages).
+
+1999-08-14 11:34  millert
+
+       * Makefile.in, INSTALL, README, config.h.in, configure,
+         configure.in, getspwuid.c, lex.yy.c, parse.lex, parse.yacc,
+         sudo.tab.h: o --with-otp deprecated, use --without-passwd instead
+         o real dependencies in the Makefile o --with-devel option to
+         enable yacc, lex, and -Wall o style -- "foo -> bar" becomes
+         "foo->bar" o ALL goes back to being a token, not a string but
+         don't leak memory o rename hsotspec -> host in parse.yacc
+
+1999-08-12 12:26  millert
+
+       * BUGS, CHANGES: recent changes
+
+1999-08-12 12:24  millert
+
+       * configure, configure.in, interfaces.c, snprintf.c, sudo.c,
+         sudo.h, auth/sudo_auth.c: o Digital UNIX needs to check for
+         *snprintf() before -ldb is added to LIBS since -ldb includes a
+         bogus snprintf().  o Add forward refs for struct mbuf and struct
+         rtentry for Digital UNIX.  o Reorder some functions in snprintf.c
+         to fix -Wall o Add missing includes to fix more -Wall
+
+1999-08-12 10:37  millert
+
+       * INSTALL, check.c, config.h.in, configure, configure.in,
+         parse.yacc, testsudoers.c, version.c, visudo.c, auth/sudo_auth.c:
+         o Add a "pedentic" flag to the parser.  This makes sudo warn in
+         cases where an alias may be used before it is defined.  Only
+         turned on for visudo and testsudoers.  o Add
+         --disable-authentication option that makes sudo not require
+         authentication by default.  The PASSWD tag can be used to require
+         authentication for an entry.  We no longer overload
+         --without-passwd.
+
+1999-08-12 10:29  millert
+
+       * lex.yy.c, parse.lex: Break 'WORD' regexp def into HOSTNAME and
+         USERNAME.  These days a username can contain just about anything
+         so be very permissive.  Also drop the unused \. punctuation.
+
+1999-08-09 18:25  millert
+
+       * parse.yacc: o add a 'val' element to aliasinfo struct and move ->
+         parse.h o find_alias() now returns an aliasinfo * instead of
+         boolean o add_alias() now takes a value parameter to store in the
+         aliasinfo.val o The cmnd, hostspec, runasuser, and user rules now
+         return: 1) positive match 0) negative match (due to '!') -1) no
+         match This means setting $$ explicitly in all cases, which I
+         should have done in the first place.  It also means that we
+         always store a value that is != -1 and when we see a '!' we can
+         set *_matches to !rv if rv != -1.  The upshot of all of this is
+         that '!' now works the way it should in lists and some of the
+         rules are more uniform and sensible.
+
+1999-08-09 18:17  millert
+
+       * Makefile.in: add parse.h dependency
+
+1999-08-09 18:17  millert
+
+       * parse.h: kill unused *_matched macros
+
+1999-08-09 10:35  millert
+
+       * parse.yacc: Allow a list of users as the first thing in a user
+         spec, not just a single entry.  This makes things more uniform,
+         though it does allow you to write user specs that are hard to
+         read.
+
+1999-08-09 10:08  millert
+
+       * configure: regen
+
+1999-08-09 10:08  millert
+
+       * configure.in: fix check for crypt() in libufc
+
+1999-08-07 14:03  millert
+
+       * README: sudo-users list now exists
+
+1999-08-07 07:46  millert
+
+       * INSTALL, PORTING, README, TODO, TROUBLESHOOTING: Update to
+         reality.
+
+1999-08-07 05:59  millert
+
+       * CHANGES, Makefile.in, TODO, TROUBLESHOOTING, check.c, compat.h,
+         config.h.in, configure.in, logging.c, sudo.h, version.c,
+         visudo.c, configure, fileops.c: 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.
+
+1999-08-06 09:49  millert
+
+       * logging.c: add fcntl locking
+
+1999-08-06 09:33  millert
+
+       * configure, config.h.in, configure.in, logging.c: Lock the log
+         file.
+
+1999-08-06 05:36  millert
+
+       * Makefile.in, TROUBLESHOOTING, parse.c, pathnames.h.in, sudo.c,
+         visudo.c, visudo.cat, visudo.html, visudo.man, visudo.pod: o
+         /etc/stmp -> /etc/sudoers.tmp since solaris uses stmp as shadow
+         temp file o _PATH_SUDO_SUDOERS -> _PATH_SUDOERS and
+         _PATH_SUDO_STMP -> _PATH_SUDOERS_TMP
+
+1999-08-05 17:38  millert
+
+       * INSTALL, check.c, config.h.in, configure, configure.in,
+         version.c: o Kill *_MESSAGE and replace with NO_LECTURE o Add
+         more things to root sudo -V config reporting
+
+1999-08-05 10:56  millert
+
+       * configure, configure.in: aix_auth.o not authenticate.o
+
+1999-08-05 10:48  millert
+
+       * config.h.in: Add --with-goodpri and --with-badpri configure
+         options to specify the syslog priority to use.
+
+1999-08-05 10:30  millert
+
+       * INSTALL, configure.in, logging.h, configure: Add --with-goodpri
+         and --with-badpri configure options to specify the syslog
+         priority to use.
+
+1999-08-05 10:25  millert
+
+       * compat.h: kill crufty AIX stuff
+
+1999-08-05 06:55  millert
+
+       * Makefile.in: Sigh, some versions of make (like Solaris's) don't
+         deal with $< like I would expect.  Both GNU and BSD makes get
+         this right but...  So, we just expand $< inline at the cost of
+         some ugliness.
+
+1999-08-05 06:52  millert
+
+       * version.c: If the invoking user is root, sudo will now print
+         configure info in -V mode.  Currently just prints logging info,
+         to be expanded later.
+
+1999-08-05 06:51  millert
+
+       * logging.c, logging.h, sudo.c, sudo.h: o new defines for syslog
+         facility and priority o use new print_version() functino for -V
+         mode
+
+1999-08-05 06:49  millert
+
+       * check.c: Don't need version.c
+
+1999-08-05 06:21  millert
+
+       * configure, configure.in, aclocal.m4, config.h.in: Add check for
+         syslog facilities and priorities tables in syslog.h
+
+1999-08-05 05:23  millert
+
+       * Makefile.in: o authenticate -> aix_auth o add version.c
+
+1999-08-05 05:21  millert
+
+       * auth/sudo_auth.c: Missed a prompt -> user_prompt conversion
+
+1999-08-04 13:32  millert
+
+       * TODO: sudo should lock its logfile
+
+1999-08-04 13:28  millert
+
+       * parse.yacc: o Add '!' correctly when expanding Aliases.  o Add
+         shortcut macros for append() to make things more readable.  o The
+         separator in append() is now a string instead of a char.  o In
+         append(), only prepend the separator if the last char is not a
+         '!'.    This is a hack but it greatly simplifies '!' handling.  o
+         In -l mode, Runas lists and NOPASSWD/PASSWD tags are now
+         inherited   across entries in a list (matches current behavior).
+         o Fix formatting in -l mode such that items in a list are
+         separated by   a space.  Greatlt improves readability.  o Space
+         for name field in struct aliasinfo is now allocated dyanically
+         instead of using a (big) buffer.  o In add_alias(), only search
+         the list once (lsearch instead of lfind + lsearch)
+
+1999-08-04 11:31  millert
+
+       * lex.yy.c, sudo.tab.h: regen
+
+1999-08-04 10:54  millert
+
+       * configure, configure.in: Solais pam doesn't require anye xtra
+         setup
+
+1999-08-04 05:35  millert
+
+       * parse.yacc: o Simpler '!' support now that the lexer deals with
+         multiple !'s for us.  o In the case of opFOO, have FOO give a
+         boolean return value and set   foo_matches in opFOO, not FOO.  o
+         Treat 'ALL' as a string since it gets fill()'d in
+         parse.lex--fixes a   small memory leak.  In the long run it may
+         be better to just fix parse.lex   and make ALL back into a token.
+         However, having it be a string is useful   since it can be
+         easily passed back to the parent rule if we so desire.
+
+1999-08-04 03:54  millert
+
+       * parse.lex: o Remove some unnecessary backslashes o collapse
+         multiple !'s by using !+ and checking if yyleng is even or odd.
+         this allows us to simplify ! handling in parse.yacc
+
+1999-08-04 03:53  millert
+
+       * sudo.c: -u flag was being ignored
+
+1999-08-01 13:04  millert
+
+       * Makefile.in: correct fix
+
+1999-08-01 12:37  millert
+
+       * Makefile.in: work around pod2man stupididy
+
+1999-08-01 12:35  millert
+
+       * Makefile.in: correct dependencies for .cat
+
+1999-08-01 12:26  millert
+
+       * sudo.cat, sudo.man, visudo.cat, visudo.man: regen
+
+1999-08-01 12:25  millert
+
+       * sudo.pod, visudo.pod: Add copyright Update to reality
+
+1999-08-01 11:42  millert
+
+       * parse.c, sudo.c, sudo.h: rename validate() to the more
+         descriptive sudoers_lookup()
+
+1999-08-01 06:49  millert
+
+       * auth/aix_auth.c: use tgetpass
+
+1999-07-31 12:32  millert
+
+       * CHANGES: updates
+
+1999-07-31 12:31  millert
+
+       * HISTORY, INSTALL, Makefile.in, README, RUNSON, TROUBLESHOOTING,
+         configure, configure.in, sudo.c: Sudo, not CU Sudo
+
+1999-07-31 12:19  millert
+
+       * Makefile.in, alloc.c, check.c, compat.h, config.h.in,
+         find_path.c, getspwuid.c, goodpath.c, ins_2001.h, ins_classic.h,
+         ins_csops.h, ins_goons.h, insults.h, interfaces.c, interfaces.h,
+         lex.yy.c, logging.c, logging.h, parse.c, parse.h, parse.lex,
+         parse.yacc, pathnames.h.in, putenv.c, strerror.c, sudo.c, sudo.h,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, version.h,
+         visudo.c, 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/secureware.c, auth/securid.c, auth/sia.c,
+         auth/sudo_auth.c, auth/sudo_auth.h, emul/search.h, emul/utime.h,
+         LICENSE: add 4th term to license similar to term 5 in the apache
+         license
+
+1999-07-31 12:02  millert
+
+       * LICENSE, aclocal.m4, check.c, configure.in, insults.h, logging.c,
+         sudo.c, sudo.h, auth/rfc1938.c: there was a 1995 release too
+
+1999-07-28 05:24  millert
+
+       * CHANGES: updates
+
+1999-07-28 05:21  millert
+
+       * check.c: Use dirs instead of files for timestamp.  This allows
+         tty and non-tty schemes to coexist reasonably.  Note, however,
+         that when you update a tty ticket, the mtime on the user dir gets
+         updated as well.
+
+1999-07-28 05:17  millert
+
+       * configure.in, configure: Fix getprpwnam() checking on SCO.  Need
+         to link with "-lprot -lx" when linking test program, not just
+         -lprot.  Also add check for getspnam().  The SCO docs indicate
+         that /etc/shadow can be used but this may be a lie.
+
+1999-07-24 03:35  millert
+
+       * auth/API: first cut at auth API description
+
+1999-07-22 15:48  millert
+
+       * auth/: fwtk.c, kerb4.c, kerb5.c, pam.c, rfc1938.c, secureware.c,
+         securid.c, sudo_auth.c, sudo_auth.h: auth API change.  There is
+         now an init method that gets run before the main loop.  This
+         allows auth routines to differentiate between initialization that
+         happens once vs. setup that needs to run each time through the
+         loop.
+
+1999-07-22 12:23  millert
+
+       * logging.c, auth/kerb5.c: use easprintf() and evasprintf()
+
+1999-07-22 12:22  millert
+
+       * alloc.c, sudo.h: add easprintf() and evasprintf(), error checking
+         versions of asprintf() and  vasprintf()
+
+1999-07-22 09:14  millert
+
+       * TODO: remove 2 items.  One done, one won't do.
+
+1999-07-22 09:10  millert
+
+       * sudo.man, visudo.man, sudo.cat, sudo.html, sudoers.html,
+         visudo.cat, visudo.html, configure, lex.yy.c: regen
+
+1999-07-22 09:06  millert
+
+       * CHANGES: new changes
+
+1999-07-22 09:01  millert
+
+       * sudo.pod: o Document -K flag and update meaning of -k flag.  o
+         BSD-style copyright o Document clearing of BIND resolver
+         environment variables o Clarify bit about shared libs o suggest
+         rc files create /tmp/.odus if your OS gives away files
+
+1999-07-22 08:59  millert
+
+       * visudo.pod: BSD license
+
+1999-07-22 08:58  millert
+
+       * tgetpass.c: o BSD copyright o no need to block signals, we now do
+         that in main() o cosmetic changes
+
+1999-07-22 08:57  millert
+
+       * testsudoers.c, visudo.c: o BSD-style copyright o Use "struct
+         sudo_user" instead of old globals.  o some cometic cleanup
+
+1999-07-22 08:56  millert
+
+       * sudo_setenv.c, version.h: BSD-style copyright
+
+1999-07-22 08:56  millert
+
+       * sudo.h: o BSD copyright o logging and parser bits moved to their
+         own .h files o new "struct sudo_user" to encapsulate many of the
+         old globals.
+
+1999-07-22 08:55  millert
+
+       * sudo.c: o no longer contains sudo 1.1/1.2 code o BSD copyright o
+         use new logging routines o simplified flow of control o BIND
+         resolver additions to badenv_table
+
+1999-07-22 08:53  millert
+
+       * strerror.c: BSD-style copyright
+
+1999-07-22 08:53  millert
+
+       * snprintf.c: Now compiles on more K&R compilers
+
+1999-07-22 08:52  millert
+
+       * putenv.c: BSD-style copyright, cosmetic changes
+
+1999-07-22 08:51  millert
+
+       * parse.c, parse.yacc, parse.h, parse.lex: BSD-style copyright.
+         Move parser-specific defines and structs into parse.h + other
+         cosmetic changes
+
+1999-07-22 08:51  millert
+
+       * logging.h: defines for logging routines
+
+1999-07-22 08:49  millert
+
+       * ins_2001.h, ins_classic.h, ins_csops.h, ins_goons.h, insults.h,
+         interfaces.h, pathnames.h.in: BSD-style copyright
+
+1999-07-22 08:48  millert
+
+       * find_path.c, getspwuid.c, goodpath.c, interfaces.c: BSD-style
+         copyright, cosmetic changes
+
+1999-07-22 08:46  millert
+
+       * configure.in: o tgetpass.c is no longer optional o kill DCE_OBJS,
+         add AUTH_OBJS o kill --disable-tgetpass o add --without-passwd o
+         changes to fill in AUTH_OBJS for new auth api o check for
+         strerror(), v?snprintf() and v?asprintf() o replace
+         --with-AuthSRV with --with-fwtk
+
+1999-07-22 08:43  millert
+
+       * config.h.in: BSD-style copyright.  Remove USE_GETPASS and
+         HAVE_UTIME_NULL.  Add HAVE_FWTK, HAVE_STRERROR, HAVE_SNPRINTF,
+         HAVE_VSNPRINTF, HAVE_ASPRINTF, HAVE_VASPRINTF, WITHOUT_PASSWD and
+         NO_PASSWD
+
+1999-07-22 08:42  millert
+
+       * compat.h: BSD-style copyright; Add S_IFLNK and MIN/MAX id they
+         are missing.
+
+1999-07-22 08:39  millert
+
+       * alloc.c: BSD-style copyright
+
+1999-07-22 08:38  millert
+
+       * TROUBLESHOOTING: no more --with-getpass
+
+1999-07-22 08:34  millert
+
+       * TODO: Take out things I've done...
+
+1999-07-22 08:34  millert
+
+       * README: Refer to LICENSE
+
+1999-07-22 08:34  millert
+
+       * PORTING: --with-getpass no longer exists
+
+1999-07-22 08:33  millert
+
+       * Makefile.in: BSD-style copyright.  Update to reflect reality wrt
+         new files and new auth modules.
+
+1999-07-22 08:32  millert
+
+       * INSTALL: Remove --with-AuthSRV and --disable-tgetpass.  Add
+         --with-fwtk and --without-passwd.
+
+1999-07-22 08:31  millert
+
+       * HISTORY: Update history a bit
+
+1999-07-22 08:29  millert
+
+       * COPYING, LICENSE: Now distributed under a BSD-style license
+
+1999-07-22 08:28  millert
+
+       * auth/sudo_auth.c: o BSD-style copyright o Add support for
+         NO_PASSWD/WITHOUT_PASSWD options.  o skey/opie replaced by
+         rfc1938 code o new struct sudo_user global
+
+1999-07-22 08:25  millert
+
+       * auth/: pam.c, sia.c: BSD-style copyright and use new log
+         functions
+
+1999-07-22 08:24  millert
+
+       * auth/kerb5.c: o BSD-style copyright o Use new log functiongs o
+         Use asprintf() and snprintf() where sensible.
+
+1999-07-22 08:19  millert
+
+       * check.c: Rewrote all the old sudo 1.1/1.2 code.  Timestamp
+         handling is now done more reasonably--better sanity checks and
+         tty-based stamps are now done as files in a directory with the
+         same name as the invoking user, eg. /var/run/sudo/millert/ttyp1.
+         It is not currently possible to mix tty and non-tty based ticket
+         schemes but this may change in the future (it requires sudo to
+         use a directory instead of a file in the non-tty case).  Also,
+         ``sudo -k'' now sets the ticket back to the epoch and ``sudo -K''
+         really deletes the file.  That way you don't get the lecture
+         again just because you killed your ticket in .logout.  BSD-style
+         copyright now.
+
+1999-07-22 08:13  millert
+
+       * logging.c: o rewritten logging routines.  log_error() now takes
+         printf-style varargs    and log_auth() for the return value of
+         validate().  o BSD-style copyright
+
+1999-07-22 07:04  millert
+
+       * auth.c, check_sia.c, dce_pwent.c, secureware.c: superceded by new
+         auth API
+
+1999-07-22 07:02  millert
+
+       * auth/fwtk.c: Use snprintf() where it makes sense and add a
+         BSD-style copyright
+
+1999-07-22 07:00  millert
+
+       * auth/: afs.c, aix_auth.c, dce.c, passwd.c, rfc1938.c,
+         secureware.c, securid.c, sudo_auth.h, kerb4.c: BSD-style
+         copyright
+
+1999-07-22 06:57  millert
+
+       * emul/utime.h, utime.c: BSD-style copyright
+
+1999-07-22 06:57  millert
+
+       * emul/search.h: this has been rewritten so use my BSD-style
+         copyright
+
+1999-07-15 11:21  millert
+
+       * snprintf.c: include malloc.h if no stdlib.h
+
+1999-07-15 10:21  millert
+
+       * snprintf.c: KTH snprintf()/asprintf() for systems w/o them
+
+1999-07-15 10:20  millert
+
+       * strerror.c: strerror() for systems w/o it
+
+1999-07-12 06:53  millert
+
+       * visudo.c: stylistic changes
+
+1999-07-12 06:25  millert
+
+       * parse.c, parse.lex, parse.yacc: Add contribution info in the main
+         comment
+
+1999-07-11 16:10  millert
+
+       * auth/pam.c: remove missed ref to PAM_nullpw
+
+1999-07-11 16:10  millert
+
+       * auth/sudo_auth.h: pasto
+
+1999-07-11 15:19  millert
+
+       * auth/kerb5.c: more or less complete now--still untested
+
+1999-07-11 15:09  millert
+
+       * auth/: afs.c, pam.c: don't use user_name macro, it will go away
+
+1999-07-11 14:42  millert
+
+       * auth/: opie.c, rfc1938.c, sudo_auth.h, skey.c: combine skey/opie
+         code into rfc1938.c
+
+1999-07-11 07:22  millert
+
+       * auth/: dce.c, sudo_auth.h: DCE authentication method; basically
+         unchanged from dce_pwent.c
+
+1999-07-11 06:44  millert
+
+       * auth/: aix_auth.c, sudo_auth.h: AIX authenticate() support.
+         Could probably be much better
+
+1999-07-11 06:43  millert
+
+       * auth/sia.c: Fix an uninitialized variable and some cleanup.  Now
+         works (tested)
+
+1999-07-11 05:37  millert
+
+       * auth/: sia.c, sudo_auth.h: SIA support for digital unix
+
+1999-07-11 05:33  millert
+
+       * auth/pam.c: don't use prompt global, it will go away
+
+1999-07-11 05:32  millert
+
+       * auth/secureware.c: correct copyright years
+
+1999-07-10 20:32  millert
+
+       * auth/: afs.c, fwtk.c, kerb4.c, sudo_auth.h, kerb5.c, opie.c,
+         pam.c, passwd.c, secureware.c, securid.c, skey.c, sudo_auth.c:
+         New authentication API and methods
+
+1999-07-08 06:46  millert
+
+       * parse.yacc: only save an entry if user_matches && host_matches,
+         even if the stack is empty (fix for previous commit)
+
+1999-07-08 06:35  millert
+
+       * parse.yacc: 1) Always save an entry on the stack if it is empty.
+         This fixes the -l and -v flags that were broken by earlier parser
+         changes.
+
+         2) In a Runas list, don't negate FALSE -> TRUE since that would
+         make !foo match any time the user specified a runas user (via -u)
+         other than foo.
+
+1999-07-08 05:45  millert
+
+       * testsudoers.c: interfaces and num_interfaces are now auto, not
+         extern
+
+1999-07-07 14:09  millert
+
+       * auth.c: use a static global to keep stae about empty passwords
+
+1999-07-07 14:08  millert
+
+       * check_sia.c: make PASSWORD_NOT_CORRECT logging consistent with
+         other modules
+
+1999-07-05 16:53  millert
+
+       * auth.c: PAM prompt code was wrong, looks like we have to kludge
+         it after all.
+
+1999-07-05 16:35  millert
+
+       * auth.c: In the PAM code, when a user hits return at the first
+         password prompt, exit without a warning just like the normal auth
+         code
+
+1999-07-05 16:15  millert
+
+       * configure, configure.in: kludge around cross-compiler false
+         positives
+
+1999-07-05 16:14  millert
+
+       * auth.c, check.c, check_sia.c, logging.c, sudo.h, tgetpass.c: New
+         (correct) PAM code Tgetpass now takes an echo flag for use with
+         PAM_PROMPT_ECHO_ON Block SIGINT and SIGTSTP during auth remove a
+         useless umask setting Change error from BAD_ALLOCATION ->
+         BAD_AUTH_INIT (for use with sia/PAM) Some cosmetic changes to
+         auth.c for consistency
+
+1999-07-05 16:11  millert
+
+       * sudo.c: Some -Wall and kill some trailing spaces
+
+1999-07-05 16:10  millert
+
+       * configure.in: define -D__EXTENSIONS__ for solaris so we get
+         crypt() proto
+
+1999-06-22 09:42  millert
+
+       * RUNSON: add Dynix 4.4.4
+
+1999-06-22 09:30  millert
+
+       * INSTALL, config.h.in, configure.in, configure: for kerberos V <
+         version, fall back on old kerb4 auth code
+
+1999-06-22 06:41  millert
+
+       * INSTALL: clarify some things
+
+1999-06-22 06:38  millert
+
+       * UPGRADE, sudoers.cat, sudoers.man, sudoers.pod: typos
+
+1999-06-14 19:47  millert
+
+       * sudo.c: mention why DONT_LEAK_PATH_INFO is not the default
+
+1999-06-03 12:34  millert
+
+       * tgetpass.c: Fix open(2) return value checking, was NULL for
+         fopen, should be -1 for open
+
+1999-06-03 12:06  millert
+
+       * configure: regen
+
+1999-06-03 12:06  millert
+
+       * configure.in: better wording for solaris pam notice
+
+1999-06-03 11:52  millert
+
+       * CHANGES: document recent changes
+
+1999-06-03 11:52  millert
+
+       * TROUBLESHOOTING: Update shadow password section
+
+1999-06-03 11:51  millert
+
+       * auth.c: move authentication code from check.c to auth.c
+
+1999-06-03 11:51  millert
+
+       * Makefile.in, check.c, sudo.h: move authentication code to auth.c
+
+1999-05-16 21:36  millert
+
+       * Makefile.in, check.c, check_sia.c, compat.h, find_path.c,
+         getspwuid.c, goodpath.c, interfaces.c, interfaces.h, lex.yy.c,
+         logging.c, parse.c, parse.lex, parse.yacc, secureware.c, sudo.c,
+         sudo.h, sudo_setenv.c, testsudoers.c, tgetpass.c, visudo.c: Move
+         interface-related defines to interfaces.h so we don't have to
+         include <netinet/in.h> everywhere.
+
+1999-05-14 12:30  millert
+
+       * CHANGES, INSTALL, TODO, check.c, compat.h, getspwuid.c,
+         logging.c, parse.yacc, sudo.c, tgetpass.c:  o Replace _PASSWD_LEN
+         braindeath with our own SUDO_MAX_PASS.
+            It turns out the old DES crypt does the right thing with
+         passwords
+            longert than 8 characters.
+          o Fix common typo (necesary -> necessary)
+          o Update TODO list
+
+1999-05-03 12:00  millert
+
+       * sudo.c: set $LOGNAME when we set $USER
+
+1999-04-27 00:00  millert
+
+       * INSTALL: add comment about digital unix and interfaces.c warning
+         with gcc
+
+1999-04-15 01:12  millert
+
+       * sample.sudoers: use modern paths and give examples for some of
+         the new parser features
+
+1999-04-10 13:03  millert
+
+       * parse.c: fix comment
+
+1999-04-10 00:49  millert
+
+       * alloc.c, check.c, check_sia.c, dce_pwent.c, find_path.c,
+         getspwuid.c, goodpath.c, interfaces.c, lex.yy.c, logging.c,
+         parse.c, parse.lex, parse.yacc, putenv.c, secureware.c, sudo.c,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, visudo.c:
+         Function names should be flush with the start of the line so they
+         can be found trivially in an editor and with grep
+
+1999-04-10 00:40  millert
+
+       * find_path.c, interfaces.c, lex.yy.c, parse.c, parse.lex,
+         parse.yacc, sudo.c, testsudoers.c, tgetpass.c, visudo.c: free(3)
+         is already void, no need to cast it
+
+1999-04-10 00:37  millert
+
+       * logging.c, sudo.c, sudo.h: catch case where cmnd_safe is not set
+         (this should not be possible)
+
+1999-04-10 00:10  millert
+
+       * CHANGES, logging.c, parse.c, parse.yacc, sudo.c, sudo.h,
+         testsudoers.c, visudo.c: Stash the "safe" path (ie: the one
+         listed in sudoers) to the command instead of stashing the struct
+         stat.  Should be safer.
+
+1999-04-08 19:56  millert
+
+       * INSTALL, Makefile.in, UPGRADE: notes on updating from an earlier
+         release
+
+1999-04-07 20:20  millert
+
+       * CHANGES: updated
+
+1999-04-07 19:18  millert
+
+       * parse.yacc, sudo.tab.h, sudoers.cat, sudoers.html, sudoers.man,
+         sudoers.pod: You can now specifiy a host list instead of just a
+         host or alias.  Ie: user = host1,host2,ALIAS,!host3 my_command
+         now works.
+
+1999-04-07 02:59  millert
+
+       * testsudoers.c: Quiet -Wall
+
+1999-04-07 02:50  millert
+
+       * parse.yacc: Move the push from the beginning of cmndspec to the
+         end.  This means we no longer have to do a push at the end of
+         privilege, just reset some values.
+
+1999-04-06 20:24  millert
+
+       * sudoers.cat, sudoers.html, sudoers.man, sudoers.pod: runas-lists
+         and NOPASSWD/PASSWD modifiers are now sticky and you can use "!"
+         most everywhere
+
+1999-04-06 14:12  millert
+
+       * sudoers.pod: modernize paths and update su example based on
+         sample.sudoers one
+
+1999-04-06 14:06  millert
+
+       * sample.sudoers: New runas semantics
+
+1999-04-06 13:54  millert
+
+       * CHANGES, Makefile.in, alloc.c, config.h.in, configure,
+         configure.in, strdup.c, sudo.h: In estrdup(), do the malloc
+         ourselves so we don't need to rely on the system strdup(3) which
+         may or may not exist.  There is now no need to provide strdup()
+         for those w/o it.  Also, the prototype for estrdup() was wrong,
+         it returns char * and its param is const.
+
+1999-04-06 13:40  millert
+
+       * getcwd.c: $Sudo tag
+
+1999-04-06 13:20  millert
+
+       * check.c: buf should be prompt; Michael Robokoff
+         <mrobo@networkcs.com>
+
+1999-04-06 01:40  millert
+
+       * CHANGES, TODO, parse.yacc: It is now possible to use the '!'
+         operator in a runas list as well as in a Cmnd_Alias, Host_Alias
+         and User_Alias.
+
+1999-04-06 01:38  millert
+
+       * logging.c, sudo.h: Kill GLOBAL_NO_SPW_ENT (not used) and crank
+         GLOBAL_PROBLEM
+
+1999-04-06 01:08  millert
+
+       * sudo.h: Definitions of *_matched were wrong--user top, not top-2
+         as subscript.
+
+1999-04-06 01:00  millert
+
+       * logging.c, parse.c, parse.yacc, sudo.c, sudo.h: Add
+         VALIDATE_NOT_OK_NOPASS for when user is not allowed to run a
+         command but the NOPASSWD flag was set.  Make runasspec,
+         runaslist, runasuser, and nopasswd typeless in parse.yacc Add
+         support for '!' in the runas list Fix double printing of '%' and
+         '+' for groups and netgroups respectively Add *_matched macros
+         (no need for local stack variable).  Should only be used directly
+         after a pop (since top must be >= 2).
+
+1999-04-05 23:25  millert
+
+       * aclocal.m4, configure.in: Add copyright, somewhat silly
+
+1999-04-05 16:57  millert
+
+       * BUGS, INSTALL, Makefile.in, README, alloc.c, check.c,
+         check_sia.c, compat.h, config.h.in, configure, configure.in,
+         dce_pwent.c, find_path.c, getspwuid.c, goodpath.c, ins_2001.h,
+         ins_classic.h, ins_csops.h, ins_goons.h, insults.h, interfaces.c,
+         lex.yy.c, logging.c, parse.c, parse.lex, parse.yacc,
+         pathnames.h.in, putenv.c, secureware.c, strdup.c, sudo.c,
+         sudo.cat, sudo.h, sudo.man, sudo_setenv.c, sudoers.cat,
+         sudoers.man, testsudoers.c, tgetpass.c, utime.c, version.h,
+         visudo.c, visudo.cat, visudo.man, emul/utime.h: Crank version to
+         1.6 and combine copyright statements
+
+1999-04-05 16:30  millert
+
+       * sample.sudoers: Use ! not ^ to do negation
+
+1999-04-05 16:29  millert
+
+       * lex.yy.c: regen
+
+1999-04-05 16:28  millert
+
+       * parse.yacc, parse.lex: Make runas and NOPASSWD tags persistent
+         across entris in a command list.  Add a PASSWD tag to reverse
+         NOPASSWD.  When you override a runas or *PASSWD tag the value
+         given becomes the new default for the rest of the command list.
+
+1999-04-02 16:03  millert
+
+       * CHANGES, RUNSON: update for 1.5.9
+
+1999-04-02 16:02  millert
+
+       * visudo.c: Shift return value of system(3) by 8 to get real exit
+         value and if it is not 1 or 0 print the retval along with the
+         error message.
+
+1999-03-30 16:45  millert
+
+       * Makefile.in: testsudoers needs LIBOBJS too
+
+1999-03-30 12:17  millert
+
+       * parse.c, parse.yacc: Fix another parser bug.  For a sudoers entry
+         like this:     millert      ALL=/bin/ls,(daemon) !/bin/ls sudo
+         would not allow millert to run ls as root.
+
+1999-03-30 01:08  millert
+
+       * CHANGES: new change
+
+1999-03-30 01:03  millert
+
+       * parse.yacc: Save entries that match a ! command on the matching
+         stack too
+
+1999-03-30 01:01  millert
+
+       * sudo.c: Make sudo's usage info better when mutually exclusive
+         args are given and don't rely on argument order to detect this;
+         nick@zeta.org.au
+
+1999-03-29 15:03  millert
+
+       * CHANGES, Makefile.in, RUNSON: updates from CU
+
+1999-03-28 23:38  millert
+
+       * Makefile.in: use gzip
+
+1999-03-28 23:31  millert
+
+       * parse.yacc: Fix off by one error introduced in *alloc changes
+
+1999-03-28 23:05  millert
+
+       * BUGS, CHANGES, INSTALL, Makefile.in, README, alloc.c, check.c,
+         check_sia.c, compat.h, config.h.in, configure, configure.in,
+         dce_pwent.c, find_path.c, getspwuid.c, goodpath.c, ins_2001.h,
+         ins_classic.h, ins_csops.h, ins_goons.h, insults.h, interfaces.c,
+         lex.yy.c, logging.c, parse.c, parse.lex, parse.yacc,
+         pathnames.h.in, putenv.c, secureware.c, strdup.c, sudo.c,
+         sudo.cat, sudo.h, sudo.man, sudo_setenv.c, sudoers.cat,
+         sudoers.man, testsudoers.c, tgetpass.c, utime.c, version.h,
+         visudo.c, visudo.cat, visudo.html, visudo.man, visudo.pod,
+         emul/utime.h: ++version
+
+1999-03-28 21:59  millert
+
+       * Makefile.in, check.c, find_path.c, getspwuid.c, goodpath.c,
+         interfaces.c, lex.yy.c, logging.c, parse.c, parse.lex,
+         parse.yacc, putenv.c, secureware.c, strdup.c, sudo.c, sudo.h,
+         sudo_setenv.c, testsudoers.c, utime.c, visudo.c: Use
+         emalloc/erealloc/estrdup
+
+1999-03-28 20:29  millert
+
+       * alloc.c: error checking memory allocation routines
+
+1999-03-28 19:23  millert
+
+       * parse.yacc: Still not right, this fixes it for real
+
+1999-03-28 19:08  millert
+
+       * parse.yacc: Fix for previous commit
+
+1999-03-28 19:05  millert
+
+       * CHANGES, INSTALL, parse.yacc: Fix a parser bug that was exposed
+         when mixing different runas specs and ! commands.  For example:
+         millert          ALL=(daemon) /usr/bin/whoami,!/bin/ls would
+         allow millert to run whoami as root as well as daemon when it
+         should just allow daemon.  The problem was that comma-separated
+         commands in a list shared the same entry on the matching stack.
+         Now they get their own entry iff there is a full match.  It may
+         be better to just make the runas spec persistent across all
+         commands in a list like the user and host entries of the matching
+         stack.  However, since that is a fairly major change it should
+         gets its own minor rev increase.
+
+1999-03-28 13:50  millert
+
+       * check.c, config.h.in: Simplify PAM code and fix a PAM-related
+         warning on Linux
+
+1999-03-26 13:17  millert
+
+       * CHANGES: updates
+
+1999-03-26 13:12  millert
+
+       * sample.sudoers: better su entry
+
+1999-03-26 13:10  millert
+
+       * configure: regen
+
+1999-03-26 13:09  millert
+
+       * check.c, configure.in: new pam code that works on solaris, should
+         work on linux too; aelberg@home.com
+
+1999-03-19 14:44  millert
+
+       * RUNSON: more entries
+
+1999-03-19 14:43  millert
+
+       * config.h.in: only include strings.h if there is no string.h
+
+1999-03-17 15:25  millert
+
+       * config.guess: Sinix is now being called ReliantUNIX;
+         bjjackso@us.oracle.com
+
+1999-03-13 13:37  millert
+
+       * sudo.c: shost must be set before log functions are called #ifdef
+         HOST_IN_LOG
+
+1999-03-07 18:34  millert
+
+       * CHANGES, lex.yy.c, parse.lex: Fix a bug wrt quoting characters in
+         command args.  Stop processing an arg when you hit a backslash so
+         the quoted-character detection can catch it.
+
+1999-02-26 01:19  millert
+
+       * interfaces.c: include sys/time.h; aparently AIX needs it.
+         ppz@cdu.elektra.ru
+
+1999-02-23 19:43  millert
+
+       * configure, configure.in: add missing case statement so
+         --without-sendmail works
+
+1999-02-22 21:51  millert
+
+       * CHANGES: more
+
+1999-02-22 15:10  millert
+
+       * configure, configure.in: only search for -lsun in irix <= 4.x
+
+1999-02-22 15:01  millert
+
+       * configure, configure.in: back out last configure.in change now
+         that I've hacked autoconf to fix the real problem and add a
+         missing newline
+
+1999-02-22 14:32  millert
+
+       * CHANGES: updated
+
+1999-02-22 14:05  millert
+
+       * getcwd.c: add def of dirfd() for those without it
+
+1999-02-22 10:58  millert
+
+       * configure.in, configure: When falling back to checking for
+         socket() when linking with "-lsocket -lnsl" check for main()
+         instead since autoconf has already cached the results of checking
+         for socket() in -lsocket.  This is really an autoconf bug as it
+         should use the extra libs as part of the cache variable name.
+
+1999-02-22 10:47  millert
+
+       * configure.in: typo
+
+1999-02-21 15:18  millert
+
+       * configure.in: fix occurrence of $with_timeout that should be
+         $with_password_timeout;
+         Michael.Neef@neuroinformatik.ruhr-uni-bochum.de
+
+1999-02-17 11:40  millert
+
+       * sudo.cat, sudo.html, sudo.man, sudo.pod: fix grammar;
+         espie@openbsd.org
+
+1999-02-11 01:41  millert
+
+       * parse.yacc, sudo.c, testsudoers.c: add cast for strdup in places
+         it does not have it
+
+1999-02-09 13:11  millert
+
+       * configure, configure.in: define for_BSD_TYPES irix
+
+1999-02-06 19:47  millert
+
+       * Makefile.in, sudo.cat, sudo.html, sudo.man, sudo.pod: Make it
+         clear that it is the user's password, not root's, that we want.
+
+1999-02-06 19:43  millert
+
+       * check.c, sudo.h: If the user enters an empty password and really
+         has no password, accept the empty password they entered.
+         Perviously, they could enter anything *but* an empty password.
+         Also, add GETPASS macro that calls either tgetpass() or getpass()
+         depending on how sudo was configured.  Problem noted by
+         jdg@maths.qmw.ac.uk
+
+1999-02-02 23:32  millert
+
+       * Makefile.in, check.c, check_sia.c, compat.h, config.h.in,
+         dce_pwent.c, find_path.c, getspwuid.c, goodpath.c, ins_2001.h,
+         ins_classic.h, ins_csops.h, ins_goons.h, insults.h, interfaces.c,
+         logging.c, parse.c, parse.lex, parse.yacc, pathnames.h.in,
+         putenv.c, secureware.c, strdup.c, sudo.c, sudo.h, sudo_setenv.c,
+         testsudoers.c, tgetpass.c, utime.c, version.h, visudo.c,
+         emul/utime.h: add explicate copyright
+
+1999-02-02 23:16  millert
+
+       * CHANGES: mention -lsocket, -lnsl configure changes
+
+1999-02-02 17:54  millert
+
+       * sudo.c: Don't clobber errno after calling check_sudoers().
+
+1999-01-31 19:46  millert
+
+       * configure.in, configure: When linking with both -lsocket and
+         -lnsl be sure to do so in that order.  Also, when we can't find
+         socket() or inet_addr() and have to try linking with both libs,
+         issue a warning.
+
+1999-01-31 19:45  millert
+
+       * sudo.cat, sudo.man, sudo.pod: clarify bad timestamp and fmt
+
+1999-01-23 12:18  millert
+
+       * INSTALL, RUNSON: be clear that pam is linux-only and add a RUNSON
+         entry
+
+1999-01-22 13:13  millert
+
+       * configure, CHANGES, INSTALL, configure.in: fix and correctly
+         document --with-umask; problem noted by adap@adap.org
+
+1999-01-19 20:38  millert
+
+       * configure.in, configure: only use /usr/{man,catman}/local to
+         store man pages if suer didn't override prefix or mandir
+
+1999-01-19 20:24  millert
+
+       * configure, INSTALL, configure.in: fix typo, make --with-SecurID
+         take an arg
+
+1999-01-18 21:53  millert
+
+       * RUNSON: updates from users
+
+1999-01-18 21:04  millert
+
+       * CHANGES, INSTALL, check.c, configure, configure.in: FWTK
+         'authsrv' support from Kevin Kadow <kadow@MSG.NET>
+
+1999-01-18 20:00  millert
+
+       * configure, configure.in: better fix for the problem of unresolved
+         symbols in -lnsl or -lsocket
+
+1999-01-18 19:39  millert
+
+       * configure, configure.in: when checking for functions in -lnsl and
+         -lsocket link with both of them to avoid unresolved symbols on
+         some weirdo systems
+
+1999-01-17 20:49  millert
+
+       * BUGS, CHANGES, RUNSON, TODO: old changes that didn't make it into
+         RCS before the RCS->CVS switch
+
+1999-01-17 18:16  millert
+
+       * Makefile.in, check.c, check_sia.c, compat.h, config.h.in,
+         configure.in, dce_pwent.c, find_path.c, getspwuid.c, goodpath.c,
+         ins_2001.h, ins_classic.h, ins_csops.h, ins_goons.h, insults.h,
+         interfaces.c, lex.yy.c, logging.c, lsearch.c, parse.c, parse.lex,
+         parse.yacc, pathnames.h.in, putenv.c, secureware.c, strdup.c,
+         sudo.c, sudo.pod, sudo_setenv.c, sudoers.pod, testsudoers.c,
+         tgetpass.c, utime.c, visudo.c, visudo.pod, emul/search.h,
+         emul/utime.h: add sudo tags
+
+1999-01-17 17:53  millert
+
+       * version.h, sudo.h: testing Sudo tag
+
+1999-01-17 17:40  millert
+
+       * BUGS, INSTALL, Makefile.in, README, check.c, check_sia.c,
+         compat.h, config.h.in, configure, configure.in, dce_pwent.c,
+         find_path.c, getspwuid.c, goodpath.c, ins_2001.h, ins_classic.h,
+         ins_csops.h, ins_goons.h, insults.h, interfaces.c, lex.yy.c,
+         logging.c, parse.c, parse.lex, parse.yacc, pathnames.h.in,
+         putenv.c, secureware.c, strdup.c, sudo.c, sudo.cat, sudo.h,
+         sudo.man, sudo_setenv.c, sudoers.cat, sudoers.man, testsudoers.c,
+         tgetpass.c, utime.c, version.h, visudo.c, visudo.cat, visudo.man,
+         emul/utime.h: crank version and regen files
+
+1999-01-17 17:27  millert
+
+       * Makefile.in: kill rcs goop in update_version and fix now that
+         version is a const
+
+1999-01-17 17:08  millert
+
+       * INSTALL, check.c, config.h.in, configure, configure.in,
+         logging.c, sudo.c, sudo.h, sudo.pod: kerb5 support from
+         fcusack@iconnet.net
+
+1999-01-17 16:45  millert
+
+       * realpath.c, sudo_realpath.c: we no longer use realpath
+
+1999-01-17 16:44  millert
+
+       * qualify.c: replaced by find_path.c
+
+1999-01-17 16:43  millert
+
+       * options.h: all options are now configure flags
+
+1999-01-17 16:42  millert
+
+       * lex.yy.c: regen
+
+1999-01-17 16:41  millert
+
+       * getwd.c: superceded by getcwd.c
+
+1999-01-17 16:36  millert
+
+       * getpass.c: superceded by tgetpass.c
+
+1999-01-17 16:36  millert
+
+       * SUPPORTED: superceded by RUNSON
+
+1999-01-17 16:33  millert
+
+       * OPTIONS: No longer used now that we have configure options for
+         everything.
+
+1999-01-17 16:32  millert
+
+       * configure: regen based on configure.in
+
+1999-01-17 16:31  millert
+
+       * sudo.man, sudoers.man, visudo.man, sudo.cat, sudo.html,
+         sudoers.cat, visudo.cat, sudoers.html, visudo.html: regen based
+         on sudo.pod, sudoers.pod, and visudo.pod
+
+1998-12-11 12:16  millert
+
+       * check.c: fix tty tickets in remove_timestamp (didn't use ':')
+
+1998-12-07 16:16  millert
+
+       * interfaces.c: close sock when we are done with it
+
+1998-11-27 19:37  millert
+
+       * parse.yacc: never say "error on line -1"
+
+1998-11-23 23:38  millert
+
+       * configure.in: check for -lnsl before -lsocket
+
+1998-11-23 23:29  millert
+
+       * configure.in: quote '[', ']' used in ranges correctly
+
+1998-11-21 17:54  millert
+
+       * config.h.in: add missing NO_ROOT_SUDO noted by drno@tsd.edu
+
+1998-11-20 18:33  millert
+
+       * version.h: 1.5.7
+
+1998-11-20 18:33  millert
+
+       * INSTALL: more info for 1.5.7
+
+1998-11-20 18:30  millert
+
+       * README: update for 1.5.7
+
+1998-11-20 14:26  millert
+
+       * parse.yacc: make increases of cm_list_size and ga_list_size be
+         similar to increases of stacksize (ie: >= not > in initial
+         compare).
+
+1998-11-20 14:22  millert
+
+       * parse.yacc: when we get a syntax error, report it for the
+         previous line since that's generally where the error occurred.
+
+1998-11-18 15:31  millert
+
+       * config.h.in, configure.in, interfaces.c: add back check for
+         sys/sockio.h but only use it if SIOCGIFCONF is not defined
+
+1998-11-18 15:25  millert
+
+       * config.h.in: define BSD_COMP for svr4
+
+1998-11-17 23:16  millert
+
+       * check.c, check_sia.c, find_path.c, getcwd.c, getspwuid.c,
+         goodpath.c, interfaces.c, logging.c, lsearch.c, parse.c,
+         parse.lex, parse.yacc, putenv.c, secureware.c, strdup.c, sudo.c,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, visudo.c: more
+         -Wall
+
+1998-11-17 23:10  millert
+
+       * configure.in: kill check for sockio,h
+
+1998-11-17 23:10  millert
+
+       * config.h.in: no more HAVE_SYS_SOCKIO_H
+
+1998-11-17 22:51  millert
+
+       * check.c, check_sia.c, find_path.c, getcwd.c, getspwuid.c,
+         goodpath.c, interfaces.c, logging.c, lsearch.c, parse.c,
+         parse.lex, parse.yacc, putenv.c, secureware.c, strdup.c, sudo.c,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, visudo.c:
+         -Wall
+
+1998-11-16 17:38  millert
+
+       * sudo.c: add missing inform_user()
+
+1998-11-13 19:21  millert
+
+       * find_path.c: return NOT_FOUND if given fully qualified path and
+         it does not exist previously it would perror(ENOENT) which
+         bypasses the option to not leak path info
+
+1998-11-13 19:20  millert
+
+       * configure.in: for kerb5, check for -lkerb4, fall back on -lkrb
+         for kerb, check for -ldes
+
+1998-11-13 14:19  millert
+
+       * INSTALL: tty tickets are user:tty now
+
+1998-11-13 14:10  millert
+
+       * check.c: when using tty tickets make it user:tty not user.tty as
+         a username could have a '.' in it
+
+1998-11-09 19:15  millert
+
+       * sudo.c: add "ignoring foo found in ." for auth successful case
+
+1998-11-09 17:57  millert
+
+       * sudo.c: add missing printf param
+
+1998-11-08 15:56  millert
+
+       * INSTALL, config.h.in, configure.in, find_path.c, sudo.c, sudo.h:
+         go back to printing "command not found" unless
+         --disable-path-info specified.  Also, tell user when we ignore
+         '.' in their path and it would have been used but for
+         --with-ignore-dot.
+
+1998-11-08 13:51  millert
+
+       * check.c, sudo.c: Only one space after a colon, not two, in
+         printf's
+
+1998-11-05 12:59  millert
+
+       * sudo.pod: document setting $USER
+
+1998-11-04 22:24  millert
+
+       * check.c: fix bugs with prompt expansion
+
+1998-11-04 21:21  millert
+
+       * sudo.c: set $USER for root too
+
+1998-11-04 17:13  millert
+
+       * getspwuid.c: typo
+
+1998-11-04 17:07  millert
+
+       * configure.in: HP-UX's iscomsec is in -lsec, not libc
+
+1998-11-03 22:24  millert
+
+       * configure.in: remove some entries in the OS case statement that
+         did nothing
+
+1998-11-03 22:19  millert
+
+       * TROUBLESHOOTING: add "cd" section and flush out syslog section
+
+1998-11-03 20:51  millert
+
+       * Makefile.in: no more sudo-lex.yy.c
+
+1998-11-03 20:50  millert
+
+       * check_sia.c: add custom prompt support
+
+1998-11-03 20:40  millert
+
+       * sudo.c: kill perror("malloc") since we already have a good error
+         messages pw_ent -> pw for brevity set $USER if -u specified
+
+1998-11-03 20:39  millert
+
+       * parse.c: kill perror("malloc") since we already have a good error
+         messages pw_ent -> pw for brevity when checking if %group
+         matches, look up user in password file so that %groups works in a
+         RunAs spec.
+
+1998-11-03 20:39  millert
+
+       * logging.c, parse.yacc: kill perror("malloc") since we already
+         have a good error messages
+
+1998-11-03 20:38  millert
+
+       * check.c, getspwuid.c, interfaces.c, testsudoers.c: kill
+         perror("malloc") since we already have a good error messages
+         pw_ent -> pw for brevity
+
+1998-11-03 15:03  millert
+
+       * tgetpass.c: the prompt is expanded before tgetpass is called
+
+1998-11-03 15:03  millert
+
+       * sudo.h: tgetpass now has the same args as getpass again
+
+1998-11-03 15:02  millert
+
+       * getspwuid.c: add iscomsec, issecure support
+
+1998-11-03 15:02  millert
+
+       * check.c: we now expand any %h or %u in the prompt before passing
+         to tgetpass
+
+1998-11-03 14:58  millert
+
+       * configure.in: add check for syslog(3) in -lsocket, -lnsl, -linet
+
+1998-11-03 14:56  millert
+
+       * config.h.in: add HAVE_ISCOMSEC and HAVE_ISSECURE
+
+1998-11-03 14:55  millert
+
+       * configure.in: add check for iscomsec in HP-UX
+
+1998-11-03 14:51  millert
+
+       * configure.in: check for issecure if we have getpwanam on SunOS
+         some options are incompatible with DUNIX SIA check for dispcrypt
+         on DUNIX
+
+1998-10-25 15:21  millert
+
+       * config.h.in: add HAVE_DISPCRYPT
+
+1998-10-25 15:21  millert
+
+       * secureware.c: add back support for non-dispcrypt based checking
+         for older DUNIX
+
+1998-10-25 00:51  millert
+
+       * INSTALL: sia changes
+
+1998-10-25 00:48  millert
+
+       * configure.in: SIA becomes the default on Digital UNIX now havbe
+         --disable-sia to turn it off...
+
+1998-10-24 23:52  millert
+
+       * check.c: move local includes after system ones
+
+1998-10-24 19:28  millert
+
+       * check.c, check_sia.c, sudo.h: add pass_warn() which prints out
+         INCORRECT_PASSWORD or an insult to stderr
+
+1998-10-24 19:07  millert
+
+       * check_sia.c: fix while loop in sia_attempt_auth() that checks the
+         password.  Only the first iteration was working.
+
+1998-10-21 21:00  millert
+
+       * aclocal.m4: don't trust UID_MAX or MAXUID
+
+1998-10-21 20:35  millert
+
+       * configure.in: fix two pastos
+
+1998-10-21 20:30  millert
+
+       * configure.in: fix typo
+
+1998-10-21 20:19  millert
+
+       * getspwuid.c, secureware.c: init crypt_type to INT_MAX since it is
+         legal to be negative in DUNX 5.0
+
+1998-10-21 20:15  millert
+
+       * configure.in: for secureware on dunix, use -lsecurity -ldb -laud
+         -lm but check for -ldb since DUNX < 4.0 lacks it
+
+1998-10-21 19:50  millert
+
+       * check.c, compat.h, config.h.in, configure.in, getspwuid.c,
+         secureware.c, sudo.c, tgetpass.c: getprpwuid is broken in HP-UX
+         10.20 at least (it sleeps for 2 minutes if the shadow files don't
+         exist).
+
+1998-10-20 17:22  millert
+
+       * INSTALL: updated --with-editor blurb
+
+1998-10-20 17:21  millert
+
+       * TROUBLESHOOTING: tell how to put sudoers in a different dir
+
+1998-10-20 16:22  millert
+
+       * configure.in: add missing quotes around $with_editor
+
+1998-10-20 14:00  millert
+
+       * configure.in: typo in --with-editor bits
+
+1998-10-20 01:24  millert
+
+       * INSTALL: I don't expect it to work on Solaris
+
+1998-10-20 01:24  millert
+
+       * check.c: add back security/pam_misc.h
+
+1998-10-19 17:13  millert
+
+       * INSTALL: remove dunix note since configure checks for this now
+
+1998-10-19 16:30  millert
+
+       * configure.in: add check for broken dunix prot.h (4.0 < 4.0D is
+         bad)
+
+1998-10-19 14:32  millert
+
+       * getspwuid.c, secureware.c, tgetpass.c: new dunix shadow code, use
+         dispcrypt(3)
+
+1998-10-19 14:32  millert
+
+       * config.h.in: add HAVE_INITPRIVS
+
+1998-10-19 14:31  millert
+
+       * sudo.c: call initprivs() if we have it for getprpwuid later on
+
+1998-10-19 14:30  millert
+
+       * Makefile.in: clean pathnames.h too
+
+1998-10-19 14:28  millert
+
+       * configure.in: quote "Sorry, try again." with [] since it has a
+         comma in it set LIBS when we add stuff to SUDO_LIBS set
+         SECUREWARE when we find getprpwuid() so we can check for
+         bigcrypt, set_auth_parameters, and initprivs later.
+
+1998-10-19 13:48  millert
+
+       * INSTALL: update Digital UNIX note about acl.h
+
+1998-10-18 20:26  millert
+
+       * INSTALL: add --with-sia --without-root-sudo ->
+         --disable-root-sudo some reordering
+
+1998-10-18 20:22  millert
+
+       * secureware.c: add whitespace
+
+1998-10-18 20:22  millert
+
+       * Makefile.in, check.c, config.h.in, configure.in, logging.c,
+         sudo.h: add SIA support
+
+1998-10-18 20:21  millert
+
+       * check_sia.c: Initial revision
+
+1998-10-18 19:42  millert
+
+       * configure.in: when checking for -lsocket, -lnsl, and -linet,
+         check for the specific functions we need from them.
+
+1998-10-18 19:10  millert
+
+       * config.h.in, sudo.h: move Syslog_* defs into sudo.h
+
+1998-10-18 18:15  millert
+
+       * sudo.h, Makefile.in: added check_secureware
+
+1998-10-18 18:12  millert
+
+       * configure.in: finished adding AC_MSG_CHECKING and AC_MSG_RESULT
+         bits
+
+1998-10-18 18:00  millert
+
+       * insults.h: don't define CLASSIC_INSULTS and CSOPS_INSULTS if no
+         other sets defined.  configure now does that for us
+
+1998-10-18 17:45  millert
+
+       * configure.in: move some --with options around change a bunch of
+         echo's to AC_MSG_CHECKING, AC_MSG_RESULT pairs
+
+1998-10-18 01:09  millert
+
+       * configure.in: change $with_foo-bar -> $with_foo_bar kill extra "
+         that caused a syntax error add some echo verbage
+
+1998-10-17 18:08  millert
+
+       * check.c: moved SecureWare stuff into secureware.c
+
+1998-10-17 18:07  millert
+
+       * secureware.c: Initial revision
+
+1998-10-17 17:02  millert
+
+       * INSTALL: update url to solaris gcc bins
+
+1998-10-17 16:39  millert
+
+       * INSTALL: change option formatter and flesh out someentries
+
+1998-10-17 16:18  millert
+
+       * sudo.pod, visudo.pod, TROUBLESHOOTING: environmental variable ->
+         environment variable
+
+1998-10-17 16:01  millert
+
+       * BUGS: everything is now done via configure
+
+1998-10-17 16:00  millert
+
+       * README: prev rev was 1.5.6
+
+1998-10-17 00:33  millert
+
+       * Makefile.in: passing SUDOERS_MODE, SUDOERS_UID, SUDOERS_GID
+         correctly
+
+1998-10-17 00:32  millert
+
+       * config.h.in: SUDOERS_MODE, SUDOERS_UID, SUDOERS_GID now come from
+         the Makefile
+
+1998-10-17 00:31  millert
+
+       * Makefile.in: merge OSDEFS and OPTIONS into DEFS get sudoers_uid,
+         sudoers_gid, sudoers_mode from configure
+
+1998-10-17 00:30  millert
+
+       * configure.in: SUDOERS_MODE, SUDOERS_UID, and SUDOERS_GID now get
+         substituted into the Makefile, not config.h
+
+1998-10-17 00:30  millert
+
+       * INSTALL: document all --with/--enable options
+
+1998-10-15 02:25  millert
+
+       * insults.h: options.h is no more
+
+1998-10-15 02:25  millert
+
+       * config.h.in: assimilated options.h
+
+1998-10-15 02:24  millert
+
+       * configure.in: moved options from options.h to configure
+
+1998-10-15 01:41  millert
+
+       * check.c, find_path.c, getspwuid.c, goodpath.c, interfaces.c,
+         logging.c, parse.c, parse.lex, parse.yacc, sudo.c, sudo.pod,
+         sudo_setenv.c, visudo.c: no more options.h
+
+1998-10-15 01:39  millert
+
+       * INSTALL, Makefile.in, PORTING, TROUBLESHOOTING: remove references
+         to options.h
+
+1998-10-15 01:32  millert
+
+       * interfaces.c, dce_pwent.c, sudo.c: kill sys/time.h
+
+1998-10-15 00:10  millert
+
+       * tgetpass.c: if select return < -1 still prompt for pw
+
+1998-10-15 00:03  millert
+
+       * options.h: convert LOGGING, LOGFAC, MAXLOGFILELEN,
+         IGNORE_DOT_PATH into configure options
+
+1998-10-14 23:57  millert
+
+       * parse.c: FAST_MATCH is no longer an optino
+
+1998-10-14 23:52  millert
+
+       * check.c: remove_timestamp() if timestamp is preposterous
+
+1998-10-14 23:36  millert
+
+       * options.h: convert more options to --with/--enable
+
+1998-10-14 23:36  millert
+
+       * INSTALL, aclocal.m4: logfile -> logpath
+
+1998-10-14 23:31  millert
+
+       * configure.in: convert more options into --with and --enable
+
+1998-10-14 23:28  millert
+
+       * tgetpass.c: catch EINTR in select and restart
+
+1998-10-14 23:15  millert
+
+       * logging.c: sys/errno -> errno
+
+1998-09-24 11:40  millert
+
+       * sudo.c: UMASK -> SUDO_UMASK.
+
+1998-09-24 11:36  millert
+
+       * check.c, logging.c: time.h, not sys/time.h
+
+1998-09-21 19:52  millert
+
+       * logging.c: MAILER -> _PATH_SENDMAIL
+
+1998-09-21 00:06  millert
+
+       * INSTALL, configure.in: no more --with-C2, now it is
+         --disable-shadow
+
+1998-09-21 00:00  millert
+
+       * aclocal.m4, check.c, compat.h, config.h.in, configure.in,
+         getspwuid.c, sudo.c, tgetpass.c: new shadow password scheme.
+         Always include shadow support if the platform supports it and the
+         user did not disable it via configure
+
+1998-09-20 19:48  millert
+
+       * configure.in: --with-getpass -> --{enable,disable}-tgetpass
+
+1998-09-20 19:16  millert
+
+       * Makefile.in: pathnames.h -> pathnames.h.in
+
+1998-09-20 19:14  millert
+
+       * check.c: fix version string
+
+1998-09-20 19:12  millert
+
+       * check.c: move pam_conv to be static to auth function remove
+         pam_misc.h (solaris doesn't have one)
+
+1998-09-20 19:10  millert
+
+       * aclocal.m4: _CONFIG_PATH_* -> _PATH_* or _PATH_SUDO_* kill
+         SUDO_PROG_PWD
+
+1998-09-20 19:10  millert
+
+       * configure.in: munge pathnames.h.in -> pathnames.h kill
+         SUDO_PROG_PWD
+
+1998-09-20 19:10  millert
+
+       * pathnames.h.in: convert to pathnames.h.in
+
+1998-09-18 20:20  millert
+
+       * configure.in: fix typo in sysv4 matching case /.
+
+1998-09-18 01:29  millert
+
+       * check.c: pam stuff needs to run as root, not user, for shadow
+         passwords
+
+1998-09-17 12:26  millert
+
+       * Makefile.in, emul/utime.h, check.c, compat.h, config.h.in,
+         dce_pwent.c, find_path.c, getspwuid.c, goodpath.c, ins_2001.h,
+         ins_classic.h, ins_csops.h, ins_goons.h, insults.h, interfaces.c,
+         logging.c, options.h, parse.c, parse.lex, parse.yacc,
+         pathnames.h.in, putenv.c, strdup.c, sudo.c, sudo.h,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, visudo.c,
+         BUGS, INSTALL, README, configure.in: updated version
+
+1998-09-17 12:13  millert
+
+       * check.c: user version.h for long message
+
+1998-09-17 11:53  millert
+
+       * check.c: this is version 1.5.6
+
+1998-09-16 13:42  millert
+
+       * Makefile.in: remove errant backslash
+
+1998-09-14 22:25  millert
+
+       * options.h, parse.yacc, pathnames.h.in: fix version string
+
+1998-09-14 22:02  millert
+
+       * BUGS, CHANGES, TODO: updtaed for 1.5.6
+
+1998-09-14 22:02  millert
+
+       * RUNSON: updated for 1.5.6
+
+1998-09-14 11:48  millert
+
+       * interfaces.c: kill unused localhost_mask var copy if name to
+         ifr_tmp after we zero it
+
+1998-09-13 15:50  millert
+
+       * INSTALL: Better description of new vs. old sudoers modes fix some
+         typos better description of /usr/ucb/cc gotchas on slowaris
+
+1998-09-13 15:49  millert
+
+       * Makefile.in: add sample.pam
+
+1998-09-13 15:32  millert
+
+       * sudo.c: set NewArgv[0] to user_shell, not basename(user_shell)
+
+1998-09-12 11:10  millert
+
+       * README: mention TROUBLESHOOTING more fix some typos
+
+1998-09-11 20:30  millert
+
+       * configure.in: move --enable/--disable to be after --with
+
+1998-09-11 20:30  millert
+
+       * INSTALL: document --enable/--disable
+
+1998-09-11 20:26  millert
+
+       * INSTALL: document --with-pam
+
+1998-09-11 19:47  millert
+
+       * configure.in: Add message for pam users
+
+1998-09-11 19:27  millert
+
+       * sample.pam: Initial revision
+
+1998-09-11 19:23  millert
+
+       * config.h.in: fix HAVE_PAM
+
+1998-09-11 19:19  millert
+
+       * check.c, config.h.in, configure.in: pam support, from Gary Calvin
+         <GCalvin@kenwoodusa.com>
+
+1998-09-10 18:51  millert
+
+       * config.h.in: add HOST_IN_LOG and WRAP_LOG
+
+1998-09-10 18:51  millert
+
+       * logging.c: add WRAP_LOG and HOST_IN_LOG
+
+1998-09-10 18:37  millert
+
+       * configure.in: add --enable-log-host and --enable-log-wrap
+
+1998-09-10 18:32  millert
+
+       * aclocal.m4: use AC_DEFINE_UNQUOTED for --with-logfile and
+         --with-timedir
+
+1998-09-08 20:45  millert
+
+       * compat.h: add howmany macro
+
+1998-09-08 20:43  millert
+
+       * tgetpass.c: include sys/param.h to get howmany macro
+
+1998-09-07 20:42  millert
+
+       * OPTIONS, options.h, parse.yacc, sudo.c, testsudoers.c, visudo.c:
+         add RUNAS_DEFAULT
+
+1998-09-07 12:51  millert
+
+       * fnmatch.c: bring in stdio.h for NULL
+
+1998-09-07 12:50  millert
+
+       * aclocal.m4: allow /bin/{ksh,bach} and /usr/bin/{ksh,bash} as sh
+
+1998-09-07 12:43  millert
+
+       * sudo.c: use HAVE_SET_AUTH_PARAMETERS
+
+1998-09-07 12:42  millert
+
+       * config.h.in: add HAVE_SET_AUTH_PARAMETERS
+
+1998-09-07 12:41  millert
+
+       * configure.in: add *-*-hiuxmpp* add test for set_auth_parameters()
+         if secureware
+
+1998-09-07 12:39  millert
+
+       * config.sub: add support for HI-UX/MPP SR220001 02-03 0 SR2201
+
+1998-09-07 12:06  millert
+
+       * interfaces.c: initialize previfname
+
+1998-09-07 11:51  millert
+
+       * interfaces.c: Don't use SIOCGIFADDR, we don't need it Use
+         SIOCGIFFLAGS if we have it check ifr_flags against IFF_UP and
+         IFF_LOOPBACK instead of kludging it
+
+1998-09-07 11:49  millert
+
+       * configure.in: typo
+
+1998-09-07 00:01  millert
+
+       * Makefile.in: don't need special build line for sudo.tab.o
+
+1998-09-06 23:58  millert
+
+       * Makefile.in: don't clean sudo.tab.[ch]
+
+1998-09-06 23:48  millert
+
+       * sudo.c: Sudo should prompt for a password before telling the user
+         that a command could not be found.
+
+1998-09-06 23:47  millert
+
+       * BUGS: for 1.5.6
+
+1998-09-06 23:25  millert
+
+       * INSTALL, README: no longer require yacc
+
+1998-09-06 23:19  millert
+
+       * Makefile.in: typo
+
+1998-09-06 23:18  millert
+
+       * Makefile.in: y.tab -> sudo.tab include pre-yacc'd parse.yacc
+
+1998-09-06 23:09  millert
+
+       * parse.lex: include sudo.tab.h, not y.tab.h don't break out of
+         command args if you get a '='
+
+1998-09-06 22:59  millert
+
+       * insults.h: fix version ,
+
+1998-09-06 22:57  millert
+
+       * compat.h, ins_2001.h, ins_classic.h, ins_csops.h, ins_goons.h:
+         fix version
+
+1998-09-06 22:55  millert
+
+       * getcwd.c: getcwd(3) from OpenBSD for those without it.
+
+1998-09-06 22:51  millert
+
+       * sudo.h: HAVE_GETWD -> HAVE_GETCWD
+
+1998-09-06 22:49  millert
+
+       * configure.in: pretend sunos doesn't have getcwd(3) since it opens
+         a pipe to getpwd!
+
+1998-09-06 22:41  millert
+
+       * parse.c: use NAMLEN() macro
+
+1998-09-06 22:34  millert
+
+       * fnmatch.c: remove duplicate include of string.h
+
+1998-09-06 22:28  millert
+
+       * configure.in: call SUDO_TYPE_DEV_T and SUDO_TYPE_INO_T
+
+1998-09-06 22:28  millert
+
+       * aclocal.m4: add SUDO_TYPE_DEV_T and SUDO_TYPE_INO_T
+
+1998-09-06 22:28  millert
+
+       * config.h.in: add dev_t and ino_t
+
+1998-07-28 12:44  millert
+
+       * check.c: fix OTP_ONLY for opie
+
+1998-06-24 12:22  millert
+
+       * testsudoers.c, tgetpass.c: include stdlib.h for malloc proto
+
+1998-05-19 00:10  millert
+
+       * Makefile.in: make update_version saner
+
+1998-05-18 23:32  millert
+
+       * config.h.in: add HAVE_WAITPID, HAVE_WAIT3, and sudo_waitpid()
+
+1998-05-18 23:32  millert
+
+       * configure.in: check for waitpid and wait3 or no waitpid
+
+1998-05-18 23:31  millert
+
+       * logging.c: used waitpid or wait3 if we have 'em
+
+1998-05-02 14:16  millert
+
+       * visudo.c: fix some fprintf args, ariel@oz.engr.sgi.com (Ariel
+         Faigon)
+
+1998-04-27 20:09  millert
+
+       * configure.in: don't need to explicately mention -lsocket -lnsl
+         for sequent
+
+1998-04-25 01:56  millert
+
+       * configure.in: dynix should not link with -linet
+
+1998-04-10 15:32  millert
+
+       * INSTALL: mention that HP-UX doesn't ship with yacc
+
+1998-04-06 22:35  millert
+
+       * check.c: ignore kerberos if we can't get the local realm
+
+1998-04-05 23:37  millert
+
+       * configure.in, BUGS, INSTALL, README: ++version
+
+1998-04-05 23:36  millert
+
+       * version.h: ++
+
+1998-04-05 23:35  millert
+
+       * Makefile.in, emul/utime.h, check.c, config.h.in, dce_pwent.c,
+         find_path.c, getspwuid.c, getcwd.c, goodpath.c, interfaces.c,
+         logging.c, parse.c, parse.lex, putenv.c, strdup.c, sudo.c,
+         sudo.h, sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c,
+         visudo.c: updated version
+
+1998-04-05 23:34  millert
+
+       * check.c, sudo.h: fix version
+
+1998-04-05 23:33  millert
+
+       * getcwd.c: don't use popen/pclose.  Do it inline.
+
+1998-04-05 23:25  millert
+
+       * lsearch.c: add rcsid
+
+1998-04-05 23:21  millert
+
+       * sudo.c: typo
+
+1998-04-05 23:17  millert
+
+       * sudo.h, pathnames.h.in, compat.h, options.h, ins_2001.h,
+         insults.h, ins_classic.h, ins_goons.h, ins_csops.h, parse.yacc,
+         check.c: updated version
+
+1998-04-05 23:15  millert
+
+       * check.c, find_path.c, parse.c, sudo.c, testsudoers.c: MAX* + 1 ->
+         MAX*
+
+1998-04-05 23:14  millert
+
+       * Makefile.in: getwd.c -> getcwd.c
+
+1998-04-05 22:49  millert
+
+       * config.h.in: kill HAVE_GETWD
+
+1998-04-05 22:49  millert
+
+       * configure.in: getcwd, not getwd
+
+1998-04-05 22:48  millert
+
+       * getcwd.c: use MAX* not MAX* + 1 always run pwd as using getwd()
+         defeats the purpose
+
+1998-03-31 00:15  millert
+
+       * OPTIONS, options.h: add STUB_LOAD_INTERFACES
+
+1998-03-31 00:05  millert
+
+       * Makefile.in, check.c, emul/utime.h, compat.h, config.h.in,
+         dce_pwent.c, find_path.c, getspwuid.c, getwd.c, goodpath.c,
+         ins_2001.h, ins_classic.h, ins_csops.h, ins_goons.h, insults.h,
+         interfaces.c, logging.c, options.h, parse.c, parse.lex,
+         parse.yacc, pathnames.h.in, putenv.c, strdup.c, sudo.c, sudo.h,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, visudo.c:
+         updated version
+
+1998-03-30 23:54  millert
+
+       * configure.in: support *-ccur-sysv4 and fix two typos
+
+1998-03-27 19:52  millert
+
+       * configure.in: don't echo about with_logfile and with_timedir
+
+1998-03-27 19:49  millert
+
+       * INSTALL: document --with-logfile and --with-timedir
+
+1998-03-27 19:46  millert
+
+       * aclocal.m4: support --with-logfile and --with-timedir
+
+1998-03-27 19:46  millert
+
+       * configure.in: Add --with-logfile and --with-timedir
+
+1998-03-27 19:27  millert
+
+       * sudo.c: change size computation of NewArgv for UNICOS
+
+1998-02-18 20:10  millert
+
+       * configure.in: treate -*-sysv4* like *-*-svr4
+
+1998-02-18 18:19  millert
+
+       * configure.in: fix spacing for --with-authenticate help
+
+1998-02-18 16:39  millert
+
+       * Makefile.in, check.c, emul/utime.h, compat.h, config.h.in,
+         dce_pwent.c, find_path.c, getspwuid.c, getwd.c, goodpath.c,
+         ins_2001.h, ins_classic.h, ins_csops.h, ins_goons.h, insults.h,
+         interfaces.c, logging.c, options.h, parse.c, parse.lex,
+         parse.yacc, pathnames.h.in, putenv.c, strdup.c, sudo.c, sudo.h,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, visudo.c:
+         updated version
+
+1998-02-18 16:23  millert
+
+       * parse.yacc: fix off by one error in push macro
+
+1998-02-17 01:15  millert
+
+       * configure.in: removed bogus alloca hack
+
+1998-02-17 01:15  millert
+
+       * check.c: added AIX 4.x authenticate() support
+
+1998-02-17 01:11  millert
+
+       * parse.yacc: include alloca.h if using bison and not gcc and it
+         exists.  fixes an alloca problem on hpux 10.x
+
+1998-02-17 00:39  millert
+
+       * INSTALL: mention --with-authenticate
+
+1998-02-17 00:37  millert
+
+       * configure.in: added AIX authenticate() support
+
+1998-02-17 00:22  millert
+
+       * config.h.in: add HAVE_AUTHENTICATE
+
+1998-02-16 23:58  millert
+
+       * interfaces.c: dynamically size ifconf buffer
+
+1998-02-16 23:56  millert
+
+       * configure.in: quote '[' and ']'
+
+1998-02-16 21:42  millert
+
+       * Makefile.in, emul/utime.h, check.c, compat.h, config.h.in,
+         dce_pwent.c, find_path.c, getspwuid.c, getwd.c, goodpath.c,
+         ins_2001.h, ins_classic.h, ins_csops.h, ins_goons.h, insults.h,
+         logging.c, options.h, parse.c, parse.lex, parse.yacc,
+         pathnames.h.in, putenv.c, strdup.c, sudo.c, sudo.h,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, visudo.c:
+         updated version
+
+1998-02-16 19:06  millert
+
+       * visudo.pod: add ERRORS section
+
+1998-02-16 18:57  millert
+
+       * TROUBLESHOOTING: add busy stmp file explanation
+
+1998-02-15 18:49  millert
+
+       * configure.in: the name of the cached var that signals whether or
+         not you are cross compiling changed.  It is now
+         ac_cv_prog_cc_cross
+
+1998-02-11 16:26  millert
+
+       * INSTALL: mention glibc 2.07 is fixed wrt lsearch()\.
+
+1998-02-06 21:55  millert
+
+       * sample.sudoers, sudoers.pod: better example of su but not root su
+
+1998-02-06 15:49  millert
+
+       * Makefile.in, check.c, emul/utime.h, compat.h, config.h.in,
+         dce_pwent.c, find_path.c, getspwuid.c, getwd.c, goodpath.c,
+         ins_2001.h, ins_classic.h, ins_csops.h, ins_goons.h, insults.h,
+         interfaces.c, logging.c, options.h, parse.c, parse.lex,
+         parse.yacc, pathnames.h.in, putenv.c, strdup.c, sudo.c, sudo.h,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, visudo.c:
+         updated version
+
+1998-02-06 15:48  millert
+
+       * Makefile.in: correct regexp for updating version
+
+1998-02-06 14:05  millert
+
+       * tgetpass.c: remove bogus flush of stderr spew prompt before
+         turning off echo.  Seems to fix a weird problem where if sudo
+         complained about a bogus stamp file the user would sometimes not
+         have a chance to enter a password
+
+1998-02-06 14:05  millert
+
+       * check.c: fix bogus flush of stderr
+
+1998-02-05 19:19  millert
+
+       * sudo.c: close fd's <=2 not <=3 and move that chunk of code up
+
+1998-02-05 19:18  millert
+
+       * configure.in: support hpux1[0-9] not just hpux10
+
+1998-01-30 14:59  millert
+
+       * parse.c: set sudoers_fp to nil after closing
+
+1998-01-24 01:05  millert
+
+       * config.guess, config.sub: updated from autoconf 2.12
+
+1998-01-24 00:50  millert
+
+       * configure.in: add *-*-svr4 rule
+
+1998-01-22 22:53  millert
+
+       * tgetpass.c: fix select usage for high fd's (dynamically allocate
+         readfds)
+
+1998-01-22 22:49  millert
+
+       * check.c: kill extra whitespace
+
+1998-01-22 19:28  millert
+
+       * sudo.c: do an initgroups() before running a command, unless the
+         target user is root.
+
+1998-01-22 12:22  millert
+
+       * TROUBLESHOOTING: tell people to use tabs, not spaces, in
+         syslog.conf
+
+1998-01-21 01:56  millert
+
+       * parse.lex, Makefile.in, config.h.in, getwd.c, strdup.c, putenv.c,
+         emul/utime.h, testsudoers.c, utime.c, dce_pwent.c: updated
+         version
+
+1998-01-21 01:32  millert
+
+       * goodpath.c, sudo_setenv.c, interfaces.c, tgetpass.c, visudo.c:
+         updated version
+
+1998-01-21 01:29  millert
+
+       * sudo.h, pathnames.h.in, options.h, compat.h, insults.h,
+         ins_2001.h, ins_classic.h, ins_goons.h, ins_csops.h, parse.yacc,
+         check.c, getspwuid.c, find_path.c, logging.c, parse.c, sudo.c:
+         updated version
+
+1998-01-21 01:20  millert
+
+       * Makefile.in: more tweaks to update_version
+
+1998-01-21 01:19  millert
+
+       * Makefile.in: fixed up update_version rule
+
+1998-01-21 00:55  millert
+
+       * configure.in: ++version
+
+1998-01-21 00:53  millert
+
+       * Makefile.in: removed supe of check.c
+
+1998-01-21 00:51  millert
+
+       * INSTALL: ++version I missed
+
+1998-01-21 00:51  millert
+
+       * RUNSON: updated
+
+1998-01-21 00:48  millert
+
+       * Makefile.in, check.c, compat.h, config.h.in, dce_pwent.c,
+         find_path.c, getspwuid.c, getwd.c, goodpath.c, ins_2001.h,
+         ins_classic.h, ins_csops.h, ins_goons.h, insults.h, interfaces.c,
+         logging.c, options.h, parse.c, parse.lex, parse.yacc,
+         pathnames.h.in, putenv.c, strdup.c, sudo.c, sudo.h,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, version.h,
+         visudo.c, emul/utime.h, BUGS, INSTALL, README: updated version
+
+1998-01-21 00:47  millert
+
+       * CHANGES: updated for 1.5.5
+
+1998-01-21 00:35  millert
+
+       * Makefile.in: add rules to update version stuff in files so I
+         don't need to do it by hand
+
+1998-01-21 00:04  millert
+
+       * sudo.h: sudoers_fp is now extern
+
+1998-01-21 00:03  millert
+
+       * sudo.c: in check_sudoers, cache the sudoers file handle in
+         sudoers_fp so we don't have to open it again in the parse.  This
+         may help with weird solaris problems where EAGAIN sometime
+         occurrs.
+
+1998-01-21 00:02  millert
+
+       * parse.c: sudoers file open is now done only in check_sudoers() so
+         we just do a rewind() instead of an open.  May help people on
+         solaris who were getting EAGAIN.
+
+1998-01-16 11:43  millert
+
+       * INSTALL: mention that newer glibc is fixed
+
+1998-01-13 12:58  millert
+
+       * sudo.c: newer irix uses _RLDN32_* envariables for 32-bit binaries
+         so ignore _RLD* instead of _RLD_*
+
+1998-01-13 10:32  millert
+
+       * parse.c: typo
+
+1998-01-13 10:19  millert
+
+       * parse.c: fix that bug for real
+
+1998-01-13 02:39  millert
+
+       * INSTALL: document Linux's libc6 brokenness.
+
+1998-01-13 02:00  millert
+
+       * parse.yacc: -Wall
+
+1998-01-13 01:22  millert
+
+       * RUNSON: updated
+
+1998-01-13 00:50  millert
+
+       * TROUBLESHOOTING: remind people to HUP syslogd
+
+1998-01-13 00:05  millert
+
+       * Makefile.in: add -O flag to tar
+
+1998-01-13 00:00  millert
+
+       * TODO, RUNSON: updated
+
+1998-01-12 23:59  millert
+
+       * sudo.pod: remove author's email addr.  people should mail
+         sudo-bugs
+
+1998-01-12 23:49  millert
+
+       * INSTALL: fix version
+
+1998-01-12 23:48  millert
+
+       * README, check.c, compat.h, config.h.in, configure.in,
+         dce_pwent.c, find_path.c, getspwuid.c, getwd.c, goodpath.c,
+         ins_2001.h, ins_classic.h, ins_csops.h, ins_goons.h, insults.h,
+         interfaces.c, logging.c, options.h, parse.c, parse.lex,
+         parse.yacc, pathnames.h.in, putenv.c, strdup.c, sudo.c, sudo.h,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, version.h,
+         visudo.c: ++version
+
+1998-01-12 23:44  millert
+
+       * RUNSON: updated
+
+1998-01-12 23:42  millert
+
+       * INSTALL, Makefile.in: ++version
+
+1998-01-12 23:41  millert
+
+       * CHANGES: updated fort 1.5.4
+
+1998-01-12 23:41  millert
+
+       * check.c: exit(1) if user enters no passwd
+
+1998-01-12 23:37  millert
+
+       * BUGS: ++version
+
+1998-01-12 23:10  millert
+
+       * parse.c: commands can start with ./* not just /* -- fixes a
+         serious security hole.
+
+1997-12-21 18:17  millert
+
+       * sudo.c: Don't set the tty variable to NULL when we lack a tty,
+         leave it as "unknown".
+
+1997-11-23 13:29  millert
+
+       * sample.sudoers: fix usage of (username) in conjunction with , and
+         !
+
+1997-11-23 13:28  millert
+
+       * visudo.c: catch the case where the user is not in the passwd file
+
+1997-11-23 13:24  millert
+
+       * tgetpass.c: use fileno(input) + 1 instead of getdtablesize() as
+         the nfds arg to select(2)
+
+1997-11-23 01:53  millert
+
+       * sudo.c: define tty global to an initial value to avoid dumping
+         core in logging functions when passwd file is unavailable.
+
+1997-11-23 01:51  millert
+
+       * sudo.c: do the set_perms(PERM_USER, sudo_mode) after we have
+         gotten the passwd entry
+
+1997-11-23 00:21  millert
+
+       * sudo.pod: talk about problem of ALL
+
+1997-10-10 00:54  millert
+
+       * README: new web location
+
+1997-10-10 00:54  millert
+
+       * INSTALL: fdesc bug is fixed in Open/Net BSD
+
+1997-10-10 00:52  millert
+
+       * HISTORY: updates from Nieusma
+
+1997-10-09 18:37  millert
+
+       * dce_pwent.c: move compat.h after the system includes
+
+1997-08-06 14:58  millert
+
+       * logging.c: save errno from being clobbered by wait().  From Theo
+
+1997-05-21 11:57  millert
+
+       * compat.h: fix an occurence of setresuid -> setreuid (typo)
+
+1997-03-19 17:45  millert
+
+       * install-sh: check for path to strip
+
+1997-01-15 19:05  millert
+
+       * logging.c: deal with maxfilelen < 0 case
+
+1997-01-15 19:05  millert
+
+       * OPTIONS: fixed descriptin
+
+1996-12-11 23:10  millert
+
+       * sudo.c: correct error message if mode/owner wrong and not
+         statable by owner but is statable by root.
+
+1996-11-23 02:18  millert
+
+       * config.guess, config.sub: autoconf 2.11
+
+1996-11-16 14:42  millert
+
+       * CHANGES, RUNSON, TODO: sudo 1.5.3.
+
+1996-11-14 15:08  millert
+
+       * sudo.h, parse.yacc: command_alias -> generic_alias
+
+1996-11-13 22:50  millert
+
+       * sample.sudoers: added Runas_Alias example and fixed syntax errors
+
+1996-11-13 22:50  millert
+
+       * OPTIONS, options.h: updated MAILSUBJECT
+
+1996-11-13 22:49  millert
+
+       * logging.c: added %h expansion
+
+1996-11-13 21:37  millert
+
+       * Makefile.in, check.c, compat.h, config.h.in, dce_pwent.c,
+         find_path.c, getspwuid.c, getwd.c, goodpath.c, ins_2001.h,
+         ins_classic.h, ins_csops.h, ins_goons.h, insults.h, interfaces.c,
+         logging.c, options.h, parse.c, parse.lex, parse.yacc,
+         pathnames.h.in, putenv.c, strdup.c, sudo.c, sudo.h,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, version.h,
+         visudo.c, INSTALL, README, configure.in: ++version
+
+1996-11-13 20:01  millert
+
+       * emul/utime.h, BUGS: ++version
+
+1996-11-13 19:45  millert
+
+       * sudoers.pod: document Runas_Alias
+
+1996-11-13 19:22  millert
+
+       * visudo.pod: q (uid) -> Q
+
+1996-11-13 19:21  millert
+
+       * visudo.c: buffer oflow checking q (uit) -> Q if yyparse() fails
+         drop into whatnow
+
+1996-11-13 19:05  millert
+
+       * parse.yacc: add size params to sprintf
+
+1996-11-13 19:04  millert
+
+       * parse.lex: allow trailing space after '\\' but before '\n'
+
+1996-11-13 19:04  millert
+
+       * find_path.c: off by one error in path size check
+
+1996-11-13 19:03  millert
+
+       * check.c: sprintf paranoia
+
+1996-11-12 11:59  millert
+
+       * parse.yacc: fixed more_aliases
+
+1996-11-12 11:58  millert
+
+       * visudo.c: now warns if killed by signal ./
+
+1996-11-11 10:49  millert
+
+       * parse.yacc: fix Runas_Alias stuff Alias's in runas list now get
+         expanded (but it is gross)
+
+1996-11-10 20:32  millert
+
+       * sudo.c: Can now deal with SUDOERS_UID == 0 and SUDOERS_MODE ==
+         0400
+
+1996-11-10 20:08  millert
+
+       * parse.yacc: add Runas_Alias support change FOO to FOO_ALIAS (ie:
+         USER_ALIAS)
+
+1996-11-10 20:02  millert
+
+       * parse.lex: Add Runas_Alias and simplify a rule.
+
+1996-11-10 19:15  millert
+
+       * parse.yacc: always store User_Alias's since they can be used
+         inside of a runas list.  Sigh.  Really need a Runas_Alias
+         instead.
+
+1996-10-30 18:04  millert
+
+       * visudo.c: deal with case where there is no sudoers file
+
+1996-10-11 23:01  millert
+
+       * TROUBLESHOOTING: added one
+
+1996-10-10 22:11  millert
+
+       * HISTORY, testsudoers.c: developement -> development
+
+1996-10-10 22:08  millert
+
+       * INSTALL: added a note
+
+1996-10-10 20:36  millert
+
+       * RUNSON: for 1.5.2
+
+1996-10-10 20:36  millert
+
+       * CHANGES: updated
+
+1996-10-10 00:56  millert
+
+       * PORTING: removed seteuid() notes
+
+1996-10-09 13:37  millert
+
+       * compat.h: better seteuid() emulatino
+
+1996-10-09 13:36  millert
+
+       * configure.in: added check for seteuid
+
+1996-10-09 13:36  millert
+
+       * config.h.in: added HAVE_SETEUID
+
+1996-10-08 19:22  millert
+
+       * configure.in: first stab at sequent support
+
+1996-10-08 19:21  millert
+
+       * config.h.in: added HAVE_SYS_SELECT_H
+
+1996-10-08 19:21  millert
+
+       * compat.h: sequent -> _SEQUENT_
+
+1996-10-08 19:11  millert
+
+       * compat.h: added seteuid() macro for DYNIX
+
+1996-10-08 18:54  millert
+
+       * tgetpass.c: _AIX -> HAVE_SYS_SELECT_H
+
+1996-10-07 01:05  millert
+
+       * emul/utime.h, check.c, compat.h, dce_pwent.c, find_path.c,
+         getspwuid.c, getwd.c, goodpath.c, ins_2001.h, ins_classic.h,
+         ins_csops.h, ins_goons.h, insults.h, interfaces.c, options.h,
+         pathnames.h.in, version.h, BUGS, INSTALL, Makefile.in, OPTIONS,
+         README, config.h.in, logging.c, parse.c, parse.lex, parse.yacc,
+         putenv.c, strdup.c, sudo_setenv.c, testsudoers.c, utime.c,
+         visudo.c, tgetpass.c: ++version
+
+1996-10-07 00:59  millert
+
+       * sudo.pod: added -H and SUDO_PS1
+
+1996-10-07 00:55  millert
+
+       * configure.in: use SUDO_FUNC_FNMATCH
+
+1996-10-07 00:54  millert
+
+       * aclocal.m4: added SUDO_FUNC_FNMATCH
+
+1996-10-07 00:53  millert
+
+       * sudo.c: added -H flag
+
+1996-10-07 00:53  millert
+
+       * sudo.h: added MODE_RESET_HOME /
+
+1996-10-05 00:00  millert
+
+       * INSTALL: mention OPIE
+
+1996-10-04 23:59  millert
+
+       * configure.in: added opie support
+
+1996-10-04 23:59  millert
+
+       * check.c: added HAVE_OPIE and changed to *_OTP_*
+
+1996-10-04 23:58  millert
+
+       * compat.h, config.h.in: added HAVE_OPIE
+
+1996-10-04 23:58  millert
+
+       * OPTIONS, options.h: SKEY -> OTP
+
+1996-10-03 23:27  millert
+
+       * check.c: moved fclose() in skey stuff.
+
+1996-10-03 19:53  millert
+
+       * putenv.c: index -> strchr remove unnecesary stuff
+
+1996-10-03 19:43  millert
+
+       * check.c: now call skeychallenge() to get challenge instead of
+         making one up ourselves.  this way, we get extra goodies in the
+         prompt.
+
+1996-09-10 00:32  millert
+
+       * CHANGES: added one
+
+1996-09-10 00:18  millert
+
+       * parse.lex: allow logins to start with a number (YUCK!)
+
+1996-09-08 15:18  millert
+
+       * TROUBLESHOOTING: added soalris 2.5 vs 2.4 note
+
+1996-09-08 15:15  millert
+
+       * configure.in: DUNIX doesn't need -lnsl
+
+1996-09-07 20:22  millert
+
+       * CHANGES: [no log message]
+
+1996-09-07 20:21  millert
+
+       * check.c, compat.h, config.h.in, dce_pwent.c, find_path.c,
+         getspwuid.c, getwd.c, goodpath.c, ins_2001.h, ins_classic.h,
+         ins_csops.h, ins_goons.h, insults.h, interfaces.c, logging.c,
+         options.h, parse.c, parse.lex, parse.yacc, pathnames.h.in,
+         putenv.c, strdup.c, sudo.c, sudo.h, sudo_setenv.c, testsudoers.c,
+         tgetpass.c, utime.c, version.h, visudo.c: courtesan
+
+1996-09-07 20:13  millert
+
+       * TROUBLESHOOTING, INSTALL, Makefile.in, PORTING, RUNSON, README:
+         courtesan
+
+1996-09-07 20:12  millert
+
+       * visudo.pod: [no log message]
+
+1996-09-07 20:00  millert
+
+       * sudo.pod, visudo.pod: courtesan
+
+1996-09-07 19:45  millert
+
+       * HISTORY: added courtesan ./
+
+1996-09-06 00:12  millert
+
+       * sudo.c: added $SUDO_PROMPT support
+
+1996-09-04 17:19  millert
+
+       * check.c: print long skey challemged to stderr, not stdout
+
+1996-08-31 23:10  millert
+
+       * CHANGES: updated for 1.5.1
+
+1996-08-31 23:07  millert
+
+       * emul/utime.h: ++version
+
+1996-08-31 12:34  millert
+
+       * RUNSON: updated for 1.5.1
+
+1996-08-30 10:49  millert
+
+       * check.c: use shost, not host for tgetpass
+
+1996-08-30 00:21  millert
+
+       * OPTIONS, sudo.pod: documented %u and %h
+
+1996-08-29 20:40  millert
+
+       * configure.in: fixed typo
+
+1996-08-29 20:37  millert
+
+       * INSTALL, Makefile.in, README, check.c, compat.h, config.h.in,
+         dce_pwent.c, find_path.c, getspwuid.c, getwd.c, goodpath.c,
+         ins_2001.h, ins_classic.h, ins_csops.h, ins_goons.h, insults.h,
+         interfaces.c, logging.c, options.h, parse.c, parse.lex,
+         parse.yacc, pathnames.h.in, putenv.c, strdup.c, sudo.c, sudo.h,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, version.h,
+         visudo.c: ++version
+
+1996-08-29 20:30  millert
+
+       * BUGS: ++version
+
+1996-08-29 18:32  millert
+
+       * configure.in, Makefile.in, version.h: ++version
+
+1996-08-29 17:58  millert
+
+       * sudo.h: new tgetpass() params
+
+1996-08-29 17:58  millert
+
+       * check.c: pass use and host to tgetpass
+
+1996-08-29 17:57  millert
+
+       * tgetpass.c: added %u and %h escapes
+
+1996-08-29 16:56  millert
+
+       * OPTIONS, options.h, check.c: added NO_MESSAGE
+
+1996-08-29 16:23  millert
+
+       * configure.in: added cray (unicos) support
+
+1996-08-27 11:36  millert
+
+       * OPTIONS, options.h, sudo.c: added SHELL_SETS_HOME
+
+1996-08-25 17:56  millert
+
+       * INSTALL: added note about "make install"
+
+1996-08-25 17:50  millert
+
+       * parse.yacc: changed length/size params from int to size_t
+
+1996-08-25 13:35  millert
+
+       * OPTIONS: now get CSOPS insults as well by default
+
+1996-08-25 13:33  millert
+
+       * insults.h: use csops insults too by default
+
+1996-08-25 13:31  millert
+
+       * INSTALL, Makefile.in, README, config.h.in, configure.in,
+         version.h: version = 1.5
+
+1996-08-25 13:27  millert
+
+       * sudo.c: added runas_homedir
+
+1996-08-25 13:27  millert
+
+       * TODO: updated for 1.5
+
+1996-08-25 13:23  millert
+
+       * RUNSON: updated for 1.5
+
+1996-08-25 13:19  millert
+
+       * CHANGES: 1.5 release
+
+1996-08-25 13:17  millert
+
+       * INSTALL: added "upgrading" notes
+
+1996-08-22 14:00  millert
+
+       * visudo.c: now do chmod and chown after edit of temp file and
+         before rename
+
+1996-08-18 12:52  millert
+
+       * Makefile.in: ++version added INSTALL.configure
+
+1996-08-18 12:52  millert
+
+       * version.h, configure.in: ++version
+
+1996-08-18 12:51  millert
+
+       * TROUBLESHOOTING: [no log message]
+
+1996-08-18 12:50  millert
+
+       * parse.yacc: added missing cast
+
+1996-08-17 20:37  millert
+
+       * sudo.c: sets $HOME to pw_dir of runas user
+
+1996-08-17 20:02  millert
+
+       * sudo.pod: document $HOME change
+
+1996-08-17 19:43  millert
+
+       * sudo.pod: fixed up some wording
+
+1996-08-17 19:25  millert
+
+       * check.c, dce_pwent.c, find_path.c, getspwuid.c, getwd.c,
+         goodpath.c, interfaces.c, logging.c, parse.c, parse.lex,
+         parse.yacc, putenv.c, strdup.c, sudo.c, sudo_setenv.c,
+         testsudoers.c, tgetpass.c, utime.c, visudo.c: ++version
+
+1996-08-17 19:19  millert
+
+       * emul/utime.h, compat.h, ins_2001.h, ins_classic.h, ins_csops.h,
+         ins_goons.h, insults.h, options.h, pathnames.h.in, sudo.h:
+         ++version
+
+1996-08-17 19:18  millert
+
+       * sudo.h: name nad type changes
+
+1996-08-17 19:17  millert
+
+       * testsudoers.c: now works with new sudo
+
+1996-08-17 19:07  millert
+
+       * parse.yacc: fixed some XXX
+
+1996-08-17 18:52  millert
+
+       * parse.yacc: some variable name changes + comment headers for
+         functions.
+
+1996-08-17 18:41  millert
+
+       * tgetpass.c: added extra paren's to make compilers happy
+
+1996-08-17 18:34  millert
+
+       * sudo.c: [no log message]
+
+1996-08-17 18:30  millert
+
+       * parse.c: now uses init_parser() if not in sudoers and tries
+         "list" or "validate" scold but don't be nasty.
+
+1996-08-17 18:29  millert
+
+       * TROUBLESHOOTING: now can use upper case login names
+
+1996-08-17 18:29  millert
+
+       * visudo.c: now uses init_parser()
+
+1996-08-17 18:28  millert
+
+       * PORTING: added info about PASSWORD_TIMEOUT
+
+1996-08-17 18:28  millert
+
+       * INSTALL, README: updated
+
+1996-08-17 18:28  millert
+
+       * INSTALL.configure: Initial revision
+
+1996-08-17 18:27  millert
+
+       * BUGS: fixed a bug ,
+
+1996-08-17 18:27  millert
+
+       * parse.yacc: now dynamically allocates memory for the stacks -- no
+         more overflows!
+
+1996-08-17 18:26  millert
+
+       * sudo.pod: -l now explands command aliases
+
+1996-08-17 13:22  millert
+
+       * parse.yacc: hacks to expand command aliases for `sudo -l'
+
+1996-08-17 13:22  millert
+
+       * sudo.c: remove $ENV and $BASH_ENV (dangerous in ksh, posix sh,
+         and bash)
+
+1996-08-17 13:22  millert
+
+       * sudo.h: added struct command_alias
+
+1996-08-17 13:20  millert
+
+       * sudo.pod: fixed a bug
+
+1996-08-17 13:15  millert
+
+       * lsearch.c: in compar() key should be first arg
+
+1996-08-15 15:48  millert
+
+       * BUGS: fixed some bugs
+
+1996-08-15 15:47  millert
+
+       * parse.yacc: can now deal with upcase HOST and USER names
+
+1996-08-15 15:47  millert
+
+       * sudo.c: don't yell too loudly at non-sudoers if they do "sudo -l"
+
+1996-08-15 15:46  millert
+
+       * sudo.pod: fixed thinko
+
+1996-08-15 15:46  millert
+
+       * parse.c: fix comment
+
+1996-08-09 18:07  millert
+
+       * parse.c, parse.yacc: added support for new `sudo -l' stuff
+
+1996-08-09 18:06  millert
+
+       * sudo.c: now uses list_matches()
+
+1996-08-09 18:06  millert
+
+       * sudo.h: added struct sudo_match
+
+1996-08-09 17:37  millert
+
+       * configure.in: now more -lgnumalloc
+
+1996-08-01 13:12  millert
+
+       * install-sh: added more paths for chown and whoami
+
+1996-07-31 10:41  millert
+
+       * check.c: typo
+
+1996-07-30 13:45  millert
+
+       * aclocal.m4: fixed DUNIX check for shadow pw
+
+1996-07-30 13:41  millert
+
+       * tgetpass.c: now only turn off echo if it is already on.  this
+         fixes a race when you use sudo in a pipelin
+
+1996-07-30 12:53  millert
+
+       * INSTALL: updated
+
+1996-07-29 22:29  millert
+
+       * configure.in: changed "test -z $foo && do_this" to if; then
+         construct
+
+1996-07-28 22:47  millert
+
+       * configure.in: added missing defines of SHADOW_TYPE
+
+1996-07-26 14:10  millert
+
+       * check.c: protect AUTH_CRYPT_OLDCRYPT and AUTH_CRYPT_C1CRYPT since
+         they are only in dunix 4.x
+
+1996-07-26 14:09  millert
+
+       * getspwuid.c: added AUTH_CRYPT_C1CRYPT support
+
+1996-07-26 13:23  millert
+
+       * parse.c: no longer return VALIDATE_NOT_OK if there was a runas
+         that didn't match.  Now we can have runas stuff on more than one
+         line.
+
+1996-07-25 23:45  millert
+
+       * configure.in: got rid of HAVE_C2_SECURITY SHADOW_TYPE is always
+         defined to something
+
+1996-07-25 23:45  millert
+
+       * config.h.in: removed HAVE_C2_SECURITY added SPW_BSD
+
+1996-07-25 23:44  millert
+
+       * compat.h, getspwuid.c, sudo.c, tgetpass.c: use SHADOW_TYPE
+         instead of HAVE_C2_SECURITY
+
+1996-07-25 23:44  millert
+
+       * check.c: SHADOW_TYPE is always defined so just against its value
+
+1996-07-25 23:44  millert
+
+       * aclocal.m4: added SUDO_CHECK_SHADOW_DUNIX
+
+1996-07-25 18:47  millert
+
+       * sudoers.pod: * -> ?* in one example added another instance of
+         (runas) and one of NOPASSWD:
+
+1996-07-24 13:02  millert
+
+       * configure.in: added back check for config.cache from other host
+         type
+
+1996-07-24 12:49  millert
+
+       * parse.lex: removed an instance of \"
+
+1996-07-24 12:49  millert
+
+       * sample.sudoers: added an example
+
+1996-07-24 12:44  millert
+
+       * sudoers.pod: updated wrt new wildcard matching
+
+1996-07-24 10:28  millert
+
+       * configure.in: new check for shadow passwords if we don't know
+         anything
+
+1996-07-24 10:28  millert
+
+       * aclocal.m4: new SUDO_CHECK_SHADOW_GENERIC
+
+1996-07-24 02:19  millert
+
+       * configure.in: added back check for -lsocket (oops)
+
+1996-07-24 02:16  millert
+
+       * configure.in: better (working) check for shadow passwd type if we
+         know to use C2.
+
+1996-07-24 01:59  millert
+
+       * configure.in: now uses AC_CANONICAL_HOST to figure out os type
+
+1996-07-24 01:59  millert
+
+       * Makefile.in: added config.{guess,sub}
+
+1996-07-24 01:58  millert
+
+       * aclocal.m4: removed unused stuff to figure out os type
+
+1996-07-23 22:58  millert
+
+       * config.sub: added openbsd
+
+1996-07-23 22:54  millert
+
+       * config.sub: Initial revision
+
+1996-07-23 22:40  millert
+
+       * config.guess: Initial revision
+
+1996-07-23 21:18  millert
+
+       * testsudoers.c: don't call fnmatch() with FNM_PATHNAME flag unless
+         it can only be a pathname.  need to check against sudoers_args
+         even if user_args is nil
+
+1996-07-23 21:18  millert
+
+       * parse.c: don't call fnmatch() with FNM_PATHNAME flag unless it
+         can only be a pathname need to check against sudoers_args even if
+         user_args is nil
+
+1996-07-23 18:52  millert
+
+       * check.c: added support for AUTH_CRYPT_OLDCRYPT w/ DUNIX C2
+
+1996-07-23 01:18  millert
+
+       * testsudoers.c: now takes command line args and uses cmnd_args
+
+1996-07-23 01:10  millert
+
+       * parse.lex: fill_args was adding an extra leading space
+
+1996-07-22 15:50  millert
+
+       * visudo.c: fixed dummy command_matches()
+
+1996-07-22 15:50  millert
+
+       * parse.yacc: fixed prototype
+
+1996-07-22 15:31  millert
+
+       * sudo.h: added cmnd_args
+
+1996-07-22 15:31  millert
+
+       * parse.yacc: now uses flat args string
+
+1996-07-22 15:30  millert
+
+       * parse.c, parse.lex: now uses flat arg string
+
+1996-07-22 15:29  millert
+
+       * visudo.c: added cmnd_args def
+
+1996-07-22 14:30  millert
+
+       * sudo.c: now sets cmnd_args global
+
+1996-07-22 14:30  millert
+
+       * logging.c: cmnd_args is now exported from sudo.[ch]
+
+1996-07-21 18:41  millert
+
+       * parse.yacc: can't rely on cmnd_matches as much as I thought --
+         added some $$ stuff back in to prevent namespace pollution
+         problems.
+
+1996-07-21 18:01  millert
+
+       * parse.yacc: Simplified parse rules wrt runas and NOPASSWD (more
+         consistent).
+
+1996-07-20 00:45  millert
+
+       * parse.lex: NOPASSWD may now have blanks before the ':' '(' only
+         starts a 'runas' if in the initial state to avoid collision with
+         command args
+
+1996-07-20 00:23  millert
+
+       * configure.in: added checks for specific shadow passwd schemes
+
+1996-07-20 00:18  millert
+
+       * aclocal.m4: added routines to check for specific shadow passwd
+         types
+
+1996-07-18 18:27  millert
+
+       * configure.in: added support for ncr boxen
+
+1996-07-18 18:26  millert
+
+       * aclocal.m4: added support for detecting ncr boxen
+
+1996-07-16 14:57  millert
+
+       * configure.in: added sinix support
+
+1996-07-13 22:29  millert
+
+       * TROUBLESHOOTING: added info about "config.cache from other other"
+         error.
+
+1996-07-13 22:22  millert
+
+       * aclocal.m4: now makes sure you don't have a config.cache file
+         from another OS
+
+1996-07-13 21:36  millert
+
+       * configure.in: now sets $LIBS when needed to configure links with
+         libs when doing tests hpux10 now uses SPW_SECUREWARE for C2 added
+         check for bigcrypt(3) if SPW_SECUREWARE
+
+1996-07-13 21:30  millert
+
+       * getspwuid.c: fixed typo
+
+1996-07-13 21:05  millert
+
+       * tgetpass.c: now include stuff for SPW_SECUREWARE to get
+         AUTH_MAX_PASSWD_LENGTH
+
+1996-07-13 21:05  millert
+
+       * getspwuid.c: no more SPW_HPUX10
+
+1996-07-13 21:04  millert
+
+       * config.h.in: no more SPW_HPUX10 added HAVE_BIGCRYPT
+
+1996-07-13 21:04  millert
+
+       * compat.h: now uses AUTH_MAX_PASSWD_LENGTH if SPW_SECUREWARE
+
+1996-07-13 21:04  millert
+
+       * check.c: SPW_SECUREWARE now uses bigcrypt
+
+1996-07-13 18:24  millert
+
+       * sample.sudoers: fixed 2 syntax errors
+
+1996-07-13 18:24  millert
+
+       * sudoers: root may now run ALL as ALL
+
+1996-07-11 20:59  millert
+
+       * interfaces.c: fixed a typo/thinko that broke BSD's with sa_len
+
+1996-07-08 16:08  millert
+
+       * check.c, configure.in: updated AFS support
+
+1996-07-08 16:07  millert
+
+       * TROUBLESHOOTING: added entry about /usr/ucb/cc
+
+1996-07-08 16:06  millert
+
+       * INSTALL: prep no longer holds gcc binaries
+
+1996-07-08 15:48  millert
+
+       * INSTALL: updated AFS note
+
+1996-07-08 15:43  millert
+
+       * Makefile.in: added @AFS_LIBS@
+
+1996-07-08 15:33  millert
+
+       * compat.h: AFS allows long passwords
+
+1996-07-08 14:16  millert
+
+       * testsudoers.c: fixed -u user support
+
+1996-07-08 14:16  millert
+
+       * parse.c: sudo -v now groks VALIDATE_OK_NOPASS
+
+1996-07-08 13:30  millert
+
+       * parse.yacc: fixed no_passwd vs. runas_matched
+
+1996-07-08 10:30  millert
+
+       * TROUBLESHOOTING: took out stuff about NFS-mounting since it is no
+         longer an issue
+
+1996-07-08 10:30  millert
+
+       * INSTALL: added --with-libraries >   --with-libpath --with-incpath
+
+1996-07-08 10:21  millert
+
+       * parse.yacc: was setting runas_matches to -1 in wrong place
+
+1996-07-08 09:58  millert
+
+       * check.c: removed usersec.h which is not present in new AFS
+         versions
+
+1996-07-08 09:55  millert
+
+       * tgetpass.c: now deals with timeout <= 0
+
+1996-07-08 09:51  millert
+
+       * OPTIONS: updated
+
+1996-07-08 00:04  millert
+
+       * configure.in: BSD/OS >= 2.0 now uses shlicc instead of just gcc
+
+1996-07-07 22:30  millert
+
+       * sudo.c: fixed backwards compatibility with sudo 1.4 sudoers mode
+         for root readable/writable filesystems
+
+1996-07-07 20:49  millert
+
+       * Makefile.in: now gives INSTALL -c flag
+
+1996-07-07 20:34  millert
+
+       * parse.yacc: slightly simpler initialization of  no_passwd and
+         runas_matches
+
+1996-07-07 20:33  millert
+
+       * testsudoers.c: added -u username support
+
+1996-07-07 20:32  millert
+
+       * configure.in: improved --with-libraries support
+
+1996-07-07 16:27  millert
+
+       * configure.in: added --with-incpath, --with-libpath,
+         --with-libraries
+
+1996-07-07 16:01  millert
+
+       * parse.yacc: now initializes some fields that weren't getting set
+         to -1 pretty gross -- need a rewrite.
+
+1996-06-25 23:19  millert
+
+       * alloca.c: removed emacs'isms
+
+1996-06-25 22:29  millert
+
+       * configure.in: no longer add -lPW to *_LIBS since we include
+         alloca.c
+
+1996-06-25 22:29  millert
+
+       * config.h.in: added HAVE_ALLOCA_H
+
+1996-06-25 22:28  millert
+
+       * Makefile.in: added alloca.c
+
+1996-06-25 22:18  millert
+
+       * alloca.c: Initial revision
+
+1996-06-25 21:58  millert
+
+       * configure.in: ++version
+
+1996-06-25 19:32  millert
+
+       * sudo.c: now set uid to 1 instead of nobody for PERM_SUDOERS since
+         nobody is not always set to a valid uid.
+
+1996-06-25 19:31  millert
+
+       * OPTIONS: fixed entry for SUDO_MODE
+
+1996-06-25 18:02  millert
+
+       * sudo.c: Fixed NFS-mounted sudoers file under solaris both uid
+         *and* gid were being set to -2.  Now beat NFS to the punch and
+         set uid to "nobody" ourselves, preserving group 0 to read
+         sudoers.
+
+1996-06-25 18:02  millert
+
+       * parse.c: moved set_perms(PERM_ROOT) to be before yyparse()
+
+1996-06-25 18:00  millert
+
+       * logging.c: fixed a typo
+
+1996-06-25 18:00  millert
+
+       * configure.in: no longer need AC_PROG_INSTALL
+
+1996-06-25 17:59  millert
+
+       * Makefile.in: always use install-sh to avoid install(1)'s that use
+         get{pw,gr}nam
+
+1996-06-25 16:07  millert
+
+       * INSTALL: make clean -> make distclean
+
+1996-06-20 01:17  millert
+
+       * parse.yacc: removed some unnecsary if's
+
+1996-06-20 01:16  millert
+
+       * Makefile.in, version.h: ++version
+
+1996-06-20 01:16  millert
+
+       * parse.c, testsudoers.c: now includes netgroup.h
+
+1996-06-20 00:45  millert
+
+       * interfaces.c: removed cats of ioctl to int since they didn't shut
+         up -Wall
+
+1996-06-20 00:43  millert
+
+       * interfaces.c: explicately cast ioctl() to int since it it not
+         always declared
+
+1996-06-20 00:41  millert
+
+       * sudo.h: added declarations for yyparse() and yylex()
+
+1996-06-20 00:27  millert
+
+       * parse.yacc: fixed an occurence of '==' -> '='
+
+1996-06-20 00:22  millert
+
+       * config.h.in, configure.in: added check for netgroup.h
+
+1996-06-20 00:20  millert
+
+       * sudo.c: fixed 2 compiler warnings
+
+1996-06-20 00:08  millert
+
+       * sudo.c: SHELL_IF_NO_ARGS caused core dump since NewArg[cv]
+         weren't being initialized
+
+1996-06-19 13:53  millert
+
+       * sudo.pod: fixed a typo
+
+1996-06-17 12:19  millert
+
+       * parse.yacc: fixed a formatting thingie
+
+1996-06-17 12:16  millert
+
+       * parse.c, parse.yacc: fixed -u support with multiple user lists on
+         a line
+
+1996-06-17 10:23  millert
+
+       * configure.in: unixware needs -lgen
+
+1996-06-17 10:23  millert
+
+       * README: updated ftp location
+
+1996-06-17 00:08  millert
+
+       * sudoers.pod: add net_addr/netmask support
+
+1996-06-17 00:07  millert
+
+       * sample.sudoers: added net_addr/mask example
+
+1996-06-17 00:02  millert
+
+       * parse.lex, parse.c: added support for net_addr/netmask
+
+1996-06-15 20:13  millert
+
+       * sudoers.pod: ^ -> !
+
+1996-06-15 18:12  millert
+
+       * RUNSON: updated for 1.4.3
+
+1996-06-15 18:12  millert
+
+       * CHANGES: udpated for 1.4.3
+
+1996-06-15 18:11  millert
+
+       * TROUBLESHOOTING, TODO, BUGS: updated
+
+1996-06-15 18:11  millert
+
+       * sample.sudoers: updated with examples of new stuff
+
+1996-06-15 18:10  millert
+
+       * INSTALL, README: ++version
+
+1996-06-15 18:01  millert
+
+       * sudoers.pod: updated wrt -u and NOPASSWD
+
+1996-06-15 17:58  millert
+
+       * sudo.pod: updated wrt -u and CAVEATS
+
+1996-06-08 23:15  millert
+
+       * sudo.c: fixed usage()
+
+1996-06-08 22:57  millert
+
+       * parse.lex: now use :foo: character classes (makes no diff for
+         generated lexer)
+
+1996-06-07 14:33  millert
+
+       * check.c: fixed LONG_SKEY_PROMPT stuff
+
+1996-06-06 15:35  millert
+
+       * visudo.c: fixed a comment
+
+1996-06-06 15:03  millert
+
+       * lsearch.c: make more like NetBSD one -- now compiles w/o warnings
+
+1996-06-06 15:02  millert
+
+       * emul/search.h: fixed decls of lsearch()
+
+1996-06-05 22:20  millert
+
+       * config.h.in, configure.in, getspwuid.c: added SPW_HPUX10
+
+1996-06-05 22:20  millert
+
+       * check.c: hpux 10 uses bigcrypt() if C2
+
+1996-06-04 19:57  millert
+
+       * parse.c: now always uses fnmatch to match args
+
+1996-06-04 19:40  millert
+
+       * tgetpass.c: back to using stdio instead of raw i/o since that
+         caused some problems
+
+1996-05-28 22:14  millert
+
+       * sudo.c: now give usage warning if use -l,-v,-k with args
+
+1996-05-28 18:22  millert
+
+       * sudo.c: NewArgc is now set to 1 for -l, -v, -k
+
+1996-05-28 12:50  millert
+
+       * sudo.c: now sets sudoers to correct group if mode is 0400
+
+1996-05-28 12:02  millert
+
+       * install-sh: updated to version used by inn and bind
+
+1996-05-28 00:08  millert
+
+       * configure.in: now uses -lgnumalloc if it exists
+
+1996-05-28 00:02  millert
+
+       * Makefile.in: "make install" now sets uid/gid and mode on sudoers
+         if it exists
+
+1996-05-28 00:01  millert
+
+       * sudo.c: rmeoved debugging statements
+
+1996-05-28 00:00  millert
+
+       * parse.yacc: added a missing free()
+
+1996-05-27 23:58  millert
+
+       * sudo.c: now uses user_gid instead of getegid (which was wrong
+         anyway) to set SUDO_GID Now sets command line args in
+         SUDO_COMMAND envariabled (logging.c depends on args being in the
+         environment)
+
+1996-05-27 23:57  millert
+
+       * logging.c: now uses SUDO_COMMAND envariable to get command args
+         rather than building it up again.
+
+1996-05-27 22:42  millert
+
+       * parse.c: now uses user_gid
+
+1996-05-27 20:02  millert
+
+       * sudo.c: fixed off by one error in allocation NewArgv
+
+1996-05-27 20:01  millert
+
+       * parse.c: in sudoers, 'command ""' now means command with no args
+
+1996-05-27 20:01  millert
+
+       * configure.in: added check for fnmatch(3) and fnmatch.h
+
+1996-05-27 20:01  millert
+
+       * config.h.in: added HAVE_FNMATCH
+
+1996-05-27 20:00  millert
+
+       * Makefile.in: replaced wildcat.* with fnmatch.*
+
+1996-05-27 20:00  millert
+
+       * testsudoers.c: now uses fnmatch()
+
+1996-05-27 19:38  millert
+
+       * parse.c: now uses fnmatch() instead of wildmat a trailing star
+         (*) by itself now matches multiple args added support for
+         wildcards in the pathname  in sudoers
+
+1996-05-25 19:23  millert
+
+       * fnmatch.c: now includes compat.h and config.h
+
+1996-05-25 18:09  millert
+
+       * config.h.in: added HAVE_FNMATCH_H
+
+1996-05-25 18:07  millert
+
+       * configure.in: now checks for alloca() (if needed by bison or dce)
+         and links with -lPW if it contains alloca() and libv and compiler
+         do not.
+
+1996-05-25 18:03  millert
+
+       * fnmatch.3, fnmatch.c, emul/fnmatch.h: Initial revision
+
+1996-04-28 22:38  millert
+
+       * sudo.c: now fixes mode on sudoers if set to 0400 to aid in
+         upgrade
+
+1996-04-28 17:44  millert
+
+       * Makefile.in: fixed pod2man usage
+
+1996-04-28 17:40  millert
+
+       * configure.in, Makefile.in, version.h: ++version
+
+1996-04-28 17:20  millert
+
+       * testsudoers.c, visudo.c: runas_user is now initialized to "root"
+
+1996-04-28 17:20  millert
+
+       * sudo.h: removed PERM_FULL_ROOT
+
+1996-04-28 17:18  millert
+
+       * sudo.c: runas_user defaults to "root" so no more need to
+         PERM_RUNAS
+
+1996-04-28 17:16  millert
+
+       * parse.c: will now only running commands as root if there was no
+         runas list (or if root is in the runas list)
+
+1996-04-28 17:15  millert
+
+       * logging.c: now logs "USER=%s"
+
+1996-04-28 17:12  millert
+
+       * parse.yacc: runas_matches is now set to false if we get a
+         negative match
+
+1996-04-28 15:01  millert
+
+       * parse.lex: make #uid work + some minor cleanup
+
+1996-04-27 21:04  millert
+
+       * sample.sudoers: added support for NOPASSWD and "runas" from
+         garp@opustel.com /
+
+1996-04-27 21:03  millert
+
+       * visudo.c: added support for "runas" from garp@opustel.com
+         replaced SUDOERS_OWNER with SUDOERS_UID, SUDOERS_GID added
+         support for SUDOERS_MODE
+
+1996-04-27 21:03  millert
+
+       * testsudoers.c: added support for "runas" from garp@opustel.com
+
+1996-04-27 21:02  millert
+
+       * sudo.h: added support for NO_PASSWD and runas from
+         garp@opustel.com replaced SUDOERS_OWNER with SUDOERS_UID and
+         SUDOERS_GID     and added support fro SUDOERS_MODE
+
+1996-04-27 21:00  millert
+
+       * sudo.c: added support for NO_PASSWD and runas from
+         garp@opustel.com replaced SUDOERS_OWNER with SUDOERS_UID and
+         SUDOERS_GID and added support fro SUDOERS_MODE
+
+1996-04-27 21:00  millert
+
+       * parse.yacc: added support for NO_PASSWD and runas from
+         garp@opustel.com
+
+1996-04-27 20:58  millert
+
+       * parse.c, parse.lex: added support for NO_PASSWD and runas from
+         garp@opustel.com
+
+1996-04-27 20:56  millert
+
+       * logging.c: added support for SUDOERS_WRONG_MODE and "runas"
+
+1996-04-27 20:40  millert
+
+       * configure.in: added --with-CC only link with -lshadow on linux
+         (with shadow pw) if libc lacks getspnam()
+
+1996-04-27 20:39  millert
+
+       * OPTIONS, options.h: removed NO_PASSWD since it is not possible to
+         do this in the sudoers file itself.  Replaced SUDOERS_OWNER with
+         SUDOERS_UID and SUDOERS_GID.  Added SUDOERS_MODE.
+
+1996-04-27 20:26  millert
+
+       * Makefile.in: now uses SUDOERS_UID and SUDOERS_GID
+
+1996-04-27 11:20  millert
+
+       * INSTALL: added --with-CC
+
+1996-04-06 16:31  millert
+
+       * parse.lex: added double quote support
+
+1996-04-06 16:29  millert
+
+       * sudoers.pod: documented double quoting
+
+1996-04-05 16:53  millert
+
+       * mkinstalldirs: Initial revision
+
+1996-04-05 16:53  millert
+
+       * check.c: fixed some indentation
+
+1996-04-05 16:48  millert
+
+       * Makefile.in: fixed a typo
+
+1996-04-04 19:39  millert
+
+       * Makefile.in: added install-dirs .
+
+1996-04-04 14:16  millert
+
+       * dce_pwent.c: new version from "Jeff A. Earickson"
+         <jaearick@colby.edu>
+
+1996-04-03 13:40  millert
+
+       * configure.in: $CSOPS -> $with_csops (whoops, missed one)
+
+1996-04-03 13:40  millert
+
+       * BUGS: updated
+
+1996-04-03 13:36  millert
+
+       * parse.lex: FQHOST now has same constraints as non-FQHOST
+
+1996-04-02 19:00  millert
+
+       * INSTALL: added note about OS's w/ shadow passwords turned on by
+         default
+
+1996-04-02 18:58  millert
+
+       * configure.in: fixed a typo
+
+1996-04-02 18:48  millert
+
+       * configure.in: added support for --without-THING sanitized shadow
+         pw situtation by adding support for --without-C2
+
+1996-04-02 16:42  millert
+
+       * tgetpass.c: fixed a typo wrt placement of an end paren
+
+1996-04-02 14:57  millert
+
+       * check.c: was closing an fd that may not have been opened
+
+1996-03-21 19:55  millert
+
+       * sudo.c, OPTIONS, options.h: added NO_PASSWD
+
+1996-03-19 19:40  millert
+
+       * configure.in: now always use shadow pw on some arches
+
+1996-03-19 17:07  millert
+
+       * configure.in: added pyramid support
+
+1996-03-19 17:04  millert
+
+       * configure.in: no longer check for C2 if alternate passwd method
+         is used no longer check for some libs twice
+
+1996-03-19 17:00  millert
+
+       * parse.yacc: moved fqdn stuff into parse.lex (FQHOST)
+
+1996-03-19 17:00  millert
+
+       * parse.lex: added FQHOST rules
+
+1996-03-18 20:57  millert
+
+       * tgetpass.c: now define TCSASOFT in necesary
+
+1996-03-18 20:31  millert
+
+       * tgetpass.c: now uses read/write instead of stdio string goop to
+         avoid problems with select(2)
+
+1996-03-18 19:37  millert
+
+       * OPTIONS, find_path.c, options.h: -DNO_DOT_PATH ->
+         -DIGNORE_DOT_PATH
+
+1996-03-17 16:18  millert
+
+       * INSTALL: added note about no shadow auto-detect if using
+         alternate auth schemes
+
+1996-03-17 15:33  millert
+
+       * configure.in: don't check for C2 if AFS or DCE (unless they said
+         --with-C2)
+
+1996-03-17 15:08  millert
+
+       * testsudoers.c: now groks shost
+
+1996-03-17 15:01  millert
+
+       * options.h, OPTIONS, find_path.c: added NO_DOT_PATH
+
+1996-03-16 14:43  millert
+
+       * find_path.c: checkdot now works correctly
+
+1996-03-12 18:01  millert
+
+       * configure.in: can't have DCE and C2 passwords both...
+
+1996-03-11 14:05  millert
+
+       * parse.yacc, sudo.c, sudo.h, visudo.c: now uses shost even if not
+         FQDN
+
+1996-03-11 14:04  millert
+
+       * configure.in: now looks for skey in /usr/lib and doesn't require
+         libskey to be in /usr/local/lib just because skey.h is (for my
+         netbsd box :-)
+
+1996-03-11 02:00  millert
+
+       * aclocal.m4, config.h.in, pathnames.h.in: _SUDO_PATH_ ->
+         _CONFIG_PATH_
+
+1996-03-10 21:01  millert
+
+       * aclocal.m4, sudo.pod: /var/run/.odus -> /var/run/sudo
+
+1996-03-10 20:59  millert
+
+       * pathnames.h.in: now uses _SUDO_PATH_TIMEDIR
+
+1996-03-10 20:59  millert
+
+       * OPTIONS: udpated FQDN
+
+1996-03-10 20:58  millert
+
+       * config.h.in: added _SUDO_PATH_TIMEDIR
+
+1996-03-10 20:58  millert
+
+       * aclocal.m4, configure.in: added SUDO_TIMEDIR
+
+1996-03-10 20:58  millert
+
+       * sudo.pod: updated wrt /var/run/sudo
+
+1996-03-10 20:16  millert
+
+       * sudo.c, sudo.h: added support for shost if FQDN
+
+1996-03-10 20:14  millert
+
+       * parse.yacc, visudo.c: now uses shost if FQDN
+
+1996-03-10 20:12  millert
+
+       * check.c: Now use skeylookup() instead off skeychallenge()
+
+1996-02-27 20:41  millert
+
+       * logging.c: mail_argv should not contain ALERTMAIL as it includes
+         "-t"
+
+1996-02-22 17:06  millert
+
+       * INSTALL, Makefile.in, README, version.h, configure.in: ++version
+
+1996-02-22 16:27  millert
+
+       * compat.h: added more _PASSWD_LEN stuff -- now uses PASS_MAX too
+
+1996-02-22 16:27  millert
+
+       * tgetpass.c: now includes limits.h moved _PASSWD_LEN -> compat.h
+
+1996-02-05 19:20  millert
+
+       * README, INSTALL: ++version
+
+1996-02-05 19:20  millert
+
+       * Makefile.in: ++versoin
+
+1996-02-05 19:16  millert
+
+       * Makefile.in: fixed a typo
+
+1996-02-05 19:16  millert
+
+       * configure.in: ++version
+
+1996-02-05 18:53  millert
+
+       * RUNSON: updated
+
+1996-02-05 18:47  millert
+
+       * CHANGES: done for 1.4.1 (I hope)
+
+1996-02-05 18:45  millert
+
+       * sudoers.pod: added info on wildcards
+
+1996-02-05 18:39  millert
+
+       * sample.sudoers: added wildcard example
+
+1996-02-05 17:03  millert
+
+       * Makefile.in: now uses *.pod to build *.man and *.cat & *.html
+
+1996-02-05 17:03  millert
+
+       * configure.in: addedSUDO_PROG_BSHELL !ll
+
+1996-02-05 16:10  millert
+
+       * visudo.pod: fixed up some formatting
+
+1996-02-05 16:10  millert
+
+       * sudoers.pod: redid section describing sample sudoers stuff
+
+1996-02-05 16:10  millert
+
+       * sudo.pod: fixed some formatting
+
+1996-02-04 22:50  millert
+
+       * getspwuid.c: now treats "" as bourne shell
+
+1996-02-04 22:49  millert
+
+       * Makefile.in: TESTOBJS nwo includes wildmat.o
+
+1996-02-04 22:48  millert
+
+       * testsudoers.c: now works with NewArg[cv]
+
+1996-02-04 21:59  millert
+
+       * sudo.c: removed an XXX (fixed it in getspwuid.c)
+
+1996-02-04 21:58  millert
+
+       * aclocal.m4: added check for bourne shell
+
+1996-02-04 21:58  millert
+
+       * pathnames.h.in: added _PATH_BSHELL
+
+1996-02-04 21:58  millert
+
+       * config.h.in: added _SUDO_PATH_BSHELL
+
+1996-02-04 16:36  millert
+
+       * visudo.c: unixware vi returns 256 instead of 0
+
+1996-02-04 16:24  millert
+
+       * INSTALL: added Linux note
+
+1996-02-04 16:13  millert
+
+       * logging.c: fixed up some XXX's.  file log format now looks a
+         little more like real syslog(3) format.
+
+1996-02-04 16:13  millert
+
+       * README, TROUBLESHOOTING: updated wrt lex/flex
+
+1996-02-04 16:11  millert
+
+       * Makefile.in: commented out rule to build lex.yy.c from parse.lex
+         since we ship with a pre-flex'd parser
+
+1996-02-04 16:09  millert
+
+       * parse.c, parse.yacc, visudo.c: path_matches -> command_matches
+
+1996-02-04 02:28  millert
+
+       * logging.c: eliminated some strcat()'s
+
+1996-02-04 02:10  millert
+
+       * configure.in: no longer checks for lex/flex (now assumes flex)
+
+1996-02-04 02:08  millert
+
+       * configure.in: now checks for $kerb_dir_candidate/krb.h instead of
+         just kerb_dir_candidate
+
+1996-02-02 20:48  millert
+
+       * parse.yacc: now use a 'hook' expression instead of an iffy one
+         :-)
+
+1996-02-02 01:14  millert
+
+       * visudo.c: now works with new sudo arg stuff
+
+1996-02-02 01:14  millert
+
+       * parse.yacc: fixed dereferencing deadbeef
+
+1996-02-01 23:53  millert
+
+       * sudo.c: changed an occurrence of Argv to NewArgv
+
+1996-02-01 23:53  millert
+
+       * parse.lex: took out support for quoted commands since there is no
+         need...
+
+1996-02-01 23:52  millert
+
+       * parse.c: fixed a typo in a for() loop
+
+1996-02-01 23:52  millert
+
+       * logging.c: protected against dereferencing rogue pointers
+
+1996-02-01 22:34  millert
+
+       * sudo.c: now uses NewArgv amd NewArgc so cmnd_aegs is no longer
+         needed this also allows us to eliminate some kludges in
+         parse_args() and eliminate superfluous code.
+
+1996-02-01 22:34  millert
+
+       * logging.c: no longer uses cmnd_args, now uses NewArgv instead.
+
+1996-02-01 22:32  millert
+
+       * sudo.h: added struct sudo_command, NewArgc, and NewArgv removed
+         cmnd_args (no longer used)
+
+1996-02-01 22:31  millert
+
+       * Makefile.in: added wildmat.c to SRCS & SUDOBJS
+
+1996-02-01 22:30  millert
+
+       * parse.yacc: COMMAND is now a struct containing the path and args
+
+1996-02-01 22:30  millert
+
+       * parse.lex: replaced append() with fill_cmnd() and fill_args.
+         command args from a sudoers entry are now stored in an arrary for
+         easy matching.
+
+1996-02-01 22:28  millert
+
+       * parse.c: command line args from sudoers file are now in an array
+         like ones passed in from the command line
+
+1996-01-31 20:59  millert
+
+       * parse.c: wildwat stuff now works
+
+1996-01-29 00:44  millert
+
+       * version.h: ++version
+
+1996-01-29 00:44  millert
+
+       * Makefile.in: ++version added wildmat.*
+
+1996-01-28 17:55  millert
+
+       * parse.lex: added support for quoted commands (w/ or w/o args)
+
+1996-01-22 01:55  millert
+
+       * sudo.pod, visudo.pod: cleaned up formatting
+
+1996-01-21 20:53  millert
+
+       * sudo.pod, visudo.pod: Initial revision
+
+1996-01-21 02:07  millert
+
+       * sudoers.pod: looks reasonable, could be mroe readable
+
+1996-01-20 23:47  millert
+
+       * sudoers.pod: Initial revision
+
+1996-01-16 14:38  millert
+
+       * RUNSON: updated
+
+1996-01-16 14:37  millert
+
+       * OPTIONS: updated NO_ROOT_SUDO entry
+
+1996-01-15 11:37  millert
+
+       * RUNSON: [no log message]
+
+1996-01-15 11:34  millert
+
+       * sudo.c: fixed SECURE_PATH
+
+1996-01-14 20:55  millert
+
+       * RUNSON: udpa`ted for 1.4
+
+1996-01-14 20:52  millert
+
+       * configure.in: AIX aixcrypt.exp now uses $(srcdir)
+
+1996-01-14 20:32  millert
+
+       * TROUBLESHOOTING: added entry for anal ansi compilers
+
+1996-01-14 16:13  millert
+
+       * INSTALL: added info on libcrypt_i for SCO
+
+1996-01-14 16:05  millert
+
+       * TODO: [no log message]
+
+1996-01-14 15:39  millert
+
+       * sample.sudoers: added comments
+
+1996-01-14 15:25  millert
+
+       * TODO: 1.4 release
+
+1996-01-14 15:22  millert
+
+       * README, config.h.in, configure.in, CHANGES: ++version
+
+1996-01-14 15:21  millert
+
+       * BUGS: ++version and fixed ISC
+
+1996-01-14 15:19  millert
+
+       * check.c, compat.h, dce_pwent.c, find_path.c, getspwuid.c,
+         getwd.c, goodpath.c, ins_2001.h, ins_classic.h, ins_csops.h,
+         ins_goons.h, insults.h, options.h, pathnames.h.in, sudo.h,
+         logging.c, putenv.c, strdup.c, sudo.c, sudo_setenv.c,
+         testsudoers.c, tgetpass.c, utime.c, visudo.c, INSTALL, OPTIONS:
+         ++version
+
+1996-01-14 15:16  millert
+
+       * interfaces.c: added STUB_LOAD_INTERFACES ++version
+
+1996-01-14 15:14  millert
+
+       * Makefile.in, version.h, parse.c, parse.lex, parse.yacc,
+         emul/utime.h: ++version
+
+1996-01-14 15:13  millert
+
+       * PORTING: added info about fd_set in tgetpass added info on
+         interfaces.c
+
+1996-01-11 13:22  millert
+
+       * dce_pwent.c: added sudo header
+
+1996-01-11 13:04  millert
+
+       * tgetpass.c: fixed a typo
+
+1996-01-11 13:01  millert
+
+       * Makefile.in: tgetpass.o is now only linked in with sudo (not
+         visudo)
+
+1996-01-09 12:56  millert
+
+       * BUGS, INSTALL, OPTIONS, README, Makefile.in, config.h.in,
+         configure.in: ++version
+
+1996-01-09 12:54  millert
+
+       * emul/utime.h: added copyright notice
+
+1996-01-09 12:52  millert
+
+       * check.c, compat.h, find_path.c, getspwuid.c, getwd.c, goodpath.c,
+         ins_2001.h, ins_classic.h, ins_csops.h, ins_goons.h, insults.h,
+         interfaces.c, logging.c, options.h, parse.c, parse.lex,
+         parse.yacc, pathnames.h.in, putenv.c, strdup.c, sudo.c, sudo.h,
+         sudo_setenv.c, testsudoers.c, tgetpass.c, utime.c, version.h,
+         visudo.c: ++version
+
+1996-01-09 12:46  millert
+
+       * tgetpass.c: minor cleanup and now includes sys/bsdtypes for
+         svr4'ish boxen
+
+1996-01-09 12:42  millert
+
+       * configure.in: ISC now gets -lcrypt now check for sys/bsdtypes.h
+
+1996-01-09 12:41  millert
+
+       * config.h.in: added check for sys/bsdtypes.h
+
+1996-01-07 16:00  millert
+
+       * parse.yacc: removed debugging stuff (setting freed ptr to NULL)
+
+1996-01-07 15:55  millert
+
+       * TROUBLESHOOTING: added 2 entries
+
+1996-01-07 15:55  millert
+
+       * Makefile.in: added FAQ
+
+1996-01-07 14:26  millert
+
+       * TROUBLESHOOTING: added section on syslog
+
+1996-01-07 14:25  millert
+
+       * configure.in: added AC_ISC_POSIX for better ISC support
+
+1996-01-07 14:25  millert
+
+       * config.h.in: fixed typo
+
+1996-01-07 14:25  millert
+
+       * config.h.in: added define for _POSIX_SOURCE
+
+1996-01-04 00:41  millert
+
+       * configure.in: fixed check for lsearch()
+
+1995-12-21 21:53  millert
+
+       * interfaces.c: fixed for AIX now deal if num_interfaces == 0
+         (should not happen)
+
+1995-12-20 17:02  millert
+
+       * configure.in: now only define HAVE_LSEARCH if there is a
+         corresponding search.h
+
+1995-12-20 15:52  millert
+
+       * interfaces.c: works on ISC again
+
+1995-12-18 17:36  millert
+
+       * configure.in: now define HAVE_LSEARCH if we find lsearch() in
+         libcompat
+
+1995-12-18 17:32  millert
+
+       * lsearch.c: char * -> const char *
+
+1995-12-18 17:29  millert
+
+       * configure.in: now looks in -lcompat for lsearch()
+
+1995-12-18 17:23  millert
+
+       * Makefile.in: remove sudo.core visudo.core for clan target
+
+1995-12-17 22:53  millert
+
+       * aclocal.m4: added UID_MAX support in check for MAX_UID_T_LEN
+
+1995-12-17 22:36  millert
+
+       * Makefile.in: fixed another occurence of sudo_getpwuid.*
+
+1995-12-17 22:30  millert
+
+       * getspwuid.c, Makefile.in: sudo_getpwuid.c -> getspwuid.c
+
+1995-12-17 22:22  millert
+
+       * configure.in: moved the "echo"
+
+1995-12-17 22:09  millert
+
+       * CHANGES, BUGS, INSTALL, Makefile.in, OPTIONS, README, check.c,
+         compat.h, config.h.in, configure.in, find_path.c, getspwuid.c,
+         getwd.c, goodpath.c, ins_2001.h, ins_classic.h, ins_csops.h,
+         ins_goons.h, insults.h, interfaces.c, logging.c, options.h,
+         parse.c, parse.lex, parse.yacc, pathnames.h.in, putenv.c,
+         strdup.c, sudo.c, sudo.h, sudo_setenv.c, testsudoers.c,
+         tgetpass.c, utime.c, version.h, visudo.c: ++version
+
+1995-12-17 22:04  millert
+
+       * testsudoers.c: added group support
+
+1995-12-17 22:00  millert
+
+       * sample.sudoers: added group entry
+
+1995-12-17 21:59  millert
+
+       * sudoers.man: documented group support
+
+1995-12-17 21:50  millert
+
+       * parse.c, parse.lex, visudo.c, parse.yacc: added group support
+
+1995-12-15 17:45  millert
+
+       * check.c: tkfile was too short and overflowed the kerberos realm
+
+1995-12-11 17:09  millert
+
+       * sudo.c: now copy command args directly from Argv
+
+1995-12-11 15:55  millert
+
+       * sudo.c: replaced code to copy cmnd_args so that is does not use
+         realloc since most realloc()'s really stink
+
+1995-12-08 14:11  millert
+
+       * configure.in: syslog() fixed in hpux 10.01
+
+1995-12-06 17:45  millert
+
+       * configure.in: AC_CHECK_LIB() now sets SUDO_LIBS (and VISUDO_LIBS
+         if appropriate)
+
+1995-12-06 17:30  millert
+
+       * configure.in: better error if cannot find skey incs or libs
+
+1995-12-06 17:26  millert
+
+       * aclocal.m4: now use a temp file for determining max len of uid_t
+         in string form.  the old hacky way broke on netbsd
+
+1995-12-05 19:02  millert
+
+       * sudo.c: added set of parens and a space
+
+1995-12-05 18:58  millert
+
+       * dce_pwent.c: fixes from Jeff Earickson <jaearick@colby.edu> ,
+
+1995-12-05 18:58  millert
+
+       * check.c: modified a comment
+
+1995-12-05 18:57  millert
+
+       * Makefile.in: fixed up testsudoers target
+
+1995-12-05 18:56  millert
+
+       * configure.in: DCE changes from Jeff Earickson
+         <jaearick@colby.edu> LIBS -> SUDO_LIBS and VISUDO_LIBS LDFLAGS ->
+         SUDO_FDFLAGS and VISUDO_LDFLAGS
+
+1995-12-05 18:17  millert
+
+       * Makefile.in: LIBS -> SUDO_LIBS , VISUDO_LIBS LDFLAGS ->
+         SUDO_LDFLAGS, VISUDO_LDFLAGS
+
+1995-11-27 23:32  millert
+
+       * configure.in: fix for C2 on hpux 10 now uses -linet if it exists
+
+1995-11-27 23:17  millert
+
+       * check.c: LONG_SKEY_PROMPT is less of a klusge /
+
+1995-11-27 23:17  millert
+
+       * configure.in: fixed typos w/ dce stuff
+
+1995-11-27 23:14  millert
+
+       * Makefile.in: added dce_pwent.c
+
+1995-11-26 13:48  millert
+
+       * INSTALL: amended section on combining authentication mechanisms
+
+1995-11-26 13:48  millert
+
+       * PORTING: minor updates for 1.3.6
+
+1995-11-26 13:47  millert
+
+       * TROUBLESHOOTING: added 2 more entries
+
+1995-11-26 13:39  millert
+
+       * BUGS: updated for 1.3.6
+
+1995-11-26 13:39  millert
+
+       * README: overhauled
+
+1995-11-25 21:23  millert
+
+       * INSTALL: rewrote for sudo 1.3.6
+
+1995-11-25 21:23  millert
+
+       * TROUBLESHOOTING: added 3 entries
+
+1995-11-25 13:53  millert
+
+       * find_path.c, getspwuid.c, sudo.c: added explict casts for strdup
+         since many includes don't prototype it.  gag me.
+
+1995-11-25 13:23  millert
+
+       * sudo.h: removed prototype for sudo_getpwuid() since convex C
+         compiler choked on it.
+
+1995-11-25 13:23  millert
+
+       * sudo.c: added prototype for sudo_getpwuid()
+
+1995-11-25 13:23  millert
+
+       * lsearch.c: now compiles on strict ANSI compilers
+
+1995-11-24 23:56  millert
+
+       * check.c: added LONG_SKEY_PROMPT support
+
+1995-11-24 23:55  millert
+
+       * Makefile.in: added extra $'s for make to eat up, yum.
+
+1995-11-24 23:38  millert
+
+       * OPTIONS, options.h: added LONG_SKEY_PROMPT
+
+1995-11-24 18:48  millert
+
+       * check.c: s/key support now works with normal s/key as well as
+         logdaemon
+
+1995-11-24 18:46  millert
+
+       * options.h, OPTIONS: added SKEY_ONLY
+
+1995-11-24 18:46  millert
+
+       * compat.h: set _PASSWD_LEN to 256 for any of KERB4, DCE, SKEY
+
+1995-11-24 00:42  millert
+
+       * INSTALL: added DCE note added more AIX notes
+
+1995-11-24 00:39  millert
+
+       * sudo.c: now include pthread.h for DCE support
+
+1995-11-23 22:22  millert
+
+       * check.c: dce_pwent() is ok after all .,
+
+1995-11-23 22:21  millert
+
+       * logging.c: now uses SYSLOG() macro that equates to either
+         syslog() or syslog_wrapper
+
+1995-11-23 21:44  millert
+
+       * dce_pwent.c: minor formatting changes.  renamed check() to
+         somthing less generic
+
+1995-11-23 21:27  millert
+
+       * check.c, logging.c, parse.yacc, sudo.c, sudo.h, testsudoers.c,
+         visudo.c: now uses user_pw_ent and simple macros to get at the
+         contents
+
+1995-11-22 20:35  millert
+
+       * check.c: simpler dec unix C2 support
+
+1995-11-22 20:35  millert
+
+       * getspwuid.c: now sets crypt_type for DEC unix C2
+
+1995-11-21 18:00  millert
+
+       * configure.in: added csops paths for skey
+
+1995-11-21 16:27  millert
+
+       * getspwuid.c: now includes string.h for strdup() prototype
+
+1995-11-21 01:47  millert
+
+       * getspwuid.c: fixed a few typos
+
+1995-11-20 22:59  millert
+
+       * check.c: now includes skey.h
+
+1995-11-20 22:10  millert
+
+       * getspwuid.c: fixed up comments
+
+1995-11-20 22:04  millert
+
+       * check.c: moved a lot of the shadow passwd crap to sudo_getpwuid()
+
+1995-11-20 22:01  millert
+
+       * sudo.c: now uses sudo_pw_ent
+
+1995-11-20 21:50  millert
+
+       * testsudoers.c: now uses sudo_pw_ent
+
+1995-11-20 21:40  millert
+
+       * visudo.c: now sets sudo_pw_ent
+
+1995-11-20 21:28  millert
+
+       * getspwuid.c: Initial revision
+
+1995-11-20 21:28  millert
+
+       * tgetpass.c: moved dce stuff into compat.h
+
+1995-11-20 21:27  millert
+
+       * sudo.h, logging.c: now uses sudo_pw_ent
+
+1995-11-20 21:27  millert
+
+       * Makefile.in: added sudo_getpwuid.c
+
+1995-11-20 21:25  millert
+
+       * compat.h: added dce support
+
+1995-11-20 21:13  millert
+
+       * parse.yacc: now uses sudo_pw_ent
+
+1995-11-20 14:40  millert
+
+       * check.c: fixed exempt_group stuff for OS's that don't put base
+         gid in group vector
+
+1995-11-20 01:39  millert
+
+       * check.c: S/Key support now works with sunos4 shadow passwords
+
+1995-11-19 22:31  millert
+
+       * Makefile.in: fixed clean rule
+
+1995-11-19 22:31  millert
+
+       * config.h.in, configure.in: added DCE support
+
+1995-11-19 22:30  millert
+
+       * tgetpass.c: DCE & KERB support
+
+1995-11-19 22:30  millert
+
+       * check.c: first stab at dce support
+
+1995-11-19 22:24  millert
+
+       * dce_pwent.c: now smells like sudo
+
+1995-11-19 22:11  millert
+
+       * dce_pwent.c: Initial revision
+
+1995-11-19 21:36  millert
+
+       * check.c: skey'd sudo now works w/ normal password as well
+
+1995-11-19 18:37  millert
+
+       * Makefile.in, OPTIONS, check.c, compat.h, config.h.in,
+         find_path.c, getwd.c, goodpath.c, ins_2001.h, ins_classic.h,
+         ins_csops.h, ins_goons.h, insults.h, interfaces.c, logging.c,
+         options.h, parse.c, parse.lex, parse.yacc, pathnames.h.in,
+         putenv.c, strdup.c, sudo.c, sudo.h, sudo_setenv.c, testsudoers.c,
+         tgetpass.c, utime.c, version.h, visudo.c: updated version number
+
+1995-11-19 18:32  millert
+
+       * README: updated to reflect version change
+
+1995-11-19 18:27  millert
+
+       * configure.in: --with options now line up ++version
+
+1995-11-19 18:26  millert
+
+       * sudo.h: removed unecesary S/Key stuff
+
+1995-11-19 18:25  millert
+
+       * configure.in: fixed S/Key support
+
+1995-11-19 18:24  millert
+
+       * Makefile.in: -I stuff now goes in CPPFLAGS
+
+1995-11-19 18:23  millert
+
+       * check.c: fixed SKey support
+
+1995-11-19 15:23  millert
+
+       * README: updated version
+
+1995-11-19 13:59  millert
+
+       * OPTIONS: fixed description of EXEMPTGROUP
+
+1995-11-19 10:47  millert
+
+       * sudo.c: more people use _RLD_ than just alphas...
+
+1995-11-18 21:35  millert
+
+       * Makefile.in: replaced $man_prefix with $mandir
+
+1995-11-18 21:30  millert
+
+       * configure.in: fixed a typo
+
+1995-11-18 21:28  millert
+
+       * Makefile.in: now use more GNU'ish dir names
+
+1995-11-18 21:27  millert
+
+       * configure.in: now set *dir correctly (can override from command
+         line)
+
+1995-11-18 19:17  millert
+
+       * sudo.c: now deal with situations where we getwd() fails
+
+1995-11-17 00:37  millert
+
+       * Makefile.in: added etc_dir, bin_dir, sbin_dir
+
+1995-11-17 00:37  millert
+
+       * configure.in: added sbin_dir
+
+1995-11-16 21:28  millert
+
+       * Makefile.in: now ship a flex-generated lex.yy.c
+
+1995-11-16 21:09  millert
+
+       * Makefile.in: now sets _PATH_SUDO_SUDOERS, _PATH_SUDO_STMP,
+         SUDOERS_OWNER
+
+1995-11-16 21:06  millert
+
+       * pathnames.h.in: _PATH_SUDO_SUDOERS & _PATH_SUDO_STMP are now
+         overridden via Makefile
+
+1995-11-16 21:05  millert
+
+       * options.h: no more error for redefining SUDOERS_OWNER
+
+1995-11-16 21:05  millert
+
+       * OPTIONS: expanded SUDOERS_OWNER section
+
+1995-11-16 03:05  millert
+
+       * visudo.c: now warn if chown(2) failed
+
+1995-11-16 02:55  millert
+
+       * logging.c: better default warning for NO_SUDOERS_FILE
+
+1995-11-16 02:54  millert
+
+       * sudo.c: added missing set_perms() no more cryptic message if the
+         sudoers file is zero length, now just give a parse error
+
+1995-11-16 02:42  millert
+
+       * logging.c: better diagnostics if NO_SUDOERS_FILE
+
+1995-11-16 02:41  millert
+
+       * sudo.c: check_sudoers() now catches sudoers files that are not
+         readable (but are stat'able).
+
+1995-11-13 01:12  millert
+
+       * configure.in: now add -D__STDC__ for convex cc (not gcc)
+
+1995-11-13 00:52  millert
+
+       * configure.in: MAN_PREFIX -> man_prefix now sets prefix and
+         exec_prefix
+
+1995-11-13 00:52  millert
+
+       * Makefile.in: now uses exec_prefix & prefix from configure
+
+1995-11-13 00:16  millert
+
+       * find_path.c, getwd.c, goodpath.c, interfaces.c, logging.c,
+         parse.c, parse.lex, parse.yacc, sudo.c, sudo.h, sudo_setenv.c,
+         tgetpass.c, utime.c, visudo.c: options.h is now <> instead of ""
+         so shadow build trees can have a custom copy of options.h
+
+1995-11-13 00:15  millert
+
+       * check.c: user_is_exempt() is no longer a hack, it now uses
+         getgrnam()
+
+1995-11-12 23:56  millert
+
+       * options.h: EXEMPTGROUP is now "sudo"
+
+1995-11-12 22:25  millert
+
+       * configure.in: MAN_POSTINSTALL now contains a leading space
+
+1995-11-12 22:25  millert
+
+       * Makefile.in: removed leading tab if @MAN_POSTINSTALL@ not defined
+         now removes testsudoers in clean:
+
+1995-11-12 22:24  millert
+
+       * tgetpass.c: includes pwd.h to get _PASSWD_LEN definition
+
+1995-10-30 15:51  millert
+
+       * sudo.c: unset the KRB_CONF envariable if using kerberos so we
+         don't get spoofed into using a bogus server
+
+1995-09-29 17:50  millert
+
+       * parse.yacc: now explicately initialize match[] tp be FALSE
+
+1995-09-23 16:48  millert
+
+       * sudo.c: removed unused variable now passes -Wall
+
+1995-09-23 16:48  millert
+
+       * parse.yacc: yyerror and dumpaliases are now void's now passes
+         -Wall
+
+1995-09-23 16:48  millert
+
+       * parse.lex: added prototype for yyerror
+
+1995-09-23 16:47  millert
+
+       * interfaces.c: rmeoved unused cruft now passes -Wall
+
+1995-09-23 16:47  millert
+
+       * check.c, logging.c, parse.c: now passes -Wall
+
+1995-09-23 16:46  millert
+
+       * Makefile.in: fixed headers that moved to emul dir
+
+1995-09-23 12:05  millert
+
+       * logging.c: fixed deref of nil pointer if no args
+
+1995-09-15 19:18  millert
+
+       * OPTIONS: added a caveat to FQDN section
+
+1995-09-13 19:48  millert
+
+       * Makefile.in: more $srcdir support for install targets
+
+1995-09-13 17:17  millert
+
+       * find_path.c, interfaces.c, parse.c, parse.lex, parse.yacc,
+         putenv.c, strdup.c, sudo.c, sudo_setenv.c, testsudoers.c,
+         visudo.c: don't include malloc.h if we include stdlib.h
+
+1995-09-12 21:44  millert
+
+       * parse.yacc: local search.h now lives in emul
+
+1995-09-12 21:41  millert
+
+       * lsearch.c: local search.h now lives in emul
+
+1995-09-12 21:41  millert
+
+       * check.c, utime.c: local utime.h now lives in emul dir
+
+1995-09-12 21:38  millert
+
+       * Makefile.in: added support for building in other than the
+         sourcedir
+
+1995-09-10 14:01  millert
+
+       * OPTIONS: annotated CSOPS_INSULTS option
+
+1995-09-10 13:56  millert
+
+       * TROUBLESHOOTING: updated shadow passwords blurb
+
+1995-09-09 21:00  millert
+
+       * sudo.c: if SHELL_IF_NO_ARGS is set, "sudo -- foo" now runs a
+         shell and passes along foo as the arguments
+
+1995-09-09 18:52  millert
+
+       * parse.lex: collapsed pathname and dir sections into one -- its
+         now less expensive
+
+1995-09-09 18:34  millert
+
+       * parse.lex: fixed spacing quoting [,:\\=] now works correctly
+         append() and fill() now take args to make the above work
+
+1995-09-08 20:51  millert
+
+       * sudo.c: fixed a typo that caused commands with no tty on fd 0 but
+         a tty on fd 1 to erroneously have "none" as their tty
+
+1995-09-04 15:35  millert
+
+       * check.c: timestampfile is now a global static removed decl of
+         timestampfile in remove_timestamp since we can just use the
+         global one
+
+1995-09-04 15:28  millert
+
+       * check.c: created touch() to update timestamps added
+         USE_TTY_TICKETS support (bit of a kludge)
+
+1995-09-04 15:28  millert
+
+       * compat.h: added _S_IFDIR and S_ISDIR
+
+1995-09-04 15:22  millert
+
+       * OPTIONS, options.h: added USE_TTY_TICKETS
+
+1995-09-04 00:38  millert
+
+       * parse.yacc: removed const from casts for lsearch() & lfind() to
+         placate irix 4.x C compiler
+
+1995-09-03 14:12  millert
+
+       * sudo.c: now only strip '/dev/' off of a tty if it starts with
+         '/dev/'
+
+1995-09-03 14:12  millert
+
+       * pathnames.h.in: added _PATH_DEV
+
+1995-09-03 14:11  millert
+
+       * configure.in: AC_HAVE_HEADERS -> AC_CHECK_HEADERS now check for
+         tcgetattr only if have termios.h
+
+1995-09-03 14:09  millert
+
+       * tgetpass.c: fixed incorrect #ifdef termio uses "unsigned short"
+         not int for c_?flag
+
+1995-09-03 13:19  millert
+
+       * parse.lex, parse.yacc: fixed a spelling error
+
+1995-09-03 13:17  millert
+
+       * Makefile.in: fixed typo
+
+1995-09-02 12:55  millert
+
+       * Makefile.in: fixed a comment
+
+1995-09-02 12:54  millert
+
+       * parse.yacc: added dotcat() to cat 2 strings w/ a dot effeciently
+         now that we dynamically allocate strings they need to be free()'d
+
+1995-09-02 12:46  millert
+
+       * parse.lex: dynamically allocates space for strings
+
+1995-09-02 12:34  millert
+
+       * sudo.h: no more MAXCOMMANDLENGTH
+
+1995-09-01 22:25  millert
+
+       * sudo.h: added decl of tty
+
+1995-09-01 22:25  millert
+
+       * logging.c, sudo.c: moved tty stuff into sudo.c
+
+1995-09-01 14:18  millert
+
+       * parse.c: fixed a logic bug.  Was denying a command if user gave
+         command line args but there were none in the sudoers file which
+         is wrong.
+
+1995-09-01 01:18  millert
+
+       * sudo.h: MAXCOMMMANDLEN dropped down to 1K
+
+1995-09-01 01:13  millert
+
+       * parse.lex: return foo; -> return(foo);
+
+1995-09-01 01:03  millert
+
+       * parse.yacc: fixed netgr_matches() prototype
+
+1995-09-01 01:02  millert
+
+       * parse.lex: added support for escaping "termination" characters
+
+1995-09-01 00:55  millert
+
+       * parse.c: buf is now of size MAXPATHLEN+1 since it never holds
+         command args
+
+1995-09-01 00:50  millert
+
+       * sudo.c: fixed comments
+
+1995-09-01 00:49  millert
+
+       * goodpath.c: fixed negation problem (doh!)
+
+1995-09-01 00:25  millert
+
+       * parse.yacc: fixed 2nd parameter to lfind()
+
+1995-09-01 00:24  millert
+
+       * parse.lex: now do bounds checking in fill() and append()
+
+1995-09-01 00:23  millert
+
+       * sudo.c: include netdb.h as we should added a missing void cast
+         added SHELL_IF_NO_ARGS support now use realloc() properly.  would
+         fail if realloc actually moved the string instead of shrinking it
+
+1995-09-01 00:17  millert
+
+       * sample.sudoers: updated with examples of new features
+
+1995-09-01 00:05  millert
+
+       * goodpath.c: now set errno to EACCES if not a regular file or not
+         executable
+
+1995-09-01 00:04  millert
+
+       * find_path.c: if given a fully-qualified or relative path we now
+         check it with sudo_goodpath() and error out with the appropriate
+         error message if the file does not exist or is not executable
+
+1995-09-01 00:03  millert
+
+       * lsearch.c, emul/search.h: now use correct args for lfind
+
+1995-09-01 00:03  millert
+
+       * logging.c: added a comment
+
+1995-08-31 23:52  millert
+
+       * insults.h: added in CSOps insults
+
+1995-08-31 23:51  millert
+
+       * ins_csops.h: Initial revision
+
+1995-08-31 23:35  millert
+
+       * tgetpass.c: added RCS id
+
+1995-08-31 22:56  millert
+
+       * sudo.h: increased MAXCOMMANDLENGTH to 8k HAVE_GETCWD ->
+         HAVE_GETWD
+
+1995-08-31 22:55  millert
+
+       * OPTIONS: added CLASSIC_INSULTS, CSOPS_INSULTS, SHELL_IF_NO_ARGS
+
+1995-08-31 22:54  millert
+
+       * sudo.c: fixed -k load_interfaces() now gets called if FQDN is set
+         -p now works with -s
+
+1995-08-31 22:54  millert
+
+       * parse.c: don't try to stat() "pseudo commands" like "validate"
+
+1995-08-31 22:53  millert
+
+       * options.h: added CLASSIC_INSULTS added CSOPS_INSULTS added
+         SHELL_IF_NO_ARGS
+
+1995-08-31 22:53  millert
+
+       * configure.in: added SecurID support added other insults to
+         --with-csops
+
+1995-08-31 22:52  millert
+
+       * config.h.in: added HAVE_SECURID
+
+1995-08-31 22:52  millert
+
+       * Makefile.in: added clobber target added ins_csops.h now gets
+         CFLAGS from configure
+
+1995-08-31 22:46  millert
+
+       * aclocal.m4: relaxed SUDO_FULL_VOID
+
+1995-08-31 22:44  millert
+
+       * visudo.c: function comment blocks are now in same style as rest
+         of code
+
+1995-08-31 22:44  millert
+
+       * testsudoers.c: added support for command line args in
+         /etc/sudoers
+
+1995-08-31 22:43  millert
+
+       * sudoers.man: updated to have command args in the sudoers file
+
+1995-08-31 22:42  millert
+
+       * sudo.man: added -s and -- flags added SHELL to ENVIRONMENT
+         VARIABLES section
+
+1995-08-19 19:32  millert
+
+       * parse.yacc: PATH renamed to COMMAND
+
+1995-08-19 19:31  millert
+
+       * parse.lex: it is now a parse error for directories to have args
+         attached to them
+
+1995-08-19 19:30  millert
+
+       * logging.c: now say command args if telling user to buzz off
+
+1995-08-19 19:30  millert
+
+       * sudo.c: -s no longer indicates end of args sped up loading on
+         cmnd_args in load_cmnd()
+
+1995-08-19 19:29  millert
+
+       * parse.c: removed an unreachable statement
+
+1995-08-19 17:53  millert
+
+       * parse.lex: made more efficient by pulling out the terminators
+         when in GOTCMND state and making them their own rule
+
+1995-08-14 00:07  millert
+
+       * sudo.h: removed MAXLOGLEN since it is no longer used
+
+1995-08-14 00:07  millert
+
+       * parse.lex: now allows command args
+
+1995-08-14 00:06  millert
+
+       * parse.c: now groks command arguments
+
+1995-08-13 23:39  millert
+
+       * logging.c: now sets tty correctly when piped input
+
+1995-08-13 23:35  millert
+
+       * sudo.c: fixed loading of cmnd_args (was including command name
+         too)
+
+1995-08-13 23:34  millert
+
+       * logging.c: fixed a core dump due to incorrect if construct
+
+1995-08-13 00:33  millert
+
+       * configure.in: only add -lsun is irix < 5 don't look for -lnsl or
+         -lsocket if irix
+
+1995-08-13 00:33  millert
+
+       * aclocal.m4: fixed check for ISC
+
+1995-08-13 00:32  millert
+
+       * sudo.c: now sets cmnd_args used by log_error() and that will be
+         used by the parse to check against command args
+
+1995-08-13 00:32  millert
+
+       * sudo.h: added cmnd_args
+
+1995-08-13 00:31  millert
+
+       * logging.c: now dynamically allocate logline since we can guess at
+         its size
+
+1995-08-05 13:52  millert
+
+       * logging.c: cleaned up a bunch of unnecesary #ifdef's eliminated a
+         buffer remove "register" since the compiler knows more than I do
+         now do a "basename" of the tty
+
+1995-07-31 18:20  millert
+
+       * configure.in: ++version
+
+1995-07-30 22:37  millert
+
+       * sudo.h: added shell extern changed MODE_* to be bit masks to
+         allow for several options together
+
+1995-07-30 22:36  millert
+
+       * sudo.c: added -s (shell) option made MODE_* masks so we can do
+         bitwise & and | to see if multiple flags are set.
+
+1995-07-30 22:01  millert
+
+       * check.c: added securid support
+
+1995-07-30 14:38  millert
+
+       * logging.c: removed a bunch of unnecesary strncpy()'s and replaced
+         with strcat()
+
+1995-07-29 17:17  millert
+
+       * Makefile.in, version.h: ++version
+
+1995-07-27 06:52  millert
+
+       * parse.yacc: fixed free() of an uninitialized pointer (yuck)
+
+1995-07-26 22:00  millert
+
+       * testsudoers.c: added netgr_matches
+
+1995-07-26 21:29  millert
+
+       * parse.c: cleaned up netgr_matches
+
+1995-07-26 00:26  millert
+
+       * RUNSON: updated for 1.3.4
+
+1995-07-24 21:51  millert
+
+       * Makefile.in: now installs sudoers.man -- really should clean this
+         up though.
+
+1995-07-24 21:18  millert
+
+       * Makefile.in: added sudoers.cat and sudoers.man
+
+1995-07-24 21:15  millert
+
+       * sudo.man: pulled out stuff on the sudoers file format into a
+         separate man page
+
+1995-07-24 21:14  millert
+
+       * sudoers.man: Initial revision
+
+1995-07-24 21:04  millert
+
+       * HISTORY: fixed up my email address
+
+1995-07-24 20:03  millert
+
+       * configure.in: added checks for innetgr and getdomainname
+
+1995-07-24 20:02  millert
+
+       * visudo.c: added dummy netgr_matches function
+
+1995-07-24 20:01  millert
+
+       * parse.c: added  netgr_matches
+
+1995-07-24 20:01  millert
+
+       * parse.lex, parse.yacc: added NETGROUP support
+
+1995-07-24 20:01  millert
+
+       * config.h.in: added HAVE_INNETGR & HAVE_GETDOMAINNAME
+
+1995-07-24 18:07  millert
+
+       * sudo.c: rewrote clean_env() that has rm_env() builtin
+
+1995-07-23 19:58  millert
+
+       * check.c: now cast uid to long in sprintf
+
+1995-07-23 19:58  millert
+
+       * OPTIONS: added _INSULTS suffix to HAL & GOONS end
+
+1995-07-23 19:57  millert
+
+       * options.h: added _INSULTS suffix to HAL & GOONS
+
+1995-07-23 19:35  millert
+
+       * ins_2001.h, ins_classic.h, ins_goons.h, insults.h: converted to
+         new scheme of insult "unions" end
+
+1995-07-23 17:48  millert
+
+       * sudo.c: now uses MAX_UID_T_LEN
+
+1995-07-23 17:48  millert
+
+       * configure.in: added SUDO_UID_T_LEN !l
+
+1995-07-23 17:48  millert
+
+       * config.h.in: added MAX_UID_T_LEN
+
+1995-07-23 17:47  millert
+
+       * check.c: now use MAX_UID_T_LEN
+
+1995-07-23 17:47  millert
+
+       * aclocal.m4: added check for max len of uid_t fixed sco vs. isc
+         check
+
+1995-07-19 19:05  millert
+
+       * configure.in: corrected version
+
+1995-07-19 17:29  millert
+
+       * configure.in: added sco support
+
+1995-07-19 17:29  millert
+
+       * aclocal.m4: hack to check for sco
+
+1995-07-18 21:27  millert
+
+       * interfaces.c: removed  #include <net/route.h> since it was hosing
+         some OS's
+
+1995-07-18 13:35  millert
+
+       * find_path.c: fixed prreadlink() prototype
+
+1995-07-17 23:54  millert
+
+       * check.c: added parens in #if's
+
+1995-07-17 23:53  millert
+
+       * configure.in: added SPW_ prefix
+
+1995-07-17 23:20  millert
+
+       * sudo.h: moved SPW_* to config.h.in
+
+1995-07-17 23:19  millert
+
+       * sudo.c: added a set of parens
+
+1995-07-17 23:19  millert
+
+       * config.h.in: added SPW_*
+
+1995-07-17 22:50  millert
+
+       * sudo.h: added SPW_* reordered error codes
+
+1995-07-17 22:49  millert
+
+       * check.c: moved SPW_* to sudo.h
+
+1995-07-17 14:29  millert
+
+       * logging.c: GLOBAL_NO_AUTH_ENT -> GLOBAL_NO_SPW_ENT
+
+1995-07-17 14:29  millert
+
+       * configure.in: AUTH -> SECUREWARE
+
+1995-07-17 14:29  millert
+
+       * check.c, sudo.c: SPW_AUTH -> SPW_SECUREWARE
+
+1995-07-17 00:22  millert
+
+       * check.c: now uses SHADOW_TYPE to make shadow pw support more
+         readable and modular.  It's a start...
+
+1995-07-17 00:21  millert
+
+       * configure.in: added autodetection of shadow passwords
+
+1995-07-17 00:20  millert
+
+       * sudo.c: now uses SHADOW_TYPE define
+
+1995-07-17 00:19  millert
+
+       * config.h.in: added SHADOW_TYPE which replaces SUNOS4 & __svr4__
+         defines
+
+1995-07-17 00:19  millert
+
+       * aclocal.m4: added SUDO_CHECK_SHADOW
+
+1995-07-12 17:09  millert
+
+       * configure.in: define SVR4 for ISC define BROKEN_SYSLOG for hpux
+         took out test for memmove() since we dno longer use it...
+
+1995-07-12 17:08  millert
+
+       * CHANGES: updated
+
+1995-07-12 17:05  millert
+
+       * logging.c: added BROKEN_SYSLOG support
+
+1995-07-12 17:05  millert
+
+       * config.h.in: added BROKEN_SYSLOG
+
+1995-07-12 17:04  millert
+
+       * check.c: now only bitch it timestamp > time_now + 2 * timeout to
+         allow for a machine udpating its time from a server
+
+1995-07-12 17:04  millert
+
+       * sudo.man: added 2 security notes updated Nieusma's email addr
+
+1995-07-12 14:18  millert
+
+       * lsearch.c: changed a memmove() to memcpy() since we don't have to
+         worry about overlapping segments.
+
+1995-07-11 15:41  millert
+
+       * interfaces.c: cleanup up the loop when interfaces are groped in
+         so that it is readable
+
+1995-07-11 14:52  millert
+
+       * Makefile.in, version.h: ++version
+
+1995-07-09 18:17  millert
+
+       * CHANGES: annotated 124-126
+
+1995-07-07 16:06  millert
+
+       * check.c: fixed permissions check on /tmp/.odus
+
+1995-07-06 19:35  millert
+
+       * check.c: fixed some comments
+
+1995-07-06 14:49  millert
+
+       * check.c: now checks owner & mode of timedir also checks for bogus
+         dates on timestamp file
+
+1995-07-06 14:49  millert
+
+       * OPTIONS: updated TIMEOUT info
+
+1995-07-06 14:48  millert
+
+       * logging.c, sudo.h: added BAD_STAMPDIR and BAD_STAMPFILE
+
+1995-07-06 14:47  millert
+
+       * compat.h: added definition of S_IRWXU
+
+1995-07-06 14:47  millert
+
+       * CHANGES: updated
+
+1995-07-03 14:16  millert
+
+       * interfaces.c: added #ifdef to make it compile on strange arches
+
+1995-07-02 18:13  millert
+
+       * aclocal.m4: fixed check for fulkl void impl.
+
+1995-07-02 09:56  millert
+
+       * check.c: added mssing "static"
+
+1995-07-01 20:41  millert
+
+       * insults.h: replaced #elif with #else #if constructs for ancient C
+         compilers
+
+1995-07-01 20:18  millert
+
+       * INSTALL: updated irix c2 & kerb5 info
+
+1995-07-01 20:15  millert
+
+       * configure.in: added shadow pw support for irix
+
+1995-07-01 16:07  millert
+
+       * CHANGES: last changes for sudo 1.3.3
+
+1995-07-01 16:07  millert
+
+       * TODO, BUGS: updated
+
+1995-07-01 16:04  millert
+
+       * configure.in: now calls SUDO_SOCK_SA_LEN
+
+1995-07-01 16:04  millert
+
+       * config.h.in: added HAVE_SA_LEN
+
+1995-07-01 16:04  millert
+
+       * aclocal.m4: added SUDO_SOCK_SA_LEN
+
+1995-07-01 15:49  millert
+
+       * interfaces.c: now works with ip implementations that use sa_len
+         in sockaddr
+
+1995-07-01 14:26  millert
+
+       * INSTALL: added note about buggy AIX compiler
+
+1995-07-01 14:24  millert
+
+       * interfaces.c: now include sys/time.h for AIX
+
+1995-06-27 22:35  millert
+
+       * Makefile.in: getcwd -> getwd
+
+1995-06-27 21:28  millert
+
+       * interfaces.c: now works for ISC and others.  yay.
+
+1995-06-26 14:24  millert
+
+       * Makefile.in, version.h: version++
+
+1995-06-22 20:26  millert
+
+       * aclocal.m4: fixed test for full void impl
+
+1995-06-22 20:25  millert
+
+       * sudo.c: now check to see that st_dev is non-zero before assuming
+         that we are being spoofed
+
+1995-06-20 16:56  millert
+
+       * aclocal.m4, configure.in: SUDO_FUNC_UTIME_NULL ->
+         AC_FUNC_UTIME_NULL
+
+1995-06-19 16:32  millert
+
+       * aclocal.m4: fixed include file order for SUDO_FUNC_UTIME_POSIX
+
+1995-06-19 16:10  millert
+
+       * logging.c: added cast for ttyname()
+
+1995-06-19 15:23  millert
+
+       * configure.in: fixed typo
+
+1995-06-19 15:19  millert
+
+       * check.c: now deal correctly with all known variation of utime()
+         -- yippe
+
+1995-06-19 15:19  millert
+
+       * configure.in: added SUDO_FUNC_UTIME_POSIX
+
+1995-06-19 15:19  millert
+
+       * aclocal.m4: added SUDO_FUNC_UTIME_NULL and SUDO_FUNC_UTIME_POSIX
+
+1995-06-19 15:14  millert
+
+       * config.h.in: added HAVE_UTIME_POSIX
+
+1995-06-19 13:38  millert
+
+       * check.c: fixed a typo
+
+1995-06-19 13:29  millert
+
+       * check.c: no longer assume !HAVE_UTIME_NULL means old BSD utime()
+
+1995-06-19 13:20  millert
+
+       * check.c: fixed fascist C compiler warning
+
+1995-06-18 23:14  millert
+
+       * interfaces.c: now set strioctl.ic_timout in STRSET() now
+         initialize num_interfaces to 0 (just to be anal)
+
+1995-06-18 18:06  millert
+
+       * sudo.h: increaed MAXLOGLEN by MAXPATHLEN to account for ttyname
+
+1995-06-18 18:05  millert
+
+       * logging.c: added tty logging
+
+1995-06-18 16:04  millert
+
+       * interfaces.c: reworked the ISC code
+
+1995-06-18 15:27  millert
+
+       * Makefile.in, version.h: updated version
+
+1995-06-18 15:24  millert
+
+       * check.c: now expect old-style utime(3) if utime() can't take NULL
+         as an arg
+
+1995-06-18 15:08  millert
+
+       * configure.in: added check for utime.h
+
+1995-06-18 15:08  millert
+
+       * config.h.in: added HAVE_UTIME_H
+
+1995-06-18 14:48  millert
+
+       * Makefile.in: added CPPFLAGS STATIC_FLAGS -> LDFLAGS
+
+1995-06-18 13:58  millert
+
+       * configure.in: now search for kerb libs and includes
+
+1995-06-18 13:03  millert
+
+       * check.c: added support for utime(2)'s that can't take a NULL
+         parameter
+
+1995-06-18 13:03  millert
+
+       * utime.c: moved HAVE_UTIME_NULL stuff to update_timestamp() where
+         t belongs
+
+1995-06-17 20:46  millert
+
+       * configure.in: added utime(s) stuff
+
+1995-06-17 20:46  millert
+
+       * check.c: now use utime()
+
+1995-06-17 20:46  millert
+
+       * config.h.in: added HAVE_UTIME and HAVE_UTIME_NULL
+
+1995-06-17 19:12  millert
+
+       * utime.c: now use HAVE_UTIME_NULL
+
+1995-06-17 19:02  millert
+
+       * utime.c, emul/utime.h: Initial revision
+
+1995-06-17 18:24  millert
+
+       * check.c: need to setuid(0) to make kerb4 stuff work.
+
+1995-06-17 18:14  millert
+
+       * tgetpass.c: no more special case for kerberos
+
+1995-06-17 18:13  millert
+
+       * config.h.in: took out setreuid and setresuid stuff added kerb5
+         stuff (use kerb4 emulation)
+
+1995-06-17 18:13  millert
+
+       * compat.h: no longer need setreuid() emulation now set _PASSWD_LEN
+         to 128 if kerberos
+
+1995-06-17 18:12  millert
+
+       * check.c: now use private ticket file for kerberos support to
+         avoid trouncing on system one
+
+1995-06-15 00:48  millert
+
+       * sudo.h: added SPOOF_ATTEMPT & cmnd_st
+
+1995-06-15 00:47  millert
+
+       * sudo.c: added anti-spoofing support
+
+1995-06-15 00:47  millert
+
+       * parse.c: now use global cmnd_st
+
+1995-06-15 00:47  millert
+
+       * logging.c: added SPOOF_ATTEMPT suypport
+
+1995-06-14 23:41  millert
+
+       * testsudoers.c, visudo.c: added void casts where appropriate
+
+1995-06-14 23:40  millert
+
+       * parse.yacc: fixed up spacing and added void casts where
+         appropriate
+
+1995-06-14 23:27  millert
+
+       * sudo.c: fixed problem with "-p prompt" but no args
+
+1995-06-14 04:43  millert
+
+       * sudo.man: added BUGS and annotated -l description
+
+1995-06-14 04:43  millert
+
+       * sudo.h: validate() now takes a flag
+
+1995-06-14 04:43  millert
+
+       * sudo.c: validate() now takes a flag added -l
+
+1995-06-14 04:42  millert
+
+       * parse.yacc: added support for -l
+
+1995-06-14 04:41  millert
+
+       * parse.c: validate() now takes a flag that says whether or not to
+         check the command
+
+1995-06-07 21:36  millert
+
+       * logging.c: now deals with Argv == 1
+
+1995-06-07 21:34  millert
+
+       * sudo.man: added -p option
+
+1995-06-07 21:27  millert
+
+       * sudo.c: added prompt support reworked parse_args()
+
+1995-06-07 20:49  millert
+
+       * sudo.h: added prompt
+
+1995-06-07 20:49  millert
+
+       * options.h: added PASSPROMPT
+
+1995-06-07 20:48  millert
+
+       * check.c: now use BUFSIZ as length of kerb password added kpass so
+         pass is always a char * now use prompt global when asking for a
+         password
+
+1995-06-07 20:47  millert
+
+       * tgetpass.c: now use BUFSIZ as _PASSWD_LEN if using kerberos
+
+1995-06-07 20:43  millert
+
+       * OPTIONS: added PASSPROMPT
+
+1995-06-07 01:44  millert
+
+       * configure.in: only look for -lufc or -lcrypt if crypt() not in
+         libc
+
+1995-06-07 01:43  millert
+
+       * check.c: don't exit on kerb error, just warn if k_errno ==
+         KDC_PR_UNKNOWN (unknown user) silently fail
+
+1995-06-06 22:44  millert
+
+       * INSTALL: added kerb4 note
+
+1995-06-06 22:43  millert
+
+       * tgetpass.c: HAVE_KERBEROS -> HAVE_KERB4
+
+1995-06-06 22:41  millert
+
+       * check.c: removed debugging printf
+
+1995-06-06 22:33  millert
+
+       * configure.in: KERBEROS -> KERB4 added checks for setreuid &
+         setresuid
+
+1995-06-06 22:32  millert
+
+       * config.h.in: HAVE_KERBEROS -> HAVE_KERB4 added HAVE_SETREUID and
+         HAVE_SETRESUID
+
+1995-06-06 22:32  millert
+
+       * compat.h: added deif of UID_NO_CHANGE & GID_NO_CHANGE added
+         setreuid emulation with setresuid if applic
+
+1995-06-06 22:31  millert
+
+       * check.c: HAVE_KERBEROS -> HAVE_KERB4 now only do the stupid
+         chown() hack if no setreuid() or a broken one
+
+1995-06-05 23:44  millert
+
+       * config.h.in: added HAVE_KERBEROS
+
+1995-06-05 23:43  millert
+
+       * tgetpass.c: added KERBEROS support (long passwords)
+
+1995-06-05 23:42  millert
+
+       * check.c, configure.in: added kerberos support
+
+1995-06-03 19:36  millert
+
+       * sudo.h: added MODE_BACKGROUND
+
+1995-06-03 19:36  millert
+
+       * sudo.man: escaped dashes added -b option
+
+1995-06-03 19:34  millert
+
+       * sudo.c: added -b option
+
+1995-06-03 18:52  millert
+
+       * check.c: added crypt() for osf/1 3.x enhanced secuiry
+
+1995-06-03 18:18  millert
+
+       * configure.in: now check for -lcrypt
+
+1995-06-03 18:00  millert
+
+       * interfaces.c: added ENXIO like EADDRNOTAVAIL
+
+1995-05-07 23:14  millert
+
+       * configure.in: now emulate getwd(), not getcwd()
+
+1995-05-07 23:13  millert
+
+       * sudo.c: getcwd() -> getwd()
+
+1995-05-07 23:12  millert
+
+       * getwd.c: getcwd -> getwd
+
+1995-05-02 01:34  millert
+
+       * ins_2001.h, ins_classic.h, ins_goons.h: Initial revision
+
+1995-05-02 01:34  millert
+
+       * insults.h: broke out insults into separate include files
+
+1995-05-02 01:32  millert
+
+       * options.h, OPTIONS: added GOONS
+
+1995-05-02 01:32  millert
+
+       * Makefile.in: added ins_2001.h ins_classic.h ins_goons.h
+
+1995-05-01 23:34  millert
+
+       * Makefile.in, version.h: ++version
+
+1995-05-01 23:34  millert
+
+       * visudo.c: moved signal handler setup to setup_signals()
+
+1995-05-01 23:33  millert
+
+       * sudo.h: added load_interfaces()
+
+1995-05-01 23:33  millert
+
+       * sudo.c: moved load_interfaces to interfaces.c
+
+1995-05-01 23:33  millert
+
+       * parse.yacc: added clearaliases
+
+1995-05-01 23:33  millert
+
+       * OPTIONS, options.h: added FAST_MATCH
+
+1995-05-01 23:32  millert
+
+       * parse.lex: now uses clearaliases variable
+
+1995-05-01 23:31  millert
+
+       * interfaces.c: Initial revision
+
+1995-05-01 23:31  millert
+
+       * Makefile.in: added interfaces.[co]
+
+1995-05-01 23:30  millert
+
+       * testsudoers.c: now uses ip addrs and netmasks via
+         load_interfaces()
+
+1995-05-01 22:47  millert
+
+       * sudo.c: now remove IFS instead of setting to "sane" value
+
+1995-05-01 16:30  millert
+
+       * parse.c: added FAST_MATCH
+
+1995-04-29 20:19  millert
+
+       * Makefile.in: sudo_goodpath.c-> goodpath.c
+
+1995-04-29 20:15  millert
+
+       * sudo.c: added Andy's new ISC changes
+
+1995-04-14 14:06  millert
+
+       * OPTIONS: added a sentence to SECURE_PATH info
+
+1995-04-14 13:57  millert
+
+       * BUGS: added one
+
+1995-04-14 13:54  millert
+
+       * RUNSON, CHANGES: updated
+
+1995-04-13 17:04  millert
+
+       * RUNSON: updated for beta3
+
+1995-04-13 14:32  millert
+
+       * Makefile.in, version.h: ++version
+
+1995-04-13 13:56  millert
+
+       * aclocal.m4: sendmail is now looked for in \17/usr/ucblib
+
+1995-04-13 13:54  millert
+
+       * sudo.c: fixed indentation
+
+1995-04-13 13:35  millert
+
+       * aclocal.m4: fixed a typo
+
+1995-04-13 13:19  millert
+
+       * sudo.c: updated ISC mods
+
+1995-04-13 13:19  millert
+
+       * configure.in: added unixware case
+
+1995-04-13 13:19  millert
+
+       * check.c: user_is_exempt is no longer hidden
+
+1995-04-13 13:19  millert
+
+       * RUNSON: updated
+
+1995-04-13 13:19  millert
+
+       * aclocal.m4: isc and riscos changes
+
+1995-04-13 13:18  millert
+
+       * OPTIONS: added NOTE about new interaction of EXEMPTGROUP and
+         SECURE_PATH
+
+1995-04-13 13:18  millert
+
+       * Makefile.in: fixed a typo and added testsudoers stuff
+
+1995-04-13 12:34  millert
+
+       * testsudoers.c: Initial revision
+
+1995-04-12 19:31  millert
+
+       * parse.yacc: applied fixed patch from Chris
+
+1995-04-11 14:30  millert
+
+       * Makefile.in: fixed a typo
+
+1995-04-11 14:14  millert
+
+       * parse.yacc: added a set of braces for bison
+
+1995-04-11 14:01  millert
+
+       * parse.yacc: merged in Chris' changes to dekludge the parser.
+
+1995-04-11 00:38  millert
+
+       * logging.c: send_mail() was calling find_path() which is wrong
+         since find_path() stores cmnd in a static var.  Anyhow, it
+         doesn't make much sense since MAILER should always be fully
+         qualified
+
+1995-04-10 19:51  millert
+
+       * sample.sudoers: added User_Alias stuff
+
+1995-04-10 19:50  millert
+
+       * aclocal.m4: SUDO_NEXT now looks for
+         /usr/lib/NextStep/software_version
+
+1995-04-10 19:50  millert
+
+       * RUNSON: added DEC UNIX 3.0 w/ gcc
+
+1995-04-10 19:49  millert
+
+       * visudo.c: Exit was being used in places where exit should be used
+
+1995-04-10 19:44  millert
+
+       * sudoers: added "User alias specification"
+
+1995-04-10 18:04  millert
+
+       * parse.yacc: fixed probs caused by making nslots and naliases a
+         size_t
+
+1995-04-10 15:09  millert
+
+       * RUNSON: added KSR, upped rev to 1.3.1b2
+
+1995-04-10 15:07  millert
+
+       * logging.c, parse.yacc: 1024 -> BUFSIZ
+
+1995-04-10 15:05  millert
+
+       * parse.yacc: void * -> VOID * naliases and nslots are now size_t
+         to appease lsearch on 64-bit machines
+
+1995-04-09 19:30  millert
+
+       * TODO: did a bunch of things and added a bunch :-)
+
+1995-04-09 19:30  millert
+
+       * PORTING: updated
+
+1995-04-09 19:24  millert
+
+       * visudo.man: closer to BSD manpage style
+
+1995-04-09 19:15  millert
+
+       * sudo.man: closer to standard BSD man format
+
+1995-04-09 18:58  millert
+
+       * compat.h, config.h.in, insults.h, options.h, pathnames.h.in,
+         sudo.h, version.h, emul/search.h: added RCS id
+
+1995-04-09 17:35  millert
+
+       * sudo.h: removed crufty #defines that are no longer used
+
+1995-04-09 17:13  millert
+
+       * BUGS: fixed a bug
+
+1995-04-09 17:12  millert
+
+       * sudo.man: updated based on sudo changes
+
+1995-04-09 17:11  millert
+
+       * parse.yacc: now allow ALL keyword in User_Aliases now allow ALL
+         keyword as well as a NAME or ALIAS
+
+1995-04-09 17:11  millert
+
+       * CHANGES: updated
+
+1995-04-09 17:04  millert
+
+       * sudo.c: now sets SUDO_COMMAND and SUDO_GID envariables.
+
+1995-04-09 15:24  millert
+
+       * aclocal.m4: fixed bug with full void impl check
+
+1995-04-08 23:11  millert
+
+       * parse.yacc: fixed User_Alias supoprt
+
+1995-04-08 22:27  millert
+
+       * parse.yacc: added stubs for User_Alias support
+
+1995-04-08 22:27  millert
+
+       * sudo.c: now sets removes # bogus interfaces from num_interfaces
+
+1995-04-08 22:26  millert
+
+       * parse.lex: added User_Alias support
+
+1995-04-07 21:10  millert
+
+       * Makefile.in: removed extraneous TODO
+
+1995-04-07 19:48  millert
+
+       * visudo.c: ntwk_matches -> addr_matches
+
+1995-04-07 15:38  millert
+
+       * parse.yacc: ntwk_matches -> addr_matches
+
+1995-04-07 15:37  millert
+
+       * parse.c: ntwk_matches -> addr_matches now use inet_addr() not
+         inet_network() (which expects octet boundaries) fixes for OSF
+         (sizeof(int) != sizeof(long))
+
+1995-04-07 15:08  millert
+
+       * sudo.c: took out debugging info
+
+1995-04-06 23:45  millert
+
+       * aclocal.m4: OS was being set to unknown before non-uname based
+         host checks.  This caused no checks to happen since $OS was not
+         zero-length.
+
+1995-04-06 23:30  millert
+
+       * sudo.c: fixed loading of interfaces struct still has debugging
+         info in though
+
+1995-04-06 22:23  millert
+
+       * parse.c: fixed typo
+
+1995-04-06 16:17  millert
+
+       * Makefile.in: ++version
+
+1995-04-06 16:16  millert
+
+       * version.h: ++
+
+1995-04-06 16:16  millert
+
+       * visudo.c: removed extraneous extern decl of "top
+
+1995-04-06 16:14  millert
+
+       * visudo.c: now zeros "top"
+
+1995-04-06 16:13  millert
+
+       * parse.yacc: removed parser_cleanup (no need for it now)
+
+1995-04-06 16:13  millert
+
+       * parse.lex: now calls reset_aliases() directly
+
+1995-04-04 18:21  millert
+
+       * OPTIONS: added a sentence to SECURE_PATH description
+
+1995-04-04 18:17  millert
+
+       * parse.c: fixed my stupid bug where I used NAMLEN on something I
+         wanted to just get the name from.  argh.
+
+1995-04-03 16:58  millert
+
+       * lsearch.c: fixed argument order of memmove() that i hosed when
+         converting from bcopy().  arghh.
+
+1995-04-03 15:33  millert
+
+       * Makefile.in: finally fixed DISTFILES line
+
+1995-04-03 15:21  millert
+
+       * Makefile.in: tabs -> spaces
+
+1995-04-03 15:15  millert
+
+       * Makefile.in: added missing files to DISTFILES
+
+1995-04-03 14:50  millert
+
+       * Makefile.in: SUPPORTED -> RUNSON
+
+1995-04-01 03:12  millert
+
+       * TODO: updated
+
+1995-04-01 01:54  millert
+
+       * RUNSON: updated for pl5b1 release
+
+1995-04-01 01:53  millert
+
+       * BUGS, TODO: updated
+
+1995-04-01 01:52  millert
+
+       * check.c: fixed bug where if you hit return at first sudo prompt
+         it would still log as a failure
+
+1995-04-01 01:29  millert
+
+       * CHANGES: updated
+
+1995-04-01 01:25  millert
+
+       * aclocal.m4: better test for bogus void * implementation
+
+1995-03-31 20:33  millert
+
+       * logging.c: added PASSWORDS_NOT_CORRECT
+
+1995-03-31 20:32  millert
+
+       * check.c: added PASSWORDS_NOT_CORRECT stuff]
+
+1995-03-31 20:30  millert
+
+       * sudo.h: added PASSWORDS_NOT_CORRECT
+
+1995-03-31 19:16  millert
+
+       * tgetpass.c: moved pathnames.h
+
+1995-03-31 19:16  millert
+
+       * sudo.c: removed some unused vars and fixed up uid2str
+
+1995-03-31 19:15  millert
+
+       * putenv.c: moved compat.h
+
+1995-03-31 19:14  millert
+
+       * getcwd.c, getwd.c: added pathnames.h
+
+1995-03-31 18:18  millert
+
+       * parse.yacc: fixed a typo I introduced in the last checkin :-(
+
+1995-03-31 18:11  millert
+
+       * parse.lex: can't have #ifdef's where N is defined so just do this
+         the broken way for AIX
+
+1995-03-31 18:08  millert
+
+       * parse.yacc: better hack from Chris (but still a hack)
+
+1995-03-31 18:05  millert
+
+       * parse.lex: stupid hack for broken aix lex
+
+1995-03-31 17:47  millert
+
+       * tgetpass.c: now includes compat.h \ 6
+
+1995-03-31 17:27  millert
+
+       * visudo.c: now includes fcntl.h
+
+1995-03-31 17:27  millert
+
+       * compat.h: added FD_SET and FD_ZERO for 4.2BSD
+
+1995-03-31 16:12  millert
+
+       * parse.yacc: dirty hack to fix parser bug.  i don't really like
+         this but it works for now...
+
+1995-03-31 16:12  millert
+
+       * sudo.c: uid2str is now static like the prototype says
+
+1995-03-29 23:48  millert
+
+       * RUNSON: Initial revision
+
+1995-03-29 23:47  millert
+
+       * TODO, CHANGES, SUPPORTED, TROUBLESHOOTING: updated
+
+1995-03-29 23:46  millert
+
+       * sudo.c: check_sudoers now returns an error code and sudo calls
+         inform_user and log_error based on the return value.
+
+1995-03-29 23:45  millert
+
+       * logging.c, sudo.h: added entries for new errors
+
+1995-03-29 23:03  millert
+
+       * parse.c: now set uid to that of SUDOERS_OWNER while parsing
+         sudoers file
+
+1995-03-29 22:52  millert
+
+       * Makefile.in: took out testsudoers \ 6
+
+1995-03-29 22:36  millert
+
+       * sudo.c: now explicately checks that it is setuid root
+
+1995-03-29 22:28  millert
+
+       * sudo.c: If a user has no passwd entry sudo would segv (writing to
+         a garbage pointer).  Now allocate space before writing :-)
+
+1995-03-29 22:06  millert
+
+       * configure.in: reordered AC_CHECK_FUNCS
+
+1995-03-29 22:06  millert
+
+       * config.h.in: fixed memset macro
+
+1995-03-29 21:47  millert
+
+       * logging.c: bzero -> memset when a parse error is logged the line
+         number of the error is now logged too
+
+1995-03-29 21:46  millert
+
+       * tgetpass.c, visudo.c: bzero -> memset
+
+1995-03-29 21:46  millert
+
+       * INSTALL: added Sunos to blurb about c2 security
+
+1995-03-29 21:45  millert
+
+       * configure.in: added a SUN4 define for C2 security
+
+1995-03-29 21:44  millert
+
+       * config.h.in: bcopy -> memmove bzero -> memset
+
+1995-03-29 21:43  millert
+
+       * lsearch.c: bcopy -> memmove char * -> VOID *
+
+1995-03-29 21:30  millert
+
+       * check.c: added support for sunos with C2 security
+
+1995-03-29 21:12  millert
+
+       * OPTIONS, options.h: reordered
+
+1995-03-29 21:12  millert
+
+       * pathnames.h.in: _PATH_SUDO_LOGFILE now set based on configure
+
+1995-03-29 21:12  millert
+
+       * configure.in: added SUDO_LOGFILE and SUDO_TYPE_SIZE_T
+
+1995-03-29 21:12  millert
+
+       * config.h.in: added _SUDO_PATH_LOGFILE
+
+1995-03-29 21:11  millert
+
+       * aclocal.m4: added SUDO_LOGFILE to find where to put sudo.log
+         added SUDO_CHECK_TYPE (just AC_CHECK_TYPE but checks unistd.h
+         too) added SUDO_TYPE_SIZE_T (calls SUDO_CHECK_TYPE)
+
+1995-03-29 18:17  millert
+
+       * TROUBLESHOOTING: Initial revision
+
+1995-03-29 17:59  millert
+
+       * sudo.c: now do set_perms(PERM_ROOT) before the getpwuid() in
+         load_global() to work around a problem is trusted hpux shadow
+         passwords. yuck.
+
+1995-03-29 17:41  millert
+
+       * parse.yacc: backed out a change in malloc/realloc
+
+1995-03-29 17:38  millert
+
+       * parse.yacc: now include stdlib.h
+
+1995-03-29 17:22  millert
+
+       * visudo.c: now do an freopen() of the stmp file so that yyin will
+         always point to the same thing.  This is important for flex since
+         we are doing a YY_NEWFILE
+
+1995-03-29 17:20  millert
+
+       * parse.yacc: replaced yywrap() with parser_cleanup() since
+         yywrap() needs to be in parse.lex to be able to use YY_NEW_FILE.
+         sigh.
+
+1995-03-29 17:18  millert
+
+       * parse.lex: now have a rule that matches anything that doesn't
+         match an explicite rule.  well, you know what i mean (. matches
+         anything not yet matched).  However, this means that there is
+         input still queued up so we need to do a YY_NEW_FILE; in yywrap.
+         So, yywrap has moved into parse.lex and it calls parser_cleanup()
+         which is most of the old yywrap() sigh.
+
+1995-03-29 17:17  millert
+
+       * SUPPORTED: no longer used
+
+1995-03-29 16:13  millert
+
+       * getcwd.c, getwd.c: moved compat.h to be the last include file
+
+1995-03-29 16:11  millert
+
+       * parse.yacc: fixed type of aliascmp() args
+
+1995-03-29 15:58  millert
+
+       * find_path.c: NULL -> '\0'
+
+1995-03-29 15:42  millert
+
+       * parse.yacc: added casts to lfind and lsearch args for irix
+
+1995-03-29 08:20  millert
+
+       * Makefile.in: bsdinstall -> install-sh
+
+1995-03-29 08:20  millert
+
+       * INSTALL: added info about make realclean
+
+1995-03-29 08:17  millert
+
+       * Makefile.in: updated VERSION added dependencies for visudo.cat
+
+1995-03-29 08:17  millert
+
+       * version.h: -> pl5b1
+
+1995-03-29 08:16  millert
+
+       * sudo.c: took out -l
+
+1995-03-29 00:03  millert
+
+       * Makefile.in: now there is a real visudo.man and visudo.cat
+
+1995-03-28 23:54  millert
+
+       * sudo.man: took out visudo stuff
+
+1995-03-28 23:54  millert
+
+       * visudo.man: Initial revision
+
+1995-03-28 23:12  millert
+
+       * parse.c, parse.lex, parse.yacc: updated copyright
+
+1995-03-28 23:05  millert
+
+       * README: updated for pl5
+
+1995-03-28 20:02  millert
+
+       * sudo.man: updated Nieusma & Hieb email addresses
+
+1995-03-28 19:57  millert
+
+       * INSTALL: updated to include options.h and OPTIONS
+
+1995-03-28 19:35  millert
+
+       * CHANGES, TODO: updated
+
+1995-03-28 19:35  millert
+
+       * BUGS: eliminated bug #1 (yay)
+
+1995-03-28 19:31  millert
+
+       * configure.in: sunos no longer gets linked statically
+
+1995-03-28 18:58  millert
+
+       * parse.lex: prototype now uses __P()
+
+1995-03-28 18:49  millert
+
+       * parse.lex: make fill() non-ansi
+
+1995-03-28 15:26  millert
+
+       * parse.c: made -v (validate) work
+
+1995-03-28 15:26  millert
+
+       * logging.c: now gives host
+
+1995-03-28 10:34  millert
+
+       * find_path.c: don't check for execute/statable if fq or relative
+         path given
+
+1995-03-28 01:07  millert
+
+       * parse.c: added a cast
+
+1995-03-28 00:49  millert
+
+       * visudo.c: now include ctype.h for islower and tolower macros
+
+1995-03-28 00:48  millert
+
+       * goodpath.c: moved _S_IFMT & _S_ISREG to compat.h
+
+1995-03-28 00:48  millert
+
+       * sudo.c: moved a set of parens
+
+1995-03-28 00:48  millert
+
+       * strdup.c: now include compat.h
+
+1995-03-28 00:47  millert
+
+       * parse.yacc: now cast malloc & realloc return vals added search
+         for HAVE_LSEARCH now use strcmp if no strcasecmp available
+
+1995-03-28 00:46  millert
+
+       * lsearch.c, emul/search.h: void * -> VOID *
+
+1995-03-28 00:45  millert
+
+       * config.h.in: removed HAVE_FLEX added VOID added HAVE_DIRENT_H,
+         HAVE_SYS_NDIR_H, HAVE_SYS_DIR_H, HAVE_NDIR_H added HAVE_LSEARCH
+
+1995-03-28 00:44  millert
+
+       * compat.h: added _S_IFMT, _S_IFREG, and S_ISREG
+
+1995-03-28 00:44  millert
+
+       * aclocal.m4: took out SUDO_PROG_INSTALL 1.x to 2.x changes added
+         echo and results to most SUDO_* macros
+
+1995-03-28 00:43  millert
+
+       * Makefile.in: no more -I.
+
+1995-03-28 00:22  millert
+
+       * configure.in: various 1.x ro 2.x autoconf changes now check for
+         strcasecmp now use AC_INSTALL_PROG instead of custom one added
+         check for fully woorking void implementation
+
+1995-03-28 00:02  millert
+
+       * Makefile.in: added lsearch & search.h visudo links into
+         $(LIBOBJS)
+
+1995-03-27 23:43  millert
+
+       * aclocal.m4: partial 1.x to 2.x changes added SUDO_FULL_VOID
+
+1995-03-27 23:40  millert
+
+       * visudo.c: whatnow_help  was prototyped to be static be was not
+         declared as such
+
+1995-03-27 21:15  millert
+
+       * configure.in: autoconf 2.x changes took out HAVE_FLEX (no longer
+         used) added check for dirent/dir/ndir.h
+
+1995-03-27 21:09  millert
+
+       * parse.c: now use groovy gnu autoconf macro AC_HEADER_DIRENT
+
+1995-03-27 20:38  millert
+
+       * getcwd.c, getwd.c: MAXPATHLEN -> MAXPATHLEN+1
+
+1995-03-27 20:23  millert
+
+       * emul/search.h, lsearch.c: Initial revision
+
+1995-03-27 18:26  millert
+
+       * parse.yacc: eliminated bison warnings
+
+1995-03-27 17:10  millert
+
+       * parse.lex: added missing case
+
+1995-03-27 17:04  millert
+
+       * visudo.c: now iincludes signal.h
+
+1995-03-27 15:16  millert
+
+       * parse.yacc: only clear data structures on a parse error
+
+1995-03-27 15:01  millert
+
+       * visudo.c: whatnow() now gives help on invalid input
+
+1995-03-27 14:54  millert
+
+       * visudo.c: added a whatnow() function (sort of like mh)
+
+1995-03-27 14:53  millert
+
+       * parse.yacc: kill_aliases -> reset_aliases yywrap() now cleans up
+         by calling reset_aliases() and clearing top took reset stuff out
+         of yyerror() since it doesn't beling there (and doesn't work
+         anyway).  errorlineno is now initially set to -1 so we can set it
+         to the first error that occurrs (it was getting set to the last)
+
+1995-03-27 14:53  millert
+
+       * parse.lex: added a void cast
+
+1995-03-27 13:26  millert
+
+       * visudo.c: rewrote from scratch based on 4.3BSD vipw.c
+
+1995-03-26 01:33  millert
+
+       * sudo.c, sudo.h: removed ocmnd
+
+1995-03-26 01:19  millert
+
+       * sudo.h: no more sudo_realpath() and find_path() changed params
+
+1995-03-26 01:19  millert
+
+       * sudo.c: find_path() changed since no more realpath()
+
+1995-03-26 01:18  millert
+
+       * parse.yacc: on error, errorlineno is set to the line where the
+         error occurred added kill_aliases() to free the aliases struct
+         now clean up in yyerror() so we can reparse cleanly
+
+1995-03-26 01:17  millert
+
+       * logging.c: changed to use new find_path()
+
+1995-03-26 01:17  millert
+
+       * options.h, parse.c: no more USE_REALPATH
+
+1995-03-26 01:16  millert
+
+       * find_path.c: removed all the realpath() stuff
+
+1995-03-26 01:16  millert
+
+       * Makefile.in: sudo_realpath.c -> sudo_goodpath.c
+
+1995-03-26 01:12  millert
+
+       * visudo.c: now works correctly with utk parser
+
+1995-03-26 00:04  millert
+
+       * goodpath.c: Initial revision
+
+1995-03-25 23:23  millert
+
+       * sudo_realpath.c: eliminated a compiler warning
+
+1995-03-25 21:56  millert
+
+       * sudo.c: elinated compiler warning
+
+1995-03-25 20:40  millert
+
+       * sudo_realpath.c: added sudo_goodpath()
+
+1995-03-25 20:40  millert
+
+       * sudo.h: added prototype for sudo_goodpath
+
+1995-03-25 20:39  millert
+
+       * parse.c: added support for /sys/dir.h
+
+1995-03-25 20:39  millert
+
+       * options.h: USE_REALPATH turned off
+
+1995-03-25 20:39  millert
+
+       * find_path.c: added calls to sudo_goodpath()
+
+1995-03-25 20:39  millert
+
+       * configure.in: added check for dirent.h
+
+1995-03-25 20:38  millert
+
+       * config.h.in: added HAVE_DIRENT_H
+
+1995-03-25 19:27  millert
+
+       * configure.in: added in linux shadow pass stuff \ 6
+
+1995-03-24 14:43  millert
+
+       * visudo.c: added back host, user, cmnd, parse_error
+
+1995-03-24 14:19  millert
+
+       * visudo.c: added in utk changes plus some minor cosmetic changes
+
+1995-03-24 14:17  millert
+
+       * sudo.c, sudo_realpath.c: added void casts for printf's
+
+1995-03-24 14:17  millert
+
+       * options.h: added a define of USE_REALPATH
+
+1995-03-24 14:17  millert
+
+       * configure.in: there is no more visudoers/Makefile
+
+1995-03-24 14:16  millert
+
+       * Makefile.in: added in utk changes (visudo is now built from the
+         toplevel)
+
+1995-03-24 14:15  millert
+
+       * find_path.c: added (void) casts to printf's
+
+1995-03-23 22:32  millert
+
+       * parse.c, parse.lex, parse.yacc, sudo.h, sudo_realpath.c: merged
+         in utk changes
+
+1995-03-22 23:13  millert
+
+       * find_path.c: now check to see that what we are trying to run is a
+         file (or a link to a file, we do a stat(2) so there is no diff)
+
+1995-03-13 15:56  millert
+
+       * CHANGES: updated
+
+1995-03-13 15:56  millert
+
+       * Makefile.in: aclocal.m4 -> acsite.m4 make realclean updated for
+         new autoconf \ 6
+
+1995-03-13 15:11  millert
+
+       * sudo.man: added myself as maintainer
+
+1995-02-16 23:31  millert
+
+       * sudo.c: changed setegid -> setgid
+
+1995-02-06 17:43  millert
+
+       * configure.in: fixed the test for irix 5.x to skip bad libs
+
+1995-02-06 17:43  millert
+
+       * aclocal.m4: now initialize OS and OSREV
+
+1995-01-26 20:52  millert
+
+       * configure.in: irix5 changes
+
+1995-01-26 20:28  millert
+
+       * configure.in: AC_WITH -> AC_ARG_WITH changes other misc changes
+         for autoconf 2.1 compatibility
+
+1995-01-18 19:49  millert
+
+       * visudo.c: use YY_NEW_FILE, not yyrestart since OSF flex doesn't
+         do the righ thing wrt yyrestart (grrrr)
+
+1995-01-16 18:44  millert
+
+       * Makefile.in: added visudoers/compat.h to DISTFILES
+
+1995-01-16 17:01  millert
+
+       * configure.in: fixed an echo
+
+1995-01-16 16:36  millert
+
+       * sudo.c: added ocmnd declaration adjusted for find_path()'s new
+         parameters
+
+1995-01-16 16:35  millert
+
+       * sudo.h: added ocmnd extern adjusted find_path() prototype
+
+1995-01-16 16:34  millert
+
+       * parse.c: cmndcmp() now takes 3 arguments and checks against the
+         qualified as well as the unqualified pathname.  more code that
+         should use cmndcmp() but did not, now does
+
+1995-01-16 16:34  millert
+
+       * options.h: added to a comment
+
+1995-01-16 16:33  millert
+
+       * logging.c: changed to use new find_path() parameter passing
+
+1995-01-16 16:32  millert
+
+       * find_path.c: find_path() now takes 2 copyout parameters (one for
+         the qualified pathname and one for the unqualified pathname).
+         The third parameter may be NULL.
+
+1995-01-16 16:31  millert
+
+       * configure.in: no longer munge pathnames.h
+
+1995-01-16 16:30  millert
+
+       * pathnames.h.in: changed _PATH_* to use _SUDO_PATH_* (which are
+         defined in config.h) as a result, pathnames.h does not need to be
+         run through configure and the user can override the configured
+         values easily.
+
+1995-01-16 16:30  millert
+
+       * config.h.in: added _SUDO_PATH_* entries
+
+1995-01-16 16:30  millert
+
+       * aclocal.m4: _PATH* -> _SUDO_PATH_*
+
+1995-01-16 16:28  millert
+
+       * Makefile.in: updated DISTFILES and HDRS .o's now depend on
+         config.h
+
+1995-01-13 12:52  millert
+
+       * compat.h: removed extraneous #endif
+
+1995-01-13 12:48  millert
+
+       * aclocal.m4: added SUDO_PROG_MV
+
+1995-01-13 12:47  millert
+
+       * configure.in: added SUDO_PROG_MV added riscos and isc os types
+         took out -DSHORT_MESSAGE from --with-csops since it is now the
+         default
+
+1995-01-13 12:46  millert
+
+       * sudo.c: move the include of id.h to compat.h now includes
+         options.h
+
+1995-01-13 12:45  millert
+
+       * sudo.h: moved compatibility #defines to compat.h
+
+1995-01-13 12:45  millert
+
+       * pathnames.h.in: added _PATH_MV
+
+1995-01-13 12:43  millert
+
+       * config.h.in: move __P to compat.h
+
+1995-01-13 12:39  millert
+
+       * getcwd.c, getwd.c, putenv.c: now includes compat.h
+
+1995-01-13 12:39  millert
+
+       * compat.h: Initial revision
+
+1995-01-11 19:11  millert
+
+       * sudo.h: pull user-configurable stuff out and put in options.h
+
+1995-01-11 18:43  millert
+
+       * check.c, find_path.c, logging.c, parse.c, sudo_realpath.c,
+         sudo_setenv.c, parse.lex, parse.yacc, visudo.c: now includes
+         options.h
+
+1995-01-11 18:41  millert
+
+       * Makefile.in: added visudoers/options.h
+
+1995-01-11 18:40  millert
+
+       * options.h, OPTIONS: Initial revision
+
+1995-01-11 18:39  millert
+
+       * Makefile.in: added OPTIONS and options.h
+
+1995-01-11 18:36  millert
+
+       * logging.c: changed #ifdef's to use LOGGING and
+         SLOG_SYSLOG/SLOG_FILE
+
+1995-01-11 11:02  millert
+
+       * check.c, sudo.h: changed PASSWORD_TIMEOUT to minutes
+
+1994-12-17 18:18  millert
+
+       * visudo.c: now only do Editor +line_num if line_num  != 0
+
+1994-12-15 21:06  millert
+
+       * visudo.c: now use mv if rename(2) fails
+
+1994-12-15 20:32  millert
+
+       * BUGS: added a visudo bug
+
+1994-12-15 19:46  millert
+
+       * check.c: expanded comment
+
+1994-11-12 18:33  millert
+
+       * check.c: fixed user_is_exempt to return 0 if EXEMPTGROUP is not
+         set
+
+1994-11-09 19:49  millert
+
+       * sudo.c: added mips & isc support
+
+1994-11-09 19:49  millert
+
+       * parse.c: added support for non-root owned sudoers file
+
+1994-11-09 19:48  millert
+
+       * check.c: added exempt group support
+
+1994-11-09 19:47  millert
+
+       * sudo.h: added set_perms() support added SUDOERS_OWNER so can have
+         non-root own sudoers file added exempt group support added isc
+         support
+
+1994-11-09 19:46  millert
+
+       * visudo.c: now copy sudoers to temp file via read/write (not
+         stdio) now chown new sudoers file to SUDOERS_OWNER
+
+1994-11-07 20:40  millert
+
+       * configure.in: added skey support
+
+1994-11-07 20:39  millert
+
+       * sudo.h: fixed typo added set_perms support added skey support
+         added seteuid()/setegid() emulation for AIX
+
+1994-11-07 20:38  millert
+
+       * sudo.c: be_* -> setperms() now check to make sure sudoers file is
+         owned by root nread/write by only root
+
+1994-11-07 20:38  millert
+
+       * logging.c, parse.c, sudo_realpath.c: be_* -> setperms()
+
+1994-11-07 20:38  millert
+
+       * check.c: be_* -> set_perms() added skey support
+
+1994-11-06 18:59  millert
+
+       * Makefile.in: ++version
+
+1994-11-06 18:59  millert
+
+       * version.h: ++
+
+1994-10-21 13:16  millert
+
+       * sudo.c: now sets IFS
+
+1994-10-21 12:02  millert
+
+       * insults.h: fixed typo
+
+1994-10-15 15:48  millert
+
+       * config.h.in: added HAVE_SKEY
+
+1994-10-04 13:00  millert
+
+       * CHANGES: updated
+
+1994-10-04 12:57  millert
+
+       * Makefile.in: ++version
+
+1994-10-04 12:57  millert
+
+       * version.h: ++
+
+1994-10-04 12:56  millert
+
+       * sudo.c: now bail if ARgv[1] > MAXPATHLEN
+
+1994-10-04 12:56  millert
+
+       * configure.in: added function check for tcgetattr(3)
+
+1994-10-04 12:55  millert
+
+       * config.h.in: only define HAVE_TERMIOS_H if you have tcgetattr(3)
+
+1994-10-04 12:53  millert
+
+       * config.h.in: added check for tcgetattr
+
+1994-09-26 17:38  millert
+
+       * CHANGES: updated
+
+1994-09-22 13:30  millert
+
+       * parse.lex: now only include unistd.h for linux
+
+1994-09-21 14:29  millert
+
+       * Makefile.in: added visudo.8 generation
+
+1994-09-21 14:07  millert
+
+       * configure.in: added -Wl,-bI:./aixcrypt.exp to aix flags
+
+1994-09-20 19:39  millert
+
+       * BUGS: added one
+
+1994-09-20 19:39  millert
+
+       * CHANGES: updated
+
+1994-09-20 19:38  millert
+
+       * README: added mailing list info
+
+1994-09-20 19:37  millert
+
+       * parse.yacc: now use sudolineno instead of yylineno fixed bison
+         warnings
+
+1994-09-20 19:37  millert
+
+       * configure.in: now use -no_library_replacement for osf don't make
+         a static binary for hpux >= 9.0
+
+1994-09-20 19:21  millert
+
+       * tgetpass.c: added string.h/strings.h inclusion
+
+1994-09-20 19:21  millert
+
+       * config.h.in: added ssize_t def
+
+1994-09-20 19:18  millert
+
+       * parse.lex: added inclusion of string.h/strings.h
+
+1994-09-20 18:48  millert
+
+       * aclocal.m4: fixed uname | sed (needed to quote the '[')
+
+1994-09-20 18:42  millert
+
+       * parse.lex: replaced yylineno with sudolineno fixed bison syntax
+         errors
+
+1994-09-20 18:13  millert
+
+       * visudo.c: changed yylineno to sudolineno since yylineno cannot be
+         counted upon.
+
+1994-09-20 18:10  millert
+
+       * TODO: updated
+
+1994-09-20 17:52  millert
+
+       * parse.c: added code to support command listings
+
+1994-09-20 17:36  millert
+
+       * sudo.c: added code for -l flag
+
+1994-09-20 17:35  millert
+
+       * sudo.man: fixed typo added info for -l flag
+
+1994-09-20 14:45  millert
+
+       * configure.in: AC_SSIZE_T -> SUDO_SSIZE_T
+
+1994-09-20 14:45  millert
+
+       * aclocal.m4: added SUDO_SSIZE_T
+
+1994-09-20 14:44  millert
+
+       * sudo.h: added MODE_LIST
+
+1994-09-20 14:43  millert
+
+       * configure.in: added AC_SSIZE_T
+
+1994-09-19 20:53  millert
+
+       * find_path.c, sudo_realpath.c: readlink() is now declared as
+         returning ssize~_t
+
+1994-09-19 20:44  millert
+
+       * configure.in: added -laud for OSF c2
+
+1994-09-02 15:55  millert
+
+       * config.h.in, parse.lex, parse.yacc, pathnames.h.in, visudo.c,
+         Makefile.in: changed sudo-bugs.cs.colorado.edu ->
+         sudo-bugs@cs.colorado.edu
+
+1994-09-02 15:54  millert
+
+       * check.c, find_path.c, getcwd.c, getwd.c, insults.h, logging.c,
+         parse.c, putenv.c, strdup.c, sudo.c, sudo.h, sudo_realpath.c,
+         sudo_setenv.c, tgetpass.c, version.h: changed
+         sudo-bugs.cs.colorado.edu -> sudo-bugs@cs.colorado.ed
+
+1994-09-01 15:56  millert
+
+       * Makefile.in: ++version
+
+1994-09-01 15:55  millert
+
+       * version.h: ++
+
+1994-09-01 15:55  millert
+
+       * logging.c: added host to alertmail messages
+
+1994-09-01 15:55  millert
+
+       * CHANGES, TODO: udpated
+
+1994-09-01 15:26  millert
+
+       * logging.c: fixed logging problem where mail would not say which
+         user it was
+
+1994-09-01 13:45  millert
+
+       * configure.in: added -laud for gcc if osf & c2
+
+1994-09-01 13:39  millert
+
+       * check.c: moved set_auth_parameters to sudo.c
+
+1994-09-01 13:38  millert
+
+       * sudo.c: added set_auth_parameters for osf
+
+1994-09-01 13:22  millert
+
+       * configure.in: cleaned up -static stuff
+
+1994-09-01 13:15  millert
+
+       * Makefile.in: ++version
+
+1994-09-01 13:15  millert
+
+       * version.h: ++
+
+1994-09-01 13:15  millert
+
+       * sudo.c: changed setenv() to sudo_setenv()
+
+1994-09-01 13:12  millert
+
+       * check.c: fixed osf problem
+
+1994-08-31 22:17  millert
+
+       * configure.in: added OSF C2 stuff
+
+1994-08-31 22:00  millert
+
+       * CHANGES: updated
+
+1994-08-31 21:56  millert
+
+       * check.c: added osf auth support & removed some extra spaces
+
+1994-08-31 21:52  millert
+
+       * INSTALL, SUPPORTED: added osf C2 stuff
+
+1994-08-31 19:52  millert
+
+       * TODO: added 2 suggestions
+
+1994-08-31 19:33  millert
+
+       * Makefile.in: removed README.v1.3.1 and added VERSION stuff
+
+1994-08-31 18:48  millert
+
+       * version.h: pl1
+
+1994-08-30 18:31  millert
+
+       * version.h: 1.3.1final
+
+1994-08-30 18:30  millert
+
+       * Makefile.in: added HISTORY
+
+1994-08-30 18:30  millert
+
+       * sudo.man: mention HISTPRY file
+
+1994-08-30 18:30  millert
+
+       * sudo.c: use sizeof instead of a constant in 1 place
+
+1994-08-30 18:30  millert
+
+       * parse.yacc: added  unistd.h
+
+1994-08-30 18:29  millert
+
+       * parse.lex: added unistd.h
+
+1994-08-30 18:27  millert
+
+       * README: udpated
+
+1994-08-30 18:15  millert
+
+       * HISTORY: Initial revision
+
+1994-08-17 12:45  millert
+
+       * version.h: ++
+
+1994-08-17 12:39  millert
+
+       * CHANGES: updated
+
+1994-08-17 12:36  millert
+
+       * sudo_setenv.c: added unistd.h include
+
+1994-08-16 15:46  millert
+
+       * sudo.c: added sys/time.h for AIX
+
+1994-08-14 21:22  millert
+
+       * configure.in: added check for -lsocket and sys/sockio.h
+
+1994-08-14 21:21  millert
+
+       * config.h.in: took out libshadow check and added in sys/sockio.h
+         check
+
+1994-08-14 21:21  millert
+
+       * sudo.c: now include sockio.h instead of ioctl.h if it exists
+         "sudo -" now gets a better error message
+
+1994-08-14 20:47  millert
+
+       * sample.sudoers: now has a dir and subnet entry
+
+1994-08-13 18:15  millert
+
+       * sudo.c: removed if_ether.h
+
+1994-08-13 17:16  millert
+
+       * TODO: added an item
+
+1994-08-13 17:15  millert
+
+       * sudo.man: added network and ip addresses to man page
+
+1994-08-13 17:09  millert
+
+       * sudo.c: no error if can't get interfaces or netmask since
+         networking may not be in the kernel.
+
+1994-08-13 17:08  millert
+
+       * parse.c: nwo check for interfaces == NULL
+
+1994-08-12 21:22  millert
+
+       * parse.c: fixed a bug that caused directory specs in a Cmnd_Alias
+         to fail if the last entry in the spec failed (ie: it was only
+         looking at the last entry).  CLeaned things up by adding the
+         cmndcmp() function--all neat & tidy
+
+1994-08-12 21:21  millert
+
+       * CHANGES: added one
+
+1994-08-11 23:42  millert
+
+       * sudo.c: now do two passes to skip bogus interfaces (lo0, etc)
+
+1994-08-11 21:58  millert
+
+       * logging.c, sudo_realpath.c, sudo_setenv.c: added ninclude of
+         netinet/in.h
+
+1994-08-11 21:58  millert
+
+       * check.c, find_path.c, getcwd.c, getwd.c, parse.lex, parse.yacc,
+         visudo.c: added include of netinet/in.h
+
+1994-08-11 21:57  millert
+
+       * version.h: ++
+
+1994-08-11 21:57  millert
+
+       * sudo.h: added interfaces global
+
+1994-08-11 21:56  millert
+
+       * parse.c: now uses new interfaces global
+
+1994-08-11 21:56  millert
+
+       * sudo.c: now ip addresses are gleaned fw/o dns
+
+1994-08-10 19:21  millert
+
+       * sudo.c: added load_ip_addrs() to load the ip_addrs global var
+
+1994-08-10 19:21  millert
+
+       * parse.c: added hostcmp() to compare hostnames, ip addrs, and
+         network addrs
+
+1994-08-10 19:20  millert
+
+       * sudo.h: added ip_addrs def added load_ip_addrs prototype
+
+1994-08-08 16:03  millert
+
+       * CHANGES: updated
+
+1994-08-08 15:57  millert
+
+       * Makefile.in: removed multiple entries in DISTFILES
+
+1994-08-08 13:05  millert
+
+       * visudo.c: ansified the !STDC_HEADERS decls
+
+1994-08-08 13:05  millert
+
+       * find_path.c, getcwd.c, getwd.c, putenv.c, strdup.c: don't do
+         malloc decl if gnuc
+
+1994-08-08 13:04  millert
+
+       * sudo.c: can't use getopt(3) since it munges args to the command
+         to be run as root don't do malloc decl if gnuc
+
+1994-08-08 00:41  millert
+
+       * find_path.c, getcwd.c, getwd.c, putenv.c, strdup.c, sudo.c,
+         sudo_realpath.c, sudo_setenv.c: ansi-fied !STDC_HEADER function
+         prottypes
+
+1994-08-08 00:27  millert
+
+       * getcwd.c, getwd.c: added missing paren
+
+1994-08-08 00:23  millert
+
+       * Makefile.in: added putenv.c to DISTFILES
+
+1994-08-08 00:08  millert
+
+       * sudo_setenv.c: added params to func decls when STDC_HEADERS is
+         not defined now can count on putenv() being there
+
+1994-08-08 00:08  millert
+
+       * sudo_realpath.c: took out errno decl since sudo.h does it for us
+         fixed up a next cc warning added params to func decls when
+         STDC_HEADERS is not defined
+
+1994-08-08 00:07  millert
+
+       * sudo.h: took out environ extern added local declaratio of
+         putenv() if local version is needed
+
+1994-08-08 00:05  millert
+
+       * find_path.c, getcwd.c, getwd.c, strdup.c, sudo.c: added params to
+         func decls when STDC_HEADERS is not defined
+
+1994-08-08 00:04  millert
+
+       * config.h.in: added memcpy check check to see that ansi vs bsd
+         macros are ntot already defiend before defining (ie: avoid
+         redefinition)
+
+1994-08-08 00:03  millert
+
+       * configure.in: removed fluff setenv check plus check w/ replace
+         for putenv if also no setenv
+
+1994-08-08 00:01  millert
+
+       * putenv.c: Initial revision
+
+1994-08-06 19:19  millert
+
+       * sudo_setenv.c: Initial revision
+
+1994-08-06 19:19  millert
+
+       * sudo.h: rm'd s realp[ath added sudo_realpath and sudo_setenv
+
+1994-08-06 19:19  millert
+
+       * sudo.c: now use sudo_setenvc
+
+1994-08-06 19:18  millert
+
+       * configure.in: added puteenv and setenv, removed realpath
+
+1994-08-06 19:18  millert
+
+       * config.h.in: added putenv & setenv
+
+1994-08-06 19:18  millert
+
+       * Makefile.in: added sudo_setenv
+
+1994-08-06 19:16  millert
+
+       * version.h: ++
+
+1994-08-05 19:43  millert
+
+       * configure.in: added MAN_POSTINSTALL and /usr/share/catman for
+         irix
+
+1994-08-05 19:43  millert
+
+       * Makefile.in: added MAN_POSTINSTALL
+
+1994-08-05 19:43  millert
+
+       * CHANGES: added
+
+1994-08-05 19:10  millert
+
+       * sudo.man: added SUDO_* plus new options
+
+1994-08-05 19:10  millert
+
+       * CHANGES: added one
+
+1994-08-05 19:07  millert
+
+       * configure.in: took out shadow lib
+
+1994-08-05 18:35  millert
+
+       * TODO: adde done
+
+1994-08-05 17:52  millert
+
+       * visudo.c: now use yyrestart() if flex now reset yylineno to 0
+
+1994-08-05 17:49  millert
+
+       * Makefile.in: support for installing a cat page instead of a man
+         page if no nroff
+
+1994-08-05 17:48  millert
+
+       * configure.in: now defines HAVE_FLEX fixed up man stuff so that it
+         looks for nroff to determine whether or not to install a cat or
+         man page
+
+1994-08-05 17:48  millert
+
+       * config.h.in: added HAVE_FLEX
+
+1994-08-05 16:14  millert
+
+       * sudo.c: not set ret to MODE_RUN initially
+
+1994-08-05 16:12  millert
+
+       * find_path.c: made command (and therefor cmnd dynamically
+         allocated)
+
+1994-08-04 20:25  millert
+
+       * TODO: did #8
+
+1994-08-04 20:24  millert
+
+       * version.h: ++
+
+1994-08-04 20:24  millert
+
+       * sudo_realpath.c: changed bufs from MAXPATHLEN to MAXPATHLEN+1
+
+1994-08-04 20:24  millert
+
+       * sudo.h: added MODE_ removed validate_only and added
+         remove_timestamp()
+
+1994-08-04 20:22  millert
+
+       * sudo.c: usage() now takes an int (exit value) added parse_args()
+         to parse command line arguments moved call to find_path() from
+         load_globals to new function load_cmnd() removed validate_only
+         global -- now use the concept of "modes" added -h and -k options
+
+1994-08-04 20:21  millert
+
+       * parse.c: no longer use global validate_only now checks for
+         command called "validate" removed check for non-fully qualified
+         commands since that is done by find_path
+
+1994-08-04 20:20  millert
+
+       * find_path.c: changed MAXPATHLEN r to MAXPATHLEN+1
+
+1994-08-04 20:17  millert
+
+       * find_path.c: fixed off by one error with MAXPATHLEN and fixed a
+         comment
+
+1994-08-04 20:17  millert
+
+       * check.c: check_timestamp no longer runs reminder(), it is implied
+         in the return val added remove_timestamp()
+
+1994-08-04 20:16  millert
+
+       * CHANGES: updated
+
+1994-08-04 16:38  millert
+
+       * BUGS: fixed on
+
+1994-08-04 16:38  millert
+
+       * sudo_realpath.c: took out old_errno
+
+1994-08-04 16:37  millert
+
+       * CHANGES: updated
+
+1994-08-03 12:08  millert
+
+       * logging.c: moved send_mail to after syslog
+
+1994-08-02 22:41  millert
+
+       * sudo.c: now set SUDO_ envariables
+
+1994-08-01 13:40  millert
+
+       * version.h: ++
+
+1994-08-01 13:39  millert
+
+       * sudo_realpath.c: now print error if chdir fails
+
+1994-08-01 13:39  millert
+
+       * find_path.c: removed an XXX
+
+1994-07-25 20:40  millert
+
+       * CHANGES: updated
+
+1994-07-25 20:36  millert
+
+       * configure.in: no more static binaries for aix
+
+1994-07-25 18:37  millert
+
+       * INSTALL: fixed typo
+
+1994-07-25 18:33  millert
+
+       * sudo_realpath.c: took out stuff not needed for sudo now does
+         be_root/be_user itself now uses cwd global
+
+1994-07-25 18:32  millert
+
+       * version.h: +=2
+
+1994-07-25 18:31  millert
+
+       * logging.c, sudo.c: be_root/be_user is now down in sudo_realpath()
+
+1994-07-25 18:26  millert
+
+       * logging.c, sudo.h: now works with 4.2BSD syslog (blech)
+
+1994-07-25 18:25  millert
+
+       * find_path.c: now use sudo_realpath()
+
+1994-07-25 18:25  millert
+
+       * config.h.in: took out realpth() stuff since we now use
+         sudo_realpath()
+
+1994-07-25 18:25  millert
+
+       * configure.in: ultrix enhanced sec
+
+1994-07-25 18:25  millert
+
+       * SUPPORTED: added ultrix enhanced sec.
+
+1994-07-25 18:24  millert
+
+       * INSTALL: updated
+
+1994-07-25 18:21  millert
+
+       * check.c: ultrix enhanced security suport
+
+1994-07-25 18:20  millert
+
+       * Makefile.in: added sudo_realpath.c
+
+1994-07-25 18:18  millert
+
+       * CHANGES: updated
+
+1994-07-25 14:28  millert
+
+       * tgetpass.c: increased passwd len to 24 for c2 security
+
+1994-07-25 13:17  millert
+
+       * BUGS: updated BUGS
+
+1994-07-15 11:49  millert
+
+       * check.c: now use user global var
+
+1994-07-15 11:48  millert
+
+       * configure.in: took out -ls
+
+1994-07-14 19:11  millert
+
+       * configure.in: added AFS libs
+
+1994-07-14 17:45  millert
+
+       * sudo.h: user is now a char * added epasswd
+
+1994-07-14 17:43  millert
+
+       * sudo.c: added tzset() to load_globals added epasswd (encrypted
+         password) global made user dynamically allocated
+
+1994-07-14 17:43  millert
+
+       * configure.in: added tzset test
+
+1994-07-14 17:43  millert
+
+       * config.h.in: added HAVE_TZSET
+
+1994-07-14 17:42  millert
+
+       * check.c: cleaned up encrypted passwd grab somewhat
+
+1994-07-14 12:34  millert
+
+       * configure.in: fixed AFS typo
+
+1994-07-14 12:34  millert
+
+       * INSTALL: added AFS not
+
+1994-07-14 12:34  millert
+
+       * CHANGES: udpated
+
+1994-07-14 12:33  millert
+
+       * logging.c: can now log to both syslog & a file
+
+1994-07-14 12:12  millert
+
+       * sudo.h: added BOTH_LOGS
+
+1994-07-14 11:34  millert
+
+       * CHANGES: updated
+
+1994-07-14 11:32  millert
+
+       * configure.in: --with-AFS
+
+1994-07-14 11:32  millert
+
+       * config.h.in: added HAVE_AFS
+
+1994-07-14 11:31  millert
+
+       * check.c: added afs changes
+
+1994-07-14 11:21  millert
+
+       * sudo.h: removed AFS stuff :-)
+
+1994-07-14 11:19  millert
+
+       * tgetpass.c: include sys/select for AIX
+
+1994-07-14 11:17  millert
+
+       * sudo.h: added AFS
+
+1994-07-14 11:16  millert
+
+       * version.h: ++
+
+1994-07-07 14:45  millert
+
+       * SUPPORTED, CHANGES: updated
+
+1994-07-07 14:44  millert
+
+       * logging.c: can now have MAILER undefined
+
+1994-07-07 14:37  millert
+
+       * INSTALL: new sub-note about MAILER
+
+1994-07-06 23:11  millert
+
+       * sudo.man: added blurb about password timeout
+
+1994-07-06 20:52  millert
+
+       * configure.in: convex c2 changes
+
+1994-07-06 20:52  millert
+
+       * aclocal.m4: took out duplicate define of _CONVEX_SOURCE
+
+1994-07-06 20:51  millert
+
+       * Makefile.in: added OSDEFS
+
+1994-07-06 20:46  millert
+
+       * config.h.in: added spaces
+
+1994-07-06 20:08  millert
+
+       * tgetpass.c: added a goto if fgets fails
+
+1994-07-06 20:08  millert
+
+       * sudo.h: use __hpux not hpux convex c2 stuff
+
+1994-07-06 20:08  millert
+
+       * sudo.c: use __hpux not hpux
+
+1994-07-06 20:08  millert
+
+       * logging.c: convex c2 stuff
+
+1994-07-06 20:07  millert
+
+       * config.h.in: define ansi-ish cpp os defines if non-ansi are
+         defined for hpux & convex
+
+1994-07-06 20:07  millert
+
+       * INSTALL: updated to say we support sonvex C2
+
+1994-07-06 20:05  millert
+
+       * check.c: added convex c2 support
+
+1994-07-01 12:06  millert
+
+       * tgetpass.c: no more ioctl never returns NULL uses fgets() and
+         select() to timeout
+
+1994-06-29 17:04  millert
+
+       * configure.in: things were testing -n "$GCC" instead of -z "$GCC"
+
+1994-06-29 16:39  millert
+
+       * tgetpass.c: now works + uses fgets()
+
+1994-06-28 18:25  millert
+
+       * tgetpass.c: select doesn't seem to recognize a single '\n' as
+         input waiting so we can;t use it, sigh.
+
+1994-06-26 16:38  millert
+
+       * PORTING: updated tgetpass() blurb
+
+1994-06-26 16:35  millert
+
+       * configure.in: added --with-getpass
+
+1994-06-26 16:35  millert
+
+       * Makefile.in: added tgetpass stuff
+
+1994-06-26 15:25  millert
+
+       * tgetpass.c: now uses stdio
+
+1994-06-26 15:17  millert
+
+       * version.h: ++
+
+1994-06-24 19:48  millert
+
+       * PORTING: updated ,.
+
+1994-06-24 19:46  millert
+
+       * config.h.in: added USE_GETPASS && HAVE_C2_SECURITY
+
+1994-06-24 19:45  millert
+
+       * configure.in: fixed a test aded --with-C2 and --with-tgetpass
+
+1994-06-24 19:45  millert
+
+       * check.c: added hpux C2 shit
+
+1994-06-24 19:45  millert
+
+       * Makefile.in: took out tgetpass.*
+
+1994-06-24 19:45  millert
+
+       * INSTALL: added C2 blurb
+
+1994-06-13 15:54  millert
+
+       * configure.in: no termio(s) for ultrix since it is broken
+
+1994-06-13 15:41  millert
+
+       * check.c: added a space (yeah, anal)
+
+1994-06-13 15:17  millert
+
+       * realpath.c, sudo_realpath.c: fixed it (duh, rtfm)
+
+1994-06-08 14:34  millert
+
+       * config.h.in: took out bsd signal stuff for irix
+
+1994-06-08 14:26  millert
+
+       * visudo.c: comments in #endif
+
+1994-06-08 14:09  millert
+
+       * configure.in: don't define BSD signals for irix
+
+1994-06-08 12:57  millert
+
+       * TODO: did some...
+
+1994-06-08 12:57  millert
+
+       * CHANGES: updated
+
+1994-06-08 12:56  millert
+
+       * realpath.c, sudo_realpath.c: took out unneeded code by changing
+         where a strings was terminated
+
+1994-06-07 19:21  millert
+
+       * realpath.c, sudo_realpath.c: fix bug where /dirname would return
+         NULL
+
+1994-06-07 17:40  millert
+
+       * sudo.h: move __P to config.h
+
+1994-06-07 17:40  millert
+
+       * getcwd.c, getwd.c, realpath.c, sudo_realpath.c: added errno
+         definition
+
+1994-06-07 17:40  millert
+
+       * config.h.in: added __P
+
+1994-06-07 17:21  millert
+
+       * config.h.in: added HAVE_FCHDIR
+
+1994-06-07 17:18  millert
+
+       * strdup.c: now include stdio
+
+1994-06-07 14:55  millert
+
+       * realpath.c, sudo_realpath.c: now works if no fchdir
+
+1994-06-07 14:55  millert
+
+       * visudo.c: define SA_RESETHAND to null if not defined
+
+1994-06-07 14:54  millert
+
+       * configure.in: added check & replace
+
+1994-06-06 20:05  millert
+
+       * configure.in: took out -static for nextstep -- it doesn't work
+
+1994-06-06 19:59  millert
+
+       * logging.c: moved #endif to where it belongs
+
+1994-06-06 19:54  millert
+
+       * SUPPORTED: correction
+
+1994-06-06 19:42  millert
+
+       * configure.in: now checks for strdup realpath getcwd bzero
+
+1994-06-06 19:31  millert
+
+       * config.h.in: emulate bzero
+
+1994-06-06 16:57  millert
+
+       * visudo.c: added posic signals
+
+1994-06-06 16:57  millert
+
+       * tgetpass.c: bzero cast
+
+1994-06-06 16:57  millert
+
+       * logging.c: added posix signals
+
+1994-06-06 16:56  millert
+
+       * configure.in: removed BROKEN_GETPASS added  new srcs toreplace
+         missing functions
+
+1994-06-06 16:56  millert
+
+       * config.h.in: added posix signal stuff
+
+1994-06-06 16:56  millert
+
+       * Makefile.in: added new srcs
+
+1994-06-06 12:53  millert
+
+       * visudo.c: updated useag
+
+1994-06-06 12:39  millert
+
+       * tgetpass.c: now uses posix signals
+
+1994-06-05 20:17  millert
+
+       * PORTING: updated sto reflect major changes
+
+1994-06-05 20:05  millert
+
+       * TODO, CHANGES: updated
+
+1994-06-05 20:04  millert
+
+       * tgetpass.c: uses sysconf() if available
+
+1994-06-05 20:04  millert
+
+       * sudo.h: added PASSWORD_TIMEOUT + prototypes for new functions
+
+1994-06-05 20:04  millert
+
+       * realpath.c, sudo_realpath.c: for those w/o this in libc
+
+1994-06-05 20:03  millert
+
+       * getcwd.c, getwd.c: Initial revision
+
+1994-06-05 20:03  millert
+
+       * find_path.c: rewrote to use realpath(3) - nis now all my code
+
+1994-06-05 20:02  millert
+
+       * config.h.in: added HAVE_REALPATH
+
+1994-06-05 20:02  millert
+
+       * check.c: now use tgetpass
+
+1994-06-05 20:02  millert
+
+       * Makefile.in: added LIBOBJS use tgetpass.c
+
+1994-06-05 18:55  millert
+
+       * tgetpass.c: works now :-)
+
+1994-06-05 18:27  millert
+
+       * tgetpass.c: Initial revision
+
+1994-06-05 17:17  millert
+
+       * pathnames.h.in: added /dev/tty
+
+1994-06-04 17:12  millert
+
+       * version.h: incremented
+
+1994-06-04 15:29  millert
+
+       * sudo.c: always use getcwd
+
+1994-06-04 14:49  millert
+
+       * config.h.in: added check for getwd
+
+1994-06-04 14:48  millert
+
+       * configure.in: replace strdup & realpath & getcwd if missing
+
+1994-06-04 14:47  millert
+
+       * pathnames.h.in: added _PATH_PWD
+
+1994-06-04 14:46  millert
+
+       * aclocal.m4: added SUDO_PROG_PWD
+
+1994-06-04 14:37  millert
+
+       * realpath.c, sudo_realpath.c, strdup.c: Initial revision
+
+1994-06-03 11:31  millert
+
+       * configure.in: quoted quare brackets
+
+1994-06-02 17:49  millert
+
+       * sudo.c: no need to strdup() a constant
+
+1994-06-02 15:45  millert
+
+       * CHANGES: updated
+
+1994-06-02 15:44  millert
+
+       * sudo.man: added validate
+
+1994-06-02 15:42  millert
+
+       * sudo.c: added -v to usage
+
+1994-06-02 15:41  millert
+
+       * parse.c, sudo.c, sudo.h: added validate_only stuff
+
+1994-05-29 21:29  millert
+
+       * configure.in: now finds sed
+
+1994-05-29 21:28  millert
+
+       * aclocal.m4: $OSREV is now an int
+
+1994-05-29 19:13  millert
+
+       * configure.in: added mtxinu to caser
+
+1994-05-29 18:37  millert
+
+       * sudo.h: added EXEC macro
+
+1994-05-29 18:36  millert
+
+       * sudo.c: now use the EXEC nmacro now only do a gethostbyname() if
+         FQDN is set
+
+1994-05-29 18:36  millert
+
+       * logging.c: changed mail_argv[] def now use EXEC() macro
+
+1994-05-29 18:35  millert
+
+       * check.c: took out crypt() definition
+
+1994-05-29 17:23  millert
+
+       * version.h: upped the version
+
+1994-05-29 15:52  millert
+
+       * configure.in: always look for -lnsl
+
+1994-05-29 15:29  millert
+
+       * aclocal.m4: added an echo
+
+1994-05-29 15:25  millert
+
+       * sudo.h: SHORT_MESSAGE is now the default
+
+1994-05-29 15:18  millert
+
+       * config.h.in: fixed typo
+
+1994-05-29 01:29  millert
+
+       * configure.in: added missing AC_DEFINE(SVR4) for solaris
+
+1994-05-28 20:42  millert
+
+       * sudo.man: documented the -v flag
+
+1994-05-28 20:34  millert
+
+       * SUPPORTED: updated
+
+1994-05-28 20:31  millert
+
+       * check.c: proto-ized crypt()
+
+1994-05-28 20:28  millert
+
+       * config.h.in: added LIBSHADOW undef
+
+1994-05-28 20:18  millert
+
+       * configure.in: nwo set OS to be lowercase
+
+1994-05-28 19:36  millert
+
+       * configure.in: now use SUDO_OSTYPE to set $OS
+
+1994-05-28 19:36  millert
+
+       * aclocal.m4: now use uname to determine os
+
+1994-05-28 16:23  millert
+
+       * visudo.c: added prototypes & moved sig handler around
+
+1994-05-28 15:13  millert
+
+       * sudo.h: added prototyppes
+
+1994-05-28 15:13  millert
+
+       * parse.c: added comment
+
+1994-05-28 15:12  millert
+
+       * config.h.in: nwo use _BSD_SIGNALS not _BSD_COMPAT
+
+1994-05-28 15:11  millert
+
+       * check.c, logging.c, sudo.c: added prototypes
+
+1994-05-28 15:11  millert
+
+       * aixcrypt.exp: Initial revision
+
+1994-05-28 15:11  millert
+
+       * Makefile.in: added aixcrypt.exp
+
+1994-05-28 13:21  millert
+
+       * parse.lex, parse.yacc: moved config.h to top of includes
+
+1994-05-25 15:48  millert
+
+       * find_path.c: now don't bitch if get EACCESS (treat like EPERM)
+
+1994-05-24 23:08  millert
+
+       * visudo.c: added -v flag and usage()
+
+1994-05-24 23:08  millert
+
+       * version.h: fixed a typo
+
+1994-05-24 23:08  millert
+
+       * sudo.c: cast Argv to a const for exec added -v flag
+
+1994-05-24 23:07  millert
+
+       * logging.c: mail_argv is now a const
+
+1994-05-24 23:07  millert
+
+       * configure.in: only set RETSIGTYPE if it is not set already
+
+1994-05-24 23:07  millert
+
+       * aclocal.m4: now defines  & STDC_HEADERS for Irix
+
+1994-05-24 23:07  millert
+
+       * Makefile.in: added version.h
+
+1994-05-24 21:25  millert
+
+       * insults.h, sudo.h: prevent multiple inclusion
+
+1994-05-24 21:20  millert
+
+       * version.h: Initial revision
+
+1994-05-24 21:09  millert
+
+       * parse.lex, parse.yacc: now includes config.h
+
+1994-05-24 20:54  millert
+
+       * aclocal.m4: now talks about sunos 4.x
+
+1994-05-24 20:23  millert
+
+       * visudo.c: calls to Exit now pass an arg
+
+1994-05-24 18:00  millert
+
+       * visudo.c: signal handler now takes an int argument
+
+1994-05-24 18:00  millert
+
+       * CHANGES: updated
+
+1994-05-24 17:44  millert
+
+       * sudo.c: ok, the getcwd() is now *really* done as the user
+
+1994-05-24 17:44  millert
+
+       * configure.in: changed AIX STATIC_FLAGS
+
+1994-05-24 16:27  millert
+
+       * aclocal.m4: solaris now defines SVR4
+
+1994-05-24 16:18  millert
+
+       * sudo.h: added cwd and fixed stupid core dump that makes no sense.
+         sigh.
+
+1994-05-24 16:18  millert
+
+       * sudo.c: moved getcwd stuff into load_globals
+
+1994-05-24 16:18  millert
+
+       * parse.c: took out externs that are in suod.h
+
+1994-05-24 16:18  millert
+
+       * logging.c: moved cwd into load_globals
+
+1994-05-24 16:17  millert
+
+       * find_path.c: moved cwd stuff
+
+1994-05-24 15:55  millert
+
+       * Makefile.in: fixed make distclean & realclean
+
+1994-05-24 12:51  millert
+
+       * TODO: updated .,
+
+1994-05-24 12:51  millert
+
+       * CHANGES: added solaris changes
+
+1994-05-24 12:51  millert
+
+       * aclocal.m4: added solaris changes, need to rework
+
+1994-05-24 12:50  millert
+
+       * configure.in: cleaned up for solaris
+
+1994-05-24 12:13  millert
+
+       * logging.c: reinstall reapchild signal handler for non-bsd signals
+
+1994-05-24 12:03  millert
+
+       * sudo.h: took out getdtablesize() emulation for HP-UX (no longer
+         needed)
+
+1994-05-24 12:03  millert
+
+       * sudo.c: support for HAVE_SYSCONF
+
+1994-05-24 12:02  millert
+
+       * visudo.c: added <fcntl.h> for solaris & reorg'd the includes +
+         minor prettying up /
+
+1994-05-23 20:26  millert
+
+       * config.h.in: added HAVE_SYSCONF
+
+1994-05-16 18:57  millert
+
+       * configure.in: now tells you what os you are running /.
+
+1994-05-16 18:56  millert
+
+       * aclocal.m4: took out extra ','
+
+1994-05-14 17:56  millert
+
+       * config.h.in: added _BSD_COMPAT
+
+1994-05-14 17:56  millert
+
+       * aclocal.m4: fixed for irix5
+
+1994-05-14 17:55  millert
+
+       * CHANGES: updated
+
+1994-05-14 17:27  millert
+
+       * sudo.c: uid seinitialized to -2
+
+1994-04-28 12:36  millert
+
+       * sudo.c: now removes LIBPATH for AIX
+
+1994-03-12 20:41  millert
+
+       * configure.in: now uses ufc if it finds it
+
+1994-03-12 17:42  millert
+
+       * sudo.h: no longer define yyval & yylval since yacc does it
+
+1994-03-12 17:42  millert
+
+       * parse.lex: now defines yylval as extenr
+
+1994-03-12 17:41  millert
+
+       * configure.in: BROKEN_GETPASS is now an OPTION
+
+1994-03-12 17:41  millert
+
+       * config.h.in: took out BROKEN_GETPASS
+
+1994-03-12 17:20  millert
+
+       * Makefile.in: took out big comment
+
+1994-03-12 16:24  millert
+
+       * README: updated
+
+1994-03-12 16:20  millert
+
+       * Makefile.in: took out README.beta
+
+1994-03-12 16:19  millert
+
+       * SUPPORTED: Initial revision
+
+1994-03-12 16:19  millert
+
+       * INSTALL: now reference SUPPORTED .,
+
+1994-03-12 16:17  millert
+
+       * config.h.in: now check for convex OR __convex__
+
+1994-03-12 16:16  millert
+
+       * aclocal.m4: now check for convex or __convex__
+
+1994-03-12 16:15  millert
+
+       * Makefile.in: added dist target
+
+1994-03-12 15:19  millert
+
+       * aclocal.m4: use __convex__
+
+1994-03-12 14:33  millert
+
+       * find_path.c: now use _S_* stat stuff to be ansi-like
+
+1994-03-12 14:11  millert
+
+       * INSTALL: updated for configure directions
+
+1994-03-12 14:05  millert
+
+       * Makefile.in: distclean now removes config.h and pathnames.h
+
+1994-03-12 14:03  millert
+
+       * CHANGES: updated
+
+1994-03-12 14:00  millert
+
+       * TODO: fixed typoe
+
+1994-03-12 13:57  millert
+
+       * Makefile.in, visudo.c: updated version
+
+1994-03-12 13:57  millert
+
+       * config.h.in, pathnames.h.in: added copyright header
+
+1994-03-12 13:55  millert
+
+       * check.c, find_path.c, insults.h, logging.c, parse.c, parse.lex,
+         parse.yacc, sudo.c, sudo.h: udpated version
+
+1994-03-12 13:39  millert
+
+       * visudo.c: udpated to use configure + pathnames.h
+
+1994-03-12 13:37  millert
+
+       * Makefile.in, config.h.in, configure.in, aclocal.m4: updated
+
+1994-03-12 13:37  millert
+
+       * sudo.h: now works with configure
+
+1994-03-12 13:36  millert
+
+       * check.c, find_path.c, getpass.c, logging.c, parse.c, sudo.c:
+         updated to work with configure + pathnames.h
+
+1994-03-12 10:40  millert
+
+       * Makefile.in: added LEXLIB
+
+1994-03-10 03:18  millert
+
+       * COPYING: updated gnu general licence to versio 2
+
+1994-03-10 02:44  millert
+
+       * pathnames.h.in, config.h.in: Initial revision
+
+1994-03-10 01:43  millert
+
+       * sudo.h: changed to work with configure
+
+1994-03-09 18:51  millert
+
+       * Makefile.in, aclocal.m4, configure.in: Initial revision
+
+1994-03-09 17:36  millert
+
+       * visudo.c: now uses defines used by configure
+
+1994-03-01 16:31  millert
+
+       * find_path.c: sudo won't bitch about EPERM now, for real
+
+1994-02-28 00:36  millert
+
+       * logging.c: renamed exec_argv to eliminate a libc name clash with
+         ksros
+
+1994-02-28 00:28  millert
+
+       * CHANGES: corrected
+
+1994-02-28 00:27  millert
+
+       * logging.c, sudo.c, sudo.h: execve -> execv
+
+1994-02-27 23:27  millert
+
+       * TODO: upated
+
+1994-02-27 23:19  millert
+
+       * PORTING: added 2 mroe items
+
+1994-02-27 23:12  millert
+
+       * CHANGES: updated
+
+1994-02-27 23:11  millert
+
+       * sudo.h: added UMASK and mode_t declaration
+
+1994-02-27 23:11  millert
+
+       * sudo.c: added UMASK
+
+1994-02-27 20:55  millert
+
+       * logging.c: now opens log file with mode 077
+
+1994-02-27 20:55  millert
+
+       * check.c: saved current umask ans restores it
+
+1994-02-27 20:36  millert
+
+       * sudo.h: added MAXLOGFILELEN
+
+1994-02-27 20:35  millert
+
+       * logging.c: split long log lines.  FOr syslog, split into multiple
+         entries, for a log file, indent the extra for readability
+
+1994-02-27 17:22  millert
+
+       * CHANGES: added changes
+
+1994-02-27 17:18  millert
+
+       * sudo.h: MAXLOGLEN & MAXSYSLOGLEN are now different (as they
+         should be)
+
+1994-02-25 16:04  millert
+
+       * TODO: added input from Brett M Hogden <hogden@rge.com>
+
+1994-02-16 13:35  millert
+
+       * sudo.c: added rmenv() to remove stuff from environ.  can now uses
+         execvp() OR execve() becuase of this.
+
+1994-02-16 13:35  millert
+
+       * logging.c: now uses execvp() OR execve()
+
+1994-02-16 13:31  millert
+
+       * sudo.h: added USE_EXECVE
+
+1994-02-16 13:27  millert
+
+       * sudo.h: added environ
+
+1994-02-16 12:53  millert
+
+       * find_path.c: now ignore EPERM
+
+1994-02-15 23:52  millert
+
+       * sudo.h: moved some func decls out of sudo.h and into sudo.c as
+         statics /.
+
+1994-02-15 23:52  millert
+
+       * CHANGES: updated
+
+1994-02-15 23:40  millert
+
+       * sudo.h: took out Envp
+
+1994-02-14 12:28  millert
+
+       * BUGS: Initial revision
+
+1994-02-10 14:29  millert
+
+       * sudo.c, sudo.h, CHANGES: added SECURE_PATH
+
+1994-02-10 14:05  millert
+
+       * sudo.h: added SECURE_PATH
+
+1994-02-10 13:50  millert
+
+       * INSTALL: added sample.sudoers note
+
+1994-02-10 13:47  millert
+
+       * sudoers: Initial revision
+
+1994-02-09 14:54  millert
+
+       * find_path.c: fixed typo
+
+1994-02-08 23:06  millert
+
+       * PORTING: took out SAVED_UID garbage
+
+1994-02-08 22:55  millert
+
+       * INSTALL: mentioned HAL
+
+1994-02-08 22:50  millert
+
+       * sudo.h: added HAL line
+
+1994-02-08 22:48  millert
+
+       * insults.h: added HAL insults
+
+1994-02-08 22:48  millert
+
+       * TODO: updated
+
+1994-02-08 22:02  millert
+
+       * logging.c: more verbose error if mailer not found
+
+1994-02-08 22:02  millert
+
+       * check.c: now do getpwent as root for soem shadow password systems
+         (bsdi)
+
+1994-02-08 13:22  millert
+
+       * sudo.h: took out SAVED_UID garbade
+
+1994-02-08 13:21  millert
+
+       * sudo.c: took out SAVED_UID garbage since it don't work
+
+1994-02-06 17:43  millert
+
+       * README: updated
+
+1994-02-06 17:40  millert
+
+       * insults.h: added a missing space :-)
+
+1994-02-05 19:48  millert
+
+       * sudo.c, sudo.h: took out multimax cruft
+
+1994-02-05 19:30  millert
+
+       * INSTALL: minor update
+
+1994-02-05 19:30  millert
+
+       * PORTING: finished
+
+1994-02-05 19:19  millert
+
+       * sudo.c: fixed a typo + indentation
+
+1994-02-05 18:43  millert
+
+       * sudo.h: took outumoved some defines to the config file ,.  ,.
+
+1994-02-05 15:17  millert
+
+       * PORTING: Initial revision
+
+1994-02-05 15:17  millert
+
+       * TODO: did #6
+
+1994-02-05 15:16  millert
+
+       * sudo.h: added HAS_SAVED_UID
+
+1994-02-05 15:16  millert
+
+       * sudo.c: put back AIX cruft
+
+1994-02-03 00:44  millert
+
+       * sudo.c: aix changes
+
+1994-02-02 01:31  millert
+
+       * CHANGES: updated
+
+1994-02-02 01:30  millert
+
+       * check.c, logging.c, parse.c, sudo.c, sudo.h: now is only root
+         when abs necesary
+
+1994-02-01 22:21  millert
+
+       * check.c: added missing %s\n
+
+1994-01-31 02:06  millert
+
+       * install-sh: Initial revision
+
+1994-01-31 01:58  millert
+
+       * CHANGES, TODO: updated
+
+1994-01-31 01:56  millert
+
+       * sudo.c: now removed _RLD_* for alphas
+
+1994-01-31 01:50  millert
+
+       * INSTALL: updated for new config scheme
+
+1994-01-30 19:42  millert
+
+       * find_path.c: more verbose eror messages
+
+1994-01-27 14:08  millert
+
+       * TODO: now have solaris
+
+1994-01-27 14:07  millert
+
+       * sudo.h: define __svr4__ for SOLARIS
+
+1994-01-27 14:07  millert
+
+       * check.c: added svr4 junk for shadow pws for solaris 2.x
+
+1994-01-27 13:19  millert
+
+       * check.c, sudo.c: took out setuid(0) and setreuid(udi) garbage.
+         Its not needed since we start out setuid with the correct perms.
+
+1994-01-26 19:51  millert
+
+       * check.c, sudo.c, sudo.h: now use setreuid()
+
+1994-01-26 18:58  millert
+
+       * sudo.man: revised AUTHORS secrtion & added ENV_EDITOR stuff to
+         VARIABLES sectoin
+
+1994-01-26 18:52  millert
+
+       * visudo.c: now uses ENV_EDITOR if you want to use the EDITOR envar
+
+1994-01-26 18:52  millert
+
+       * sudo.h: now uses ENV_EDITOR if you want to use the EDITOR envar
+         >> .
+
+1993-12-07 01:33  millert
+
+       * README: minor update + spell fix
+
+1993-12-07 01:33  millert
+
+       * INSTALL: rewrote most of this
+
+1993-12-07 01:13  millert
+
+       * sudo.h: added all options that are in the Makefile
+
+1993-12-07 00:23  millert
+
+       * getpass.c: now use USE_TERMIO #define for sgi & hpux
+
+1993-12-06 23:19  millert
+
+       * TODO: todo: posix sigs
+
+1993-12-06 01:12  millert
+
+       * check.c, find_path.c: always include strings.h
+
+1993-12-05 20:34  millert
+
+       * visudo.c: added STATICEDITOR
+
+1993-12-05 20:30  millert
+
+       * sudo.h: sgi has vi in /usr/bin too
+
+1993-12-05 20:23  millert
+
+       * sudo.man: added VISUAL
+
+1993-12-02 22:20  millert
+
+       * sudo.h: sue /usr/bin/vi on some systems
+
+1993-12-02 22:19  millert
+
+       * sudo.c: fixed warning (include strings.h)
+
+1993-12-02 22:06  millert
+
+       * sudo.man: added John_Rouillard@dl5000.bc.edu's changes (new
+         features)
+
+1993-12-02 21:38  millert
+
+       * CHANGES: changes from John_Rouillard@dl5000.bc.edu
+
+1993-12-02 21:35  millert
+
+       * visudo.c: added EDITOR envar
+
+1993-12-02 21:34  millert
+
+       * check.c, find_path.c, parse.c, sudo.c: added patches from
+         John_Rouillard      directory spec  uses EDITOR
+
+1993-12-01 19:32  millert
+
+       * getpass.c: added flush for hpux
+
+1993-11-30 13:37  millert
+
+       * sudo.c: no longer assume malloc returns a char *
+
+1993-11-29 20:35  millert
+
+       * sudo.c: alpha change to remove LD_-like thing fixed SHLIB_PATH
+         stuff -- now gets removed correctly
+
+1993-11-29 19:31  millert
+
+       * sudo.h: added STD_HEADERS macro
+
+1993-11-29 19:14  millert
+
+       * sudo.c: now uses STD_HEADERS macor for ansi
+
+1993-11-29 19:14  millert
+
+       * find_path.c: now uses STD_HEADERS macro
+
+1993-11-29 19:13  millert
+
+       * check.c: niceties for C compiler bitches -- no real change
+
+1993-11-29 13:04  millert
+
+       * visudo.c: now doesn't fclose a file never opened.
+
+1993-11-28 16:35  millert
+
+       * sudo.man: added visudo line
+
+1993-11-28 16:31  millert
+
+       * sudo.man: added error stuff added me in there...
+
+1993-11-28 03:12  millert
+
+       * CHANGES: noted insults
+
+1993-11-28 03:01  millert
+
+       * INSTALL: added blurb about reading stuff
+
+1993-11-28 03:00  millert
+
+       * sudo.h: added insults
+
+1993-11-28 03:00  millert
+
+       * insults.h: corrected somments and removed newlines
+
+1993-11-28 03:00  millert
+
+       * check.c: now uses insults
+
+1993-11-28 02:45  millert
+
+       * insults.h: Initial revision
+
+1993-11-27 19:46  millert
+
+       * INSTALL: added dec syslog note
+
+1993-11-27 19:25  millert
+
+       * sample.sudoers: added real stuff in there
+
+1993-11-27 19:24  millert
+
+       * TODO: added a todo
+
+1993-11-27 19:10  millert
+
+       * TODO: added one
+
+1993-11-27 18:59  millert
+
+       * sample.sudoers: Initial revision
+
+1993-11-27 18:59  millert
+
+       * sudo.man: updated with changes
+
+1993-11-27 18:52  millert
+
+       * sudo.man: Initial revision
+
+1993-11-27 18:48  millert
+
+       * CHANGES, COPYING, INSTALL, README, TODO, indent.pro: Initial
+         revision
+
+1993-11-27 18:46  millert
+
+       * visudo.c: updated version number and took out jeff's old addr
+         since it is no good
+
+1993-11-27 18:42  millert
+
+       * sudo.h, check.c, find_path.c, logging.c, parse.c, parse.lex,
+         parse.yacc, sudo.c: updated version number and took out jeff's
+         email (since it is invalid)
+
+1993-10-28 09:36  millert
+
+       * check.c: added fflush()
+
+1993-10-22 20:46  millert
+
+       * find_path.c: now return NULL instead pf\b\bof exiting for
+         nopn\b\bn-fatal errors
+
+1993-10-21 16:57  millert
+
+       * check.c: new banner
+
+1993-10-21 16:42  millert
+
+       * parse.lex: now sudo.h gets included first
+
+1993-10-17 20:31  millert
+
+       * parse.lex: now can use flex
+
+1993-10-17 20:31  millert
+
+       * sudo.h: linux patch
+
+1993-10-17 20:30  millert
+
+       * sudo.c: hpux 9 fix, removes SHLIB_PATH linux patch
+
+1993-10-17 20:30  millert
+
+       * check.c: linux diff
+
+1993-10-15 16:03  millert
+
+       * find_path.c: stat now ignores EINVAL
+
+1993-10-05 21:48  millert
+
+       * find_path.c, sudo.c: now declare strdup as extern
+
+1993-10-04 15:23  millert
+
+       * visudo.c: reformatted with indent + by hand
+
+1993-10-04 15:10  millert
+
+       * check.c, find_path.c, getpass.c, logging.c, parse.c, sudo.c,
+         sudo.h: used indent to "fix" coding style
+
+1993-10-03 20:12  millert
+
+       * find_path.c: now checks '.' or '.' or '' in PATH -- but does it
+         LAST should maybe move the code that does this into the loop
+         body.  makes it messier tho.  hmmm.
+
+1993-09-08 11:53  millert
+
+       * find_path.c: redid the fix for non-executable files in an easier
+         to read way plus some minor aethetic changes
+
+1993-09-08 11:39  millert
+
+       * find_path.c: fixed bug with non-executable tings of same name in
+         path introduced by checkig errno after stat(2).
+
+1993-09-05 10:02  millert
+
+       * sudo.c: fixed off by one error
+
+1993-09-05 09:55  millert
+
+       * find_path.c: now handles decending below '/' correctly
+
+1993-09-05 08:35  millert
+
+       * sudo.c: now actually builds Envp instead of munging envp
+
+1993-09-04 15:42  millert
+
+       * parse.yacc: now  includes sys/param.h
+
+1993-09-04 15:41  millert
+
+       * visudo.c: now includes sys/param.h
+
+1993-09-04 15:30  millert
+
+       * sudo.h: fixed ifndef -> ifdef
+
+1993-09-04 15:19  millert
+
+       * qualify.c: make more like find_path.c
+
+1993-09-04 15:18  millert
+
+       * find_path.c: rewritten by millert
+
+1993-09-04 15:17  millert
+
+       * sudo.h: fixed MAXCOMMANDLENGTH now uses USE_CWD and NEED_STRDUP
+         added info about new defines in the comment
+
+1993-09-04 15:15  millert
+
+       * logging.c: now uses USE_CWD
+
+1993-09-04 14:10  millert
+
+       * sudo.h: added delc for clean_envp() and Envp
+
+1993-09-04 14:09  millert
+
+       * sudo.c: now rips LD_* env vars out of envp and passed sanitized
+         Envp to exec
+
+1993-09-04 14:09  millert
+
+       * logging.c: now uses execve()
+
+1993-09-04 14:08  millert
+
+       * find_path.c: ENOTDIR is ok now too (in case part of the path is
+         bogus)
+
+1993-09-04 08:17  millert
+
+       * qualify.c: now works correctly (ttaltotal rewrite)
+
+1993-09-04 07:59  millert
+
+       * parse.lex: now includes sys/param.h didn't match trailing / --
+         fix from rouilj@cs.umb.edu
+
+1993-06-11 18:04  millert
+
+       * sudo.c: moved around the #ifndef _AIX
+
+1993-06-11 18:03  millert
+
+       * check.c, logging.c, parse.c: Initial revision
+
+1993-03-20 07:57  millert
+
+       * qualify.c: Initial revision
+
+1993-03-13 15:09  millert
+
+       * find_path.c: now works if you do sudo bin/test
+
+1993-03-13 14:20  millert
+
+       * find_path.c: works
+
+1993-03-02 18:28  millert
+
+       * sudo.h: Initial revision
+
+1993-03-02 11:35  millert
+
+       * visudo.c: Initial revision
+
+1993-03-02 11:32  millert
+
+       * parse.lex, parse.yacc: Initial revision
+
+1993-02-16 13:24  millert
+
+       * sudo.c: took out errno.h
+
+1993-02-16 13:22  millert
+
+       * sudo.c: now spews error if exec fails and exits with -1
+
+1993-02-16 12:07  millert
+
+       * sudo.c: Initial revision
+
+1993-02-15 22:27  millert
+
+       * find_path.c: now only execs files with (an) executable bit set.
+
+1993-02-15 22:01  millert
+
+       * find_path.c: Initial revision
+
+1993-02-15 14:32  millert
+
+       * getpass.c: added nice comment
+
+1993-02-15 14:19  millert
+
+       * getpass.c: now works on sgi's
+
+1993-02-15 13:57  millert
+
+       * getpass.c: Initial revision
+
diff --git a/HISTORY b/HISTORY
index 17d0b79416a9d2f058cc307949ce9f6fee50bb51..f9a12b2c38a80e3200914131d4cbda7bc23d5643 100644 (file)
--- a/HISTORY
+++ b/HISTORY
@@ -1,47 +1,49 @@
-A Brief history of sudo(8):
-
-Sudo was first conceived and implemented by Bob Coggeshall and Cliff
-Spencer around 1980 at the Department of Computer Science at
-SUNY/Buffalo.  It ran on a VAX-11/750 running 4.1BSD.  An updated
-version, credited to Phil Betchel, Cliff Spencer, Gretchen Phillips,
-John LoVerso and Don Gworek, was posted to the net.sources newsgroup
-in December of 1985.
-
-In the Summer of 1986, Garth Snyder released an enhanced version
-of sudo. For the next 5 years, sudo was fed and watered by a handful
-of folks at CU-Boulder, including Bob Coggeshall, Bob Manchek, and
-Trent Hein.
-
-In 1991, Dave Hieb and Jeff Nieusma wrote a new version of sudo
-with an enhanced sudoers format under contract to a consulting firm
-called "The Root Group".  This version was later released under the
-GNU public license.
-
-In 1994, after maintaining sudo informally within CU-Boulder for
-some time, Todd Miller made a public release of "CU sudo" (version
-1.3) with bug fixes and support for more operating systems.  The
-"CU" was added to differentiate it from the "official" version from
-"The Root Group".
-
-In 1996, Todd, who had been maintaining sudo for several years in
-his spare time, brought sudo development under the umbrella of his
-consulting firm, Courtesan Consulting.  Courtesan remains committed
-to a free sudo and is sponsoring another sudo rewrite as well as
-continued development of the sudo 1.x code base.
-
-In 1999, the "CU" prefix was dropped from the name since there has
-been no formal release of sudo from "The Root Group" since 1991
-(the original authors now work elsewhere).  As of version 1.6, Sudo
-no longer contains any of the original "Root Group" code and is
-available under an ISC-style license.
-
-In 2004, Todd incorporated as GratiSoft, Inc. to provide commercial
-support and enhancements to the sudo community.
-
-In 2005, GratiSoft was put on hold.
+A brief history of sudo:
+
+Sudo was first conceived and implemented by Bob Coggeshall and Cliff Spencer
+around 1980 at the Department of Computer Science at SUNY/Buffalo. It ran on
+a VAX-11/750 running 4.1BSD. An updated version, credited to Phil Betchel,
+Cliff Spencer, Gretchen Phillips, John LoVerso and Don Gworek, was posted to
+the net.sources Usenet newsgroup in December of 1985.
+
+In the Summer of 1986, Garth Snyder released an enhanced version of sudo.
+For the next 5 years, sudo was fed and watered by a handful of folks at
+CU-Boulder, including Bob Coggeshall, Bob Manchek, and Trent Hein.
+
+In 1991, Dave Hieb and Jeff Nieusma wrote a new version of sudo with an
+enhanced sudoers format under contract to a consulting firm called "The Root
+Group". This version was later released under the GNU public license.
+
+In 1994, after maintaining sudo informally within CU-Boulder for some time,
+Todd Miller made a public release of "CU sudo" (version 1.3) with bug fixes
+and support for more operating systems. The "CU" was added to differentiate
+it from the "official" version from "The Root Group".
+
+In 1995, a new parser for the sudoers file was contributed by Chris Jepeway.
+The new parser was a proper grammar (unlike the old one) and could work with
+both sudo and visudo (previously they had slightly different parsers).
+
+In 1996, Todd, who had been maintaining sudo for several years in his spare
+time, moved distribution of sudo from a CU-Boulder ftp site to his domain,
+courtesan.com.
+
+In 1999, the "CU" prefix was dropped from the name since there has been no
+formal release of sudo from "The Root Group" since 1991 (the original
+authors now work elsewhere). As of version 1.6, Sudo no longer contains any
+of the original "Root Group" code and is available under an ISC-style
+license.
+
+In 2001, the sudo web site, ftp site and mailing lists were moved from
+courtesan.com to the sudo.ws domain (sudo.org was already taken).
+
+In 2005, Todd rewrote the sudoers parser to better support the features that
+had been added in the past ten years. This new parser removes some
+limitations of the previous one, removes ordering constraints and adds
+support for including multiple sudoers files.
 
 sudo, in its current form, is maintained by:
 
-       Todd Miller <Todd.Miller@courtesan.com>
+        Todd Miller <Todd.Miller@courtesan.com>
 
 Todd continues to enhance sudo and fix bugs.
+
diff --git a/INSTALL b/INSTALL
index 1692887912e1b9deaba49606cedf0ef10fa6f4df..2ffb8f214b1580574e77781c92541a0641047b38 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -1,5 +1,5 @@
-Installation instructions for Sudo 1.6.9
-========================================
+Installation instructions for Sudo 1.7
+======================================
 
 Sudo uses a `configure' script to probe the capabilities and type
 of the system in question.  In this release, `configure' takes many
@@ -189,6 +189,12 @@ Special features/options:
        this file instead of /etc/ldap.secret to read the secret password
        when rootbinddn is specified in the ldap config file.
 
+  --with-nsswitch[=filename]
+       Path to nsswitch.conf or "no" to disable nsswitch support.
+       If specified, sudo uses this file instead of /etc/nsswitch.conf.
+       If nsswitch is disabled but LDAP is enabled, sudo will check
+       LDAP first, then the sudoers file.
+
   --with-aixauth
        Enable support for the AIX 4.x general authentication function.
        This will use the authentication scheme specified for the user
@@ -200,7 +206,7 @@ Special features/options:
        Linux, Solaris and HP-UX (version 11 and higher).
 
        NOTE: on RedHat Linux and Fedora you *must* have an /etc/pam.d/sudo
-       file installed.  You may either use the sample.pam file included with
+       file install.  You may either use the sample.pam file included with
        sudo or use /etc/pam.d/su as a reference.  The sample.pam file
        included with sudo may or may not work with other Linux distributions.
        On Solaris and HP-UX 11 systems you should check (and understand)
@@ -228,10 +234,6 @@ Special features/options:
        unless the 'use_loginclass' option is defined in sudoers or the user
        specifies a class on the command line.
 
-  --with-project
-         Enable support for Solaris project resource limits.
-         This option is only available on Solaris 9 and above.
-
   --with-bsdauth
        Enable support for BSD authentication.  This is the default
        for BSD/OS and OpenBSD systems that support it.
@@ -241,6 +243,10 @@ Special features/options:
        is supported.  If you don't have /usr/include/bsd_auth.h
        then you cannot use this.
 
+  --with-project
+       Enable support for Solaris project resource limits.
+       This option is only available on Solaris 9 and above.
+
   --with-noexec[=PATH]
        Enable support for the "noexec" functionality which prevents
        a dynamically-linked program being run by sudo from executing
@@ -522,6 +528,13 @@ The following options are also configurable at runtime:
        option.  visudo will then only use the VISUAL or EDITOR variables
        if they match a value specified via --with-editor.
 
+  --with-askpass=PATH
+        Set PATH as the "askpass" program to use when no tty is
+        available.  Typically, this is a graphical password prompter,
+        similar to the one used by ssh.  The program must take a
+        prompt as an argument and print the received password to
+        the standard output.
+
   --disable-authentication
        By default, sudo requires the user to authenticate via a
        password or similar means.  This options causes sudo to
@@ -533,6 +546,13 @@ The following options are also configurable at runtime:
        "chaining" sudo commands to get a root shell by doing something
        like "sudo sudo /bin/sh".
 
+  --enable-gss-krb5-ccache-name
+        Use the gss_krb5_ccache_name() function to set the Kerberos
+        V credential cache file name.  By default, sudo will use
+        the KRB5CCNAME environment variable to set this.  While
+        gss_krb5_ccache_name() provides a better API to do this it
+        is not supported by all Kerberos V and SASL combinations.
+
   --enable-log-host
        Log the hostname in the log file.
 
@@ -702,6 +722,11 @@ HP-UX:
     noexec to work.  Binary packages of gcc are available from
     http://hpux.connect.org.uk/ and http://hpux.cs.utah.edu/.
 
+    To prevent PAM from overriding the value of umask on HP-UX 11,
+    you will need to add a line like the following to /etc/pam.conf:
+
+    sudo       session required        libpam_hpsec.so.1 bypass_umask
+
 SunOS 4.x:
     The /bin/sh shipped with SunOS blows up while running configure.
     You can work around this by installalling bash or zsh.  If you
diff --git a/LICENSE b/LICENSE
index 69266beec3eaa39c8916fee50e96515bc56e94b1..786b7a096eee5a953eaf9e9ad528c38d567fbce7 100644 (file)
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,7 @@
 Sudo is distributed under the following ISC-style license:
 
-   Copyright (c) 1994-1996,1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+   Copyright (c) 1994-1996, 1998-2008
+        Todd C. Miller <Todd.Miller@courtesan.com>
 
    Permission to use, copy, modify, and distribute this software for any
    purpose with or without fee is hereby granted, provided that the above
@@ -18,11 +19,11 @@ Sudo is distributed under the following ISC-style license:
    Agency (DARPA) and Air Force Research Laboratory, Air Force
    Materiel Command, USAF, under agreement number F39502-99-1-0512.
 
-Additionally, fnmatch.c, fnmatch.h, getcwd.c, glob.c, glob.h, mkstemp.c
-and snprintf.c bear the following UCB license:
+Additionally, fnmatch.c, fnmatch.h, getcwd.c, glob.c, glob.h and snprintf.c
+bear the following UCB license:
 
    Copyright (c) 1987, 1989, 1990, 1991, 1992, 1993, 1994
-       The Regents of the University of California.  All rights reserved.
+        The Regents of the University of California.  All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
index 1650803fe2a81674e24b1123de51942454364eaf..c097af7eee1be95871e24e93f5373c6ad1bce6c1 100644 (file)
@@ -1,5 +1,6 @@
 #
-# Copyright (c) 1996, 1998-2007 Todd C. Miller <Todd.Miller@courtesan.com>
+# Copyright (c) 1996, 1998-2005, 2007-2008
+#      Todd C. Miller <Todd.Miller@courtesan.com>
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
 #
 # @configure_input@
 #
-# $Sudo: Makefile.in,v 1.246.2.32 2008/06/22 20:29:03 millert Exp $
+# $Sudo: Makefile.in,v 1.326 2008/12/03 20:40:47 millert Exp $
 #
 
 #### Start of system configuration section. ####
 
 srcdir = @srcdir@
+devdir = @devdir@
 authdir = $(srcdir)/auth
 top_builddir = .
-VPATH = @srcdir@
 
 # Compiler & tools to use
 CC = @CC@
 LEX = flex
 YACC = @YACC@
-NROFF = nroff
+NROFF = nroff -Tascii
 LIBTOOL = @LIBTOOL@
 
 # Our install program supports extra flags...
@@ -61,11 +62,11 @@ exec_prefix = @exec_prefix@
 bindir = @bindir@
 sbindir = @sbindir@
 sysconfdir = @sysconfdir@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
 mandir = @mandir@
 noexecfile = @NOEXECFILE@
 noexecdir = @NOEXECDIR@
-libexecdir = @libexecdir@
-datarootdir = @datarootdir@
 
 # Directory in which to install sudo.
 sudodir = $(bindir)
@@ -93,7 +94,7 @@ sudoers_gid = @SUDOERS_GID@
 sudoers_mode = @SUDOERS_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\" -DSUDOERS_UID=$(sudoers_uid) -DSUDOERS_GID=$(sudoers_gid) -DSUDOERS_MODE=$(sudoers_mode)
 
 #### End of system configuration section. ####
 
@@ -101,60 +102,68 @@ SHELL = /bin/sh
 
 PROGS = @PROGS@
 
-SRCS = alloc.c alloca.c check.c closefrom.c def_data.c defaults.c env.c err.c \
-       fileops.c find_path.c fnmatch.c getcwd.c getprogname.c getspwuid.c \
-       gettime.c glob.c goodpath.c interfaces.c ldap.c lex.yy.c lsearch.c \
-       logging.c memrchr.c mkstemp.c parse.c parse.lex parse.yacc set_perms.c \
-       sigaction.c snprintf.c strcasecmp.c strerror.c strlcat.c strlcpy.c \
-       sudo.c sudo_noexec.c sudo.tab.c sudo_edit.c testsudoers.c tgetpass.c \
-       utimes.c visudo.c zero_bytes.c selinux.c sesh.c $(AUTH_SRCS)
+SRCS = aix.c alias.c alloc.c check.c closefrom.c def_data.c defaults.c env.c \
+       error.c fileops.c find_path.c fnmatch.c getcwd.c getprogname.c \
+       getspwuid.c gettime.c glob.c goodpath.c gram.c gram.y interfaces.c \
+       isblank.c lbuf.c ldap.c list.c logging.c match.c mkstemp.c memrchr.c \
+       parse.c pwutil.c  set_perms.c sigaction.c snprintf.c strcasecmp.c \
+       strerror.c strlcat.c strlcpy.c sudo.c sudo_noexec.c sudo_edit.c \
+       sudo_nss.c testsudoers.c tgetpass.c toke.c toke.l tsgetgrpw.c utimes.c \
+       visudo.c zero_bytes.c redblack.c selinux.c sesh.c $(AUTH_SRCS)
 
 AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/bsdauth.c auth/dce.c auth/fwtk.c \
            auth/kerb4.c auth/kerb5.c auth/pam.c auth/passwd.c auth/rfc1938.c \
            auth/secureware.c auth/securid.c auth/securid5.c auth/sia.c \
            auth/sudo_auth.c
 
-HDRS = compat.h def_data.h defaults.h ins_2001.h ins_classic.h ins_csops.h \
-       ins_goons.h insults.h interfaces.h logging.h parse.h sudo.h sudo.tab.h \
-       version.h auth/sudo_auth.h emul/err.h emul/fnmatch.h emul/search.h \
-       emul/utime.h emul/glob.h emul/timespec.h
+HDRS = compat.h def_data.h defaults.h error.h ins_2001.h ins_classic.h \
+       ins_csops.h ins_goons.h insults.h interfaces.h lbuf.h list.h \
+       logging.h parse.h sudo.h sudo_nss.h gram.h version.h auth/sudo_auth.h \
+       emul/charclass.h emul/fnmatch.h emul/glob.h emul/timespec.h \
+       emul/utime.h redblack.h
 
 AUTH_OBJS = sudo_auth.o @AUTH_OBJS@
 
-PARSEOBJS = sudo.tab.o lex.yy.o alloc.o defaults.o
+# Note: gram.o must come first here
+COMMON_OBJS = gram.o alias.o alloc.o defaults.o error.o list.o match.o \
+             toke.o redblack.o zero_bytes.o
 
-SUDOBJS = check.o env.o getspwuid.o gettime.o goodpath.o fileops.o find_path.o \
-         interfaces.o logging.o parse.o set_perms.o sudo.o sudo_edit.o \
-         tgetpass.o zero_bytes.o @SUDO_OBJS@ $(AUTH_OBJS) $(PARSEOBJS)
+SUDO_OBJS = $(COMMON_OBJS) $(AUTH_OBJS) @SUDO_OBJS@ check.o env.o \
+           getspwuid.o gettime.o goodpath.o fileops.o find_path.o \
+           interfaces.o lbuf.o logging.o parse.o pwutil.o set_perms.o \
+           sudo.o sudo_edit.o sudo_nss.o tgetpass.o
 
-VISUDOBJS = visudo.o fileops.o gettime.o goodpath.o find_path.o $(PARSEOBJS)
+VISUDO_OBJS = $(COMMON_OBJS) visudo.o fileops.o gettime.o goodpath.o \
+             find_path.o pwutil.o
 
-TESTOBJS = interfaces.o testsudoers.o $(PARSEOBJS)
+TEST_OBJS = $(COMMON_OBJS) interfaces.o testsudoers.o tsgetgrpw.o tspwutil.o
 
-LIBOBJS = @LIBOBJS@ @ALLOCA@
+LIB_OBJS = @LIBOBJS@
 
-VERSION = 1.6.9p17
+VERSION = 1.7.0
 
-DISTFILES = $(SRCS) $(HDRS) BUGS CHANGES HISTORY INSTALL INSTALL.configure \
-            LICENSE Makefile.in PORTING README README.LDAP \
-            TROUBLESHOOTING UPGRADE aclocal.m4 acsite.m4 aixcrypt.exp \
-            config.guess config.h.in config.sub configure configure.in \
-            def_data.in fnmatch.3 indent.pro install-sh ltmain.sh \
-            mkdefaults mkinstalldirs pathnames.h.in sample.pam \
-            sample.syslog.conf sample.sudoers schema.OpenLDAP \
-            schema.iPlanet sudo.cat sudo.man.in sudo.pod sudoers \
-            sudoers.cat sudoers.man.in sudoers.pod sudoers2ldif \
-            visudo.cat visudo.man.in visudo.pod auth/API
+DISTFILES = $(SRCS) $(HDRS) ChangeLog HISTORY INSTALL INSTALL.configure \
+            LICENSE Makefile.in PORTING README README.LDAP TROUBLESHOOTING \
+           UPGRADE WHATSNEW aclocal.m4 acsite.m4 aixcrypt.exp config.guess \
+           config.h.in config.sub configure configure.in def_data.in \
+           indent.pro install-sh ltmain.sh mkdefaults mkinstalldirs \
+           pathnames.h.in sample.pam sample.syslog.conf sample.sudoers \
+           schema.ActiveDirectory schema.OpenLDAP schema.iPlanet sudo.cat \
+           sudo.man.in sudo.pod sudo.psf sudo_usage.h.in sudoers sudoers.cat \
+            sudoers.man.in sudoers.pod sudoers.ldap.cat sudoers.ldap.man.in \
+           sudoers.ldap.pod sudoers2ldif visudo.cat visudo.man.in visudo.pod \
+           auth/API
 
-BINFILES= BUGS CHANGES HISTORY LICENSE README TROUBLESHOOTING \
+BINFILES= ChangeLog HISTORY LICENSE README TROUBLESHOOTING \
          UPGRADE install-sh mkinstalldirs sample.syslog.conf sample.sudoers \
          sudo sudo.cat sudo.man sudo.pod sudoers sudoers.cat sudoers.man \
          sudoers.pod visudo visudo.cat visudo.man visudo.pod
 
-BINSPECIAL= INSTALL.binary Makefile.binary libtool
+BINSPECIAL= INSTALL.binary Makefile.binary.in libtool
 
 SUDODEP = $(srcdir)/sudo.h $(srcdir)/compat.h $(srcdir)/defaults.h \
-         $(srcdir)/logging.h config.h def_data.h pathnames.h
+         $(srcdir)/error.h $(srcdir)/list.h $(srcdir)/logging.h \
+         $(srcdir)/sudo_nss.h $(devdir)/def_data.h pathnames.h config.h
 
 AUTHDEP = $(SUDODEP) $(authdir)/sudo_auth.h
 
@@ -163,7 +172,7 @@ INSDEP = $(srcdir)/ins_2001.h $(srcdir)/ins_classic.h $(srcdir)/ins_csops.h \
 
 all: $(PROGS)
 
-.SUFFIXES: .o .c .h .lex .yacc .man .cat .lo
+.SUFFIXES: .o .c .h .l .y .man .cat .lo
 
 .c.o:
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $<
@@ -173,16 +182,16 @@ all: $(PROGS)
 
 .man.cat:
        @rm -f $(srcdir)/$@
-       $(NROFF) -man $< > $(srcdir)/$@
+       sed '1s/^/.if n .ll 78n/' $< | $(NROFF) -man > $(srcdir)/$@
 
-sudo: $(SUDOBJS) $(LIBOBJS)
-       $(CC) -o $@ $(SUDOBJS) $(LIBOBJS) $(SUDO_LDFLAGS) $(SUDO_LIBS)
+sudo: $(SUDO_OBJS) $(LIB_OBJS)
+       $(CC) -o $@ $(SUDO_OBJS) $(LIB_OBJS) $(SUDO_LDFLAGS) $(SUDO_LIBS)
 
-visudo: $(VISUDOBJS) $(LIBOBJS)
-       $(CC) -o $@ $(VISUDOBJS) $(LIBOBJS) $(LDFLAGS) $(LIBS) $(NET_LIBS)
+visudo: $(VISUDO_OBJS) $(LIB_OBJS)
+       $(CC) -o $@ $(VISUDO_OBJS) $(LIB_OBJS) $(LDFLAGS) $(LIBS) $(NET_LIBS)
 
-testsudoers: $(TESTOBJS) $(LIBOBJS)
-       $(CC) -o $@ $(TESTOBJS) $(LIBOBJS) $(LDFLAGS) $(LIBS) $(NET_LIBS)
+testsudoers: $(TEST_OBJS) $(LIB_OBJS)
+       $(CC) -o $@ $(TEST_OBJS) $(LIB_OBJS) $(LDFLAGS) $(LIBS) $(NET_LIBS)
 
 sudo_noexec.lo: $(srcdir)/sudo_noexec.c
        $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_noexec.c
@@ -191,61 +200,129 @@ sudo_noexec.la: sudo_noexec.lo
        $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ sudo_noexec.lo -avoid-version -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
+@DEV@GENERATED = gram.h gram.c toke.c def_data.c def_data.h
 
-# Uncomment the following if you intend to modify parse.yacc
-@DEV@sudo.tab.c sudo.tab.h: parse.yacc
-@DEV@  rm -f sudo.tab.h sudo.tab.c
-@DEV@  $(YACC) -d -b sudo $(srcdir)/parse.yacc
+# Uncomment the lines before -@true if you intend to modify gram.y
+$(devdir)/gram.c: $(srcdir)/gram.y
+@DEV@  $(YACC) -d $(srcdir)/gram.y
+@DEV@  mv -f y.tab.c gram.c
+@DEV@  if cmp -s y.tab.h gram.h; then rm -f y.tab.h; else mv -f y.tab.h gram.h; fi
+       -@true
 
-# Uncomment the following if you intend to modify parse.lex
-@DEV@lex.yy.c: parse.lex
-@DEV@  rm -f lex.yy.c
-@DEV@  $(LEX) $(srcdir)/parse.lex
+# Uncomment the lines before -@true if you intend to modify toke.l
+$(devdir)/toke.c: $(srcdir)/toke.l
+@DEV@  $(LEX) $(srcdir)/toke.l
+@DEV@  mv -f lex.yy.c toke.c
+       -@true
 
 # Uncomment the following if you intend to modify def_data.in
-@DEV@def_data.h def_data.c: def_data.in
+@DEV@$(devdir)/def_data.h $(devdir)/def_data.c: $(srcdir)/def_data.in
 @DEV@  perl $(srcdir)/mkdefaults -o def_data $(srcdir)/def_data.in
 
 # Dependencies (not counting auth functions)
-alloc.o: alloc.c $(SUDODEP)
-check.o: check.c $(SUDODEP)
-closefrom.o: closefrom.c config.h
-env.o: env.c $(SUDODEP)
-err.o: err.c config.h compat.h emul/err.h
-fileops.o: fileops.c $(SUDODEP)
-find_path.o: find_path.c $(SUDODEP)
-getprogname.o: getprogname.c config.h
-getspwuid.o: getspwuid.c $(SUDODEP)
-goodpath.o: goodpath.c $(SUDODEP)
-logging.o: logging.c $(SUDODEP)
-set_perms.o: set_perms.c $(SUDODEP)
-tgetpass.o: tgetpass.c $(SUDODEP)
-visudo.o: visudo.c $(SUDODEP) version.h
-sudo.o: sudo.c $(SUDODEP) interfaces.h version.h
-interfaces.o: interfaces.c $(SUDODEP) interfaces.h
-testsudoers.o: testsudoers.c $(SUDODEP) parse.h interfaces.h
-parse.o: parse.c $(SUDODEP) parse.h interfaces.h
-lex.yy.o: lex.yy.c $(SUDODEP) parse.h sudo.tab.h
-sudo.tab.o: sudo.tab.c $(SUDODEP) parse.h sudo.tab.c sudo.tab.h
-defaults.o: defaults.c $(SUDODEP) def_data.c auth/sudo_auth.h
-fnmatch.o: fnmatch.c config.h compat.h emul/fnmatch.h
-getcwd.o: getcwd.c config.h compat.h
-glob.o: glob.c config.h compat.h emul/glob.h
-lsearch.o: lsearch.c config.h compat.h emul/search.h
-memrchr.o: memrchr.c config.h compat.h
-mkstemp.o: mkstemp.c config.h compat.h
-selinux.o: selinux.c $(SUDODEP)
-snprintf.o: snprintf.c config.h compat.h
-strcasecmp.o: strcasecmp.c config.h
-strlcat.o: strlcat.c config.h
-strlcpy.o: strlcpy.c config.h
-strerror.o: strerror.c config.h
-utime.o: utime.c config.h pathnames.h compat.h emul/utime.h
-ldap.o: ldap.c $(SUDODEP) parse.h
-sudo_edit.o: sudo_edit.c $(SUDODEP)
-
-# Authentication functions live in "auth" dir and so need extra care
+aix.o: $(srcdir)/aix.c
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/aix.c
+alias.o: $(srcdir)/alias.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/redblack.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/alias.c
+alloc.o: $(srcdir)/alloc.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/alloc.c
+check.o: $(srcdir)/check.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/check.c
+closefrom.o: $(srcdir)/closefrom.c config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/closefrom.c
+defaults.o: $(srcdir)/defaults.c $(SUDODEP) $(srcdir)/def_data.c $(authdir)/sudo_auth.h $(devdir)/gram.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/defaults.c
+env.o: $(srcdir)/env.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/env.c
+error.o: $(srcdir)/error.c $(srcdir)/compat.h $(srcdir)/error.h config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/error.c
+fileops.o: $(srcdir)/fileops.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/fileops.c
+find_path.o: $(srcdir)/find_path.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/find_path.c
+fnmatch.o: $(srcdir)/fnmatch.c $(srcdir)/emul/fnmatch.h $(srcdir)/compat.h config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/fnmatch.c
+getcwd.o: $(srcdir)/getcwd.c $(srcdir)/compat.h config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getcwd.c
+getprogname.o: $(srcdir)/getprogname.c config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getprogname.c
+getspwuid.o: $(srcdir)/getspwuid.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getspwuid.c
+gettime.o: $(srcdir)/gettime.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/gettime.c
+glob.o: $(srcdir)/glob.c $(srcdir)/emul/glob.h $(srcdir)/compat.h config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/glob.c
+goodpath.o: $(srcdir)/goodpath.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/goodpath.c
+gram.o: $(devdir)/gram.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(devdir)/gram.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(devdir)/gram.c
+interfaces.o: $(srcdir)/interfaces.c $(SUDODEP) $(srcdir)/interfaces.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/interfaces.c
+isblank.o: $(srcdir)/isblank.c $(srcdir)/compat.h config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/isblank.c
+lbuf.o: $(srcdir)/lbuf.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/lbuf.c
+ldap.o: $(srcdir)/ldap.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/ldap.c
+list.o: $(srcdir)/list.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/list.c
+logging.o: $(srcdir)/logging.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/logging.c
+match.o: $(srcdir)/match.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/interfaces.h $(devdir)/gram.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/match.c
+memrchr.o: $(srcdir)/memrchr.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/memrchr.c
+mkstemp.o: $(srcdir)/mkstemp.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/mkstemp.c
+parse.o: $(srcdir)/parse.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(devdir)/gram.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/parse.c
+pwutil.o: $(srcdir)/pwutil.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/pwutil.c
+redblack.o: $(srcdir)/redblack.c $(SUDODEP) $(srcdir)/redblack.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/redblack.c
+set_perms.o: $(srcdir)/set_perms.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/set_perms.c
+sigaction.o: $(srcdir)/sigaction.c $(srcdir)/compat.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sigaction.c
+snprintf.o: $(srcdir)/snprintf.c $(srcdir)/compat.h config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/snprintf.c
+strcasecmp.o: $(srcdir)/strcasecmp.c $(srcdir)/compat.h  config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strcasecmp.c
+strerror.o: $(srcdir)/strerror.c $(srcdir)/compat.h config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strerror.c
+strlcat.o: $(srcdir)/strlcat.c $(srcdir)/compat.h config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strlcat.c
+strlcpy.o: $(srcdir)/strlcpy.c $(srcdir)/compat.h config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strlcpy.c
+selinux.o: $(srcdir)/selinux.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/selinux.c
+sudo.o: $(srcdir)/sudo.c $(SUDODEP) sudo_usage.h $(srcdir)/interfaces.h $(srcdir)/version.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo.c
+sudo_edit.o: $(srcdir)/sudo_edit.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_edit.c
+sudo_noexec.o: $(srcdir)/sudo_noexec.c $(srcdir)/compat.h config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_noexec.c
+sudo_nss.o: $(srcdir)/sudo_nss.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_nss.c
+testsudoers.o: $(srcdir)/testsudoers.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/interfaces.h $(devdir)/gram.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/testsudoers.c
+tgetpass.o: $(srcdir)/tgetpass.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/tgetpass.c
+toke.o: $(devdir)/toke.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(devdir)/gram.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(devdir)/toke.c
+tsgetgrpw.o: $(srcdir)/tsgetgrpw.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/tsgetgrpw.c
+utimes.o: $(srcdir)/utimes.c $(srcdir)/compat.h $(srcdir)/emul/utime.h config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/utimes.c
+visudo.o: $(srcdir)/visudo.c $(SUDODEP) $(srcdir)/version.h $(devdir)/gram.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/visudo.c
+zero_bytes.o: $(srcdir)/zero_bytes.c $(srcdir)/compat.h config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/zero_bytes.c
+
+# Private copy of pwutil.o with MYPW defined for testsudoers
+tspwutil.o: $(srcdir)/pwutil.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) -DMYPW -o tspwutil.o $(srcdir)/pwutil.c
+
 sudo_auth.o: $(authdir)/sudo_auth.c $(AUTHDEP) $(INSDEP)
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/sudo_auth.c
 afs.o: $(authdir)/afs.c $(AUTHDEP)
@@ -304,6 +381,24 @@ sudoers.man:: sudoers.man.in
 
 sudoers.cat: sudoers.man
 
+sudoers.ldap.man.in: $(srcdir)/sudoers.ldap.pod
+       @rm -f $(srcdir)/$@
+       ( cd $(srcdir); mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' sudoers.ldap.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectform --release=$(VERSION) --center="MAINTENANCE COMMANDS" sudoers.ldap.pod | sed -e "s/(5)/($$mansectform)/" -e "s/(8)/($$mansectsu)/" >> $@ )
+
+sudoers.ldap.man:: sudoers.ldap.man.in
+       CONFIG_FILES=$@ CONFIG_HEADERS= sh ./config.status
+
+sudoers.ldap.cat: sudoers.ldap.man
+
+@DEV@HISTORY: history.pod
+@DEV@  pod2text -l -i0 $> > $@
+@DEV@
+@DEV@LICENSE: license.pod
+@DEV@  pod2text -l -i0 $> | sed '1,2d' > $@
+
+ChangeLog:
+       cvs2cl --follow-only trunk
+
 install: install-dirs install-binaries @INSTALL_NOEXEC@ install-sudoers install-man
 
 install-dirs:
@@ -333,27 +428,22 @@ install-man:
        ln $(DESTDIR)$(mandirsu)/sudo.$(mansectsu) $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu)
        $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 @mansrcdir@/visudo.$(mantype) $(DESTDIR)$(mandirsu)/visudo.$(mansectsu)
        $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 @mansrcdir@/sudoers.$(mantype) $(DESTDIR)$(mandirform)/sudoers.$(mansectform)
+       @LDAP@$(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 @mansrcdir@/sudoers.ldap.$(mantype) $(DESTDIR)$(mandirform)/sudoers.ldap.$(mansectform)
 @MAN_POSTINSTALL@
 
 check:
        @echo nothing to check
 
-tags: $(SRCS)
-       ctags $(SRCS)
-
-TAGS: $(SRCS)
-       etags $(SRCS)
-
 clean:
-       -rm -f *.o $(PROGS) testsudoers core sudo.core visudo.core \
-              testsudoers.core
+       -rm -f *.o *.lo stamp-* $(PROGS) testsudoers core *.core core.*
 
 mostlyclean: clean
 
 distclean: clean
        -rm -rf Makefile pathnames.h config.h config.status config.cache \
-               config.log libtool sudo_noexec.lo .libs $(PARSESRCS) \
-               sudo.man sudoers.man visudo.man
+               config.log libtool sudo_noexec.lo .libs $(GENERATED) \
+               sudo.man sudoers.man sudoers.ldap.man visudo.man sudo_usage.h \
+               Makefile.binary
 
 clobber: distclean
 
@@ -394,9 +484,43 @@ bindist:
          fi ; \
          cp $(srcdir)/INSTALL.binary $$tdir/INSTALL ; \
          sh ./config.status --file=Makefile.binary && cp Makefile.binary $$tdir/Makefile ; \
-         strip sudo ; \
-         strip visudo ; \
+         strip $$tdir/sudo ; \
+         strip $$tdir/visudo ; \
          cd tmp.$$ARCH && tar Ocf ../sudo-$(VERSION)-$$ARCH.tar sudo-$(VERSION) && cd .. ; \
-         gzip --best sudo-$(VERSION)-$$ARCH.tar ; \
+         gzip -f --best sudo-$(VERSION)-$$ARCH.tar ; \
          rm -rf tmp.$$ARCH ; \
        )
+
+depot:
+       ( \
+         tdir=tmp.depot ; \
+         mkdir $$tdir ; \
+         for i in sudo visudo sudo.man visudo.man sudoers.man sudoers ChangeLog HISTORY LICENSE README TROUBLESHOOTING UPGRADE sample.syslog.conf sample.sudoers; do \
+           if [ -f $$i ]; then \
+             cp $$i $$tdir ; \
+           elif [ -f $(srcdir)/$$i ]; then \
+             cp $(srcdir)/$$i $$tdir ; \
+           else \
+             echo cannot find $$i ; \
+             exit 1 ; \
+           fi ; \
+         done ; \
+         if [ -f sudo_noexec.la ]; then \
+           cp libtool $$tdir ; \
+           $(LIBTOOL) --mode=install $(INSTALL) sudo_noexec.la `pwd`/$$tdir ; \
+         fi ; \
+         sed 's/@VERSION@/$(VERSION)/g' <$(srcdir)/sudo.psf >$$tdir/sudo.psf ; \
+         printf '#!/sbin/sh\nrm -f /usr/local/bin/sudoedit\nln /usr/local/bin/sudo /usr/local/bin/sudoedit\n' > $$tdir/sudo-exec.postinstall ; \
+         printf '#!/sbin/sh\nrm -f /usr/local/man/man1m/sudoedit.1m\nln /usr/local/man/man1m/sudo.1m /usr/local/man/man1m/sudoedit.1m\n' > $$tdir/sudo-man.postinstall ; \
+         printf '#!/sbin/sh\nif [ ! -s /etc/sudoers ]; then\n\techo installing /usr/local/doc/sudo/sudoers as /etc/sudoers\n\techo use /usr/local/sbin/visudo to configure sudo\n\tcp /usr/local/doc/sudo/sudoers /etc/sudoers\n\tchmod 440 /etc/sudoers\n\tchown root:root /etc/sudoers\nfi\n' > $$tdir/sudo-config.postinstall ; \
+         chmod 755 $$tdir/sudo-exec.postinstall $$tdir/sudo-man.postinstall $$tdir/sudo-config.postinstall ; \
+         strip $$tdir/sudo ; \
+         strip $$tdir/visudo ; \
+         cd $$tdir ; \
+         swpackage -x target_type=tape -d ../sudo-$(VERSION).depot -s sudo.psf ; \
+         cd .. ; \
+         gzip -f --best sudo-$(VERSION).depot; \
+         rm -rf tmp.depot ; \
+       )
+
+.PHONY:        ChangeLog
diff --git a/README b/README
index 4986b56aaf2ab72f4d14eb73e2fb6e7e2b7de50e..301ca5517586737da92f08ca5390394dffb15f15 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-This is Sudo version 1.6.9
+This is Sudo version 1.7.0
 
 The sudo philosophy
 ===================
@@ -80,15 +80,14 @@ for the appropriate links.
 
 Web page
 ========
-There is a sudo `web page' at http://www.sudo.ws/sudo/
-that contains an overview of sudo as well as pointers to BETA versions
-and other useful info.
+There is a sudo web page at http://www.sudo.ws/sudo/ that contains
+an overview of sudo, documentation, downloads, information about
+beta versions and other useful info.
 
 Bug reports
 ===========
-A list of known bugs may be found in the `BUGS' file.  If you have
-found what you believe to be a bug, you can file a bug report with
-the sudo bug database, on at web at http://www.sudo.ws/bugs/.
+If you have found what you believe to be a bug, you can file a bug
+report with the sudo bug database, on at web at http://www.sudo.ws/bugs/.
 
 Please read over the `TROUBLESHOOTING' file *before* submitting a
 bug report.  When reporting bugs, please be sure to include the
index df4ad2107ec62633268c254be87e52de17581164..85f05f54994bac5364963a2429492968d7fc26cb 100644 (file)
@@ -1,16 +1,27 @@
-This file explains how to use the optional LDAP functionality of SUDO to
+This file explains how to build the optional LDAP functionality of SUDO to
 store /etc/sudoers information.  This feature is distinct from LDAP passwords.
 
+For general sudo LDAP configuration details, see the sudoers.ldap manual that
+comes with the sudo distribution.  A pre-formatted version of the manual may
+be found in the sudoers.ldap.cat file.
+
+The sudo binary compiled with LDAP support should be totally backward
+compatible and be syntactically and source code equivalent to its
+non LDAP-enabled build.
+
 LDAP philosophy
 ===============
 As times change and servers become cheap, an enterprise can easily have 500+
 UNIX servers.  Using LDAP to synchronize Users, Groups, Hosts, Mounts, and
 others across an enterprise can greatly reduce the administrative overhead.
 
-Sudo in the past has only used a single local configuration file /etc/sudoers.
-Some have attempted to workaround this by synchronizing changes via
-RCS/CVS/RSYNC/RDIST/RCP/SCP and even NFS.  Many have asked for a Hesiod, NIS,
-or LDAP patch for sudo, so here is my attempt at LDAP'izing sudo.
+In the past, sudo has used a single local configuration file, /etc/sudoers.
+While the same sudoers file can be shared among machines, no built-in
+mechanism exists to distribute it.  Some have attempted to workaround this
+by synchronizing changes via CVS/RSYNC/RDIST/RCP/SCP and even NFS.
+
+By using LDAP for sudoers we gain a centrally administered, globally
+available configuration source for sudo.
 
 For information on OpenLDAP, please see http://www.openldap.org/.
 
@@ -22,75 +33,6 @@ server, structure and contents.
 Many times 'options' are used in this document to refer to sudoer 'defaults'.
 They are one and the same.
 
-Design Features
-===============
-
-  * Sudo no longer needs to read sudoers in its entirety.  Parsing of
-    /etc/sudoers requires the entire file to be read.  The LDAP feature of sudo
-    uses two (sometimes three) LDAP queries per invocation.  It never reads all
-    the sudoer entries in the LDAP store.  This makes it especially fast and
-    particularly usable in LDAP environments.  The first query is to parse
-    default options (see below).  The second is to match against the username or
-    groups a user belongs to.  (The special ALL tag is matched in this query
-    too.) If no match is made against the username, the third query pulls the
-    entries that match against user netgroups to compare back to the user.
-
-  * Sudo no longer blows up if there is a typo.  Parsing of /etc/sudoers can
-    still blow up when sudo is invoked.  However when using the LDAP feature of
-    sudo, LDAP syntax rules are applied before the data is uploaded into the
-    LDAP server, so proper syntax is always guaranteed!  One can of course still
-    insert a bogus hostname or username, but sudo will not care.
-
-  * Options inside of entries now override global default options.
-    /etc/sudoers allowed for only default options and limited options associated
-    with user/host/command aliases.  The syntax can be difficult for the newbie.
-    The LDAP feature attempts to simplify this and yet still provide maximum
-    flexibility.
-
-    Sudo first looks for an entry called 'cn=default' in the SUDOers container.
-    If found, the multi-valued sudoOption attribute is parsed the same way the
-    global 'Defaults' line in /etc/sudoers is parsed.
-
-    If on the second or third query, a response contains a sudoRole which
-    matches against the user, host, and command, then the matched object is
-    scanned for a additional options to override the top-level defaults.  See
-    the example LDAP content below for more information.
-
-  * Visudo is no longer needed.  Visudo provides locking and syntax checking
-    against the /etc/sudoers file.  Since LDAP updates are atomic, locking is no
-    longer necessary.  Because syntax is checked when the data is inserted into
-    LDAP, the sudoers syntax check becomes unnecessary.
-
-  * Aliases are no longer needed.  User, Host, and Command Aliases were setup
-    to allow simplification and readability of the sudoers files.  Since the
-    LDAP sudoer entry allows multiple values for each of its attributes and
-    since most LDAP browsers are graphical and easy to work with, original
-    aliases are no longer needed.
-
-    If you want to specify lots of users into an entry or want to have similar
-    entries with identical users, then use either groups or user netgroups.
-    Thats what groups and netgroups are for and Sudo handles this well.
-    Alternately, one can just paste them all into the LDAP record.
-
-    If you want to specify lots of hosts into an entry, use netgroups or IP
-    address matches (10.2.3.4/255.255.0.0).  Thats what netgroups are for and
-    Sudo handles this well.  Or just past them all into the LDAP record.
-
-    If you want to specify lots of commands, use directories or wildcards, or
-    just paste them all into LDAP.  That's what it's for.
-
-  * The /etc/sudoers file can be disabled.  Paranoid security administrators
-    can now disallow parsing of any local /etc/sudoers file by an LDAP
-    sudoOption 'ignore_local_sudoers'.  This way all sudoers can be controlled
-    and audited in one place because local entries are not allowed.
-    In fact, if this option is included in the cn=defaults object of LDAP,
-    sudo won't even look for a /etc/sudoers file.
-
-  * The sudo binary compiled with LDAP support should be totally backward
-    compatible and be syntactically and source code equivalent to its non
-    LDAP-enabled build.
-
-
 Build instructions
 ==================
 The most simplest way to build sudo with LDAP support is to include the
@@ -103,33 +45,56 @@ to specify them at configure time.  E.g.
 
   $ ./configure --with-ldap=/usr/local/ldapsdk
 
-Sudo is developed using OpenLDAP.  Other LDAP implementations may
-require adding '-lldif' to SUDO_LIBS in the Makefile.
+Sudo is developed using OpenLDAP but Netscape-based LDAP libraries
+(such as those present in Solaris) are also known to work.
 
 Your Mileage may vary.  Please let the sudo workers mailing list
-<sudo-workers@sudo.ws> know what combinations worked best for your
-OS and LDAP Combinations so we can improve sudo.
-
-More Build Notes:
-HP-UX 11.23 (gcc3) Galen Johnson <Galen.Johnson@sas.com>
-  CFLAGS="-D__10_10_compat_code" LDFLAGS="-L/opt/ldapux/lib"
+<sudo-workers@sudo.ws> know if special configuration was required
+to build an LDAP-enabled sudo so we can improve sudo.
 
 Schema Changes
 ==============
-Add the appropriate schema to your LDAP server so that it may contain
-sudoers content.
+You must add the appropriate schema to your LDAP server before it
+can store sudoers content.
+
+For OpenLDAP, copy the file schema.OpenLDAP to the schema directory
+(e.g. /etc/openldap/schema).  You must then edit your slapd.conf and
+add an include line the new schema, e.g.
+
+    # Sudo LDAP schema
+    include    /etc/openldap/schema/sudo.schema
+
+In order for sudoRole LDAP queries to be efficient, the server must index
+the attribute 'sudoUser', e.g.
+
+    # Indices to maintain
+    index      sudoUser        eq
+
+After making the changes to slapd.conf, restart slapd.
 
-For OpenLDAP, simply copy schema.OpenLDAP to the schema directory
-(e.g. /etc/openldap/schema) and 'include' it in your slapd.conf and
-restart slapd.  For other LDAP servers, provide this to your LDAP
-Administrator.  Make sure to index the attribute 'sudoUser'.
+For Netscape-derived LDAP servers such as SunONE, iPlanet or Fedora Directory,
+copy the schema.iPlanet file to the schema directory with the name 99sudo.ldif.
 
-For netscape-derived LDAP servers such as SunONE, iPlanet or Fedora
-Directory, use the schema.iPlanet file.
+On Solaris, schemas are stored in /var/Sun/mps/slapd-`hostname`/config/schema/.
+For Fedora Directory Server, they are stored in /etc/dirsrv/schema/.
 
-Importing /etc/sudoers to LDAP
-==============================
-Importing is a two step process.
+After copying the schema file to the appropriate directory, restart
+the LDAP server.
+
+Finally, using an LDAP browser/editor, enable indexing by editing the
+client profile to provide a Service Search Descriptor (SSD) for sudoers,
+replacing example.com with your domain:
+
+    serviceSearchDescriptor: sudoers: ou=sudoers,dc=example,dc=com
+
+If using an Active Directory server, copy schema.ActiveDirectory
+to your Windows domain controller and run the following command:
+
+    ldifde -i -f schema.ActiveDirectory -c dc=X dc=example,dc=com
+
+Importing /etc/sudoers into LDAP
+================================
+Importing sudoers is a two-step process.
 
 Step 1:
 Ask your LDAP Administrator where to create the ou=SUDOers container.
@@ -150,28 +115,12 @@ options.
   # ./sudoers2ldif /etc/sudoers > /tmp/sudoers.ldif
 
 Step 2:
-Import into your directory server.  If you are using OpenLDAP, do the following
-if you are using another directory, provide the LDIF file to your LDAP
-Administrator.  An example is shown below.
+Import into your directory server.  The following example is for
+OpenLDAP.  If you are using another directory, provide the LDIF
+file to your LDAP Administrator.
 
   # ldapadd -f /tmp/sudoers.ldif -h ldapserver \
-  > -D cn=Manager,dc=example,dc=com -W -x
-
-Example sudoers Entries in LDAP
-===============================
-The equivalent of a sudoer in LDAP is a 'sudoRole'.  It contains sudoUser(s),
-sudoHost, sudoCommand and optional sudoOption(s) and sudoRunAs(s).
-
-The following example allows users in group wheel to run any
-command on any host through sudo:
-
-dn: cn=%wheel,ou=SUDOers,dc=example,dc=com
-objectClass: top
-objectClass: sudoRole
-cn: %wheel
-sudoUser: %wheel
-sudoHost: ALL
-sudoCommand: ALL
+    -D cn=Manager,dc=example,dc=com -W -x
 
 Managing LDAP entries
 =====================
@@ -198,168 +147,32 @@ I recommend using any of the following LDAP browsers to administer your SUDOers.
 
   There are dozens of others, some Open Source, some free, some not.
 
-
-Configure your /etc/ldap.conf
-=============================
+Configure your /etc/ldap.conf and /etc/nsswitch.conf
+====================================================
 The /etc/ldap.conf file is meant to be shared between sudo, pam_ldap, nss_ldap
 and other ldap applications and modules.  IBM Secureway unfortunately uses
 the same filename but has a different syntax.  If you need to rename where
 this file is stored, re-run configure with the --with-ldap-conf-file=filename
 option.
 
-Make sure you sudoers_base matches exactly with the location you specified
-when you imported the sudoers.  Below is an example /etc/ldap.conf
-
-  # Either specify one or more URIs or one or more host:port pairs.
-  # If neither is specified sudo will default to localhost, port 389.
-  #
-  #host          ldapserver
-  #host          ldapserver1 ldapserver2:390
-  #
-  # Default port if host is specified without one, defaults to 389.
-  #port          389
-  #
-  # URI will override the host and port settings.
-  uri            ldap://ldapserver
-  #uri            ldaps://secureldapserver
-  #uri            ldaps://secureldapserver ldap://ldapserver
-  #
-  # The amount of time, in seconds, to wait while trying to connect to
-  # an LDAP server.
-  bind_timelimit 30
-  #
-  # The amount of time, in seconds, to wait while performing an LDAP query.
-  timelimit 30
-  #
-  # must be set or sudo will ignore LDAP
-  sudoers_base   ou=SUDOers,dc=example,dc=com
-  #
-  # verbose sudoers matching from ldap
-  #sudoers_debug 2
-  #
-  # optional proxy credentials
-  #binddn        <who to search as>
-  #bindpw        <password>
-  #rootbinddn    <who to search as, uses /etc/ldap.passwd for bindpw>
-  #
-  # LDAP protocol version, defaults to 3
-  #ldap_version 3
-  #
-  # Define if you want to use an encrypted LDAP connection.
-  # Typically, you must also set the port to 636 (ldaps).
-  #ssl on
-  #
-  # Define if you want to use port 389 and switch to
-  # encryption before the bind credentials are sent.
-  # Only supported by LDAP servers that support the start_tls
-  # extension such as OpenLDAP.
-  #ssl start_tls
-  #
-  # Additional TLS options follow that allow tweaking of the
-  # SSL/TLS connection.
-  #
-  #tls_checkpeer yes # verify server SSL certificate
-  #tls_checkpeer no  # ignore server SSL certificate
-  #
-  # If you enable tls_checkpeer, specify either tls_cacertfile
-  # or tls_cacertdir.  Only supported when using OpenLDAP.
-  #
-  #tls_cacertfile /etc/certs/trusted_signers.pem
-  #tls_cacertdir  /etc/certs
-  #
-  # For systems that don't have /dev/random
-  # use this along with PRNGD or EGD.pl to seed the
-  # random number pool to generate cryptographic session keys.
-  # Only supported when using OpenLDAP.
-  #
-  #tls_randfile /etc/egd-pool
-  #
-  # You may restrict which ciphers are used.  Consult your SSL
-  # documentation for which options go here.
-  # Only supported when using OpenLDAP.
-  #
-  #tls_ciphers <cipher-list>
-  #
-  # Sudo can provide a client certificate when communicating to
-  # the LDAP server.
-  # Tips:
-  #   * Enable both lines at the same time.
-  #   * Do not password protect the key file.
-  #   * Ensure the keyfile is only readable by root.
-  #
-  # For OpenLDAP:
-  #tls_cert /etc/certs/client_cert.pem
-  #tls_key  /etc/certs/client_key.pem
-  #
-  # For SunONE or iPlanet LDAP, the file specified by tls_cert may
-  # contain CA certs and/or the client's cert.  If the client's
-  # cert is included, tls_key should be specified as well.
-  # For backward compatibility, sslpath may be used in place of tls_cert.
-  #tls_cert /var/ldap/cert7.db
-  #tls_key /var/ldap/key3.db
+See the "Configuring ldap.conf" section in the sudoers.ldap manual
+for a list of supported ldap.conf parameters and an example ldap.conf
+
+Make sure you sudoers_base matches the location you specified when you
+imported the sudoers ldif data.
+
+After configuring /etc/ldap.conf, you must add a line in /etc/nsswitch.conf
+to tell sudo to look in LDAP for sudoers.  See the "Configuring nsswitch.conf"
+section in the sudoers.ldap manual for details.  Note that sudo will use
+/etc/nsswitch.conf even if the underlying operating system does not support it.
+To disable nsswitch support, run configure with the --with-nsswitch=no option.
+This will cause sudo to consult LDAP first and /etc/sudoers second, unless the
+ignore_sudoers_file flag is set in the global LDAP options.
 
 Debugging your LDAP configuration
 =================================
 Enable debugging if you believe sudo is not parsing LDAP the way you think it
-it should.  A value of 1 shows moderate debugging.  A value of 2 shows the
-results of the matches themselves.  Make sure to set the value back to zero
-so that other users don't get confused by the debugging messages.  This value
-is 'sudoers_debug' in the /etc/ldap.conf.
-
-Parsing Differences between /etc/sudoers and LDAP
-=================================================
-There are some subtle differences in the way sudoers is handled once in LDAP.
-Probably the biggest is that according to the RFC, LDAP's ordering is
-arbitrary and you cannot expect that Attributes & Entries are returned in
-any order.  If there are conflicting command rules on an entry, the negative
-takes precedence.  This is called paranoid behavior (not necessarily the
-most specific match).
-
-Here is an example:
-
-  # /etc/sudoers:
-  # Allow all commands except shell
-  johnny  ALL=(root) ALL,!/bin/sh
-  # Always allows all commands because ALL is matched last
-  puddles ALL=(root) !/bin/sh,ALL
-
-  # LDAP equivalent of Johnny
-  # Allows all commands except shell
-  dn: cn=role1,ou=Sudoers,dc=my-domain,dc=com
-  objectClass: sudoRole
-  objectClass: top
-  cn: role1
-  sudoUser: johnny
-  sudoHost: ALL
-  sudoCommand: ALL
-  sudoCommand: !/bin/sh
-
-  # LDAP equivalent of Puddles
-  # Notice that even though ALL comes last, it still behaves like
-  # role1 since the LDAP code assumes the more paranoid configuration
-  dn: cn=role2,ou=Sudoers,dc=my-domain,dc=com
-  objectClass: sudoRole
-  objectClass: top
-  cn: role2
-  sudoUser: puddles
-  sudoHost: ALL
-  sudoCommand: !/bin/sh
-  sudoCommand: ALL
-
-Another difference is that negations on the Host, User or Runas are
-currently ignorred.  For example, these attributes do not work how
-they first seem.
-
-  # does not match all but joe
-  # rather, does not match anyone
-  sudoUser: !joe
-
-  # does not match all but joe
-  # rather, matches everyone including Joe
-  sudoUser: ALL
-  sudoUser: !joe
-
-  # does not match all but web01
-  # rather, matches all hosts including web01
-  sudoHost: ALL
-  sudoHost: !web01
+should.  Setting the 'sudoers_debug' parameter to a value of 1 shows moderate
+debugging.  A value of 2 shows the results of the matches themselves.  Make
+sure to set the value back to zero so that other users don't get confused by
+the debugging messages.
index 4bf571bf31d4d6df9d92b927e200ead06c25970a..a90b5eb9ff67c70be25f0b34487e13972411d474 100644 (file)
@@ -158,9 +158,12 @@ A) "cd" is a shell built-in command, you can't run it as a command
 
 Q) When I try to use "cd" with sudo the command completes without
    errors but nothing happens.
-A) Some SVR4-derived OS's include a /usr/bin/cd command for reasons
-   unfathomable.  A "cd" command is totally useless since a child process
-   cannot affect the current working directory of the parent (your shell).
+A) Even though "cd" is a shell built-in command, some operating systems
+   include a /usr/bin/cd command for some reason.  A standalone
+   "cd" command is totally useless since a child process (cd) cannot
+   affect the current working directory of the parent (your shell).
+   Thus, "sudo cd /foo" will start a child process, change the
+   directory and immediately exit without doing anything useful.
 
 Q) When I run sudo it says I am not allowed to run the command as root
    but I don't want to run it as root, I want to run it as another user.
diff --git a/UPGRADE b/UPGRADE
index 5d8591fa2646beeeb2fd70e77f46f6c9378c293d..86e646f353bbf835abce6521e5478f6056ba08c9 100644 (file)
--- a/UPGRADE
+++ b/UPGRADE
@@ -1,6 +1,33 @@
 Notes on upgrading from an older release
 ========================================
 
+o Upgrading from a version prior to 1.7.0:
+
+    Starting with sudo 1.7.0 comments in the sudoers file must not
+    have a digit or minus sign immediately after the comment character
+    ('#').  Otherwise, the comment may be interpreted as a user or
+    group ID.
+
+    When sudo is build with LDAP support the /etc/nsswitch.conf file is
+    now used to determine the sudoers seach order.  sudo will default to
+    only using /etc/sudoers unless /etc/nsswitch.conf says otherwise.
+    This can be changed with an nsswitch.conf line, e.g.:
+        sudoers:        ldap files
+    Would case LDAP to be searched first, then the sudoers file.
+    To restore the pre-1.7.0 behavior, run configure with the
+    --with-nsswitch=no flag.
+
+    Sudo now ignores user .ldaprc files as well as system LDAP defaults.
+    All LDAP configuration is now in /etc/ldap.conf (or whichever file
+    was specified by configure's --with-ldap-conf-file option).
+    If you are using TLS, you may now need to specify:
+       tls_checkpeer no
+    in sudo's ldap.conf unless ldap.conf references a valid certificate
+    authority file(s).
+
+    Please also see the WHATSNEW file for a list of new features in
+    sudo 1.7.0.
+
 o Upgrading from a version prior to 1.6.9:
 
     Starting with sudo 1.6.9, if an OS supports a modular authentication
diff --git a/WHATSNEW b/WHATSNEW
new file mode 100644 (file)
index 0000000..2d36f06
--- /dev/null
+++ b/WHATSNEW
@@ -0,0 +1,79 @@
+What's new in Sudo 1.7.0?
+
+ * Rewritten parser that converts sudoers into a set of data structures.
+   This eliminates a number of ordering issues and makes it possible to
+   apply sudoers Defaults entries before searching for the command.
+   It also adds support for per-command Defaults specifications.
+
+ * Sudoers now supports a #include facility to allow the inclusion of other
+   sudoers-format files.
+
+ * Sudo's -l (list) flag has been enhanced:
+    o applicable Defaults options are now listed
+    o a command argument can be specified for testing whether a user
+      may run a specific command.
+    o a new -U flag can be used in conjunction with "sudo -l" to allow
+      root (or a user with "sudo ALL") list another user's privileges.
+
+ * A new -g flag has been added to allow the user to specify a
+   primary group to run the command as.  The sudoers syntax has been
+   extended to include a group section in the Runas specification.
+
+ * A uid may now be used anywhere a username is valid.
+
+ * The "secure_path" run-time Defaults option has been restored.
+
+ * Password and group data is now cached for fast lookups.
+
+ * The file descriptor at which sudo starts closing all open files is now
+   configurable via sudoers and, optionally, the command line.
+
+ * Visudo will now warn about aliases that are defined but not used.
+
+ * The -i and -s command line flags now take an optional command
+   to be run via the shell.  Previously, the argument was passed
+   to the shell as a script to run.
+
+ * Improved LDAP support.  SASL authentication may now be used in
+   conjunction when connecting to an LDAP server.  The krb5_ccname
+   parameter in ldap.conf may be used to enable Kerberos.
+
+ * Support for /etc/nsswitch.conf.  LDAP users may now use nsswitch.conf
+   to specify the sudoers order.  E.g.:
+       sudoers: ldap files
+   to check LDAP, then /etc/sudoers.  The default is "files", even
+   when LDAP support is compiled in.  This differs from sudo 1.6
+   where LDAP was always consulted first.
+
+ * Support for /etc/environment on AIX and Linux.  If sudo is run
+   with the -i flag, the contents of /etc/environment are used to
+   populate the new environment that is passed to the command being
+   run.
+
+ * If no terminal is available or if the new -A flag is specified,
+   sudo will use a helper program to read the password if one is
+   configured.  Typically, this is a graphical password prompter
+   such as ssh-askpass.
+
+ * A new Defaults option, "mailfrom" that sets the value of the
+   "From:" field in the warning/error mail.  If unspecified, the
+   login name of the invoking user is used.
+
+ * A new Defaults option, "env_file" that refers to a file containing
+   environment variables to be set in the command being run.
+
+ * A new flag, -n, may be used to indicate that sudo should not
+   prompt the user for a password and, instead, exit with an error
+   if authentication is required.
+
+ * If sudo needs to prompt for a password and it is unable to disable
+   echo (and no askpass program is defined), it will refuse to run
+   unless the "visiblepw" Defaults option has been specified.
+
+ * Prior to version 1.7.0, hitting enter/return at the Password: prompt
+   would exit sudo.  In sudo 1.7.0 and beyond, this is treated as
+   an empty password.  To exit sudo, the user must press ^C or ^D
+   at the prompt.
+
+ * visudo will now check the sudoers file owner and mode in -c (check)
+   mode when the -s (strict) flag is specified.
index b751eeb8fcdf74801f37dcac58a00632ce05df55..13089f0901268a802c7fd02a01af47ba7e052c23 100644 (file)
@@ -1,6 +1,6 @@
 dnl Local m4 macros for autoconf (used by sudo)
 dnl
-dnl Copyright (c) 1994-1996,1998-2007 Todd C. Miller <Todd.Miller@courtesan.com>
+dnl Copyright (c) 1994-1996,1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
 dnl
 dnl XXX - should cache values in all cases!!!
 dnl
@@ -155,15 +155,6 @@ else
 fi
 ])dnl
 
-dnl
-dnl check for fullly working void
-dnl
-AC_DEFUN(SUDO_FULL_VOID, [AC_MSG_CHECKING(for full void implementation)
-AC_TRY_COMPILE(, [void *foo;
-foo = (void *)0; (void *)"test";], AC_DEFINE(VOID, void, [Define to "void" if your compiler supports void pointers, else use "char"].)
-AC_MSG_RESULT(yes), AC_DEFINE(VOID, char)
-AC_MSG_RESULT(no))])
-
 dnl
 dnl SUDO_CHECK_TYPE(TYPE, DEFAULT)
 dnl XXX - should require the check for unistd.h...
@@ -234,6 +225,8 @@ AC_DEFUN([SUDO_FUNC_ISBLANK],
 ] [
   if test "$sudo_cv_func_isblank" = "yes"; then
     AC_DEFINE(HAVE_ISBLANK, 1, [Define if you have isblank(3).])
+  else
+    AC_LIBOBJ(isblank)
   fi
 ])
 
diff --git a/aix.c b/aix.c
new file mode 100644 (file)
index 0000000..5897b6f
--- /dev/null
+++ b/aix.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2008 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/resource.h>
+
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#include <usersec.h>
+
+#include <compat.h>
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: aix.c,v 1.7 2008/11/06 00:42:37 millert Exp $";
+#endif /* lint */
+
+#ifdef HAVE_GETUSERATTR
+
+#ifndef RLIM_SAVED_MAX
+# define RLIM_SAVED_MAX        RLIM_INFINITY
+#endif
+
+struct aix_limit {
+    int resource;
+    char *soft;
+    char *hard;
+    int factor;
+};
+
+static struct aix_limit aix_limits[] = {
+    { RLIMIT_FSIZE, S_UFSIZE, S_UFSIZE_HARD, 512 },
+    { RLIMIT_CPU, S_UCPU, S_UCPU_HARD, 1 },
+    { RLIMIT_DATA, S_UDATA, S_UDATA_HARD, 512 },
+    { RLIMIT_STACK, S_USTACK, S_USTACK_HARD, 512 },
+    { RLIMIT_RSS, S_URSS, S_URSS_HARD, 512 },
+    { RLIMIT_CORE, S_UCORE, S_UCORE_HARD, 512 },
+    { RLIMIT_NOFILE, S_UNOFILE, S_UNOFILE_HARD, 1 }
+};
+
+static int
+aix_getlimit(user, lim, valp)
+    char *user;
+    char *lim;
+    int *valp;
+{
+    if (getuserattr(user, lim, valp, SEC_INT) != 0)
+       return getuserattr("default", lim, valp, SEC_INT);
+    return(0);
+}
+
+void
+aix_setlimits(user)
+    char *user;
+{
+    struct rlimit rlim;
+    int i, n;
+
+    /*
+     * For each resource limit, get the soft/hard values for the user
+     * and set those values via setrlimit().  Must be run as euid 0.
+     */
+    for (n = 0; n < sizeof(aix_limits) / sizeof(aix_limits[0]); n++) {
+       /*
+        * We have two strategies, depending on whether or not the
+        * hard limit has been defined.
+        */
+       if (aix_getlimit(user, aix_limits[n].hard, &i) == 0) {
+           rlim.rlim_max = i == -1 ? RLIM_INFINITY : i * aix_limits[n].factor;
+           if (aix_getlimit(user, aix_limits[n].soft, &i) == 0)
+               rlim.rlim_cur = i == -1 ? RLIM_INFINITY : i * aix_limits[n].factor;
+           else
+               rlim.rlim_cur = rlim.rlim_max;  /* soft not specd, use hard */
+       } else {
+           /* No hard limit set, try soft limit. */
+           if (aix_getlimit(user, aix_limits[n].soft, &i) == 0)
+               rlim.rlim_cur = i == -1 ? RLIM_INFINITY : i * aix_limits[n].factor;
+
+           /* Set hard limit per AIX /etc/security/limits documentation. */
+           switch (aix_limits[n].resource) {
+               case RLIMIT_CPU:
+               case RLIMIT_FSIZE:
+                   rlim.rlim_max = rlim.rlim_cur;
+                   break;
+               case RLIMIT_STACK:
+                   rlim.rlim_max = RLIM_SAVED_MAX;
+                   break;
+               default:
+                   rlim.rlim_max = RLIM_INFINITY;
+                   break;
+           }
+       }
+       (void)setrlimit(aix_limits[n].resource, &rlim);
+    }
+}
+
+#endif /* HAVE_GETUSERATTR */
diff --git a/alias.c b/alias.c
new file mode 100644 (file)
index 0000000..9a03069
--- /dev/null
+++ b/alias.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2004-2005m, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 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 <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include "sudo.h"
+#include "parse.h"
+#include "redblack.h"
+#include <gram.h>
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: alias.c,v 1.14 2008/11/18 13:29:58 millert Exp $";
+#endif /* lint */
+
+/*
+ * Globals
+ */
+struct rbtree *aliases;
+unsigned int alias_seqno;
+
+/*
+ * Local protoypes
+ */
+static int   alias_compare     __P((const void *, const void *));
+static void  alias_free                __P((void *));
+
+/*
+ * Comparison function for the red-black tree.
+ * Aliases are sorted by name with the type used as a tie-breaker.
+ */
+static int
+alias_compare(v1, v2)
+    const void *v1, *v2;
+{
+    const struct alias *a1 = (const struct alias *)v1;
+    const struct alias *a2 = (const struct alias *)v2;
+    int res;
+
+    if (v1 == NULL)
+       res = -1;
+    else if (v2 == NULL)
+       res = 1;
+    else if ((res = strcmp(a1->name, a2->name)) == 0)
+       res = a1->type - a2->type;
+    return(res);
+}
+
+/*
+ * Search the tree for an alias with the specified name and type.
+ * Returns a pointer to the alias structure or NULL if not found.
+ */
+struct alias *
+find_alias(name, type)
+    char *name;
+    int type;
+{
+    struct alias key;
+    struct rbnode *node;
+    struct alias *a = NULL;
+
+    key.name = name;
+    key.type = type;
+    if ((node = rbfind(aliases, &key)) != NULL) {
+           /*
+            * Compare the global sequence number with the one stored
+            * in the alias.  If they match then we've seen this alias
+            * before and found a loop.
+            */
+           a = node->data;
+           if (a->seqno == alias_seqno)
+               return(NULL);
+           a->seqno = alias_seqno;
+    }
+    return(a);
+}
+
+/*
+ * Add an alias to the aliases redblack tree.
+ * Returns NULL on success and an error string on failure.
+ */
+char *
+alias_add(name, type, members)
+    char *name;
+    int type;
+    struct member *members;
+{
+    static char errbuf[512];
+    struct alias *a;
+
+    a = emalloc(sizeof(*a));
+    a->name = name;
+    a->type = type;
+    a->seqno = 0;
+    list2tq(&a->members, members);
+    if (rbinsert(aliases, a)) {
+       alias_free(a);
+       snprintf(errbuf, sizeof(errbuf), "Alias `%s' already defined", name);
+       return(errbuf);
+    }
+    return(NULL);
+}
+
+/*
+ * Apply a function to each alias entry and pass in a cookie.
+ */
+void
+alias_apply(func, cookie)
+    int (*func) __P((void *, void *));
+    void *cookie;
+{
+    rbapply(aliases, func, cookie, inorder);
+}
+
+/*
+ * Returns TRUE if there are no aliases, else FALSE.
+ */
+int
+no_aliases()
+{
+    return(rbisempty(aliases));
+}
+
+/*
+ * Free memory used by an alias struct and its members.
+ */
+static void
+alias_free(v)
+    void *v;
+{
+    struct alias *a = (struct alias *)v;
+    struct member *m;
+    struct sudo_command *c;
+    void *next;
+
+    efree(a->name);
+    for (m = a->members.first; m != NULL; m = next) {
+       next = m->next;
+       if (m->type == COMMAND) {
+               c = (struct sudo_command *) m->name;
+               efree(c->cmnd);
+               efree(c->args);
+       }
+       efree(m->name);
+       efree(m);
+    }
+    efree(a);
+}
+
+/*
+ * Find the named alias, delete it from the tree and recover its resources.
+ */
+int
+alias_remove(name, type)
+    char *name;
+    int type;
+{
+    struct rbnode *node;
+    struct alias key, *a;
+
+    key.name = name;
+    key.type = type;
+    if ((node = rbfind(aliases, &key)) == NULL)
+       return(FALSE);
+    a = rbdelete(aliases, node);
+    alias_free(a);
+    return(TRUE);
+}
+
+void
+init_aliases()
+{
+    if (aliases != NULL)
+       rbdestroy(aliases, alias_free);
+    aliases = rbcreate(alias_compare);
+}
diff --git a/alloc.c b/alloc.c
index 745c8ae66e1aa7037fb5a614e14f9a049ef99328..c2405bf1c69d2578cd08351f90e4c1ccd1464eee 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2007
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
 # include <malloc.h>
 #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #ifdef HAVE_INTTYPES_H
 # include <inttypes.h>
 #endif
@@ -53,7 +49,7 @@
 #include "sudo.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: alloc.c,v 1.23.2.4 2007/09/11 12:20:15 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: alloc.c,v 1.33 2008/11/09 14:13:12 millert Exp $";
 #endif /* lint */
 
 /*
@@ -74,17 +70,17 @@ __unused static const char rcsid[] = "$Sudo: alloc.c,v 1.23.2.4 2007/09/11 12:20
  * emalloc() calls the system malloc(3) and exits with an error if
  * malloc(3) fails.
  */
-VOID *
+void *
 emalloc(size)
     size_t size;
 {
-    VOID *ptr;
+    void *ptr;
 
     if (size == 0)
-       errx(1, "internal error, tried to emalloc(0)");
+       errorx(1, "internal error, tried to emalloc(0)");
 
-    if ((ptr = (VOID *) malloc(size)) == NULL)
-       errx(1, "unable to allocate memory");
+    if ((ptr = malloc(size)) == NULL)
+       errorx(1, "unable to allocate memory");
     return(ptr);
 }
 
@@ -92,21 +88,21 @@ emalloc(size)
  * emalloc2() allocates nmemb * size bytes and exits with an error
  * if overflow would occur or if the system malloc(3) fails.
  */
-VOID *
+void *
 emalloc2(nmemb, size)
     size_t nmemb;
     size_t size;
 {
-    VOID *ptr;
+    void *ptr;
 
     if (nmemb == 0 || size == 0)
-       errx(1, "internal error, tried to emalloc2(0)");
+       errorx(1, "internal error, tried to emalloc2(0)");
     if (nmemb > SIZE_MAX / size)
-       errx(1, "internal error, emalloc2() overflow");
+       errorx(1, "internal error, emalloc2() overflow");
 
     size *= nmemb;
-    if ((ptr = (VOID *) malloc(size)) == NULL)
-       errx(1, "unable to allocate memory");
+    if ((ptr = malloc(size)) == NULL)
+       errorx(1, "unable to allocate memory");
     return(ptr);
 }
 
@@ -115,18 +111,18 @@ emalloc2(nmemb, size)
  * realloc(3) fails.  You can call erealloc() with a NULL pointer even
  * if the system realloc(3) does not support this.
  */
-VOID *
+void *
 erealloc(ptr, size)
-    VOID *ptr;
+    void *ptr;
     size_t size;
 {
 
     if (size == 0)
-       errx(1, "internal error, tried to erealloc(0)");
+       errorx(1, "internal error, tried to erealloc(0)");
 
-    ptr = ptr ? (VOID *) realloc(ptr, size) : (VOID *) malloc(size);
+    ptr = ptr ? realloc(ptr, size) : malloc(size);
     if (ptr == NULL)
-       errx(1, "unable to allocate memory");
+       errorx(1, "unable to allocate memory");
     return(ptr);
 }
 
@@ -136,22 +132,22 @@ erealloc(ptr, size)
  * You can call erealloc() with a NULL pointer even if the system realloc(3)
  * does not support this.
  */
-VOID *
+void *
 erealloc3(ptr, nmemb, size)
-    VOID *ptr;
+    void *ptr;
     size_t nmemb;
     size_t size;
 {
 
     if (nmemb == 0 || size == 0)
-       errx(1, "internal error, tried to erealloc3(0)");
+       errorx(1, "internal error, tried to erealloc3(0)");
     if (nmemb > SIZE_MAX / size)
-       errx(1, "internal error, erealloc3() overflow");
+       errorx(1, "internal error, erealloc3() overflow");
 
     size *= nmemb;
-    ptr = ptr ? (VOID *) realloc(ptr, size) : (VOID *) malloc(size);
+    ptr = ptr ? realloc(ptr, size) : malloc(size);
     if (ptr == NULL)
-       errx(1, "unable to allocate memory");
+       errorx(1, "unable to allocate memory");
     return(ptr);
 }
 
@@ -199,7 +195,7 @@ easprintf(ret, fmt, va_alist)
     va_end(ap);
 
     if (len == -1)
-       errx(1, "unable to allocate memory");
+       errorx(1, "unable to allocate memory");
     return(len);
 }
 
@@ -216,7 +212,7 @@ evasprintf(ret, format, args)
     int len;
 
     if ((len = vasprintf(ret, format, args)) == -1)
-       errx(1, "unable to allocate memory");
+       errorx(1, "unable to allocate memory");
     return(len);
 }
 
@@ -225,7 +221,7 @@ evasprintf(ret, format, args)
  */
 void
 efree(ptr)
-    VOID *ptr;
+    void *ptr;
 {
     if (ptr != NULL)
        free(ptr);
diff --git a/alloca.c b/alloca.c
deleted file mode 100644 (file)
index be98a41..0000000
--- a/alloca.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/* alloca.c -- allocate automatically reclaimed memory
-   (Mostly) portable public-domain implementation -- D A Gwyn
-
-   This implementation of the PWB library alloca function,
-   which is used to allocate space off the run-time stack so
-   that it is automatically reclaimed upon procedure exit,
-   was inspired by discussions with J. Q. Johnson of Cornell.
-   J.Otto Tennant <jot@cray.com> contributed the Cray support.
-
-   There are some preprocessor constants that can
-   be defined when compiling for your specific system, for
-   improved efficiency; however, the defaults should be okay.
-
-   The general concept of this implementation is to keep
-   track of all alloca-allocated blocks, and reclaim any
-   that are found to be deeper in the stack than the current
-   invocation.  This heuristic does not reclaim storage as
-   soon as it becomes invalid, but it will do so eventually.
-
-   As a special case, alloca(0) reclaims storage without
-   allocating any.  It is a good idea to use alloca(0) in
-   your main control loop, etc. to force garbage collection.  */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-/* If compiling with GCC 2, this file's not needed.  */
-#if !defined (__GNUC__) || __GNUC__ < 2
-
-/* If someone has defined alloca as a macro,
-   there must be some other way alloca is supposed to work.  */
-#ifndef alloca
-
-/* If your stack is a linked list of frames, you have to
-   provide an "address metric" ADDRESS_FUNCTION macro.  */
-
-#if defined (CRAY) && defined (CRAY_STACKSEG_END)
-long i00afunc ();
-#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
-#else
-#define ADDRESS_FUNCTION(arg) &(arg)
-#endif
-
-#if __STDC__
-typedef void *pointer;
-#else
-typedef char *pointer;
-#endif
-
-#ifndef NULL
-#define        NULL    0
-#endif
-
-extern pointer malloc ();
-
-/* Define STACK_DIRECTION if you know the direction of stack
-   growth for your system; otherwise it will be automatically
-   deduced at run-time.
-
-   STACK_DIRECTION > 0 => grows toward higher addresses
-   STACK_DIRECTION < 0 => grows toward lower addresses
-   STACK_DIRECTION = 0 => direction of growth unknown  */
-
-#ifndef STACK_DIRECTION
-#define        STACK_DIRECTION 0       /* Direction unknown.  */
-#endif
-
-#if STACK_DIRECTION != 0
-
-#define        STACK_DIR       STACK_DIRECTION /* Known at compile-time.  */
-
-#else /* STACK_DIRECTION == 0; need run-time code.  */
-
-static int stack_dir;          /* 1 or -1 once known.  */
-#define        STACK_DIR       stack_dir
-
-static void
-find_stack_direction ()
-{
-  static char *addr = NULL;    /* Address of first `dummy', once known.  */
-  auto char dummy;             /* To get stack address.  */
-
-  if (addr == NULL)
-    {                          /* Initial entry.  */
-      addr = ADDRESS_FUNCTION (dummy);
-
-      find_stack_direction (); /* Recurse once.  */
-    }
-  else
-    {
-      /* Second entry.  */
-      if (ADDRESS_FUNCTION (dummy) > addr)
-       stack_dir = 1;          /* Stack grew upward.  */
-      else
-       stack_dir = -1;         /* Stack grew downward.  */
-    }
-}
-
-#endif /* STACK_DIRECTION == 0 */
-
-/* An "alloca header" is used to:
-   (a) chain together all alloca'ed blocks;
-   (b) keep track of stack depth.
-
-   It is very important that sizeof(header) agree with malloc
-   alignment chunk size.  The following default should work okay.  */
-
-#ifndef        ALIGN_SIZE
-#define        ALIGN_SIZE      sizeof(double)
-#endif
-
-typedef union hdr
-{
-  char align[ALIGN_SIZE];      /* To force sizeof(header).  */
-  struct
-    {
-      union hdr *next;         /* For chaining headers.  */
-      char *deep;              /* For stack depth measure.  */
-    } h;
-} header;
-
-static header *last_alloca_header = NULL;      /* -> last alloca header.  */
-
-/* Return a pointer to at least SIZE bytes of storage,
-   which will be automatically reclaimed upon exit from
-   the procedure that called alloca.  Originally, this space
-   was supposed to be taken from the current stack frame of the
-   caller, but that method cannot be made to work for some
-   implementations of C, for example under Gould's UTX/32.  */
-
-pointer
-alloca (size)
-     unsigned size;
-{
-  auto char probe;             /* Probes stack depth: */
-  register char *depth = ADDRESS_FUNCTION (probe);
-
-#if STACK_DIRECTION == 0
-  if (STACK_DIR == 0)          /* Unknown growth direction.  */
-    find_stack_direction ();
-#endif
-
-  /* Reclaim garbage, defined as all alloca'd storage that
-     was allocated from deeper in the stack than currently. */
-
-  {
-    register header *hp;       /* Traverses linked list.  */
-
-    for (hp = last_alloca_header; hp != NULL;)
-      if ((STACK_DIR > 0 && hp->h.deep > depth)
-         || (STACK_DIR < 0 && hp->h.deep < depth))
-       {
-         register header *np = hp->h.next;
-
-         free ((pointer) hp);  /* Collect garbage.  */
-
-         hp = np;              /* -> next header.  */
-       }
-      else
-       break;                  /* Rest are not deeper.  */
-
-    last_alloca_header = hp;   /* -> last valid storage.  */
-  }
-
-  if (size == 0)
-    return NULL;               /* No allocation required.  */
-
-  /* Allocate combined header + user data storage.  */
-
-  {
-    register pointer new = malloc (sizeof (header) + size);
-    /* Address of header.  */
-
-    ((header *) new)->h.next = last_alloca_header;
-    ((header *) new)->h.deep = depth;
-
-    last_alloca_header = (header *) new;
-
-    /* User storage begins just after header.  */
-
-    return (pointer) ((char *) new + sizeof (header));
-  }
-}
-
-#if defined (CRAY) && defined (CRAY_STACKSEG_END)
-
-#ifdef DEBUG_I00AFUNC
-#include <stdio.h>
-#endif
-
-#ifndef CRAY_STACK
-#define CRAY_STACK
-#ifndef CRAY2
-/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
-struct stack_control_header
-  {
-    long shgrow:32;            /* Number of times stack has grown.  */
-    long shaseg:32;            /* Size of increments to stack.  */
-    long shhwm:32;             /* High water mark of stack.  */
-    long shsize:32;            /* Current size of stack (all segments).  */
-  };
-
-/* The stack segment linkage control information occurs at
-   the high-address end of a stack segment.  (The stack
-   grows from low addresses to high addresses.)  The initial
-   part of the stack segment linkage control information is
-   0200 (octal) words.  This provides for register storage
-   for the routine which overflows the stack.  */
-
-struct stack_segment_linkage
-  {
-    long ss[0200];             /* 0200 overflow words.  */
-    long sssize:32;            /* Number of words in this segment.  */
-    long ssbase:32;            /* Offset to stack base.  */
-    long:32;
-    long sspseg:32;            /* Offset to linkage control of previous
-                                  segment of stack.  */
-    long:32;
-    long sstcpt:32;            /* Pointer to task common address block.  */
-    long sscsnm;               /* Private control structure number for
-                                  microtasking.  */
-    long ssusr1;               /* Reserved for user.  */
-    long ssusr2;               /* Reserved for user.  */
-    long sstpid;               /* Process ID for pid based multi-tasking.  */
-    long ssgvup;               /* Pointer to multitasking thread giveup.  */
-    long sscray[7];            /* Reserved for Cray Research.  */
-    long ssa0;
-    long ssa1;
-    long ssa2;
-    long ssa3;
-    long ssa4;
-    long ssa5;
-    long ssa6;
-    long ssa7;
-    long sss0;
-    long sss1;
-    long sss2;
-    long sss3;
-    long sss4;
-    long sss5;
-    long sss6;
-    long sss7;
-  };
-
-#else /* CRAY2 */
-/* The following structure defines the vector of words
-   returned by the STKSTAT library routine.  */
-struct stk_stat
-  {
-    long now;                  /* Current total stack size.  */
-    long maxc;                 /* Amount of contiguous space which would
-                                  be required to satisfy the maximum
-                                  stack demand to date.  */
-    long high_water;           /* Stack high-water mark.  */
-    long overflows;            /* Number of stack overflow ($STKOFEN) calls.  */
-    long hits;                 /* Number of internal buffer hits.  */
-    long extends;              /* Number of block extensions.  */
-    long stko_mallocs;         /* Block allocations by $STKOFEN.  */
-    long underflows;           /* Number of stack underflow calls ($STKRETN).  */
-    long stko_free;            /* Number of deallocations by $STKRETN.  */
-    long stkm_free;            /* Number of deallocations by $STKMRET.  */
-    long segments;             /* Current number of stack segments.  */
-    long maxs;                 /* Maximum number of stack segments so far.  */
-    long pad_size;             /* Stack pad size.  */
-    long current_address;      /* Current stack segment address.  */
-    long current_size;         /* Current stack segment size.  This
-                                  number is actually corrupted by STKSTAT to
-                                  include the fifteen word trailer area.  */
-    long initial_address;      /* Address of initial segment.  */
-    long initial_size;         /* Size of initial segment.  */
-  };
-
-/* The following structure describes the data structure which trails
-   any stack segment.  I think that the description in 'asdef' is
-   out of date.  I only describe the parts that I am sure about.  */
-
-struct stk_trailer
-  {
-    long this_address;         /* Address of this block.  */
-    long this_size;            /* Size of this block (does not include
-                                  this trailer).  */
-    long unknown2;
-    long unknown3;
-    long link;                 /* Address of trailer block of previous
-                                  segment.  */
-    long unknown5;
-    long unknown6;
-    long unknown7;
-    long unknown8;
-    long unknown9;
-    long unknown10;
-    long unknown11;
-    long unknown12;
-    long unknown13;
-    long unknown14;
-  };
-
-#endif /* CRAY2 */
-#endif /* not CRAY_STACK */
-
-#ifdef CRAY2
-/* Determine a "stack measure" for an arbitrary ADDRESS.
-   I doubt that "lint" will like this much. */
-
-static long
-i00afunc (address)
-     long *address;
-{
-  struct stk_stat status;
-  struct stk_trailer *trailer;
-  long *block, size;
-  long result = 0;
-
-  /* We want to iterate through all of the segments.  The first
-     step is to get the stack status structure.  We could do this
-     more quickly and more directly, perhaps, by referencing the
-     $LM00 common block, but I know that this works.  */
-
-  STKSTAT (&status);
-
-  /* Set up the iteration.  */
-
-  trailer = (struct stk_trailer *) (status.current_address
-                                   + status.current_size
-                                   - 15);
-
-  /* There must be at least one stack segment.  Therefore it is
-     a fatal error if "trailer" is null.  */
-
-  if (trailer == 0)
-    abort ();
-
-  /* Discard segments that do not contain our argument address.  */
-
-  while (trailer != 0)
-    {
-      block = (long *) trailer->this_address;
-      size = trailer->this_size;
-      if (block == 0 || size == 0)
-       abort ();
-      trailer = (struct stk_trailer *) trailer->link;
-      if ((block <= address) && (address < (block + size)))
-       break;
-    }
-
-  /* Set the result to the offset in this segment and add the sizes
-     of all predecessor segments.  */
-
-  result = address - block;
-
-  if (trailer == 0)
-    {
-      return result;
-    }
-
-  do
-    {
-      if (trailer->this_size <= 0)
-       abort ();
-      result += trailer->this_size;
-      trailer = (struct stk_trailer *) trailer->link;
-    }
-  while (trailer != 0);
-
-  /* We are done.  Note that if you present a bogus address (one
-     not in any segment), you will get a different number back, formed
-     from subtracting the address of the first block.  This is probably
-     not what you want.  */
-
-  return (result);
-}
-
-#else /* not CRAY2 */
-/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
-   Determine the number of the cell within the stack,
-   given the address of the cell.  The purpose of this
-   routine is to linearize, in some sense, stack addresses
-   for alloca.  */
-
-static long
-i00afunc (address)
-     long address;
-{
-  long stkl = 0;
-
-  long size, pseg, this_segment, stack;
-  long result = 0;
-
-  struct stack_segment_linkage *ssptr;
-
-  /* Register B67 contains the address of the end of the
-     current stack segment.  If you (as a subprogram) store
-     your registers on the stack and find that you are past
-     the contents of B67, you have overflowed the segment.
-
-     B67 also points to the stack segment linkage control
-     area, which is what we are really interested in.  */
-
-  stkl = CRAY_STACKSEG_END ();
-  ssptr = (struct stack_segment_linkage *) stkl;
-
-  /* If one subtracts 'size' from the end of the segment,
-     one has the address of the first word of the segment.
-
-     If this is not the first segment, 'pseg' will be
-     nonzero.  */
-
-  pseg = ssptr->sspseg;
-  size = ssptr->sssize;
-
-  this_segment = stkl - size;
-
-  /* It is possible that calling this routine itself caused
-     a stack overflow.  Discard stack segments which do not
-     contain the target address.  */
-
-  while (!(this_segment <= address && address <= stkl))
-    {
-#ifdef DEBUG_I00AFUNC
-      fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
-#endif
-      if (pseg == 0)
-       break;
-      stkl = stkl - pseg;
-      ssptr = (struct stack_segment_linkage *) stkl;
-      size = ssptr->sssize;
-      pseg = ssptr->sspseg;
-      this_segment = stkl - size;
-    }
-
-  result = address - this_segment;
-
-  /* If you subtract pseg from the current end of the stack,
-     you get the address of the previous stack segment's end.
-     This seems a little convoluted to me, but I'll bet you save
-     a cycle somewhere.  */
-
-  while (pseg != 0)
-    {
-#ifdef DEBUG_I00AFUNC
-      fprintf (stderr, "%011o %011o\n", pseg, size);
-#endif
-      stkl = stkl - pseg;
-      ssptr = (struct stack_segment_linkage *) stkl;
-      size = ssptr->sssize;
-      pseg = ssptr->sspseg;
-      result += size;
-    }
-  return (result);
-}
-
-#endif /* not CRAY2 */
-#endif /* CRAY */
-
-#endif /* no alloca */
-#endif /* not GCC version 2 */
index d586c640a922ae6cb39790175542f051cc96226d..fd183fe8421054c9f3350adf5dd78a1b8d0bd000 100644 (file)
--- a/auth/API
+++ b/auth/API
@@ -10,7 +10,7 @@ typedef struct sudo_auth {
     short flags;                /* various flags, see below */
     short status;               /* status from verify routine */
     char *name;                        /* name of the method in string form */
-    VOID *data;                 /* method-specific data pointer */
+    void *data;                 /* method-specific data pointer */
 
     int (*init) __P((struct passwd *pw, char **prompt, sudo_auth *auth));
     int (*setup) __P((struct passwd *pw, char **prompt, sudo_auth *auth));
index 9118326b40ce0b2a08b0f00d37fe540dcfcb0e68..fed48ba06738340cfb4f216ebb4e91c323535f02 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1999, 2001-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999, 2001-2005, 2007
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #include "sudo.h"
 #include "sudo_auth.h"
 
-#undef VOID
 #include <afs/stds.h>
 #include <afs/kautils.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: afs.c,v 1.10.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: afs.c,v 1.15 2008/11/09 14:13:13 millert Exp $";
 #endif /* lint */
 
 int
index 168f358740e14a3aa13edc07827cb62bc8c793c4..14343efb0146005d49c2c1ae04d7180fc5ec7f5a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -47,7 +47,7 @@
 #include "sudo_auth.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: aix_auth.c,v 1.18.2.3 2007/06/21 22:29:15 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: aix_auth.c,v 1.25 2008/11/09 14:13:13 millert Exp $";
 #endif /* lint */
 
 /*
@@ -75,3 +75,14 @@ aixauth_verify(pw, prompt, auth)
     }
     return(rval);
 }
+
+int
+aixauth_cleanup(pw, auth)
+    struct passwd *pw;
+    sudo_auth *auth;
+{
+    /* Unset AUTHSTATE as it may not be correct for the runas user. */
+    sudo_unsetenv("AUTHSTATE");
+
+    return(AUTH_SUCCESS);
+}
index a881bf93795e12093713a57cc0a269fb34bf2b27..aae7fd6899141861b9eadfef1b81c897ae571a09 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2000-2005, 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -52,7 +52,7 @@
 #include "sudo_auth.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: bsdauth.c,v 1.16.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: bsdauth.c,v 1.23 2008/11/09 14:13:13 millert Exp $";
 #endif /* lint */
 
 extern char *login_style;              /* from sudo.c */
@@ -88,7 +88,7 @@ bsdauth_init(pw, promptp, auth)
        return(AUTH_FATAL);
     }
 
-    auth->data = (VOID *) as;
+    auth->data = (void *) as;
     return(AUTH_SUCCESS);
 }
 
@@ -104,7 +104,6 @@ bsdauth_verify(pw, prompt, auth)
     int authok = 0;
     sigaction_t sa, osa;
     auth_session_t *as = (auth_session_t *) auth->data;
-    extern int nil_pw;
 
     /* save old signal handler */
     sigemptyset(&sa.sa_mask);
@@ -142,11 +141,8 @@ bsdauth_verify(pw, prompt, auth)
        }
     }
 
-    if (!pass || *pass == '\0')                /* ^C or empty password */
-       nil_pw = 1;
-
     if (pass) {
-       authok = auth_userresponse(as, (char *)pass, 1);
+       authok = auth_userresponse(as, pass, 1);
        zero_bytes(pass, strlen(pass));
     }
 
@@ -156,6 +152,9 @@ bsdauth_verify(pw, prompt, auth)
     if (authok)
        return(AUTH_SUCCESS);
 
+    if (!pass)
+       return(AUTH_INTR);
+
     if ((s = auth_getvalue(as, "errormsg")) != NULL)
        log_error(NO_EXIT|NO_MAIL, "%s", s);
     return(AUTH_FAILURE);
index a27303b0a9d4b9076728412314abbe92e3f30137..f8ddcbae5d9db3223170949897312ae4624cad3c 100644 (file)
@@ -65,7 +65,7 @@
 #include "sudo_auth.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: dce.c,v 1.11.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: dce.c,v 1.14 2005/02/12 22:56:07 millert Exp $";
 #endif /* lint */
 
 static int check_dce_status __P((error_status_t, char *));
index 4e365fc6456bf1742eea223e28f9a97434be0f28..d09b132d7fa81d15db2679de33dc74ce2b33d9b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <pwd.h>
 
 #include <auth.h>
@@ -55,7 +50,7 @@
 #include "sudo_auth.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: fwtk.c,v 1.23.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: fwtk.c,v 1.29 2008/11/09 14:13:13 millert Exp $";
 #endif /* lint */
 
 int
@@ -68,22 +63,22 @@ fwtk_init(pw, promptp, auth)
     char resp[128];                    /* Response from the server */
 
     if ((confp = cfg_read("sudo")) == (Cfg *)-1) {
-       warnx("cannot read fwtk config");
+       warningx("cannot read fwtk config");
        return(AUTH_FATAL);
     }
 
     if (auth_open(confp)) {
-       warnx("cannot connect to authentication server");
+       warningx("cannot connect to authentication server");
        return(AUTH_FATAL);
     }
 
     /* Get welcome message from auth server */
     if (auth_recv(resp, sizeof(resp))) {
-       warnx("lost connection to authentication server");
+       warningx("lost connection to authentication server");
        return(AUTH_FATAL);
     }
     if (strncmp(resp, "Authsrv ready", 13) != 0) {
-       warnx("authentication server error:\n%s", resp);
+       warningx("authentication server error:\n%s", resp);
        return(AUTH_FATAL);
     }
 
@@ -100,13 +95,12 @@ fwtk_verify(pw, prompt, auth)
     char buf[SUDO_PASS_MAX + 12];      /* General prupose buffer */
     char resp[128];                    /* Response from the server */
     int error;
-    extern int nil_pw;
 
     /* Send username to authentication server. */
     (void) snprintf(buf, sizeof(buf), "authorize %s 'sudo'", pw->pw_name);
 restart:
     if (auth_send(buf) || auth_recv(resp, sizeof(resp))) {
-       warnx("lost connection to authentication server");
+       warningx("lost connection to authentication server");
        return(AUTH_FATAL);
     }
 
@@ -128,19 +122,17 @@ restart:
        strlcpy(buf, "response dummy", sizeof(buf));
        goto restart;
     } else {
-       warnx("%s", resp);
+       warningx("%s", resp);
        return(AUTH_FATAL);
     }
     if (!pass) {                       /* ^C or error */
-       nil_pw = 1;
-       return(AUTH_FAILURE);
-    } else if (*pass == '\0')          /* empty password */
-       nil_pw = 1;
+       return(AUTH_INTR);
+    }
 
     /* Send the user's response to the server */
     (void) snprintf(buf, sizeof(buf), "response '%s'", pass);
     if (auth_send(buf) || auth_recv(resp, sizeof(resp))) {
-       warnx("lost connection to authentication server");
+       warningx("lost connection to authentication server");
        error = AUTH_FATAL;
        goto done;
     }
@@ -152,7 +144,7 @@ restart:
 
     /* Main loop prints "Permission Denied" or insult. */
     if (strcmp(resp, "Permission Denied.") != 0)
-       warnx("%s", resp);
+       warningx("%s", resp);
     error = AUTH_FAILURE;
 done:
     zero_bytes(pass, strlen(pass));
index 60d22ca3cae509a2bec813cb0cc14ab273099bdf..2f6c1099c9c1d07ccc5a85ae3d7b26ca83280146 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -48,7 +48,7 @@
 #include "sudo_auth.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: kerb4.c,v 1.11.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: kerb4.c,v 1.16 2008/11/09 14:13:13 millert Exp $";
 #endif /* lint */
 
 int
@@ -68,7 +68,7 @@ kerb4_init(pw, promptp, auth)
        return(AUTH_FAILURE);
 
     /* Stash a pointer to the realm (used in kerb4_verify) */
-    auth->data = (VOID *) realm;
+    auth->data = (void *) realm;
 
     return(AUTH_SUCCESS);
 }
index 89d43a7dd85af4b6b408553d0ca497aee7c547f7..5e17685bc06b31ec143c892f05b0209025ccb9db 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -54,7 +54,7 @@
 #include "sudo_auth.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: kerb5.c,v 1.23.2.8 2008/02/13 22:17:41 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: kerb5.c,v 1.36 2008/11/09 14:13:13 millert Exp $";
 #endif /* lint */
 
 #ifdef HAVE_HEIMDAL
@@ -74,6 +74,24 @@ static struct _sudo_krb5_data {
 } sudo_krb5_data = { NULL, NULL, NULL };
 typedef struct _sudo_krb5_data *sudo_krb5_datap;
 
+#ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
+static krb5_error_code
+krb5_get_init_creds_opt_alloc(context, opts)
+    krb5_context               context;
+    krb5_get_init_creds_opt   **opts;
+{
+    *opts = emalloc(sizeof(krb5_get_init_creds_opt));
+    return 0;
+}
+
+static void
+krb5_get_init_creds_opt_free(opts)
+    krb5_get_init_creds_opt *opts;
+{
+    free(opts);
+}
+#endif
+
 int
 kerb5_init(pw, promptp, auth)
     struct passwd *pw;
@@ -87,7 +105,7 @@ kerb5_init(pw, promptp, auth)
     char               cache_name[64];
     char               *pname;
 
-    auth->data = (VOID *) &sudo_krb5_data; /* Stash all our data here */
+    auth->data = (void *) &sudo_krb5_data; /* Stash all our data here */
 
 #ifdef HAVE_KRB5_INIT_SECURE_CONTEXT
     error = krb5_init_secure_context(&(sudo_krb5_data.sudo_context));
@@ -220,10 +238,10 @@ kerb5_verify(pw, pass, auth)
 
 done:
     if (opts) {
-#ifdef HAVE_HEIMDAL
-       krb5_get_init_creds_opt_free(opts);
-#else
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_TWO_ARGS
        krb5_get_init_creds_opt_free(sudo_context, opts);
+#else
+       krb5_get_init_creds_opt_free(opts);
 #endif
     }
     if (creds)
index b2fe41a745671b84cf46f6500569c52c0d263904..cefb6d55516c0c5358210efa96f9a7f0f9883bec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -45,6 +45,7 @@
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include <pwd.h>
+#include <errno.h>
 
 #ifdef HAVE_PAM_PAM_APPL_H
 # include <pam/pam_appl.h>
 #endif
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: pam.c,v 1.43.2.10 2008/02/22 20:19:45 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: pam.c,v 1.66 2008/12/09 23:48:19 millert Exp $";
 #endif /* lint */
 
 static int sudo_conv __P((int, PAM_CONST struct pam_message **,
-                         struct pam_response **, VOID *));
+                         struct pam_response **, void *));
 static char *def_prompt;
+static int gotintr;
 
 #ifndef PAM_DATA_SILENT
 #define PAM_DATA_SILENT        0
@@ -96,7 +98,7 @@ pam_init(pw, promptp, auth)
 
     /* Initial PAM setup */
     if (auth != NULL)
-       auth->data = (VOID *) &pam_status;
+       auth->data = (void *) &pam_status;
     pam_conv.conv = sudo_conv;
     pam_status = pam_start("sudo", pw->pw_name, &pam_conv, &pamh);
     if (pam_status != PAM_SUCCESS) {
@@ -162,6 +164,10 @@ pam_verify(pw, prompt, auth)
            }
            /* FALLTHROUGH */
        case PAM_AUTH_ERR:
+           if (gotintr) {
+               /* error or ^C from tgetpass() */
+               return(AUTH_INTR);
+           }
        case PAM_MAXTRIES:
        case PAM_PERM_DENIED:
            return(AUTH_FAILURE);
@@ -244,17 +250,16 @@ sudo_conv(num_msg, msg, response, appdata_ptr)
     int num_msg;
     PAM_CONST struct pam_message **msg;
     struct pam_response **response;
-    VOID *appdata_ptr;
+    void *appdata_ptr;
 {
     struct pam_response *pr;
     PAM_CONST struct pam_message *pm;
     const char *prompt;
     char *pass;
     int n, flags, std_prompt;
-    extern int nil_pw;
 
     if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL)
-       return(PAM_CONV_ERR);
+       return(PAM_SYSTEM_ERR);
     zero_bytes(*response, num_msg * sizeof(struct pam_response));
 
     for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) {
@@ -266,7 +271,7 @@ sudo_conv(num_msg, msg, response, appdata_ptr)
                prompt = def_prompt;
 
                /* Is the sudo prompt standard? (If so, we'l just use PAM's) */
-               std_prompt = strncmp(def_prompt, "Password:", 9) == 0 &&
+               std_prompt =  strncmp(def_prompt, "Password:", 9) == 0 &&
                    (def_prompt[9] == '\0' ||
                    (def_prompt[9] == ' ' && def_prompt[10] == '\0'));
 
@@ -282,18 +287,20 @@ sudo_conv(num_msg, msg, response, appdata_ptr)
                    && (pm->msg[9] != ' ' || pm->msg[10] != '\0'))))
                    prompt = pm->msg;
 #endif
-               /* Read the password. */
+               /* Read the password unless interrupted. */
                pass = tgetpass(prompt, def_passwd_timeout * 60, flags);
                if (pass == NULL) {
                    /* We got ^C instead of a password; abort quickly. */
-                   nil_pw = 1;
+                   if (errno == EINTR)
+                       gotintr = 1;
+#if defined(__darwin__) || defined(__APPLE__)
+                   pass = "";
+#else
                    goto err;
+#endif
                }
                pr->resp = estrdup(pass);
-               if (*pr->resp == '\0')
-                   nil_pw = 1;         /* empty password */
-               else
-                   zero_bytes(pass, strlen(pass));
+               zero_bytes(pass, strlen(pass));
                break;
            case PAM_TEXT_INFO:
                if (pm->msg)
@@ -324,5 +331,5 @@ err:
     zero_bytes(*response, num_msg * sizeof(struct pam_response));
     free(*response);
     *response = NULL;
-    return(PAM_CONV_ERR);
+    return(gotintr ? PAM_AUTH_ERR : PAM_CONV_ERR);
 }
index ffd12e33ed1ecfd1a94aa6bf1b65bbc1f433b6f0..7746a7016aa5db1f94e0096f34117dc3d0812dc8 100644 (file)
@@ -47,7 +47,7 @@
 #include "sudo_auth.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: passwd.c,v 1.14.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: passwd.c,v 1.17 2005/02/12 22:56:07 millert Exp $";
 #endif /* lint */
 
 #define DESLEN                 13
index 079985bbeb5edc18b16db03f153a823f72f2dcd1..8da824b32a22b498b90a6df72b95d1761324d339 100644 (file)
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <pwd.h>
 
 #if defined(HAVE_SKEY)
@@ -69,7 +64,7 @@
 #include "sudo_auth.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: rfc1938.c,v 1.16.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: rfc1938.c,v 1.20 2005/02/12 22:56:07 millert Exp $";
 #endif /* lint */
 
 int
@@ -113,7 +108,7 @@ rfc1938_setup(pw, promptp, auth)
      */
     if (rfc1938challenge(&rfc1938, pw->pw_name, challenge, sizeof(challenge))) {
        if (IS_ONEANDONLY(auth)) {
-           warnx("you do not exist in the %s database", auth->name);
+           warningx("you do not exist in the %s database", auth->name);
            return(AUTH_FATAL);
        } else {
            return(AUTH_FAILURE);
index 435957d53211239f013f62762cd21b097e3e0d9a..d398a60d5de8c88620bf65b4a7468f27c6251ec1 100644 (file)
@@ -54,7 +54,7 @@
 #include "sudo_auth.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: secureware.c,v 1.10.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: secureware.c,v 1.13 2005/02/12 22:56:07 millert Exp $";
 #endif /* lint */
 
 int
index b16d44fa8686e539986e36c63549913b06a4378e..8ec7bbeff7c8d6ddae8d7c671ef2d5719101791d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <pwd.h>
 
 #include <sdi_athd.h>
@@ -59,7 +54,7 @@
 #include "sudo_auth.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: securid.c,v 1.12.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: securid.c,v 1.18 2008/11/09 14:13:13 millert Exp $";
 #endif /* lint */
 
 union config_record configure;
@@ -72,7 +67,7 @@ securid_init(pw, promptp, auth)
 {
     static struct SD_CLIENT sd_dat;            /* SecurID data block */
 
-    auth->data = (VOID *) &sd_dat;             /* For method-specific data */
+    auth->data = (void *) &sd_dat;             /* For method-specific data */
 
     if (creadcfg() == 0)
        return(AUTH_SUCCESS);
@@ -94,7 +89,7 @@ securid_setup(pw, promptp, auth)
        strlcpy(sd->username, pw->pw_name, 32);
        return(AUTH_SUCCESS);
     } else {
-       warnx("unable to contact the SecurID server");
+       warningx("unable to contact the SecurID server");
        return(AUTH_FATAL);
     }
 }
index b6585c3f01b04cb77e00bfd7703fd9f6f5fd481d..db254c2f51a3b50f420a4237d44bd079ad3c9bb9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
  * Copyright (c) 2002 Michael Stroucken <michael@stroucken.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <pwd.h>
 
 /* Needed for SecurID v5.0 Authentication on UNIX */
@@ -61,7 +56,7 @@
 #include "sudo_auth.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: securid5.c,v 1.6.2.2 2007/06/12 00:56:44 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: securid5.c,v 1.13 2008/11/09 14:13:13 millert Exp $";
 #endif /* lint */
 
 /*
@@ -84,13 +79,13 @@ securid_init(pw, promptp, auth)
 {
     static SDI_HANDLE sd_dat;                  /* SecurID handle */
 
-    auth->data = (VOID *) &sd_dat;             /* For method-specific data */
+    auth->data = (void *) &sd_dat;             /* For method-specific data */
 
     /* Start communications */
     if (AceInitialize() != SD_FALSE)
        return(AUTH_SUCCESS);
 
-    warnx("failed to initialise the ACE API library");
+    warningx("failed to initialise the ACE API library");
     return(AUTH_FATAL);
 }
 
@@ -118,7 +113,7 @@ securid_setup(pw, promptp, auth)
 
     /* Re-initialize SecurID every time. */
     if (SD_Init(sd) != ACM_OK) {
-       warnx("unable to contact the SecurID server");
+       warningx("unable to contact the SecurID server");
        return(AUTH_FATAL);
     }
 
@@ -127,23 +122,23 @@ securid_setup(pw, promptp, auth)
 
     switch (retval) {
        case ACM_OK:
-               warnx("User ID locked for SecurID Authentication");
+               warningx("User ID locked for SecurID Authentication");
                return(AUTH_SUCCESS);
 
         case ACE_UNDEFINED_USERNAME:
-               warnx("invalid username length for SecurID");
+               warningx("invalid username length for SecurID");
                return(AUTH_FATAL);
 
        case ACE_ERR_INVALID_HANDLE:
-               warnx("invalid Authentication Handle for SecurID");
+               warningx("invalid Authentication Handle for SecurID");
                return(AUTH_FATAL);
 
        case ACM_ACCESS_DENIED:
-               warnx("SecurID communication failed");
+               warningx("SecurID communication failed");
                return(AUTH_FATAL);
 
        default:
-               warnx("unknown SecurID error");
+               warningx("unknown SecurID error");
                return(AUTH_FATAL);
        }
 }
@@ -179,17 +174,17 @@ securid_verify(pw, pass, auth)
                break;
 
        case ACE_UNDEFINED_PASSCODE:
-               warnx("invalid passcode length for SecurID");
+               warningx("invalid passcode length for SecurID");
                rval = AUTH_FATAL;
                break;
 
        case ACE_UNDEFINED_USERNAME:
-               warnx("invalid username length for SecurID");
+               warningx("invalid username length for SecurID");
                rval = AUTH_FATAL;
                break;
 
        case ACE_ERR_INVALID_HANDLE:
-               warnx("invalid Authentication Handle for SecurID");
+               warningx("invalid Authentication Handle for SecurID");
                rval = AUTH_FATAL;
                break;
 
@@ -228,7 +223,7 @@ then enter the new token code.\n", \
                break;
 
        default:
-               warnx("unknown SecurID error");
+               warningx("unknown SecurID error");
                rval = AUTH_FATAL;
                break;
     }
index d35a59d340c6ea9cc5e9edaccf56ec2361278660..852e8c77dc5fc9fe5ce4a400ed13cf9883e4fab0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -50,7 +50,7 @@
 #include "sudo_auth.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: sia.c,v 1.14.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: sia.c,v 1.19 2008/11/09 14:13:13 millert Exp $";
 #endif /* lint */
 
 static int sudo_collect        __P((int, int, uchar_t *, int, prompt_t *));
@@ -108,7 +108,7 @@ sia_setup(pw, promptp, auth)
        return(AUTH_FATAL);
     }
 
-    auth->data = (VOID *) siah;
+    auth->data = (void *) siah;
     return(AUTH_SUCCESS);
 }
 
index a3cb56b66d7a1ba6c3d07d3b9eff546d568df1ed..509f26ff5b00a746259a877b143221b65fd6e5d5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -53,7 +53,7 @@
 #include "insults.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: sudo_auth.c,v 1.33.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: sudo_auth.c,v 1.38 2008/11/07 17:45:52 millert Exp $";
 #endif /* lint */
 
 sudo_auth auth_switch[] = {
@@ -88,8 +88,6 @@ sudo_auth auth_switch[] = {
     AUTH_ENTRY(0, NULL, NULL, NULL, NULL, NULL)
 };
 
-int nil_pw;            /* I hate resorting to globals like this... */
-
 void
 verify_user(pw, prompt)
     struct passwd *pw;
@@ -156,14 +154,11 @@ verify_user(pw, prompt)
        }
 
        /* Get the password unless the auth function will do it for us */
-       nil_pw = 0;
 #ifdef AUTH_STANDALONE
        p = prompt;
 #else
        p = (char *) tgetpass(prompt, def_passwd_timeout * 60,
            tgetpass_flags);
-       if (!p || *p == '\0')
-           nil_pw = 1;
 #endif /* AUTH_STANDALONE */
 
        /* Call authentication functions. */
@@ -186,16 +181,8 @@ verify_user(pw, prompt)
        if (p)
            zero_bytes(p, strlen(p));
 #endif
-
-       /* Exit loop on nil password, but give it a chance to match first. */
-       if (nil_pw) {
-           if (counter == def_passwd_tries)
-               exit(1);
-           else
-               break;
-       }
-
-       pass_warn(stderr);
+       if (!ISSET(tgetpass_flags, TGP_ASKPASS))
+           pass_warn(stderr);
     }
 
 cleanup:
@@ -218,14 +205,18 @@ cleanup:
        case AUTH_SUCCESS:
            (void) sigaction(SIGTSTP, &osa, NULL);
            return;
+       case AUTH_INTR:
        case AUTH_FAILURE:
-           if (def_mail_badpass || def_mail_always)
-               flags = 0;
-           else
-               flags = NO_MAIL;
-           log_error(flags, "%d incorrect password attempt%s",
-               def_passwd_tries - counter,
-               (def_passwd_tries - counter == 1) ? "" : "s");
+           if (counter != def_passwd_tries) {
+               if (def_mail_badpass || def_mail_always)
+                   flags = 0;
+               else
+                   flags = NO_MAIL;
+               log_error(flags, "%d incorrect password attempt%s",
+                   def_passwd_tries - counter,
+                   (def_passwd_tries - counter == 1) ? "" : "s");
+           }
+           /* FALLTHROUGH */
        case AUTH_FATAL:
            exit(1);
     }
index f3b224e161a3b12d998c0b82b03a68a42eceb341..ed1545f40e871187e1fc6d0184150b3b150d28e2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -13,7 +13,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $Sudo: sudo_auth.h,v 1.20.2.2 2007/06/12 01:28:42 millert Exp $
+ * $Sudo: sudo_auth.h,v 1.28 2008/12/02 17:30:39 millert Exp $
  */
 
 #ifndef SUDO_AUTH_H
 /* Auth function return values.  */
 #define AUTH_SUCCESS   0
 #define AUTH_FAILURE   1
-#define AUTH_FATAL     2
+#define AUTH_INTR      2
+#define AUTH_FATAL     3
 
 typedef struct sudo_auth {
     short flags;               /* various flags, see below */
     short status;              /* status from verify routine */
     char *name;                        /* name of the method as a string */
-    VOID *data;                        /* method-specific data pointer */
+    void *data;                        /* method-specific data pointer */
     int (*init) __P((struct passwd *pw, char **prompt, struct sudo_auth *auth));
     int (*setup) __P((struct passwd *pw, char **prompt, struct sudo_auth *auth));
     int (*verify) __P((struct passwd *pw, char *p, struct sudo_auth *auth));
@@ -57,6 +58,7 @@ int sia_setup __P((struct passwd *pw, char **prompt, sudo_auth *auth));
 int sia_verify __P((struct passwd *pw, char *prompt, sudo_auth *auth));
 int sia_cleanup __P((struct passwd *pw, sudo_auth *auth));
 int aixauth_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
+int aixauth_cleanup __P((struct passwd *pw, sudo_auth *auth));
 int bsdauth_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
 int bsdauth_verify __P((struct passwd *pw, char *prompt, sudo_auth *auth));
 int bsdauth_cleanup __P((struct passwd *pw, sudo_auth *auth));
@@ -92,14 +94,14 @@ int securid_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
 #  define AUTH_STANDALONE \
        AUTH_ENTRY(0, "SecurId", \
            securid_init, securid_setup, securid_verify, NULL)
-#elif defined(HAVE_SIA)
+#elif defined(HAVE_SIA_SES_INIT)
 #  define AUTH_STANDALONE \
        AUTH_ENTRY(0, "sia", \
            NULL, sia_setup, sia_verify, sia_cleanup)
 #elif defined(HAVE_AIXAUTH)
 #  define AUTH_STANDALONE \
        AUTH_ENTRY(0, "aixauth", \
-           NULL, NULL, aixauth_verify, NULL)
+           NULL, NULL, aixauth_verify, aixauth_cleanup)
 #elif defined(HAVE_FWTK)
 #  define AUTH_STANDALONE \
        AUTH_ENTRY(0, "fwtk", \
diff --git a/check.c b/check.c
index 4889ac7af96acbdcfb49f6d15f147540561b4d1b..fedc91640af8fc1b99b51c113c0a4ba5a825e22b 100644 (file)
--- a/check.c
+++ b/check.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1993-1996,1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1993-1996,1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
@@ -63,7 +59,7 @@
 #include "sudo.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: check.c,v 1.223.2.10 2008/01/05 23:59:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: check.c,v 1.245 2008/11/25 17:01:34 millert Exp $";
 #endif /* lint */
 
 /* Status codes for timestamp_status() */
@@ -88,8 +84,9 @@ static void  update_timestamp __P((char *, char *));
  * verify who he/she is.
  */
 void
-check_user(validated)
+check_user(validated, interactive)
     int validated;
+    int interactive;
 {
     char *timestampdir = NULL;
     char *timestampfile = NULL;
@@ -103,7 +100,29 @@ check_user(validated)
     status = timestamp_status(timestampdir, timestampfile, user_name,
        TS_MAKE_DIRS);
     if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) {
-       lecture(status);
+       /* Bail out if we are non-interactive and a password is required */
+       if (!interactive)
+           errorx(1, "sorry, a password is required to run %s", getprogname());
+
+       /* If user specified -A, make sure we have an askpass helper. */
+       if (ISSET(tgetpass_flags, TGP_ASKPASS)) {
+           if (user_askpass == NULL)
+               log_error(NO_MAIL,
+                   "no askpass program specified, try setting SUDO_ASKPASS");
+       } else if (!ISSET(tgetpass_flags, TGP_STDIN)) {
+           /* If no tty but DISPLAY is set, use askpass if we have it. */
+           if (!user_ttypath && !tty_present()) {
+               if (user_askpass && user_display && *user_display != '\0') {
+                   SET(tgetpass_flags, TGP_ASKPASS);
+               } else if (!def_visiblepw) {
+                   log_error(NO_MAIL,
+                       "no tty present and no askpass program specified");
+               }
+           }
+       }
+
+       if (!ISSET(tgetpass_flags, TGP_ASKPASS))
+           lecture(status);
 
        /* Expand any escapes in the prompt. */
        prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt,
@@ -211,7 +230,7 @@ expand_prompt(old_prompt, user, host)
                    if (def_rootpw)
                            len += 2;
                    else if (def_targetpw || def_runaspw)
-                           len += strlen(*user_runas) - 2;
+                           len += strlen(runas_pw->pw_name) - 2;
                    else
                            len += strlen(user_name) - 2;
                    subst = 1;
@@ -223,7 +242,7 @@ expand_prompt(old_prompt, user, host)
                    break;
                case 'U':
                    p++;
-                   len += strlen(*user_runas) - 2;
+                   len += strlen(runas_pw->pw_name) - 2;
                    subst = 1;
                    break;
                case '%':
@@ -262,7 +281,7 @@ expand_prompt(old_prompt, user, host)
                        if (def_rootpw)
                                n = strlcpy(np, "root", np - endp);
                        else if (def_targetpw || def_runaspw)
-                               n = strlcpy(np, *user_runas, np - endp);
+                               n = strlcpy(np, runas_pw->pw_name, np - endp);
                        else
                                n = strlcpy(np, user_name, np - endp);
                        if (n >= np - endp)
@@ -278,7 +297,7 @@ expand_prompt(old_prompt, user, host)
                        continue;
                    case 'U':
                        p++;
-                       n = strlcpy(np,  *user_runas, np - endp);
+                       n = strlcpy(np,  runas_pw->pw_name, np - endp);
                        if (n >= np - endp)
                            goto oflow;
                        np += n;
@@ -304,7 +323,7 @@ expand_prompt(old_prompt, user, host)
 
 oflow:
     /* We pre-allocate enough space, so this should never happen. */
-    errx(1, "internal error, expand_prompt() overflow");
+    errorx(1, "internal error, expand_prompt() overflow");
 }
 
 /*
@@ -319,7 +338,7 @@ user_is_exempt()
     if (!def_exempt_group)
        return(FALSE);
 
-    if (!(grp = getgrnam(def_exempt_group)))
+    if (!(grp = sudo_getgrnam(def_exempt_group)))
        return(FALSE);
 
     if (user_gid == grp->gr_gid)
@@ -362,14 +381,14 @@ build_timestamp(timestampdir, timestampfile)
            p = user_tty;
        if (def_targetpw)
            len = easprintf(timestampfile, "%s/%s/%s:%s", dirparent, user_name,
-               p, *user_runas);
+               p, runas_pw->pw_name);
        else
            len = easprintf(timestampfile, "%s/%s/%s", dirparent, user_name, p);
        if (len >= PATH_MAX)
            log_error(0, "timestamp path too long: %s", *timestampfile);
     } else if (def_targetpw) {
        len = easprintf(timestampfile, "%s/%s/%s", dirparent, user_name,
-           *user_runas);
+           runas_pw->pw_name);
        if (len >= PATH_MAX)
            log_error(0, "timestamp path too long: %s", *timestampfile);
     } else
@@ -584,7 +603,7 @@ remove_timestamp(remove)
        } else {
            timespecclear(&ts);
            if (touch(-1, path, &ts) == -1)
-               err(1, "can't reset %s to Epoch", path);
+               error(1, "can't reset %s to Epoch", path);
        }
     }
 
index 2cdca655798e1d539fafcc9873671d64b72e756f..0f043f4807b9c2e44584681c9729c71457ac3639 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2004-2005, 2007
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -49,7 +50,7 @@
 #include "sudo.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.6.2.3 2007/06/20 11:06:50 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.14 2008/11/09 14:13:12 millert Exp $";
 #endif /* lint */
 
 #ifndef HAVE_FCNTL_CLOSEM
index 6469bb93c2ae5f295080447a598cdbb47ee13a10..39fcdd7e9bf6e8a1a1a0a1fa974fa37c9b13beb7 100644 (file)
--- a/compat.h
+++ b/compat.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1996, 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1996, 1998-2005, 2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,7 +18,7 @@
  * Agency (DARPA) and Air Force Research Laboratory, Air Force
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  *
- * $Sudo: compat.h,v 1.76.2.4 2007/06/12 01:28:41 millert Exp $
+ * $Sudo: compat.h,v 1.90 2008/11/09 14:13:12 millert Exp $
  */
 
 #ifndef _SUDO_COMPAT_H
 #if !defined(__GNUC__) || __GNUC__ < 2 || __GNUC__ == 2 && __GNUC_MINOR__ < 5
 # define __attribute__(x)
 #endif
+
 /* For silencing gcc warnings about rcsids */
 #ifndef __unused
 # if defined(__GNUC__) && (__GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ > 7)
-#  define __unused      __attribute__((__unused__))
+#  define __unused     __attribute__((__unused__))
 # else
 #  define __unused
 # endif
@@ -53,7 +54,7 @@
 /* For catching format string mismatches */
 #ifndef __printflike
 # if defined(__GNUC__) && (__GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7)
-#  define __printflike(f, v)    __attribute__((__format__ (__printf__, f, v)))
+#  define __printflike(f, v)   __attribute__((__format__ (__printf__, f, v)))
 # else
 #  define __printflike(f, v)
 # endif
 #endif
 
 /*
- * Simple isblank() macro for systems without it.
+ * Simple isblank() macro and function for systems without it.
  */
 #ifndef HAVE_ISBLANK
+int isblank __P((int));
 # define isblank(_x)   ((_x) == ' ' || (_x) == '\t')
 #endif
 
index a009a090ae5c041ab0732fdde0061cb492716e07..70de108a3b6bbc00b14906b00760f334134c62f5 100644 (file)
@@ -3,6 +3,10 @@
 #ifndef _SUDO_CONFIG_H
 #define _SUDO_CONFIG_H
 
+/* Define to `signed' or nothing if compiler does not support a signed
+   type qualifier. */
+#undef __signed
+
 /* Define to 1 if the `syslog' function returns a non-zero int to denote
    failure. */
 #undef BROKEN_SYSLOG
 /* Define to 1 if you have the `asprintf' function. */
 #undef HAVE_ASPRINTF
 
-/* Define to 1 if you have the `authenticate' function. */
-#undef HAVE_AUTHENTICATE
-
-/* Define to 1 if you have the `auth_challenge' function. */
-#undef HAVE_AUTH_CHALLENGE
-
 /* Define to 1 if you have the `bigcrypt' function. */
 #undef HAVE_BIGCRYPT
 
@@ -94,9 +92,6 @@
 /* Define to 1 if you have the `dispcrypt' function. */
 #undef HAVE_DISPCRYPT
 
-/* Define to 1 if you have the <err.h> header file. */
-#undef HAVE_ERR_H
-
 /* Define to 1 if your glob.h defines the GLOB_BRACE and GLOB_TILDE flags. */
 #undef HAVE_EXTENDED_GLOB
 
 /* Define to 1 if you have the `gettimeofday' function. */
 #undef HAVE_GETTIMEOFDAY
 
+/* Define to 1 if you have the `getuserattr' function. */
+#undef HAVE_GETUSERATTR
+
 /* Define to 1 if you have the `glob' function. */
 #undef HAVE_GLOB
 
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_KRB5_H
+
+/* Define to 1 if you have the `gss_krb5_ccache_name' function. */
+#undef HAVE_GSS_KRB5_CCACHE_NAME
+
 /* Define to 1 if your Kerberos is Heimdal. */
 #undef HAVE_HEIMDAL
 
 /* Define to 1 if you use Kerberos V. */
 #undef HAVE_KERB5
 
+/* Define to 1 if you have the `krb5_get_init_creds_opt_alloc' function. */
+#undef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
+
+/* Define to 1 if your `krb5_get_init_creds_opt_alloc' function takes two arguments. */
+#undef HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_TWO_ARGS
+
 /* Define to 1 if you have the `krb5_init_secure_context' function. */
 #undef HAVE_KRB5_INIT_SECURE_CONTEXT
 
 /* Define to 1 if you use LDAP for sudoers. */
 #undef HAVE_LDAP
 
+/* Define to 1 if you have the `ldap_create' function. */
+#undef HAVE_LDAP_CREATE
+
 /* Define to 1 if you have the `ldap_initialize' function. */
 #undef HAVE_LDAP_INITIALIZE
 
+/* Define to 1 if you have the `ldap_sasl_bind_s' function. */
+#undef HAVE_LDAP_SASL_BIND_S
+
+/* Define to 1 if you have the `ldap_sasl_interactive_bind_s' function. */
+#undef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
+
+/* Define to 1 if you have the `ldap_search_ext_s' function. */
+#undef HAVE_LDAP_SEARCH_EXT_S
+
 /* Define to 1 if you have the <ldap_ssl.h> header file. */
 #undef HAVE_LDAP_SSL_H
 
 /* Define to 1 if you have the `ldap_start_tls_s' function. */
 #undef HAVE_LDAP_START_TLS_S
 
+/* Define to 1 if you have the `ldap_str2dn' function. */
+#undef HAVE_LDAP_STR2DN
+
+/* Define to 1 if you have the `ldap_unbind_ext_s' function. */
+#undef HAVE_LDAP_UNBIND_EXT_S
+
 /* Define to 1 if you have the `ldapssl_init' function. */
 #undef HAVE_LDAPSSL_INIT
 
 /* Define to 1 if you have the `lrand48' function. */
 #undef HAVE_LRAND48
 
-/* Define to 1 if you have the `lsearch' function. */
-#undef HAVE_LSEARCH
-
 /* Define to 1 if you have the <malloc.h> header file. */
 #undef HAVE_MALLOC_H
 
 /* Define to 1 if you have the `random' function. */
 #undef HAVE_RANDOM
 
+/* Define to 1 if you have the <sasl/sasl.h> header file. */
+#undef HAVE_SASL_SASL_H
+
 /* Define if your struct sockadr has an sa_len field. */
 #undef HAVE_SA_LEN
 
 /* Define to 1 if you use SecurID for authentication. */
 #undef HAVE_SECURID
 
-/* Define to 1 if you have the <security/pam_appl.h> header file. */
-#undef HAVE_SECURITY_PAM_APPL_H
-
 /* Define to 1 to enable SELinux RBAC support. */
 #undef HAVE_SELINUX
 
 /* Define to 1 if you have the `set_auth_parameters' function. */
 #undef HAVE_SET_AUTH_PARAMETERS
 
-/* Define to 1 if you use SIA authentication. */
-#undef HAVE_SIA
-
 /* Define to 1 if you have the `sia_ses_init' function. */
 #undef HAVE_SIA_SES_INIT
 
 /* Define to 1 if <signal.h> has the sigaction_t typedef. */
 #undef HAVE_SIGACTION_T
 
-/* Define to 1 if the system has the type `sig_atomic_t'. */
-#undef HAVE_SIG_ATOMIC_T
-
 /* Define to 1 if you use S/Key. */
 #undef HAVE_SKEY
 
 /* Define to 1 if you want a two line OTP (S/Key or OPIE) prompt. */
 #undef LONG_OTP_PROMPT
 
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
-   */
-#undef LT_OBJDIR
-
 /* The subject of the mail sent by sudo to the MAILTO user/address. */
 #undef MAILSUBJECT
 
 /* Define to 1 if you want a different ticket file for each tty. */
 #undef USE_TTY_TICKETS
 
-/* Define to "void" if your compiler supports void pointers, else use "char".
-   */
-#undef VOID
-
 /* Define to avoid using the passwd/shadow file for authentication. */
 #undef WITHOUT_PASSWD
 
-/* Path to the ldap.conf file */
-#undef _PATH_LDAP_CONF
-
-/* Path to the ldap.secret file */
-#undef _PATH_LDAP_SECRET
-
-/* The fully qualified pathname of sudo_noexec.so */
-#undef _PATH_SUDO_NOEXEC
-
 /* Define to empty if `const' does not conform to ANSI C. */
 #undef const
 
index c2fd1925a17cfa8c7fee8ed5263fbc2e6b87b2b1..0bf4e23cf85afae991b60ba2825d13955efdb1ca 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for sudo 1.6.9.
+# Generated by GNU Autoconf 2.61 for sudo 1.7.
 #
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
 # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
@@ -722,8 +722,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='sudo'
 PACKAGE_TARNAME='sudo'
-PACKAGE_VERSION='1.6.9'
-PACKAGE_STRING='sudo 1.6.9'
+PACKAGE_VERSION='1.7'
+PACKAGE_STRING='sudo 1.7'
 PACKAGE_BUGREPORT=''
 
 # Factoring default headers for most tests.
@@ -822,6 +822,7 @@ SELINUX
 BAMAN
 LCMAN
 SEMAN
+devdir
 mansectsu
 mansectform
 mansrcdir
@@ -830,6 +831,10 @@ NOEXECDIR
 noexec_file
 INSTALL_NOEXEC
 DONT_LEAK_PATH_INFO
+BSDAUTH_USAGE
+SELINUX_USAGE
+LDAP
+LOGINCAP_USAGE
 timedir
 timeout
 password_timeout
@@ -856,6 +861,9 @@ tty_tickets
 insults
 root_sudo
 path_info
+ldap_conf
+ldap_secret
+nsswitch_conf
 EGREPPROG
 CC
 ac_ct_CC
@@ -890,7 +898,6 @@ NROFFPROG
 YACC
 YFLAGS
 LIBOBJS
-ALLOCA
 KRB5CONFIG
 LTLIBOBJS'
 ac_subst_files=''
@@ -1407,7 +1414,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures sudo 1.6.9 to adapt to many kinds of systems.
+\`configure' configures sudo 1.7 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1473,7 +1480,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of sudo 1.6.9:";;
+     short | recursive ) echo "Configuration of sudo 1.7:";;
    esac
   cat <<\_ACEOF
 
@@ -1490,8 +1497,10 @@ Optional Features:
   --enable-log-host       Log the hostname in the log file
   --enable-noargs-shell   If sudo is given no arguments run a shell
   --enable-shell-sets-home
-                          set $HOME to target user in shell mode
+                          Set $HOME to target user in shell mode
   --disable-path-info     Print 'command not allowed' not 'command not found'
+  --enable-gss-krb5-ccache-name
+                          Use GSS-API to set the Kerberos V cred cache name
   --enable-static[=PKGS]  build static libraries [default=no]
   --enable-shared[=PKGS]  build shared libraries [default=yes]
   --enable-fast-install[=PKGS]
@@ -1567,6 +1576,7 @@ Optional Packages:
   --with-csops-insults    include CSOps insults
   --with-hal-insults      include 2001-like insults
   --with-goons-insults    include the insults from the "Goon Show"
+  --with-nsswitch[=PATH]  path to nsswitch.conf
   --with-ldap[=DIR]       enable LDAP support
   --with-ldap-conf-file   path to LDAP configuration file
   --with-ldap-secret-file path to LDAP secret password file
@@ -1574,6 +1584,7 @@ Optional Packages:
   --with-secure-path      override the user's path with a built-in one
   --without-interfaces    don't try to read the ip addr of ether interfaces
   --with-stow             properly handle GNU stow packaging
+  --with-askpass=PATH     Fully qualified pathname of askpass helper
   --with-selinux          enable SELinux support
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
   --with-pic              try to use only PIC/non-PIC objects [default=use
@@ -1658,7 +1669,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-sudo configure 1.6.9
+sudo configure 1.7
 generated by GNU Autoconf 2.61
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1672,7 +1683,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by sudo $as_me 1.6.9, which was
+It was created by sudo $as_me 1.7, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   $ $0 $@
@@ -2027,8 +2038,16 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 ac_config_headers="$ac_config_headers config.h pathnames.h"
 
-{ echo "$as_me:$LINENO: Configuring Sudo version 1.6.9" >&5
-echo "$as_me: Configuring Sudo version 1.6.9" >&6;}
+{ echo "$as_me:$LINENO: Configuring Sudo version 1.7" >&5
+echo "$as_me: Configuring Sudo version 1.7" >&6;}
+
+
+
+
+
+
+
+
 
 
 
@@ -2112,6 +2131,7 @@ insults=off
 root_sudo=on
 path_info=on
 INSTALL_NOEXEC=
+devdir='$(srcdir)'
 PROGS="sudo visudo"
 : ${MANTYPE='man'}
 : ${mansrcdir='.'}
@@ -2119,6 +2139,7 @@ PROGS="sudo visudo"
 : ${SUDOERS_UID='0'}
 : ${SUDOERS_GID='0'}
 DEV="#"
+LDAP="#"
 SELINUX="#"
 BAMAN='.\" '
 LCMAN='.\" '
@@ -2282,6 +2303,7 @@ echo "$as_me: Setting up for development: -Wall, flex, yacc" >&6;}
                PROGS="${PROGS} testsudoers"
                OSDEFS="${OSDEFS} -DSUDO_DEVEL"
                DEV=""
+               devdir=.
                ;;
     no)                ;;
     *)         { echo "$as_me:$LINENO: WARNING: Ignoring unknown argument to --with-devel: $with_devel" >&5
@@ -3547,6 +3569,27 @@ fi
 
 
 
+# Check whether --with-nsswitch was given.
+if test "${with_nsswitch+set}" = set; then
+  withval=$with_nsswitch; case $with_nsswitch in
+    no)                ;;
+    yes)       with_nsswitch="/etc/nsswitch.conf"
+               ;;
+    *)         ;;
+esac
+fi
+
+if test ${with_nsswitch-"yes"} != "no"; then
+    cat >>confdefs.h <<EOF
+#define _PATH_NSSWITCH_CONF "${with_nsswitch-/etc/nsswitch.conf}"
+EOF
+
+    nsswitch_conf=${with_nsswitch-/etc/nsswitch.conf}
+else
+    nsswitch_conf='/etc/nsswitch.conf'
+fi
+
+
 # Check whether --with-ldap was given.
 if test "${with_ldap+set}" = set; then
   withval=$with_ldap; case $with_ldap in
@@ -3564,25 +3607,29 @@ esac
 fi
 
 
+
 # Check whether --with-ldap-conf-file was given.
 if test "${with_ldap_conf_file+set}" = set; then
   withval=$with_ldap_conf_file;
-cat >>confdefs.h <<_ACEOF
-#define _PATH_LDAP_CONF "$with_ldap_conf_file"
-_ACEOF
-
 fi
 
+cat >>confdefs.h <<EOF
+#define _PATH_LDAP_CONF "${with_ldap_conf_file-/etc/ldap.conf}"
+EOF
+
+ldap_conf=${with_ldap_conf_file-'/etc/ldap.conf'}
+
 
 # Check whether --with-ldap-secret-file was given.
 if test "${with_ldap_secret_file+set}" = set; then
   withval=$with_ldap_secret_file;
-cat >>confdefs.h <<_ACEOF
-#define _PATH_LDAP_SECRET "$with_ldap_secret_file"
-_ACEOF
-
 fi
 
+cat >>confdefs.h <<EOF
+#define _PATH_LDAP_SECRET "${with_ldap_secret_file-/etc/ldap.secret}"
+EOF
+
+ldap_secret=${with_ldap_secret_file-'/etc/ldap.secret'}
 
 
 # Check whether --with-pc-insults was given.
@@ -3698,6 +3745,30 @@ echo "${ECHO_T}no" >&6; }
 fi
 
 
+{ echo "$as_me:$LINENO: checking whether to use an askpass helper" >&5
+echo $ECHO_N "checking whether to use an askpass helper... $ECHO_C" >&6; }
+
+# Check whether --with-askpass was given.
+if test "${with_askpass+set}" = set; then
+  withval=$with_askpass; case $with_askpass in
+    yes)       { { echo "$as_me:$LINENO: error: \"--with-askpass takes a path as an argument.\"" >&5
+echo "$as_me: error: \"--with-askpass takes a path as an argument.\"" >&2;}
+   { (exit 1); exit 1; }; }
+               ;;
+    no)                ;;
+    *)
+cat >>confdefs.h <<_ACEOF
+#define _PATH_SUDO_ASKPASS "$with_askpass"
+_ACEOF
+
+               ;;
+esac
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
 
 { echo "$as_me:$LINENO: checking whether to do user authentication by default" >&5
 echo $ECHO_N "checking whether to do user authentication by default... $ECHO_C" >&6; }
@@ -3947,7 +4018,8 @@ fi
 # Check whether --with-selinux was given.
 if test "${with_selinux+set}" = set; then
   withval=$with_selinux; case $with_selinux in
-    yes)       cat >>confdefs.h <<\_ACEOF
+    yes)       SELINUX_USAGE="[-r role] [-t type] "
+               cat >>confdefs.h <<\_ACEOF
 #define HAVE_SELINUX 1
 _ACEOF
 
@@ -3966,6 +4038,14 @@ esac
 fi
 
 
+# Check whether --enable-gss_krb5_ccache_name was given.
+if test "${enable_gss_krb5_ccache_name+set}" = set; then
+  enableval=$enable_gss_krb5_ccache_name; check_gss_krb5_ccache_name=$enableval
+else
+  check_gss_krb5_ccache_name=no
+fi
+
+
 # Extract the first word of "egrep", so it can be a program name with args.
 set dummy egrep; ac_word=$2
 { echo "$as_me:$LINENO: checking for $ac_word" >&5
@@ -6129,7 +6209,7 @@ ia64-*-hpux*)
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 6132 "configure"' > conftest.$ac_ext
+  echo '#line 6212 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -7988,11 +8068,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:7991: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8071: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:7995: \$? = $ac_status" >&5
+   echo "$as_me:8075: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8278,11 +8358,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8281: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8361: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:8285: \$? = $ac_status" >&5
+   echo "$as_me:8365: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8382,11 +8462,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8385: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8465: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:8389: \$? = $ac_status" >&5
+   echo "$as_me:8469: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -10742,7 +10822,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 10745 "configure"
+#line 10825 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10842,7 +10922,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 10845 "configure"
+#line 10925 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
 done
 
                fi
+
+               # AIX-specific functions
+
+for ac_func in getuserattr
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+               SUDO_OBJS="$SUDO_OBJS aix.o"
                ;;
     *-*-hiuxmpp*)
                : ${mansectsu='1m'}
@@ -11881,6 +12058,10 @@ done
                : ${mansectsu='1m'}
                : ${mansectform='4'}
 
+               # HP-UX bundled compiler can't generate shared objects
+               if test "x$ac_cv_prog_cc_c89" = "xno"; then
+                   with_noexec=no
+               fi
                case "$host" in
                        *-*-hpux1-8.*)
                            cat >>confdefs.h <<\_ACEOF
 
 done
 
+if test "$OS" != "ultrix"; then
+    { echo "$as_me:$LINENO: checking POSIX termios" >&5
+echo $ECHO_N "checking POSIX termios... $ECHO_C" >&6; }
+if test "${ac_cv_sys_posix_termios+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <unistd.h>
+#include <termios.h>
+
+int
+main ()
+{
+/* SunOS 4.0.3 has termios.h but not the library calls.  */
+   tcgetattr(0, 0);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_sys_posix_termios=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_sys_posix_termios=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sys_posix_termios" >&5
+echo "${ECHO_T}$ac_cv_sys_posix_termios" >&6; }
+
+    if test "$ac_cv_sys_posix_termios" = "yes"; then
+       cat >>confdefs.h <<\_ACEOF
+#define HAVE_TERMIOS_H 1
+_ACEOF
+
+    else
 
-for ac_header in err.h
+for ac_header in termio.h
 do
 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
 if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
@@ -13703,248 +13947,38 @@ if test `eval echo '${'$as_ac_Header'}'` = yes; then
 #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
 
-else
-  case " $LIBOBJS " in
-  *" err.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS err.$ac_objext"
- ;;
-esac
-
 fi
 
 done
 
-if test "$OS" != "ultrix"; then
-    { echo "$as_me:$LINENO: checking POSIX termios" >&5
-echo $ECHO_N "checking POSIX termios... $ECHO_C" >&6; }
-if test "${ac_cv_sys_posix_termios+set}" = set; then
+    fi
+fi
+if test ${with_logincap-'no'} != "no"; then
+
+for ac_header in login_cap.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
 else
-  cat >conftest.$ac_ext <<_ACEOF
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-#include <sys/types.h>
-#include <unistd.h>
-#include <termios.h>
-
-int
-main ()
-{
-/* SunOS 4.0.3 has termios.h but not the library calls.  */
-   tcgetattr(0, 0);
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext &&
-       $as_test_x conftest$ac_exeext; then
-  ac_cv_sys_posix_termios=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_sys_posix_termios=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-{ echo "$as_me:$LINENO: result: $ac_cv_sys_posix_termios" >&5
-echo "${ECHO_T}$ac_cv_sys_posix_termios" >&6; }
-
-    if test "$ac_cv_sys_posix_termios" = "yes"; then
-       cat >>confdefs.h <<\_ACEOF
-#define HAVE_TERMIOS_H 1
-_ACEOF
-
-    else
-
-for ac_header in termio.h
-do
-as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { echo "$as_me:$LINENO: checking for $ac_header" >&5
-echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-fi
-ac_res=`eval echo '${'$as_ac_Header'}'`
-              { echo "$as_me:$LINENO: result: $ac_res" >&5
-echo "${ECHO_T}$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
-echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-echo "${ECHO_T}$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
-echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
-fi
-
-rm -f conftest.err conftest.$ac_ext
-{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-echo "${ECHO_T}$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
-
-    ;;
-esac
-{ echo "$as_me:$LINENO: checking for $ac_header" >&5
-echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval echo '${'$as_ac_Header'}'`
-              { echo "$as_me:$LINENO: result: $ac_res" >&5
-echo "${ECHO_T}$ac_res" >&6; }
-
-fi
-if test `eval echo '${'$as_ac_Header'}'` = yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-
-done
-
-    fi
-fi
-if test ${with_logincap-'no'} != "no"; then
-
-for ac_header in login_cap.h
-do
-as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { echo "$as_me:$LINENO: checking for $ac_header" >&5
-echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-fi
-ac_res=`eval echo '${'$as_ac_Header'}'`
-              { echo "$as_me:$LINENO: result: $ac_res" >&5
-echo "${ECHO_T}$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
-echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
+$ac_includes_default
+#include <$ac_header>
 _ACEOF
 rm -f conftest.$ac_objext
 if { (ac_try="$ac_compile"
@@ -14055,7 +14089,7 @@ if test `eval echo '${'$as_ac_Header'}'` = yes; then
   cat >>confdefs.h <<_ACEOF
 #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
- LCMAN=""
+ LOGINCAP_USAGE='[-c class|-] '; LCMAN=""
        case "$OS" in
            freebsd|netbsd)     SUDO_LIBS="${SUDO_LIBS} -lutil"
            ;;
@@ -14305,9 +14339,9 @@ _ACEOF
 
 fi
 
-{ echo "$as_me:$LINENO: checking for sig_atomic_t" >&5
-echo $ECHO_N "checking for sig_atomic_t... $ECHO_C" >&6; }
-if test "${ac_cv_type_sig_atomic_t+set}" = set; then
+{ echo "$as_me:$LINENO: checking for __signed char" >&5
+echo $ECHO_N "checking for __signed char... $ECHO_C" >&6; }
+if test "${ac_cv_type___signed_char+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat >conftest.$ac_ext <<_ACEOF
@@ -14316,10 +14350,8 @@ _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-#include <sys/types.h>
-#include <signal.h>
-
-typedef sig_atomic_t ac__type_new_;
+$ac_includes_default
+typedef __signed char ac__type_new_;
 int
 main ()
 {
@@ -14348,35 +14380,24 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
         test -z "$ac_c_werror_flag" ||
         test ! -s conftest.err
        } && test -s conftest.$ac_objext; then
-  ac_cv_type_sig_atomic_t=yes
+  ac_cv_type___signed_char=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_cv_type_sig_atomic_t=no
+       ac_cv_type___signed_char=no
 fi
 
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-{ echo "$as_me:$LINENO: result: $ac_cv_type_sig_atomic_t" >&5
-echo "${ECHO_T}$ac_cv_type_sig_atomic_t" >&6; }
-if test $ac_cv_type_sig_atomic_t = yes; then
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_SIG_ATOMIC_T 1
-_ACEOF
-
-
+{ echo "$as_me:$LINENO: result: $ac_cv_type___signed_char" >&5
+echo "${ECHO_T}$ac_cv_type___signed_char" >&6; }
+if test $ac_cv_type___signed_char = yes; then
+  :
 else
-  cat >>confdefs.h <<\_ACEOF
-#define sig_atomic_t int
-_ACEOF
-
-fi
-
-{ echo "$as_me:$LINENO: checking for sigaction_t" >&5
-echo $ECHO_N "checking for sigaction_t... $ECHO_C" >&6; }
-if test "${ac_cv_type_sigaction_t+set}" = set; then
+  { echo "$as_me:$LINENO: checking for signed char" >&5
+echo $ECHO_N "checking for signed char... $ECHO_C" >&6; }
+if test "${ac_cv_type_signed_char+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat >conftest.$ac_ext <<_ACEOF
@@ -14385,10 +14406,8 @@ _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-#include <sys/types.h>
-#include <signal.h>
-
-typedef sigaction_t ac__type_new_;
+$ac_includes_default
+typedef signed char ac__type_new_;
 int
 main ()
 {
@@ -14417,33 +14436,166 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
         test -z "$ac_c_werror_flag" ||
         test ! -s conftest.err
        } && test -s conftest.$ac_objext; then
-  ac_cv_type_sigaction_t=yes
+  ac_cv_type_signed_char=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_cv_type_sigaction_t=no
+       ac_cv_type_signed_char=no
 fi
 
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-{ echo "$as_me:$LINENO: result: $ac_cv_type_sigaction_t" >&5
-echo "${ECHO_T}$ac_cv_type_sigaction_t" >&6; }
-if test $ac_cv_type_sigaction_t = yes; then
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_SIGACTION_T 1
+{ echo "$as_me:$LINENO: result: $ac_cv_type_signed_char" >&5
+echo "${ECHO_T}$ac_cv_type_signed_char" >&6; }
+if test $ac_cv_type_signed_char = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define __signed signed
 _ACEOF
 
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_SIGACTION_T 1
+else
+  cat >>confdefs.h <<\_ACEOF
+#define __signed
 _ACEOF
 
 fi
 
-{ echo "$as_me:$LINENO: checking for struct timespec" >&5
-echo $ECHO_N "checking for struct timespec... $ECHO_C" >&6; }
-if test "${ac_cv_type_struct_timespec+set}" = set; then
+fi
+
+{ echo "$as_me:$LINENO: checking for sig_atomic_t" >&5
+echo $ECHO_N "checking for sig_atomic_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_sig_atomic_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <signal.h>
+
+typedef sig_atomic_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_sig_atomic_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_sig_atomic_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_sig_atomic_t" >&5
+echo "${ECHO_T}$ac_cv_type_sig_atomic_t" >&6; }
+if test $ac_cv_type_sig_atomic_t = yes; then
+  :
+else
+  cat >>confdefs.h <<\_ACEOF
+#define sig_atomic_t int
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for sigaction_t" >&5
+echo $ECHO_N "checking for sigaction_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_sigaction_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <signal.h>
+
+typedef sigaction_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_sigaction_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_sigaction_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_sigaction_t" >&5
+echo "${ECHO_T}$ac_cv_type_sigaction_t" >&6; }
+if test $ac_cv_type_sigaction_t = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SIGACTION_T 1
+_ACEOF
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIGACTION_T 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for struct timespec" >&5
+echo $ECHO_N "checking for struct timespec... $ECHO_C" >&6; }
+if test "${ac_cv_type_struct_timespec+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat >conftest.$ac_ext <<_ACEOF
@@ -14729,61 +14881,6 @@ _ACEOF
 
 fi
 
-{ echo "$as_me:$LINENO: checking for full void implementation" >&5
-echo $ECHO_N "checking for full void implementation... $ECHO_C" >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-int
-main ()
-{
-void *foo;
-foo = (void *)0; (void *)"test";
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-
-cat >>confdefs.h <<\_ACEOF
-#define VOID void
-_ACEOF
-
-{ echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6; }
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       cat >>confdefs.h <<\_ACEOF
-#define VOID char
-_ACEOF
-
-{ echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6; }
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
 { echo "$as_me:$LINENO: checking max length of uid_t" >&5
 echo $ECHO_N "checking max length of uid_t... $ECHO_C" >&6; }
@@ -16742,7 +16839,7 @@ fi
 done
 
 
-for ac_func in lsearch
+for ac_func in utimes
 do
 as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
 { echo "$as_me:$LINENO: checking for $ac_func" >&5
@@ -16832,20 +16929,37 @@ if test `eval echo '${'$as_ac_var'}'` = yes; then
 #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
 _ACEOF
 
-else
-  { echo "$as_me:$LINENO: checking for lsearch in -lcompat" >&5
-echo $ECHO_N "checking for lsearch in -lcompat... $ECHO_C" >&6; }
-if test "${ac_cv_lib_compat_lsearch+set}" = set; then
+
+for ac_func in futimes futimesat
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lcompat  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
+  cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
 
 /* Override any GCC internal prototype to avoid an error.
    Use char because int might match the return type of a GCC
@@ -16853,11 +16967,18 @@ cat >>conftest.$ac_ext <<_ACEOF
 #ifdef __cplusplus
 extern "C"
 #endif
-char lsearch ();
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
 int
 main ()
 {
-return lsearch ();
+return $ac_func ();
   ;
   return 0;
 }
@@ -16880,282 +17001,36 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
         test ! -s conftest.err
        } && test -s conftest$ac_exeext &&
        $as_test_x conftest$ac_exeext; then
-  ac_cv_lib_compat_lsearch=yes
+  eval "$as_ac_var=yes"
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_cv_lib_compat_lsearch=no
+       eval "$as_ac_var=no"
 fi
 
 rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
       conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
 fi
-{ echo "$as_me:$LINENO: result: $ac_cv_lib_compat_lsearch" >&5
-echo "${ECHO_T}$ac_cv_lib_compat_lsearch" >&6; }
-if test $ac_cv_lib_compat_lsearch = yes; then
-  { echo "$as_me:$LINENO: checking for search.h" >&5
-echo $ECHO_N "checking for search.h... $ECHO_C" >&6; }
-if test "${ac_cv_header_search_h+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <search.h>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_cv_header_search_h=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_cv_header_search_h=no
-fi
-
-rm -f conftest.err conftest.$ac_ext
-fi
-{ echo "$as_me:$LINENO: result: $ac_cv_header_search_h" >&5
-echo "${ECHO_T}$ac_cv_header_search_h" >&6; }
-if test $ac_cv_header_search_h = yes; then
-  cat >>confdefs.h <<\_ACEOF
-#define HAVE_LSEARCH 1
-_ACEOF
- LIBS="${LIBS} -lcompat"
-else
-  case " $LIBOBJS " in
-  *" lsearch.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS lsearch.$ac_objext"
- ;;
-esac
-
-fi
-
-
-else
-  case " $LIBOBJS " in
-  *" lsearch.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS lsearch.$ac_objext"
- ;;
-esac
-
-fi
-
-fi
-done
-
-
-for ac_func in utimes
-do
-as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ echo "$as_me:$LINENO: checking for $ac_func" >&5
-echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
-
-int
-main ()
-{
-return $ac_func ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext &&
-       $as_test_x conftest$ac_exeext; then
-  eval "$as_ac_var=yes"
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       eval "$as_ac_var=no"
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-ac_res=`eval echo '${'$as_ac_var'}'`
-              { echo "$as_me:$LINENO: result: $ac_res" >&5
-echo "${ECHO_T}$ac_res" >&6; }
-if test `eval echo '${'$as_ac_var'}'` = yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
-
-
-for ac_func in futimes futimesat
-do
-as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ echo "$as_me:$LINENO: checking for $ac_func" >&5
-echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
-
-int
-main ()
-{
-return $ac_func ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext &&
-       $as_test_x conftest$ac_exeext; then
-  eval "$as_ac_var=yes"
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       eval "$as_ac_var=no"
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-ac_res=`eval echo '${'$as_ac_var'}'`
-              { echo "$as_me:$LINENO: result: $ac_res" >&5
-echo "${ECHO_T}$ac_res" >&6; }
-if test `eval echo '${'$as_ac_var'}'` = yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
- break
-fi
-done
-
-else
-
-for ac_func in futime
-do
-as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ echo "$as_me:$LINENO: checking for $ac_func" >&5
-echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ break
+fi
+done
+
+else
+
+for ac_func in futime
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat >conftest.$ac_ext <<_ACEOF
@@ -17379,6 +17254,13 @@ cat >>confdefs.h <<\_ACEOF
 #define HAVE_ISBLANK 1
 _ACEOF
 
+  else
+    case " $LIBOBJS " in
+  *" isblank.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS isblank.$ac_objext"
+ ;;
+esac
+
   fi
 
 
 
 fi
 
-if test "$with_DCE" = "yes" -o "$ac_cv_prog_YACC" = "bison -y"; then
-    # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
-# for constant arguments.  Useless!
-{ echo "$as_me:$LINENO: checking for working alloca.h" >&5
-echo $ECHO_N "checking for working alloca.h... $ECHO_C" >&6; }
-if test "${ac_cv_working_alloca_h+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <alloca.h>
-int
-main ()
-{
-char *p = (char *) alloca (2 * sizeof (int));
-                         if (p) return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext &&
-       $as_test_x conftest$ac_exeext; then
-  ac_cv_working_alloca_h=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_working_alloca_h=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-{ echo "$as_me:$LINENO: result: $ac_cv_working_alloca_h" >&5
-echo "${ECHO_T}$ac_cv_working_alloca_h" >&6; }
-if test $ac_cv_working_alloca_h = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_ALLOCA_H 1
-_ACEOF
-
-fi
-
-{ echo "$as_me:$LINENO: checking for alloca" >&5
-echo $ECHO_N "checking for alloca... $ECHO_C" >&6; }
-if test "${ac_cv_func_alloca_works+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#ifdef __GNUC__
-# define alloca __builtin_alloca
-#else
-# ifdef _MSC_VER
-#  include <malloc.h>
-#  define alloca _alloca
-# else
-#  ifdef HAVE_ALLOCA_H
-#   include <alloca.h>
-#  else
-#   ifdef _AIX
- #pragma alloca
-#   else
-#    ifndef alloca /* predefined by HP cc +Olibcalls */
-char *alloca ();
-#    endif
-#   endif
-#  endif
-# endif
-#endif
-
-int
-main ()
-{
-char *p = (char *) alloca (1);
-                                   if (p) return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext &&
-       $as_test_x conftest$ac_exeext; then
-  ac_cv_func_alloca_works=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_func_alloca_works=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-{ echo "$as_me:$LINENO: result: $ac_cv_func_alloca_works" >&5
-echo "${ECHO_T}$ac_cv_func_alloca_works" >&6; }
-
-if test $ac_cv_func_alloca_works = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_ALLOCA 1
-_ACEOF
-
-else
-  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
-# that cause trouble.  Some versions do not even contain alloca or
-# contain a buggy version.  If you still want to use their alloca,
-# use ar to extract alloca.o from them instead of compiling alloca.c.
-
-ALLOCA=\${LIBOBJDIR}alloca.$ac_objext
-
-cat >>confdefs.h <<\_ACEOF
-#define C_ALLOCA 1
-_ACEOF
-
-
-{ echo "$as_me:$LINENO: checking whether \`alloca.c' needs Cray hooks" >&5
-echo $ECHO_N "checking whether \`alloca.c' needs Cray hooks... $ECHO_C" >&6; }
-if test "${ac_cv_os_cray+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#if defined CRAY && ! defined CRAY2
-webecray
-#else
-wenotbecray
-#endif
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "webecray" >/dev/null 2>&1; then
-  ac_cv_os_cray=yes
-else
-  ac_cv_os_cray=no
-fi
-rm -f conftest*
-
-fi
-{ echo "$as_me:$LINENO: result: $ac_cv_os_cray" >&5
-echo "${ECHO_T}$ac_cv_os_cray" >&6; }
-if test $ac_cv_os_cray = yes; then
-  for ac_func in _getb67 GETB67 getb67; do
-    as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ echo "$as_me:$LINENO: checking for $ac_func" >&5
-echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+
+for ac_func in getprogname
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat >conftest.$ac_ext <<_ACEOF
@@ -19610,147 +19309,115 @@ ac_res=`eval echo '${'$as_ac_var'}'`
               { echo "$as_me:$LINENO: result: $ac_res" >&5
 echo "${ECHO_T}$ac_res" >&6; }
 if test `eval echo '${'$as_ac_var'}'` = yes; then
-
-cat >>confdefs.h <<_ACEOF
-#define CRAY_STACKSEG_END $ac_func
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
 _ACEOF
 
-    break
-fi
-
-  done
-fi
+else
 
-{ echo "$as_me:$LINENO: checking stack direction for C alloca" >&5
-echo $ECHO_N "checking stack direction for C alloca... $ECHO_C" >&6; }
-if test "${ac_cv_c_stack_direction+set}" = set; then
+    { echo "$as_me:$LINENO: checking for __progname" >&5
+echo $ECHO_N "checking for __progname... $ECHO_C" >&6; }
+    if test "${sudo_cv___progname+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
-  if test "$cross_compiling" = yes; then
-  ac_cv_c_stack_direction=0
-else
-  cat >conftest.$ac_ext <<_ACEOF
+
+    cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-$ac_includes_default
-int
-find_stack_direction ()
-{
-  static char *addr = 0;
-  auto char dummy;
-  if (addr == 0)
-    {
-      addr = &dummy;
-      return find_stack_direction ();
-    }
-  else
-    return (&dummy > addr) ? 1 : -1;
-}
 
 int
 main ()
 {
-  return find_stack_direction () < 0;
+extern char *__progname; (void)puts(__progname);
+  ;
+  return 0;
 }
 _ACEOF
-rm -f conftest$ac_exeext
+rm -f conftest.$ac_objext conftest$ac_exeext
 if { (ac_try="$ac_link"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
 eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
+  (eval "$ac_link") 2>conftest.er1
   ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_c_stack_direction=1
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  sudo_cv___progname=yes
 else
-  echo "$as_me: program exited with status $ac_status" >&5
-echo "$as_me: failed program was:" >&5
+  echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-( exit $ac_status )
-ac_cv_c_stack_direction=-1
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+       sudo_cv___progname=no
 fi
 
-
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
 fi
-{ echo "$as_me:$LINENO: result: $ac_cv_c_stack_direction" >&5
-echo "${ECHO_T}$ac_cv_c_stack_direction" >&6; }
 
-cat >>confdefs.h <<_ACEOF
-#define STACK_DIRECTION $ac_cv_c_stack_direction
+    if test "$sudo_cv___progname" = "yes"; then
+       cat >>confdefs.h <<\_ACEOF
+#define HAVE___PROGNAME 1
 _ACEOF
 
+    else
+       case " $LIBOBJS " in
+  *" getprogname.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS getprogname.$ac_objext"
+ ;;
+esac
+
+    fi
+    { echo "$as_me:$LINENO: result: $sudo_cv___progname" >&5
+echo "${ECHO_T}$sudo_cv___progname" >&6; }
 
 fi
+done
+
 
+
+if test -z "${AUTH_EXCL}${AUTH_REG}" -a -n "$AUTH_EXCL_DEF"; then
+    for auth in $AUTH_EXCL_DEF; do
+       case $auth in
+           AIX_AUTH)   with_aixauth=maybe;;
+           BSD_AUTH)   with_bsdauth=maybe;;
+           PAM)        with_pam=maybe;;
+           SIA)        CHECKSIA=true;;
+       esac
+    done
 fi
 
-for ac_func in getprogname
-do
-as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ echo "$as_me:$LINENO: checking for $ac_func" >&5
-echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+if test ${with_pam-"no"} != "no"; then
+                { echo "$as_me:$LINENO: checking for main in -ldl" >&5
+echo $ECHO_N "checking for main in -ldl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_dl_main+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
 
 int
 main ()
 {
-return $ac_func ();
+return main ();
   ;
   return 0;
 }
@@ -19773,163 +19440,17 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
         test ! -s conftest.err
        } && test -s conftest$ac_exeext &&
        $as_test_x conftest$ac_exeext; then
-  eval "$as_ac_var=yes"
+  ac_cv_lib_dl_main=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-       eval "$as_ac_var=no"
+       ac_cv_lib_dl_main=no
 fi
 
 rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
       conftest$ac_exeext conftest.$ac_ext
-fi
-ac_res=`eval echo '${'$as_ac_var'}'`
-              { echo "$as_me:$LINENO: result: $ac_res" >&5
-echo "${ECHO_T}$ac_res" >&6; }
-if test `eval echo '${'$as_ac_var'}'` = yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
-
-else
-
-    { echo "$as_me:$LINENO: checking for __progname" >&5
-echo $ECHO_N "checking for __progname... $ECHO_C" >&6; }
-    if test "${sudo_cv___progname+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-
-    cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-int
-main ()
-{
-extern char *__progname; (void)puts(__progname);
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext &&
-       $as_test_x conftest$ac_exeext; then
-  sudo_cv___progname=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       sudo_cv___progname=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-
-    if test "$sudo_cv___progname" = "yes"; then
-       cat >>confdefs.h <<\_ACEOF
-#define HAVE___PROGNAME 1
-_ACEOF
-
-    else
-       case " $LIBOBJS " in
-  *" getprogname.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS getprogname.$ac_objext"
- ;;
-esac
-
-    fi
-    { echo "$as_me:$LINENO: result: $sudo_cv___progname" >&5
-echo "${ECHO_T}$sudo_cv___progname" >&6; }
-
-fi
-done
-
-
-
-if test -z "${AUTH_EXCL}${AUTH_REG}" -a -n "$AUTH_EXCL_DEF"; then
-    for auth in $AUTH_EXCL_DEF; do
-       case $auth in
-           AIX_AUTH)   with_aixauth=maybe;;
-           BSD_AUTH)   with_bsdauth=maybe;;
-           PAM)        with_pam=maybe;;
-           SIA)        CHECKSIA=true;;
-       esac
-    done
-fi
-
-if test ${with_pam-"no"} != "no"; then
-                { echo "$as_me:$LINENO: checking for main in -ldl" >&5
-echo $ECHO_N "checking for main in -ldl... $ECHO_C" >&6; }
-if test "${ac_cv_lib_dl_main+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-
-int
-main ()
-{
-return main ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext &&
-       $as_test_x conftest$ac_exeext; then
-  ac_cv_lib_dl_main=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_lib_dl_main=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+LIBS=$ac_check_lib_save_LIBS
 fi
 { echo "$as_me:$LINENO: result: $ac_cv_lib_dl_main" >&5
 echo "${ECHO_T}$ac_cv_lib_dl_main" >&6; }
@@ -20099,8 +19620,9 @@ echo "${ECHO_T}yes" >&6; }
                        ;;
                no)             { echo "$as_me:$LINENO: result: no" >&5
 echo "${ECHO_T}no" >&6; }
-                           cat >>confdefs.h <<\_ACEOF
-#define NO_PAM_SESSION 1
+
+cat >>confdefs.h <<\_ACEOF
+#define NO_PAM_SESSION
 _ACEOF
 
                            ;;
@@ -20385,6 +19907,7 @@ if test $ac_cv_header_bsd_auth_h = yes; then
 _ACEOF
 
        AUTH_OBJS="$AUTH_OBJS bsdauth.o"
+       BSDAUTH_USAGE='[-a auth_type] '
        AUTH_EXCL=BSD_AUTH; BAMAN=""
 else
   { { echo "$as_me:$LINENO: error: BSD authentication was specified but bsd_auth.h could not be found" >&5
@@ -21423,6 +20946,7 @@ echo "${ECHO_T}yes" >&6; }
 #define HAVE_HEIMDAL 1
 _ACEOF
 
+           # XXX - need to check whether -lcrypo is needed!
            SUDO_LIBS="${SUDO_LIBS} -lkrb5 -lcrypto -ldes -lcom_err -lasn1"
            { echo "$as_me:$LINENO: checking for main in -lroken" >&5
 echo $ECHO_N "checking for main in -lroken... $ECHO_C" >&6; }
@@ -21560,7 +21084,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     LIBS="${LIBS} ${SUDO_LIBS}"
 
 
-for ac_func in krb5_verify_user krb5_init_secure_context
+
+for ac_func in krb5_verify_user krb5_init_secure_context krb5_get_init_creds_opt_alloc
 do
 as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
 { echo "$as_me:$LINENO: checking for $ac_func" >&5
@@ -21653,6 +21178,69 @@ _ACEOF
 fi
 done
 
+    { echo "$as_me:$LINENO: checking whether krb5_get_init_creds_opt_free takes a two argument2" >&5
+echo $ECHO_N "checking whether krb5_get_init_creds_opt_free takes a two argument2... $ECHO_C" >&6; }
+if test "${sudo_cv_krb5_get_init_creds_opt_free_two_args+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+           cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <krb5.h>
+int
+main ()
+{
+
+                   krb5_context context = NULL;
+                   krb5_get_init_creds_opt *opts = NULL;
+                   krb5_get_init_creds_opt_free(context, opts);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  sudo_cv_krb5_get_init_creds_opt_free_two_args=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       sudo_cv_krb5_get_init_creds_opt_free_two_args=no
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+fi
+{ echo "$as_me:$LINENO: result: $sudo_cv_krb5_get_init_creds_opt_free_two_args" >&5
+echo "${ECHO_T}$sudo_cv_krb5_get_init_creds_opt_free_two_args" >&6; }
+    if test X"$sudo_cv_krb5_get_init_creds_opt_free_two_args" = X"yes"; then
+       cat >>confdefs.h <<\_ACEOF
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_TWO_ARGS 1
+_ACEOF
+
+    fi
     LIBS="$_LIBS"
 fi
 
@@ -22748,6 +22336,7 @@ if test ${with_ldap-'no'} != "no"; then
 
        CPPFLAGS="${CPPFLAGS} -I${with_ldap}/include"
        with_ldap=yes
+       LDAP=""
     fi
     SUDO_OBJS="${SUDO_OBJS} ldap.o"
 
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-
-    { echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6; }
-    cat >>confdefs.h <<\_ACEOF
-#define HAVE_LBER_H 1
-_ACEOF
-
+
+    { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+    cat >>confdefs.h <<\_ACEOF
+#define HAVE_LBER_H 1
+_ACEOF
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in ldap_initialize ldap_start_tls_s ldap_sasl_interactive_bind_s ldapssl_init ldapssl_set_strength ldap_search_ext_s ldap_unbind_ext_s ldap_str2dn ldap_create ldap_sasl_bind_s
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_header in sasl/sasl.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in ldap_ssl.h mps/ldap_ssl.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ldap.h>
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+ break
+fi
+
+done
+
+
+    if test X"$check_gss_krb5_ccache_name" = X"yes"; then
+       { echo "$as_me:$LINENO: checking for gss_krb5_ccache_name in -lgssapi" >&5
+echo $ECHO_N "checking for gss_krb5_ccache_name in -lgssapi... $ECHO_C" >&6; }
+if test "${ac_cv_lib_gssapi_gss_krb5_ccache_name+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgssapi  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gss_krb5_ccache_name ();
+int
+main ()
+{
+return gss_krb5_ccache_name ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_gssapi_gss_krb5_ccache_name=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_gssapi_gss_krb5_ccache_name=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_gssapi_gss_krb5_ccache_name" >&5
+echo "${ECHO_T}$ac_cv_lib_gssapi_gss_krb5_ccache_name" >&6; }
+if test $ac_cv_lib_gssapi_gss_krb5_ccache_name = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_GSS_KRB5_CCACHE_NAME 1
+_ACEOF
+
+           LDAP_LIBS="${LDAP_LIBS} -lgssapi"
+else
+  { echo "$as_me:$LINENO: checking for gss_krb5_ccache_name in -lgssapi_krb5" >&5
+echo $ECHO_N "checking for gss_krb5_ccache_name in -lgssapi_krb5... $ECHO_C" >&6; }
+if test "${ac_cv_lib_gssapi_krb5_gss_krb5_ccache_name+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgssapi_krb5  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gss_krb5_ccache_name ();
+int
+main ()
+{
+return gss_krb5_ccache_name ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_gssapi_krb5_gss_krb5_ccache_name=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_gssapi_krb5_gss_krb5_ccache_name=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_gssapi_krb5_gss_krb5_ccache_name" >&5
+echo "${ECHO_T}$ac_cv_lib_gssapi_krb5_gss_krb5_ccache_name" >&6; }
+if test $ac_cv_lib_gssapi_krb5_gss_krb5_ccache_name = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_GSS_KRB5_CCACHE_NAME 1
+_ACEOF
+
+               LDAP_LIBS="${LDAP_LIBS} -lgssapi_krb5"
+fi
+
+
+fi
+
+
+       # gssapi headers may be separate or part of Kerberos V
+       found=no
+       O_CPPFLAGS="$CPPFLAGS"
+       for dir in "" "kerberosV" "krb5" "kerberos5" "kerberosv5"; do
+           test X"$dir" != X"" && CPPFLAGS="$O_CPPFLAGS -I/usr/include/${dir}"
+           cat >conftest.$ac_ext <<_ACEOF
+#include <gssapi/gssapi.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  found="gssapi/gssapi.h"; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  cat >conftest.$ac_ext <<_ACEOF
+#include <gssapi.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  found="gssapi.h"; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f conftest.err conftest.$ac_ext
+fi
+
+rm -f conftest.err conftest.$ac_ext
+       done
+       if test X"$found" != X"no"; then
+
+for ac_header in $found
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-
-
-
-
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
 
-for ac_func in ldap_initialize ldap_start_tls_s ldapssl_init ldapssl_set_strength
-do
-as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ echo "$as_me:$LINENO: checking for $ac_func" >&5
-echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
-
-int
-main ()
-{
-return $ac_func ();
-  ;
-  return 0;
-}
+#include <$ac_header>
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
+if { (ac_try="$ac_cpp conftest.$ac_ext"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
 eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_link") 2>conftest.er1
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
   ac_status=$?
   grep -v '^ *+' conftest.er1 >conftest.err
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
         test ! -s conftest.err
-       } && test -s conftest$ac_exeext &&
-       $as_test_x conftest$ac_exeext; then
-  eval "$as_ac_var=yes"
+       }; then
+  ac_header_preproc=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-       eval "$as_ac_var=no"
+  ac_header_preproc=no
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
 fi
-ac_res=`eval echo '${'$as_ac_var'}'`
+ac_res=`eval echo '${'$as_ac_Header'}'`
               { echo "$as_me:$LINENO: result: $ac_res" >&5
 echo "${ECHO_T}$ac_res" >&6; }
-if test `eval echo '${'$as_ac_var'}'` = yes; then
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
   cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
 
 fi
-done
 
+done
 
+           if test X"$found" = X"gssapi/gssapi.h"; then
 
-for ac_header in ldap_ssl.h mps/ldap_ssl.h
+for ac_header in gssapi/gssapi_krb5.h
 do
 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
-{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
 if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
 else
-  cat >conftest.$ac_ext <<_ACEOF
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-#include <ldap.h>
-
+$ac_includes_default
 #include <$ac_header>
 _ACEOF
 rm -f conftest.$ac_objext
@@ -23091,34 +23237,114 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
         test -z "$ac_c_werror_flag" ||
         test ! -s conftest.err
        } && test -s conftest.$ac_objext; then
-  eval "$as_ac_Header=yes"
+  ac_header_compiler=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-       eval "$as_ac_Header=no"
+       ac_header_compiler=no
 fi
 
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
 fi
 ac_res=`eval echo '${'$as_ac_Header'}'`
               { echo "$as_me:$LINENO: result: $ac_res" >&5
 echo "${ECHO_T}$ac_res" >&6; }
+
+fi
 if test `eval echo '${'$as_ac_Header'}'` = yes; then
   cat >>confdefs.h <<_ACEOF
 #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
- break
+
 fi
 
 done
 
+           fi
+       else
+           CPPFLAGS="$O_CPPFLAGS"
+           { echo "$as_me:$LINENO: WARNING: Unable to locate gssapi.h, you will have to edit the Makefile and add -I/path/to/gssapi/includes to CPPFLAGS" >&5
+echo "$as_me: WARNING: Unable to locate gssapi.h, you will have to edit the Makefile and add -I/path/to/gssapi/includes to CPPFLAGS" >&2;}
+       fi
+    fi
 
     SUDO_LIBS="${SUDO_LIBS} ${LDAP_LIBS}"
     LIBS="$_LIBS"
     LDFLAGS="$_LDFLAGS"
-    # XXX - OpenLDAP has deprecated ldap_get_values()
-    CPPFLAGS="${CPPFLAGS} -DLDAP_DEPRECATED"
 fi
 
 if test -n "$blibpath"; then
@@ -23267,7 +23493,7 @@ _ACEOF
     exec_prefix="$oexec_prefix"
 fi
 
-ac_config_files="$ac_config_files Makefile sudo.man visudo.man sudoers.man"
+ac_config_files="$ac_config_files Makefile sudo.man visudo.man sudoers.man sudoers.ldap.man sudo_usage.h"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -23665,7 +23891,7 @@ exec 6>&1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by sudo $as_me 1.6.9, which was
+This file was extended by sudo $as_me 1.7, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -23714,7 +23940,7 @@ Report bugs to <bug-autoconf@gnu.org>."
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-sudo config.status 1.6.9
+sudo config.status 1.7
 configured by $0, generated by GNU Autoconf 2.61,
   with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
@@ -23827,6 +24053,8 @@ do
     "sudo.man") CONFIG_FILES="$CONFIG_FILES sudo.man" ;;
     "visudo.man") CONFIG_FILES="$CONFIG_FILES visudo.man" ;;
     "sudoers.man") CONFIG_FILES="$CONFIG_FILES sudoers.man" ;;
+    "sudoers.ldap.man") CONFIG_FILES="$CONFIG_FILES sudoers.ldap.man" ;;
+    "sudo_usage.h") CONFIG_FILES="$CONFIG_FILES sudo_usage.h" ;;
 
   *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
 echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
@@ -23948,6 +24176,7 @@ SELINUX!$SELINUX$ac_delim
 BAMAN!$BAMAN$ac_delim
 LCMAN!$LCMAN$ac_delim
 SEMAN!$SEMAN$ac_delim
+devdir!$devdir$ac_delim
 mansectsu!$mansectsu$ac_delim
 mansectform!$mansectform$ac_delim
 mansrcdir!$mansrcdir$ac_delim
@@ -23956,6 +24185,10 @@ NOEXECDIR!$NOEXECDIR$ac_delim
 noexec_file!$noexec_file$ac_delim
 INSTALL_NOEXEC!$INSTALL_NOEXEC$ac_delim
 DONT_LEAK_PATH_INFO!$DONT_LEAK_PATH_INFO$ac_delim
+BSDAUTH_USAGE!$BSDAUTH_USAGE$ac_delim
+SELINUX_USAGE!$SELINUX_USAGE$ac_delim
+LDAP!$LDAP$ac_delim
+LOGINCAP_USAGE!$LOGINCAP_USAGE$ac_delim
 timedir!$timedir$ac_delim
 timeout!$timeout$ac_delim
 password_timeout!$password_timeout$ac_delim
@@ -23980,11 +24213,6 @@ env_editor!$env_editor$ac_delim
 passwd_tries!$passwd_tries$ac_delim
 tty_tickets!$tty_tickets$ac_delim
 insults!$insults$ac_delim
-root_sudo!$root_sudo$ac_delim
-path_info!$path_info$ac_delim
-EGREPPROG!$EGREPPROG$ac_delim
-CC!$CC$ac_delim
-ac_ct_CC!$ac_ct_CC$ac_delim
 _ACEOF
 
   if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
@@ -24026,6 +24254,14 @@ _ACEOF
 ac_delim='%!_!# '
 for ac_last_try in false false false false false :; do
   cat >conf$$subs.sed <<_ACEOF
+root_sudo!$root_sudo$ac_delim
+path_info!$path_info$ac_delim
+ldap_conf!$ldap_conf$ac_delim
+ldap_secret!$ldap_secret$ac_delim
+nsswitch_conf!$nsswitch_conf$ac_delim
+EGREPPROG!$EGREPPROG$ac_delim
+CC!$CC$ac_delim
+ac_ct_CC!$ac_ct_CC$ac_delim
 EXEEXT!$EXEEXT$ac_delim
 OBJEXT!$OBJEXT$ac_delim
 CPP!$CPP$ac_delim
@@ -24057,12 +24293,11 @@ NROFFPROG!$NROFFPROG$ac_delim
 YACC!$YACC$ac_delim
 YFLAGS!$YFLAGS$ac_delim
 LIBOBJS!$LIBOBJS$ac_delim
-ALLOCA!$ALLOCA$ac_delim
 KRB5CONFIG!$KRB5CONFIG$ac_delim
 LTLIBOBJS!$LTLIBOBJS$ac_delim
 _ACEOF
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 34; then
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 41; then
     break
   elif $ac_last_try; then
     { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
 
 
 
+
+
+
+
+
+
+
+
+
+
 
 
 
index 109fc9a721f750e3893fd5b7734d555bde58da18..6b09b5f18fd535788bc7c6ed76428e6673ea26ab 100644 (file)
@@ -1,15 +1,15 @@
 dnl
 dnl Process this file with GNU autoconf to produce a configure script.
-dnl $Sudo: configure.in,v 1.413.2.53 2008/06/22 20:23:56 millert Exp $
+dnl $Sudo: configure.in,v 1.538 2008/12/09 21:13:01 millert Exp $
 dnl
-dnl Copyright (c) 1994-1996,1998-2007 Todd C. Miller <Todd.Miller@courtesan.com>
+dnl Copyright (c) 1994-1996,1998-2008 Todd C. Miller <Todd.Miller@courtesan.com>
 dnl
-AC_INIT([sudo], [1.6.9])
+AC_INIT([sudo], [1.7])
 AC_CONFIG_HEADER(config.h pathnames.h)
 dnl
 dnl This won't work before AC_INIT
 dnl
-AC_MSG_NOTICE([Configuring Sudo version 1.6.9])
+AC_MSG_NOTICE([Configuring Sudo version 1.7])
 dnl
 dnl Variables that get substituted in the Makefile and man pages
 dnl
@@ -37,6 +37,7 @@ AC_SUBST(SELINUX)
 AC_SUBST(BAMAN)
 AC_SUBST(LCMAN)
 AC_SUBST(SEMAN)
+AC_SUBST(devdir)
 AC_SUBST(mansectsu)
 AC_SUBST(mansectform)
 AC_SUBST(mansrcdir)
@@ -45,6 +46,10 @@ AC_SUBST(NOEXECDIR)
 AC_SUBST(noexec_file)
 AC_SUBST(INSTALL_NOEXEC)
 AC_SUBST(DONT_LEAK_PATH_INFO)
+AC_SUBST(BSDAUTH_USAGE)
+AC_SUBST(SELINUX_USAGE)
+AC_SUBST(LDAP)
+AC_SUBST(LOGINCAP_USAGE)
 dnl
 dnl Variables that get substituted in docs (not overridden by environment)
 dnl
@@ -74,6 +79,9 @@ AC_SUBST(tty_tickets)
 AC_SUBST(insults)
 AC_SUBST(root_sudo)
 AC_SUBST(path_info)
+AC_SUBST(ldap_conf)
+AC_SUBST(ldap_secret)
+AC_SUBST(nsswitch_conf)
 dnl
 dnl Initial values for above
 dnl
@@ -103,6 +111,7 @@ insults=off
 root_sudo=on
 path_info=on
 INSTALL_NOEXEC=
+devdir='$(srcdir)'
 dnl
 dnl Initial values for Makefile variables listed above
 dnl May be overridden by environment variables..
@@ -114,6 +123,7 @@ PROGS="sudo visudo"
 : ${SUDOERS_UID='0'}
 : ${SUDOERS_GID='0'}
 DEV="#"
+LDAP="#"
 SELINUX="#"
 BAMAN='.\" '
 LCMAN='.\" '
@@ -230,6 +240,7 @@ AC_ARG_WITH(devel, [  --with-devel            add development options],
                PROGS="${PROGS} testsudoers"
                OSDEFS="${OSDEFS} -DSUDO_DEVEL"
                DEV=""
+               devdir=.
                ;;
     no)                ;;
     *)         AC_MSG_WARN([Ignoring unknown argument to --with-devel: $with_devel])
@@ -912,6 +923,20 @@ AC_ARG_WITH(goons-insults, [  --with-goons-insults    include the insults from t
                ;;
 esac])
 
+AC_ARG_WITH(nsswitch, [  --with-nsswitch[[=PATH]]  path to nsswitch.conf],
+[case $with_nsswitch in
+    no)                ;;
+    yes)       with_nsswitch="/etc/nsswitch.conf"
+               ;;
+    *)         ;;
+esac])
+if test ${with_nsswitch-"yes"} != "no"; then
+    SUDO_DEFINE_UNQUOTED(_PATH_NSSWITCH_CONF, "${with_nsswitch-/etc/nsswitch.conf}")
+    nsswitch_conf=${with_nsswitch-/etc/nsswitch.conf}
+else
+    nsswitch_conf='/etc/nsswitch.conf'
+fi
+
 AC_ARG_WITH(ldap, [  --with-ldap[[=DIR]]       enable LDAP support],
 [case $with_ldap in
     no)                with_ldap="";;
@@ -920,10 +945,14 @@ AC_ARG_WITH(ldap, [  --with-ldap[[=DIR]]       enable LDAP support],
                AC_MSG_RESULT(yes)
                ;;
 esac])
-AC_ARG_WITH(ldap-conf-file, [  --with-ldap-conf-file   path to LDAP configuration file],
-[AC_DEFINE_UNQUOTED(_PATH_LDAP_CONF, "$with_ldap_conf_file", [Path to the ldap.conf file])])
-AC_ARG_WITH(ldap-secret-file, [  --with-ldap-secret-file path to LDAP secret password file],
-[AC_DEFINE_UNQUOTED(_PATH_LDAP_SECRET, "$with_ldap_secret_file", [Path to the ldap.secret file])])
+
+AC_ARG_WITH(ldap-conf-file, [  --with-ldap-conf-file   path to LDAP configuration file])
+SUDO_DEFINE_UNQUOTED(_PATH_LDAP_CONF, "${with_ldap_conf_file-/etc/ldap.conf}", [Path to the ldap.conf file])
+ldap_conf=${with_ldap_conf_file-'/etc/ldap.conf'}
+
+AC_ARG_WITH(ldap-secret-file, [  --with-ldap-secret-file path to LDAP secret password file])
+SUDO_DEFINE_UNQUOTED(_PATH_LDAP_SECRET, "${with_ldap_secret_file-/etc/ldap.secret}", [Path to the ldap.secret file])
+ldap_secret=${with_ldap_secret_file-'/etc/ldap.secret'}
 
 AC_ARG_WITH(pc-insults, [  --with-pc-insults       replace politically incorrect insults with less offensive ones],
 [case $with_pc_insults in
@@ -982,6 +1011,16 @@ AC_ARG_WITH(stow, [  --with-stow             properly handle GNU stow packaging]
                ;;
 esac], AC_MSG_RESULT(no))
 
+AC_MSG_CHECKING(whether to use an askpass helper)
+AC_ARG_WITH(askpass, [  --with-askpass=PATH     Fully qualified pathname of askpass helper],
+[case $with_askpass in
+    yes)       AC_MSG_ERROR(["--with-askpass takes a path as an argument."])
+               ;;
+    no)                ;;
+    *)         AC_DEFINE_UNQUOTED(_PATH_SUDO_ASKPASS, "$with_askpass", [The fully qualified pathname of askpass])
+               ;;
+esac], AC_MSG_RESULT(no))
+
 dnl
 dnl Options for --enable
 dnl
@@ -1098,7 +1137,7 @@ AC_ARG_ENABLE(noargs-shell,
 AC_MSG_CHECKING(whether to set \$HOME to target user in shell mode)
 AC_ARG_ENABLE(shell-sets-home,
 [  --enable-shell-sets-home
-                          set $HOME to target user in shell mode],
+                          Set $HOME to target user in shell mode],
 [ case "$enableval" in
     yes)       AC_MSG_RESULT(yes)
                AC_DEFINE(SHELL_SETS_HOME)
@@ -1129,7 +1168,8 @@ AC_ARG_ENABLE(path_info,
 
 AC_ARG_WITH(selinux, [  --with-selinux          enable SELinux support],
 [case $with_selinux in
-    yes)       AC_DEFINE(HAVE_SELINUX)
+    yes)       SELINUX_USAGE="[[-r role]] [[-t type]] "
+               AC_DEFINE(HAVE_SELINUX)
                SUDO_LIBS="${SUDO_LIBS} -lselinux"
                SUDO_OBJS="${SUDO_OBJS} selinux.o"
                PROGS="${PROGS} sesh"
@@ -1141,6 +1181,12 @@ AC_ARG_WITH(selinux, [  --with-selinux          enable SELinux support],
                ;;
 esac])
 
+dnl
+dnl gss_krb5_ccache_name() may not work on Heimdal so we don't use it by default
+dnl
+AC_ARG_ENABLE(gss_krb5_ccache_name, [  --enable-gss-krb5-ccache-name
+                          Use GSS-API to set the Kerberos V cred cache name], [check_gss_krb5_ccache_name=$enableval], [check_gss_krb5_ccache_name=no])
+
 dnl
 dnl If we don't have egrep we can't do anything...
 dnl
@@ -1287,6 +1333,10 @@ case "$host" in
                if test X"$with_aixauth" = X""; then
                    AC_CHECK_FUNCS(authenticate, [AUTH_EXCL_DEF="AIX_AUTH"])
                fi
+
+               # AIX-specific functions
+               AC_CHECK_FUNCS(getuserattr)
+               SUDO_OBJS="$SUDO_OBJS aix.o"
                ;;
     *-*-hiuxmpp*)
                : ${mansectsu='1m'}
@@ -1300,6 +1350,10 @@ case "$host" in
                : ${mansectsu='1m'}
                : ${mansectform='4'}
 
+               # HP-UX bundled compiler can't generate shared objects
+               if test "x$ac_cv_prog_cc_c89" = "xno"; then
+                   with_noexec=no
+               fi
                case "$host" in
                        *-*-hpux[1-8].*)
                            AC_DEFINE(BROKEN_SYSLOG)
@@ -1650,7 +1704,6 @@ AC_HEADER_STDC
 AC_HEADER_DIRENT
 AC_HEADER_TIME
 AC_CHECK_HEADERS(malloc.h paths.h utime.h netgroup.h sys/sockio.h sys/bsdtypes.h sys/select.h)
-AC_CHECK_HEADERS([err.h], [], [AC_LIBOBJ(err)])
 dnl ultrix termio/termios are broken
 if test "$OS" != "ultrix"; then
     AC_SYS_POSIX_TERMIOS
@@ -1661,7 +1714,7 @@ if test "$OS" != "ultrix"; then
     fi
 fi
 if test ${with_logincap-'no'} != "no"; then
-    AC_CHECK_HEADERS(login_cap.h, [LCMAN=""
+    AC_CHECK_HEADERS(login_cap.h, [LOGINCAP_USAGE='[[-c class|-]] '; LCMAN=""
        case "$OS" in
            freebsd|netbsd)     SUDO_LIBS="${SUDO_LIBS} -lutil"
            ;;
@@ -1677,7 +1730,8 @@ dnl typedef checks
 dnl
 AC_TYPE_MODE_T
 AC_TYPE_UID_T
-AC_CHECK_TYPES([sig_atomic_t], , [AC_DEFINE(sig_atomic_t, int)], [#include <sys/types.h>
+AC_CHECK_TYPE([__signed char], [], [AC_CHECK_TYPE([signed char], [AC_DEFINE(__signed, signed)], [AC_DEFINE(__signed, [])])])
+AC_CHECK_TYPE([sig_atomic_t], [], [AC_DEFINE(sig_atomic_t, int)], [#include <sys/types.h>
 #include <signal.h>])
 AC_CHECK_TYPES([sigaction_t], [AC_DEFINE(HAVE_SIGACTION_T)], [], [#include <sys/types.h>
 #include <signal.h>])
@@ -1692,7 +1746,6 @@ SUDO_TYPE_SIZE_T
 SUDO_TYPE_SSIZE_T
 SUDO_TYPE_DEV_T
 SUDO_TYPE_INO_T
-SUDO_FULL_VOID
 SUDO_UID_T_LEN
 SUDO_TYPE_LONG_LONG
 SUDO_SOCK_SA_LEN
@@ -1732,7 +1785,6 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <glob.h>]], [[int i = GLOB_BRACE |
 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(utimes, [AC_CHECK_FUNCS(futimes futimesat, [break])], [AC_CHECK_FUNCS(futime) AC_LIBOBJ(utimes)])
 SUDO_FUNC_FNMATCH([AC_DEFINE(HAVE_FNMATCH)], [AC_LIBOBJ(fnmatch)])
 SUDO_FUNC_ISBLANK
@@ -1791,13 +1843,6 @@ dnl If syslog(3) not in libc, check -lsocket, -lnsl and -linet
 dnl
 AC_CHECK_FUNC(syslog, , [AC_CHECK_LIB(socket, syslog, [NET_LIBS="${NET_LIBS} -lsocket"; LIBS="${LIBS} -lsocket"], AC_CHECK_LIB(nsl, syslog, [NET_LIBS="${NET_LIBS} -lnsl"; LIBS="${LIBS} -lnsl"], AC_CHECK_LIB(inet, syslog, [NET_LIBS="${NET_LIBS} -linet"; LIBS="${LIBS} -linet"])))])
 dnl
-dnl Bison and DCE use alloca(3), if not in libc, use the sudo one (from gcc)
-dnl (gcc includes its own alloca(3) but other compilers may not)
-dnl
-if test "$with_DCE" = "yes" -o "$ac_cv_prog_YACC" = "bison -y"; then
-    AC_FUNC_ALLOCA
-fi
-dnl
 dnl Check for getprogname() or __progname
 dnl
 AC_CHECK_FUNCS(getprogname, , [
@@ -1859,7 +1904,7 @@ if test ${with_pam-"no"} != "no"; then
                yes)    AC_MSG_RESULT(yes)
                        ;;
                no)             AC_MSG_RESULT(no)
-                           AC_DEFINE(NO_PAM_SESSION)
+                           AC_DEFINE([NO_PAM_SESSION], [], [PAM session support disabled])
                            ;;
                *)              AC_MSG_RESULT(no)
                            AC_MSG_WARN([Ignoring unknown argument to --enable-pam-session: $enableval])
@@ -1901,6 +1946,7 @@ dnl
 if test ${with_bsdauth-'no'} != "no"; then
     AC_CHECK_HEADER(bsd_auth.h, AC_DEFINE(HAVE_BSD_AUTH_H)
        [AUTH_OBJS="$AUTH_OBJS bsdauth.o"]
+       [BSDAUTH_USAGE='[[-a auth_type]] ']
        [AUTH_EXCL=BSD_AUTH; BAMAN=""],
        [AC_MSG_ERROR([BSD authentication was specified but bsd_auth.h could not be found])])
 fi
@@ -2093,6 +2139,7 @@ if test ${with_kerb5-'no'} != "no" -a -z "$KRB5CONFIG"; then
     AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <krb5.h>]], [[const char *tmp = heimdal_version;]])], [
            AC_MSG_RESULT(yes)
            AC_DEFINE(HAVE_HEIMDAL)
+           # XXX - need to check whether -lcrypo is needed!
            SUDO_LIBS="${SUDO_LIBS} -lkrb5 -lcrypto -ldes -lcom_err -lasn1"
            AC_CHECK_LIB(roken, main, [SUDO_LIBS="${SUDO_LIBS} -lroken"])
        ], [
@@ -2103,7 +2150,23 @@ if test ${with_kerb5-'no'} != "no" -a -z "$KRB5CONFIG"; then
     AUTH_OBJS="$AUTH_OBJS kerb5.o"
     _LIBS="$LIBS"
     LIBS="${LIBS} ${SUDO_LIBS}"
-    AC_CHECK_FUNCS(krb5_verify_user krb5_init_secure_context)
+    AC_CHECK_FUNCS(krb5_verify_user krb5_init_secure_context krb5_get_init_creds_opt_alloc)
+    AC_CACHE_CHECK(whether krb5_get_init_creds_opt_free takes a two argument2,
+       sudo_cv_krb5_get_init_creds_opt_free_two_args, [
+           AC_TRY_COMPILE([#include <krb5.h>],
+               [
+                   krb5_context context = NULL;
+                   krb5_get_init_creds_opt *opts = NULL;
+                   krb5_get_init_creds_opt_free(context, opts);
+               ],
+               [sudo_cv_krb5_get_init_creds_opt_free_two_args=yes],
+               [sudo_cv_krb5_get_init_creds_opt_free_two_args=no]
+           )
+       ]
+    )
+    if test X"$sudo_cv_krb5_get_init_creds_opt_free_two_args" = X"yes"; then
+       AC_DEFINE(HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_TWO_ARGS)
+    fi
     LIBS="$_LIBS"
 fi
 
@@ -2290,6 +2353,7 @@ if test ${with_ldap-'no'} != "no"; then
        SUDO_APPEND_LIBPATH(LDFLAGS, [${with_ldap}/lib])
        CPPFLAGS="${CPPFLAGS} -I${with_ldap}/include"
        with_ldap=yes
+       LDAP=""
     fi
     SUDO_OBJS="${SUDO_OBJS} ldap.o"
 
@@ -2325,14 +2389,40 @@ if test ${with_ldap-'no'} != "no"; then
     AC_MSG_RESULT([yes])
     AC_DEFINE(HAVE_LBER_H)])
 
-    AC_CHECK_FUNCS(ldap_initialize ldap_start_tls_s ldapssl_init ldapssl_set_strength)
+    AC_CHECK_FUNCS(ldap_initialize ldap_start_tls_s ldap_sasl_interactive_bind_s ldapssl_init ldapssl_set_strength ldap_search_ext_s ldap_unbind_ext_s ldap_str2dn ldap_create ldap_sasl_bind_s)
+    AC_CHECK_HEADERS([sasl/sasl.h])
     AC_CHECK_HEADERS([ldap_ssl.h] [mps/ldap_ssl.h], [break], [], [#include <ldap.h>])
 
+    if test X"$check_gss_krb5_ccache_name" = X"yes"; then
+       AC_CHECK_LIB(gssapi, gss_krb5_ccache_name,
+           AC_DEFINE(HAVE_GSS_KRB5_CCACHE_NAME)
+           [LDAP_LIBS="${LDAP_LIBS} -lgssapi"],
+           AC_CHECK_LIB(gssapi_krb5, gss_krb5_ccache_name,
+               AC_DEFINE(HAVE_GSS_KRB5_CCACHE_NAME)
+               [LDAP_LIBS="${LDAP_LIBS} -lgssapi_krb5"])
+       )
+
+       # gssapi headers may be separate or part of Kerberos V
+       found=no
+       O_CPPFLAGS="$CPPFLAGS"
+       for dir in "" "kerberosV" "krb5" "kerberos5" "kerberosv5"; do
+           test X"$dir" != X"" && CPPFLAGS="$O_CPPFLAGS -I/usr/include/${dir}"
+           AC_PREPROC_IFELSE([#include <gssapi/gssapi.h>], [found="gssapi/gssapi.h"; break], [AC_PREPROC_IFELSE([#include <gssapi.h>], [found="gssapi.h"; break])])
+       done
+       if test X"$found" != X"no"; then
+           AC_CHECK_HEADERS([$found])
+           if test X"$found" = X"gssapi/gssapi.h"; then
+               AC_CHECK_HEADERS([gssapi/gssapi_krb5.h])
+           fi
+       else
+           CPPFLAGS="$O_CPPFLAGS"
+           AC_MSG_WARN([Unable to locate gssapi.h, you will have to edit the Makefile and add -I/path/to/gssapi/includes to CPPFLAGS])
+       fi
+    fi
+
     SUDO_LIBS="${SUDO_LIBS} ${LDAP_LIBS}"
     LIBS="$_LIBS"
     LDFLAGS="$_LDFLAGS"
-    # XXX - OpenLDAP has deprecated ldap_get_values()
-    CPPFLAGS="${CPPFLAGS} -DLDAP_DEPRECATED"
 fi
 
 dnl
@@ -2392,8 +2482,7 @@ dnl
 test "$exec_prefix" = "NONE" && exec_prefix='$(prefix)'
 
 dnl
-dnl Defer setting _PATH_SUDO_NOEXEC and _PATH_SUDO_SESH
-dnl until after exec_prefix is set
+dnl Defer setting _PATH_SUDO_NOEXEC until after exec_prefix is set
 dnl XXX - this is gross!
 dnl
 if test X"$with_noexec" != X"no" -o X"$with_selinux" != X"no"; then
@@ -2422,7 +2511,7 @@ fi
 dnl
 dnl Substitute into the Makefile and man pages
 dnl
-AC_CONFIG_FILES([Makefile sudo.man visudo.man sudoers.man])
+AC_CONFIG_FILES([Makefile sudo.man visudo.man sudoers.man sudoers.ldap.man sudo_usage.h])
 AC_OUTPUT
 
 dnl
@@ -2464,12 +2553,17 @@ AH_TEMPLATE(HAVE_GETPRPWNAM, [Define to 1 if you have the `getprpwnam' function.
 AH_TEMPLATE(HAVE_GETPWANAM, [Define to 1 if you have the `getpwanam' function. (SunOS 4.x shadow passwords)])
 AH_TEMPLATE(HAVE_GETSPNAM, [Define to 1 if you have the `getspnam' function (SVR4-style shadow passwords)])
 AH_TEMPLATE(HAVE_GETSPWUID, [Define to 1 if you have the `getspwuid' function. (HP-UX <= 9.X shadow passwords)])
+AH_TEMPLATE(HAVE_GSS_KRB5_CCACHE_NAME, [Define to 1 if you have the `gss_krb5_ccache_name' function.])
 AH_TEMPLATE(HAVE_HEIMDAL, [Define to 1 if your Kerberos is Heimdal.])
 AH_TEMPLATE(HAVE_IN6_ADDR, [Define to 1 if <netinet/in.h> contains struct in6_addr.])
 AH_TEMPLATE(HAVE_ISCOMSEC, [Define to 1 if you have the `iscomsec' function. (HP-UX >= 10.x check for shadow enabled)])
 AH_TEMPLATE(HAVE_ISSECURE, [Define to 1 if you have the `issecure' function. (SunOS 4.x check for shadow enabled)])
 AH_TEMPLATE(HAVE_KERB4, [Define to 1 if you use Kerberos IV.])
 AH_TEMPLATE(HAVE_KERB5, [Define to 1 if you use Kerberos V.])
+AH_TEMPLATE(HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC, [Define to 1 if you have the `krb5_get_init_creds_opt_alloc' function.])
+AH_TEMPLATE(HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_TWO_ARGS, [Define to 1 if your `krb5_get_init_creds_opt_alloc' function takes two arguments.])
+AH_TEMPLATE(HAVE_KRB5_INIT_SECURE_CONTEXT, [Define to 1 if you have the `krb5_init_secure_context' function.])
+AH_TEMPLATE(HAVE_KRB5_VERIFY_USER, [Define to 1 if you have the `krb5_verify_user' function.])
 AH_TEMPLATE(HAVE_LBER_H, [Define to 1 if your LDAP needs <lber.h>. (OpenLDAP does not)])
 AH_TEMPLATE(HAVE_LDAP, [Define to 1 if you use LDAP for sudoers.])
 AH_TEMPLATE(HAVE_OPIE, [Define to 1 if you use NRL OPIE.])
@@ -2477,7 +2571,6 @@ AH_TEMPLATE(HAVE_PAM, [Define to 1 if you use PAM authentication.])
 AH_TEMPLATE(HAVE_PROJECT_H, [Define to 1 if you have the <project.h> header file.])
 AH_TEMPLATE(HAVE_SECURID, [Define to 1 if you use SecurID for authentication.])
 AH_TEMPLATE(HAVE_SELINUX, [Define to 1 to enable SELinux RBAC support.])
-AH_TEMPLATE(HAVE_SIA, [Define to 1 if you use SIA authentication.])
 AH_TEMPLATE(HAVE_SIGACTION_T, [Define to 1 if <signal.h> has the sigaction_t typedef.])
 AH_TEMPLATE(HAVE_SKEY, [Define to 1 if you use S/Key.])
 AH_TEMPLATE(HAVE_SKEYACCESS, [Define to 1 if your S/Key library has skeyaccess().])
@@ -2509,6 +2602,7 @@ AH_TEMPLATE(USE_STOW, [Define to 1 if you use GNU stow packaging.])
 AH_TEMPLATE(USE_TTY_TICKETS, [Define to 1 if you want a different ticket file for each tty.])
 AH_TEMPLATE(WITHOUT_PASSWD, [Define to avoid using the passwd/shadow file for authentication.])
 AH_TEMPLATE(sig_atomic_t, [Define to `int' if <signal.h> does not define.])
+AH_TEMPLATE(__signed, [Define to `signed' or nothing if compiler does not support a signed type qualifier.])
 
 dnl
 dnl Bits to copy verbatim into config.h.in
index ff9ebc654c9e8dea464448ed61c8c42d56ce3b10..72c14c9f1f3f5de22b5489cc2a9941a0aee3e532 100644 (file)
@@ -186,6 +186,10 @@ struct sudo_defs_types sudo_defs_table[] = {
        "mailto", T_STR|T_BOOL,
        "Address to send mail to: %s",
        NULL,
+    }, {
+       "mailfrom", T_STR|T_BOOL,
+       "Address to send mail from: %s",
+       NULL,
     }, {
        "mailsub", T_STR,
        "Subject line for mail messages: %s",
@@ -218,7 +222,10 @@ struct sudo_defs_types sudo_defs_table[] = {
        "runas_default", T_STR,
        "Default user to run commands as: %s",
        NULL,
-       set_runaspw,
+    }, {
+       "secure_path", T_STR|T_BOOL,
+       "Value to override user's $PATH with: %s",
+       NULL,
     }, {
        "editor", T_STR|T_PATH,
        "Path to the editor for use by visudo: %s",
@@ -243,6 +250,14 @@ struct sudo_defs_types sudo_defs_table[] = {
        "ignore_local_sudoers", T_FLAG,
        "If LDAP directory is up, do we ignore local sudoers file",
        NULL,
+    }, {
+       "closefrom", T_INT,
+       "File descriptors >= %d will be closed before executing a command",
+       NULL,
+    }, {
+       "closefrom_override", T_FLAG,
+       "If set, users may override the value of `closefrom' with the -C option",
+       NULL,
     }, {
        "setenv", T_FLAG,
        "Allow users to set arbitrary environment variables",
@@ -271,6 +286,22 @@ struct sudo_defs_types sudo_defs_table[] = {
        "type", T_STR,
        "SELinux type to use in the new security context: %s",
        NULL,
+    }, {
+       "askpass", T_STR|T_PATH|T_BOOL,
+       "Path to the askpass helper program: %s",
+       NULL,
+    }, {
+       "env_file", T_STR|T_PATH|T_BOOL,
+       "Path to the sudo-specific environment file: %s",
+       NULL,
+    }, {
+       "sudoers_locale", T_STR,
+       "Locale to use while parsing sudoers: %s",
+       NULL,
+    }, {
+       "visiblepw", T_FLAG,
+       "Allow sudo to prompt for a password even if it would be visisble",
+       NULL,
     }, {
        NULL, 0, NULL
     }
index bbbd2ab0a5f6d10148bb83e31a90e75e88bc0309..afa78e0b5fc29b6f8ded5c4d491a22942a454465 100644 (file)
 #define I_MAILERFLAGS           39
 #define def_mailto              (sudo_defs_table[40].sd_un.str)
 #define I_MAILTO                40
-#define def_mailsub             (sudo_defs_table[41].sd_un.str)
-#define I_MAILSUB               41
-#define def_badpass_message     (sudo_defs_table[42].sd_un.str)
-#define I_BADPASS_MESSAGE       42
-#define def_timestampdir        (sudo_defs_table[43].sd_un.str)
-#define I_TIMESTAMPDIR          43
-#define def_timestampowner      (sudo_defs_table[44].sd_un.str)
-#define I_TIMESTAMPOWNER        44
-#define def_exempt_group        (sudo_defs_table[45].sd_un.str)
-#define I_EXEMPT_GROUP          45
-#define def_passprompt          (sudo_defs_table[46].sd_un.str)
-#define I_PASSPROMPT            46
-#define def_passprompt_override (sudo_defs_table[47].sd_un.flag)
-#define I_PASSPROMPT_OVERRIDE   47
-#define def_runas_default       (sudo_defs_table[48].sd_un.str)
-#define I_RUNAS_DEFAULT         48
-#define def_editor              (sudo_defs_table[49].sd_un.str)
-#define I_EDITOR                49
-#define def_listpw              (sudo_defs_table[50].sd_un.tuple)
-#define I_LISTPW                50
-#define def_verifypw            (sudo_defs_table[51].sd_un.tuple)
-#define I_VERIFYPW              51
-#define def_noexec              (sudo_defs_table[52].sd_un.flag)
-#define I_NOEXEC                52
-#define def_noexec_file         (sudo_defs_table[53].sd_un.str)
-#define I_NOEXEC_FILE           53
-#define def_ignore_local_sudoers (sudo_defs_table[54].sd_un.flag)
-#define I_IGNORE_LOCAL_SUDOERS  54
-#define def_setenv              (sudo_defs_table[55].sd_un.flag)
-#define I_SETENV                55
-#define def_env_reset           (sudo_defs_table[56].sd_un.flag)
-#define I_ENV_RESET             56
-#define def_env_check           (sudo_defs_table[57].sd_un.list)
-#define I_ENV_CHECK             57
-#define def_env_delete          (sudo_defs_table[58].sd_un.list)
-#define I_ENV_DELETE            58
-#define def_env_keep            (sudo_defs_table[59].sd_un.list)
-#define I_ENV_KEEP              59
-#define def_role                (sudo_defs_table[60].sd_un.str)
-#define I_ROLE                  60
-#define def_type                (sudo_defs_table[61].sd_un.str)
-#define I_TYPE                  61
+#define def_mailfrom            (sudo_defs_table[41].sd_un.str)
+#define I_MAILFROM              41
+#define def_mailsub             (sudo_defs_table[42].sd_un.str)
+#define I_MAILSUB               42
+#define def_badpass_message     (sudo_defs_table[43].sd_un.str)
+#define I_BADPASS_MESSAGE       43
+#define def_timestampdir        (sudo_defs_table[44].sd_un.str)
+#define I_TIMESTAMPDIR          44
+#define def_timestampowner      (sudo_defs_table[45].sd_un.str)
+#define I_TIMESTAMPOWNER        45
+#define def_exempt_group        (sudo_defs_table[46].sd_un.str)
+#define I_EXEMPT_GROUP          46
+#define def_passprompt          (sudo_defs_table[47].sd_un.str)
+#define I_PASSPROMPT            47
+#define def_passprompt_override (sudo_defs_table[48].sd_un.flag)
+#define I_PASSPROMPT_OVERRIDE   48
+#define def_runas_default       (sudo_defs_table[49].sd_un.str)
+#define I_RUNAS_DEFAULT         49
+#define def_secure_path         (sudo_defs_table[50].sd_un.str)
+#define I_SECURE_PATH           50
+#define def_editor              (sudo_defs_table[51].sd_un.str)
+#define I_EDITOR                51
+#define def_listpw              (sudo_defs_table[52].sd_un.tuple)
+#define I_LISTPW                52
+#define def_verifypw            (sudo_defs_table[53].sd_un.tuple)
+#define I_VERIFYPW              53
+#define def_noexec              (sudo_defs_table[54].sd_un.flag)
+#define I_NOEXEC                54
+#define def_noexec_file         (sudo_defs_table[55].sd_un.str)
+#define I_NOEXEC_FILE           55
+#define def_ignore_local_sudoers (sudo_defs_table[56].sd_un.flag)
+#define I_IGNORE_LOCAL_SUDOERS  56
+#define def_closefrom           (sudo_defs_table[57].sd_un.ival)
+#define I_CLOSEFROM             57
+#define def_closefrom_override  (sudo_defs_table[58].sd_un.flag)
+#define I_CLOSEFROM_OVERRIDE    58
+#define def_setenv              (sudo_defs_table[59].sd_un.flag)
+#define I_SETENV                59
+#define def_env_reset           (sudo_defs_table[60].sd_un.flag)
+#define I_ENV_RESET             60
+#define def_env_check           (sudo_defs_table[61].sd_un.list)
+#define I_ENV_CHECK             61
+#define def_env_delete          (sudo_defs_table[62].sd_un.list)
+#define I_ENV_DELETE            62
+#define def_env_keep            (sudo_defs_table[63].sd_un.list)
+#define I_ENV_KEEP              63
+#define def_role                (sudo_defs_table[64].sd_un.str)
+#define I_ROLE                  64
+#define def_type                (sudo_defs_table[65].sd_un.str)
+#define I_TYPE                  65
+#define def_askpass             (sudo_defs_table[66].sd_un.str)
+#define I_ASKPASS               66
+#define def_env_file            (sudo_defs_table[67].sd_un.str)
+#define I_ENV_FILE              67
+#define def_sudoers_locale      (sudo_defs_table[68].sd_un.str)
+#define I_SUDOERS_LOCALE        68
+#define def_visiblepw           (sudo_defs_table[69].sd_un.flag)
+#define I_VISIBLEPW             69
 
 enum def_tupple {
        never,
index afc4e4cfc6842fafa98df0352a7e31401187de10..0a0a3b86deb6a741121cc306f15e67c69191a539 100644 (file)
@@ -6,6 +6,9 @@
 #      description (or NULL)
 #      array of struct def_values if TYPE == T_TUPLE
 #
+# NOTE: for tuples that can be used in a boolean context the first
+#      value corresponds to boolean FALSE and the second to TRUE.
+#
 
 syslog
        T_LOGFAC|T_BOOL
@@ -131,6 +134,9 @@ mailerflags
 mailto
        T_STR|T_BOOL
        "Address to send mail to: %s"
+mailfrom
+       T_STR|T_BOOL
+       "Address to send mail from: %s"
 mailsub
        T_STR
        "Subject line for mail messages: %s"
@@ -155,7 +161,9 @@ passprompt_override
 runas_default
        T_STR
        "Default user to run commands as: %s"
-       *set_runaspw
+secure_path
+       T_STR|T_BOOL
+       "Value to override user's $PATH with: %s"
 editor
        T_STR|T_PATH
        "Path to the editor for use by visudo: %s"
@@ -176,6 +184,12 @@ noexec_file
 ignore_local_sudoers
        T_FLAG
        "If LDAP directory is up, do we ignore local sudoers file"
+closefrom
+       T_INT
+       "File descriptors >= %d will be closed before executing a command"
+closefrom_override
+       T_FLAG
+       "If set, users may override the value of `closefrom' with the -C option"
 setenv
        T_FLAG
        "Allow users to set arbitrary environment variables"
@@ -197,3 +211,15 @@ role
 type
        T_STR
        "SELinux type to use in the new security context: %s"
+askpass
+       T_STR|T_PATH|T_BOOL
+       "Path to the askpass helper program: %s"
+env_file
+       T_STR|T_PATH|T_BOOL
+       "Path to the sudo-specific environment file: %s"
+sudoers_locale
+       T_STR
+       "Locale to use while parsing sudoers: %s"
+visiblepw
+       T_FLAG
+       "Allow sudo to prompt for a password even if it would be visisble"
index 7e7675e47e16faa57b553093b34dfed2f734729b..376fef79843a359318120097e6ee9a6be46c5c9e 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include <pwd.h>
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <ctype.h>
 
 #include "sudo.h"
+#include "parse.h"
+#include <gram.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: defaults.c,v 1.48.2.5 2007/06/18 15:51:35 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: defaults.c,v 1.73 2008/11/09 14:13:12 millert Exp $";
 #endif /* lint */
 
 /*
@@ -95,8 +93,6 @@ static struct strmap priorities[] = {
        { NULL,         -1 }
 };
 
-extern int sudolineno;
-
 /*
  * Local prototypes.
  */
@@ -232,8 +228,7 @@ set_default(var, val, op)
            break;
     }
     if (!cur->name) {
-       warnx("unknown defaults entry `%s' referenced near line %d",
-           var, sudolineno);
+       warningx("unknown defaults entry `%s'", var);
        return(FALSE);
     }
 
@@ -241,20 +236,18 @@ set_default(var, val, op)
        case T_LOGFAC:
            if (!store_syslogfac(val, cur, op)) {
                if (val)
-                   warnx("value `%s' is invalid for option `%s'", val, var);
+                   warningx("value `%s' is invalid for option `%s'", val, var);
                else
-                   warnx("no value specified for `%s' on line %d",
-                       var, sudolineno);
+                   warningx("no value specified for `%s'", var);
                return(FALSE);
            }
            break;
        case T_LOGPRI:
            if (!store_syslogpri(val, cur, op)) {
                if (val)
-                   warnx("value `%s' is invalid for option `%s'", val, var);
+                   warningx("value `%s' is invalid for option `%s'", val, var);
                else
-                   warnx("no value specified for `%s' on line %d",
-                       var, sudolineno);
+                   warningx("no value specified for `%s'", var);
                return(FALSE);
            }
            break;
@@ -262,17 +255,16 @@ set_default(var, val, op)
            if (!val) {
                /* Check for bogus boolean usage or lack of a value. */
                if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-                   warnx("no value specified for `%s' on line %d",
-                       var, sudolineno);
+                   warningx("no value specified for `%s'", var);
                    return(FALSE);
                }
            }
            if (ISSET(cur->type, T_PATH) && val && *val != '/') {
-               warnx("values for `%s' must start with a '/'", var);
+               warningx("values for `%s' must start with a '/'", var);
                return(FALSE);
            }
            if (!store_str(val, cur, op)) {
-               warnx("value `%s' is invalid for option `%s'", val, var);
+               warningx("value `%s' is invalid for option `%s'", val, var);
                return(FALSE);
            }
            break;
@@ -280,13 +272,12 @@ set_default(var, val, op)
            if (!val) {
                /* Check for bogus boolean usage or lack of a value. */
                if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-                   warnx("no value specified for `%s' on line %d",
-                       var, sudolineno);
+                   warningx("no value specified for `%s'", var);
                    return(FALSE);
                }
            }
            if (!store_int(val, cur, op)) {
-               warnx("value `%s' is invalid for option `%s'", val, var);
+               warningx("value `%s' is invalid for option `%s'", val, var);
                return(FALSE);
            }
            break;
@@ -294,13 +285,12 @@ set_default(var, val, op)
            if (!val) {
                /* Check for bogus boolean usage or lack of a value. */
                if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-                   warnx("no value specified for `%s' on line %d",
-                       var, sudolineno);
+                   warningx("no value specified for `%s'", var);
                    return(FALSE);
                }
            }
            if (!store_uint(val, cur, op)) {
-               warnx("value `%s' is invalid for option `%s'", val, var);
+               warningx("value `%s' is invalid for option `%s'", val, var);
                return(FALSE);
            }
            break;
@@ -308,20 +298,18 @@ set_default(var, val, op)
            if (!val) {
                /* Check for bogus boolean usage or lack of a value. */
                if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-                   warnx("no value specified for `%s' on line %d",
-                       var, sudolineno);
+                   warningx("no value specified for `%s'", var);
                    return(FALSE);
                }
            }
            if (!store_mode(val, cur, op)) {
-               warnx("value `%s' is invalid for option `%s'", val, var);
+               warningx("value `%s' is invalid for option `%s'", val, var);
                return(FALSE);
            }
            break;
        case T_FLAG:
            if (val) {
-               warnx("option `%s' does not take a value on line %d",
-                   var, sudolineno);
+               warningx("option `%s' does not take a value", var);
                return(FALSE);
            }
            cur->sd_un.flag = op;
@@ -334,24 +322,22 @@ set_default(var, val, op)
            if (!val) {
                /* Check for bogus boolean usage or lack of a value. */
                if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-                   warnx("no value specified for `%s' on line %d",
-                       var, sudolineno);
+                   warningx("no value specified for `%s'", var);
                    return(FALSE);
                }
            }
            if (!store_list(val, cur, op)) {
-               warnx("value `%s' is invalid for option `%s'", val, var);
+               warningx("value `%s' is invalid for option `%s'", val, var);
                return(FALSE);
            }
            break;
        case T_TUPLE:
            if (!val && !ISSET(cur->type, T_BOOL)) {
-               warnx("no value specified for `%s' on line %d",
-                   var, sudolineno);
+               warningx("no value specified for `%s'", var);
                return(FALSE);
            }
            if (!store_tuple(val, cur, op)) {
-               warnx("value `%s' is invalid for option `%s'", val, var);
+               warningx("value `%s' is invalid for option `%s'", val, var);
                return(FALSE);
            }
            break;
@@ -370,9 +356,9 @@ init_defaults()
     static int firsttime = 1;
     struct sudo_defs_types *def;
 
-    /* Free any strings that were set. */
+    /* Clear any old settings. */
     if (!firsttime) {
-       for (def = sudo_defs_table; def->name; def++)
+       for (def = sudo_defs_table; def->name; def++) {
            switch (def->type & T_MASK) {
                case T_STR:
                    efree(def->sd_un.str);
@@ -382,6 +368,8 @@ init_defaults()
                    list_op(NULL, 0, def, freeall);
                    break;
            }
+           zero_bytes(&def->sd_un, sizeof(def->sd_un));
+       }
     }
 
     /* First initialize the flags. */
@@ -436,8 +424,13 @@ init_defaults()
 #ifdef ENV_EDITOR
     def_env_editor = TRUE;
 #endif
+#ifdef _PATH_SUDO_ASKPASS
+    def_askpass = estrdup(_PATH_SUDO_ASKPASS);
+#endif
+    def_sudoers_locale = estrdup("C");
     def_env_reset = TRUE;
     def_set_logname = TRUE;
+    def_closefrom = STDERR_FILENO + 1;
 
     /* Syslog options need special care since they both strings and ints */
 #if (LOGGING & SLOG_SYSLOG)
@@ -479,6 +472,9 @@ init_defaults()
 #endif
 #ifdef EXEMPTGROUP
     def_exempt_group = estrdup(EXEMPTGROUP);
+#endif
+#ifdef SECURE_PATH
+    def_secure_path = estrdup(SECURE_PATH);
 #endif
     def_editor = estrdup(EDITOR);
 #ifdef _PATH_SUDO_NOEXEC
@@ -488,17 +484,55 @@ init_defaults()
     /* Finally do the lists (currently just environment tables). */
     init_envtables();
 
-    /*
-     * The following depend on the above values.
-     * We use a pointer to the string so that if its
-     * value changes we get the change.
-     */
-    if (user_runas == NULL)
-       user_runas = &def_runas_default;
-
     firsttime = 0;
 }
 
+/*
+ * Update the defaults based on what was set by sudoers.
+ * Pass in a an OR'd list of which default types to update.
+ */
+int
+update_defaults(what)
+    int what;
+{
+    struct defaults *def;
+
+    tq_foreach_fwd(&defaults, def) {
+       switch (def->type) {
+           case DEFAULTS:
+               if (ISSET(what, SETDEF_GENERIC) &&
+                   !set_default(def->var, def->val, def->op))
+                   return(FALSE);
+               break;
+           case DEFAULTS_USER:
+               if (ISSET(what, SETDEF_USER) &&
+                   userlist_matches(sudo_user.pw, &def->binding) == ALLOW &&
+                   !set_default(def->var, def->val, def->op))
+                   return(FALSE);
+               break;
+           case DEFAULTS_RUNAS:
+               if (ISSET(what, SETDEF_RUNAS) &&
+                   runaslist_matches(&def->binding, NULL) == ALLOW &&
+                   !set_default(def->var, def->val, def->op))
+                   return(FALSE);
+               break;
+           case DEFAULTS_HOST:
+               if (ISSET(what, SETDEF_HOST) &&
+                   hostlist_matches(&def->binding) == ALLOW &&
+                   !set_default(def->var, def->val, def->op))
+                   return(FALSE);
+               break;
+           case DEFAULTS_CMND:
+               if (ISSET(what, SETDEF_CMND) &&
+                   cmndlist_matches(&def->binding) == ALLOW &&
+                   !set_default(def->var, def->val, def->op))
+                   return(FALSE);
+               break;
+       }
+    }
+    return(TRUE);
+}
+
 static int
 store_int(val, def, op)
     char *val;
@@ -661,9 +695,9 @@ logfac2str(n)
 
     for (fac = facilities; fac->name && fac->num != n; fac++)
        ;
-    return (fac->name);
+    return(fac->name);
 #else
-    return ("default");
+    return("default");
 #endif /* LOG_NFACILITIES */
 }
 
@@ -695,7 +729,7 @@ logpri2str(n)
 
     for (pri = priorities; pri->name && pri->num != n; pri++)
        ;
-    return (pri->name);
+    return(pri->name);
 }
 
 static int
index a30948c35c7fee5c7f6e068e3a57f6458fbceb48..aac0136a36705a3eda27945c0c2603bbd3a2a231 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1999-2001 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,7 +18,7 @@
  * Agency (DARPA) and Air Force Research Laboratory, Air Force
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  *
- * $Sudo: defaults.h,v 1.28 2004/02/13 21:36:43 millert Exp $
+ * $Sudo: defaults.h,v 1.33 2008/11/09 14:13:12 millert Exp $
  */
 
 #ifndef _SUDO_DEFAULTS_H
@@ -90,12 +91,23 @@ struct sudo_defs_types {
 #undef T_PATH
 #define T_PATH         0x200
 
+/*
+ * Argument to update_defaults()
+ */
+#define SETDEF_GENERIC 0x01
+#define        SETDEF_HOST     0x02
+#define        SETDEF_USER     0x04
+#define        SETDEF_RUNAS    0x08
+#define        SETDEF_CMND     0x10
+#define SETDEF_ALL     (SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS|SETDEF_CMND)
+
 /*
  * Prototypes
  */
 void dump_default      __P((void));
 int set_default                __P((char *, char *, int));
 void init_defaults     __P((void));
+int update_defaults    __P((int));
 void list_options      __P((void));
 
 extern struct sudo_defs_types sudo_defs_table[];
diff --git a/emul/charclass.h b/emul/charclass.h
new file mode 100644 (file)
index 0000000..bbe1d9e
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Sudo: charclass.h,v 1.3 2008/12/09 20:55:50 millert Exp $
+ */
+
+/*
+ * POSIX character class support for fnmatch() and glob().
+ */
+static struct cclass {
+       const char *name;
+       int (*isctype) __P((int));
+} cclasses[] = {
+       { "alnum",      isalnum },
+       { "alpha",      isalpha },
+       { "blank",      isblank },
+       { "cntrl",      iscntrl },
+       { "digit",      isdigit },
+       { "graph",      isgraph },
+       { "lower",      islower },
+       { "print",      isprint },
+       { "punct",      ispunct },
+       { "space",      isspace },
+       { "upper",      isupper },
+       { "xdigit",     isxdigit },
+       { NULL,         NULL }
+};
+
+#define NCCLASSES      (sizeof(cclasses) / sizeof(cclasses[0]) - 1)
diff --git a/emul/err.h b/emul/err.h
deleted file mode 100644 (file)
index 637740b..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*-
- * Copyright (c) 1993
- *     The Regents of the University of California.  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. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *     @(#)err.h       8.1 (Berkeley) 6/2/93
- */
-
-#ifndef _ERR_H_
-#define        _ERR_H_
-
-#ifdef __STDC__
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
-
-#if !defined(__GNUC__) || __GNUC__ < 2 || __GNUC__ == 2 && __GNUC_MINOR__ < 5
-#define __attribute__(x)
-#endif
-
-#ifdef __STDC__
-void   err(int, const char *, ...) __attribute__((__noreturn__));
-void   verr(int, const char *, va_list) __attribute__((__noreturn__));
-void   errx(int, const char *, ...) __attribute__((__noreturn__));
-void   verrx(int, const char *, va_list) __attribute__((__noreturn__));
-void   warn(const char *, ...);
-void   vwarn(const char *, va_list);
-void   warnx(const char *, ...);
-void   vwarnx(const char *, va_list);
-#else
-void   err() __attribute__((__noreturn__));
-void   verr() __attribute__((__noreturn__));
-void   errx() __attribute__((__noreturn__));
-void   verrx() __attribute__((__noreturn__));
-void   warn();
-void   vwarn();
-void   warnx();
-void   vwarnx();
-#endif /* __STDC__ */
-
-#endif /* !_ERR_H_ */
index 7a66a46d2fb9e23b5ad69cab1358bd538163d49e..9f65bc5849eb0cdbcf58828efc065f64e05dba67 100644 (file)
  * 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. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -44,8 +40,6 @@
 #define        FNM_PERIOD      0x04    /* Period must be matched by period. */
 #define        FNM_LEADING_DIR 0x08    /* Ignore /<tail> after Imatch. */
 #define        FNM_CASEFOLD    0x10    /* Case insensitive search. */
-#define        FNM_IGNORECASE  FNM_CASEFOLD
-#define        FNM_FILE_NAME   FNM_PATHNAME
 
 int     fnmatch __P((const char *, const char *, int));
 
diff --git a/emul/search.h b/emul/search.h
deleted file mode 100644 (file)
index 4123e2a..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * $Sudo: search.h,v 1.9 2004/02/13 21:36:49 millert Exp $
- */
-
-#ifndef _SEARCH_H
-#define _SEARCH_H
-
-VOID *lfind __P((const VOID *, const VOID *, size_t *, size_t,
-               int (*)(const VOID *, const VOID *)));
-VOID *lsearch __P((const VOID *, const VOID *, size_t *, size_t,
-                 int (*)(const VOID *, const VOID *)));
-
-#endif /* _SEARCH_H */
index 66580eb7056bdb739285a4cb6d9f8050adb76f66..295184270565c66743506fff967293dc4a96c821 100644 (file)
@@ -13,7 +13,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $Sudo: timespec.h,v 1.1.2.1 2007/06/11 11:27:37 millert Exp $
+ * $Sudo: timespec.h,v 1.1 2005/06/23 03:04:35 millert Exp $
  */
 
 #ifndef _SUDO_TIMESPEC_H
diff --git a/env.c b/env.c
index dba495511509ae6eb89c8fc1210425469488bb05..af6d53554d5b83afa1af1ed30cc7926420207356 100644 (file)
--- a/env.c
+++ b/env.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2000-2007 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2000-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <pwd.h>
 
 #include "sudo.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: env.c,v 1.39.2.19 2008/06/21 19:04:07 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: env.c,v 1.94 2008/11/09 14:13:12 millert Exp $";
 #endif /* lint */
 
 /*
@@ -93,7 +89,7 @@ __unused static const char rcsid[] = "$Sudo: env.c,v 1.39.2.19 2008/06/21 19:04:
 #define KEPT_MAX       0xff00
 
 #undef VNULL
-#define        VNULL   (VOID *)NULL
+#define        VNULL   (void *)NULL
 
 struct environment {
     char **envp;               /* pointer to the new environment */
@@ -104,9 +100,14 @@ struct environment {
 /*
  * Prototypes
  */
-char **rebuild_env             __P((char **, int, int));
-static void insert_env         __P((char *, struct environment *, int));
-static char *format_env                __P((char *, ...));
+void rebuild_env               __P((int, int));
+void sudo_setenv               __P((const char *, const char *, int));
+void sudo_unsetenv             __P((const char *));
+static void _sudo_setenv       __P((const char *, const char *, int));
+static void insert_env         __P((char *, int, int));
+static void sync_env           __P((void));
+
+extern char **environ;         /* global environment */
 
 /*
  * Copy of the sudo-managed environment.
@@ -133,6 +134,7 @@ static const char *initial_badenv_table[] = {
 #ifdef _AIX
     "LDR_*",
     "LIBPATH",
+    "AUTHSTATE",
 #endif
 #ifdef __APPLE__
     "DYLD_*",
@@ -213,86 +215,150 @@ static const char *initial_keepenv_table[] = {
 };
 
 /*
- * Given a variable and value, allocate and format an environment string.
+ * Syncronize our private copy of the environment with what is
+ * in environ.
  */
-static char *
-#ifdef __STDC__
-format_env(char *var, ...)
-#else
-format_env(var, va_alist)
-    char *var;
-    va_dcl
-#endif
+static void
+sync_env()
+{
+    size_t evlen;
+    char **ep;
+
+    for (ep = environ; *ep != NULL; ep++)
+       continue;
+    evlen = ep - environ;
+    if (evlen + 1 > env.env_size) {
+       efree(env.envp);
+       env.env_size = evlen + 1 + 128;
+       env.envp = emalloc2(env.env_size, sizeof(char *));
+    }
+    memcpy(env.envp, environ, (evlen + 1) * sizeof(char *));
+    env.env_len = evlen;
+    environ = env.envp;
+}
+
+/*
+ * Similar to setenv(3) but operates on sudo's private copy of the environment
+ * and it always overwrites.  The dupcheck param determines whether we need
+ * to verify that the variable is not already set.
+ */
+static void
+_sudo_setenv(var, val, dupcheck)
+    const char *var;
+    const char *val;
+    int dupcheck;
 {
     char *estring;
-    char *val;
     size_t esize;
-    va_list ap;
 
-#ifdef __STDC__
-    va_start(ap, var);
-#else
-    va_start(ap);
-#endif
-    esize = strlen(var) + 2;
-    while ((val = va_arg(ap, char *)) != NULL)
-       esize += strlen(val);
-    va_end(ap);
-    estring = (char *) emalloc(esize);
+    esize = strlen(var) + 1 + strlen(val) + 1;
+    estring = emalloc(esize);
 
-    /* Store variable name and the '=' separator.  */
+    /* Build environment string and insert it. */
     if (strlcpy(estring, var, esize) >= esize ||
-       strlcat(estring, "=", esize) >= esize) {
+       strlcat(estring, "=", esize) >= esize ||
+       strlcat(estring, val, esize) >= esize) {
 
-       errx(1, "internal error, format_env() overflow");
+       errorx(1, "internal error, sudo_setenv() overflow");
     }
+    insert_env(estring, dupcheck, FALSE);
+}
 
-    /* Now store the variable's value (if any) */
-#ifdef __STDC__
-    va_start(ap, var);
-#else
-    va_start(ap);
-#endif
-    while ((val = va_arg(ap, char *)) != NULL) {
-       if (strlcat(estring, val, esize) >= esize)
-           errx(1, "internal error, format_env() overflow");
+#ifdef HAVE_LDAP
+/*
+ * External version of sudo_setenv() that keeps things in sync with
+ * the environ pointer.
+ */
+void
+sudo_setenv(var, val, dupcheck)
+    const char *var;
+    const char *val;
+    int dupcheck;
+{
+    char *estring;
+    size_t esize;
+
+    /* Make sure we are operating on the current environment. */
+    if (env.envp != environ)
+       sync_env();
+
+    esize = strlen(var) + 1 + strlen(val) + 1;
+    estring = emalloc(esize);
+
+    /* Build environment string and insert it. */
+    if (strlcpy(estring, var, esize) >= esize ||
+       strlcat(estring, "=", esize) >= esize ||
+       strlcat(estring, val, esize) >= esize) {
+
+       errorx(1, "internal error, sudo_setenv() overflow");
     }
-    va_end(ap);
+    insert_env(estring, dupcheck, TRUE);
+}
+#endif /* HAVE_LDAP */
+
+#if defined(HAVE_LDAP) || defined(HAVE_AIXAUTH)
+/*
+ * Similar to unsetenv(3) but operates on sudo's private copy of the
+ * environment.
+ */
+void
+sudo_unsetenv(var)
+    const char *var;
+{
+    char **nep;
+    size_t varlen;
 
-    return(estring);
+    /* Make sure we are operating on the current environment. */
+    if (env.envp != environ)
+       sync_env();
+
+    varlen = strlen(var);
+    for (nep = env.envp; *nep; nep++) {
+       if (strncmp(var, *nep, varlen) == 0 && (*nep)[varlen] == '=') {
+           /* Found it; move everything over by one and update len. */
+           memmove(nep, nep + 1,
+               (env.env_len - (nep - env.envp)) * sizeof(char *));
+           env.env_len--;
+           return;
+       }
+    }
 }
+#endif /* HAVE_LDAP || HAVE_AIXAUTH */
 
 /*
- * Insert str into e->envp, assumes str has an '=' in it.
+ * Insert str into env.envp, assumes str has an '=' in it.
  */
 static void
-insert_env(str, e, dupcheck)
+insert_env(str, dupcheck, dosync)
     char *str;
-    struct environment *e;
     int dupcheck;
+    int dosync;
 {
     char **nep;
     size_t varlen;
 
     /* Make sure there is room for the new entry plus a NULL. */
-    if (e->env_len + 2 > e->env_size) {
-       e->env_size += 128;
-       e->envp = erealloc3(e->envp, e->env_size, sizeof(char *));
+    if (env.env_len + 2 > env.env_size) {
+       env.env_size += 128;
+       env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
+       if (dosync)
+           environ = env.envp;
     }
 
     if (dupcheck) {
            varlen = (strchr(str, '=') - str) + 1;
 
-           for (nep = e->envp; *nep; nep++) {
+           for (nep = env.envp; *nep; nep++) {
                if (strncmp(str, *nep, varlen) == 0) {
-                   *nep = str;
+                   if (dupcheck != -1)
+                       *nep = str;
                    return;
                }
            }
     } else
-       nep = e->envp + e->env_len;
+       nep = env.envp + env.env_len;
 
-    e->env_len++;
+    env.env_len++;
     *nep++ = str;
     *nep = NULL;
 }
@@ -391,13 +457,13 @@ matches_env_keep(var)
  * variables from the old one or start with a clean slate.
  * Also adds sudo-specific variables (SUDO_*).
  */
-char **
-rebuild_env(envp, sudo_mode, noexec)
-    char **envp;
+void
+rebuild_env(sudo_mode, noexec)
     int sudo_mode;
     int noexec;
 {
-    char **ep, *cp, *ps1;
+    char **old_envp, **ep, *cp, *ps1;
+    char idbuf[MAX_UID_T_LEN];
     unsigned int didvar;
 
     /*
@@ -405,10 +471,13 @@ rebuild_env(envp, sudo_mode, noexec)
      */
     ps1 = NULL;
     didvar = 0;
-    memset(&env, 0, sizeof(env));
+    env.env_len = 0;
+    env.env_size = 128;
+    old_envp = env.envp;
+    env.envp = emalloc2(env.env_size, sizeof(char *));
     if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
        /* Pull in vars we want to keep from the old environment. */
-       for (ep = envp; *ep; ep++) {
+       for (ep = environ; *ep; ep++) {
            int keepit;
 
            /* Skip variables with values beginning with () (bash functions) */
@@ -460,7 +529,7 @@ rebuild_env(envp, sudo_mode, noexec)
                            SET(didvar, DID_USERNAME);
                        break;
                }
-               insert_env(*ep, &env, 0);
+               insert_env(*ep, FALSE, FALSE);
            }
        }
        didvar |= didvar << 8;          /* convert DID_* to KEPT_* */
@@ -471,35 +540,31 @@ rebuild_env(envp, sudo_mode, noexec)
         * on sudoers options).
         */
        if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
-           insert_env(format_env("HOME", runas_pw->pw_dir, VNULL), &env,
-               ISSET(didvar, DID_HOME));
-           insert_env(format_env("SHELL", runas_pw->pw_shell, VNULL), &env,
-               ISSET(didvar, DID_SHELL));
-           insert_env(format_env("LOGNAME", runas_pw->pw_name, VNULL), &env,
+           _sudo_setenv("HOME", runas_pw->pw_dir, ISSET(didvar, DID_HOME));
+           _sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL));
+           _sudo_setenv("LOGNAME", runas_pw->pw_name,
                ISSET(didvar, DID_LOGNAME));
-           insert_env(format_env("USER", runas_pw->pw_name, VNULL), &env,
-               ISSET(didvar, DID_USER));
-           insert_env(format_env("USERNAME", runas_pw->pw_name, VNULL), &env,
+           _sudo_setenv("USER", runas_pw->pw_name, ISSET(didvar, DID_USER));
+           _sudo_setenv("USERNAME", runas_pw->pw_name,
                ISSET(didvar, DID_USERNAME));
        } else {
            if (!ISSET(didvar, DID_HOME))
-               insert_env(format_env("HOME", user_dir, VNULL), &env, 0);
+               _sudo_setenv("HOME", user_dir, FALSE);
            if (!ISSET(didvar, DID_SHELL))
-               insert_env(format_env("SHELL", sudo_user.pw->pw_shell, VNULL),
-                   &env, 0);
+               _sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE);
            if (!ISSET(didvar, DID_LOGNAME))
-               insert_env(format_env("LOGNAME", user_name, VNULL), &env, 0);
+               _sudo_setenv("LOGNAME", user_name, FALSE);
            if (!ISSET(didvar, DID_USER))
-               insert_env(format_env("USER", user_name, VNULL), &env, 0);
+               _sudo_setenv("USER", user_name, FALSE);
            if (!ISSET(didvar, DID_USERNAME))
-               insert_env(format_env("USERNAME", user_name, VNULL), &env, 0);
+               _sudo_setenv("USERNAME", user_name, FALSE);
        }
     } else {
        /*
-        * Copy envp entries as long as they don't match env_delete or
+        * Copy environ entries as long as they don't match env_delete or
         * env_check.
         */
-       for (ep = envp; *ep; ep++) {
+       for (ep = environ; *ep; ep++) {
            int okvar;
 
            /* Skip variables with values beginning with () (bash functions) */
@@ -523,28 +588,25 @@ rebuild_env(envp, sudo_mode, noexec)
                    SET(didvar, DID_PATH);
                else if (strncmp(*ep, "TERM=", 5) == 0)
                    SET(didvar, DID_TERM);
-               insert_env(*ep, &env, 0);
+               insert_env(*ep, FALSE, FALSE);
            }
        }
     }
-
-#ifdef SECURE_PATH
-    /* Replace the PATH envariable with a secure one. */
-    if (!user_is_exempt()) {
-       insert_env(format_env("PATH", SECURE_PATH, VNULL), &env, 1);
+    /* Replace the PATH envariable with a secure one? */
+    if (def_secure_path && !user_is_exempt()) {
+       _sudo_setenv("PATH", def_secure_path, TRUE);
        SET(didvar, DID_PATH);
     }
-#endif
 
     /* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is true. */
     /* XXX - not needed for MODE_LOGIN_SHELL */
     if (def_set_logname && runas_pw->pw_name) {
        if (!ISSET(didvar, KEPT_LOGNAME))
-           insert_env(format_env("LOGNAME", runas_pw->pw_name, VNULL), &env, 1);
+           _sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE);
        if (!ISSET(didvar, KEPT_USER))
-           insert_env(format_env("USER", runas_pw->pw_name, VNULL), &env, 1);
+           _sudo_setenv("USER", runas_pw->pw_name, TRUE);
        if (!ISSET(didvar, KEPT_USERNAME))
-           insert_env(format_env("USERNAME", runas_pw->pw_name, VNULL), &env, 1);
+           _sudo_setenv("USERNAME", runas_pw->pw_name, TRUE);
     }
 
     /* Set $HOME for `sudo -H'.  Only valid at PERM_FULL_RUNAS. */
@@ -553,14 +615,14 @@ rebuild_env(envp, sudo_mode, noexec)
        if (ISSET(sudo_mode, MODE_RESET_HOME) ||
            (ISSET(sudo_mode, MODE_RUN) && (def_always_set_home ||
            (ISSET(sudo_mode, MODE_SHELL) && def_set_home))))
-           insert_env(format_env("HOME", runas_pw->pw_dir, VNULL), &env, 1);
+           _sudo_setenv("HOME", runas_pw->pw_dir, TRUE);
     }
 
     /* Provide default values for $TERM and $PATH if they are not set. */
     if (!ISSET(didvar, DID_TERM))
-       insert_env("TERM=unknown", &env, 0);
+       insert_env("TERM=unknown", FALSE, FALSE);
     if (!ISSET(didvar, DID_PATH))
-       insert_env(format_env("PATH", _PATH_DEFPATH, VNULL), &env, 0);
+       _sudo_setenv("PATH", _PATH_DEFPATH, FALSE);
 
     /*
      * Preload a noexec file?  For a list of LD_PRELOAD-alikes, see
@@ -569,78 +631,63 @@ rebuild_env(envp, sudo_mode, noexec)
      */
     if (noexec && def_noexec_file != NULL) {
 #if defined(__darwin__) || defined(__APPLE__)
-       insert_env(format_env("DYLD_INSERT_LIBRARIES", def_noexec_file, VNULL),
-           &env, 1);
-       insert_env(format_env("DYLD_FORCE_FLAT_NAMESPACE", VNULL), &env, 1);
+       _sudo_setenv("DYLD_INSERT_LIBRARIES", def_noexec_file, TRUE);
+       _sudo_setenv("DYLD_FORCE_FLAT_NAMESPACE", "", TRUE);
 #else
 # if defined(__osf__) || defined(__sgi)
-       insert_env(format_env("_RLD_LIST", def_noexec_file, ":DEFAULT", VNULL),
-           &env, 1);
+       easprintf(&cp, "%s:DEFAULT", def_noexec_file);
+       _sudo_setenv("_RLD_LIST", cp, TRUE);
+       efree(cp);
 # else
 #  ifdef _AIX
-       insert_env(format_env("LDR_PRELOAD", def_noexec_file, VNULL), &env, 1);
+       _sudo_setenv("LDR_PRELOAD", def_noexec_file, TRUE);
 #  else
-       insert_env(format_env("LD_PRELOAD", def_noexec_file, VNULL), &env, 1);
+       _sudo_setenv("LD_PRELOAD", def_noexec_file, TRUE);
 #  endif /* _AIX */
 # endif /* __osf__ || __sgi */
 #endif /* __darwin__ || __APPLE__ */
     }
 
     /* Set PS1 if SUDO_PS1 is set. */
-    if (ps1)
-       insert_env(ps1, &env, 1);
+    if (ps1 != NULL)
+       insert_env(ps1, TRUE, FALSE);
 
     /* Add the SUDO_COMMAND envariable (cmnd + args). */
-    if (user_args)
-       insert_env(format_env("SUDO_COMMAND", user_cmnd, " ", user_args, VNULL),
-           &env, 1);
-    else
-       insert_env(format_env("SUDO_COMMAND", user_cmnd, VNULL), &env, 1);
+    if (user_args) {
+       easprintf(&cp, "%s %s", user_cmnd, user_args);
+       _sudo_setenv("SUDO_COMMAND", cp, TRUE);
+       efree(cp);
+    } else
+       _sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE);
 
     /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
-    insert_env(format_env("SUDO_USER", user_name, VNULL), &env, 1);
-    easprintf(&cp, "SUDO_UID=%lu", (unsigned long) user_uid);
-    insert_env(cp, &env, 1);
-    easprintf(&cp, "SUDO_GID=%lu", (unsigned long) user_gid);
-    insert_env(cp, &env, 1);
-
-    return(env.envp);
+    _sudo_setenv("SUDO_USER", user_name, TRUE);
+    snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_uid);
+    _sudo_setenv("SUDO_UID", idbuf, TRUE);
+    snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_gid);
+    _sudo_setenv("SUDO_GID", idbuf, TRUE);
+
+    /* Install new environment. */
+    environ = env.envp;
+    efree(old_envp);
 }
 
-char **
-insert_env_vars(envp, env_vars)
-    char **envp;
+void
+insert_env_vars(env_vars)
     struct list_member *env_vars;
 {
     struct list_member *cur;
 
     if (env_vars == NULL)
-       return (envp);
+       return;
 
-    /*
-     * Make sure we still own the environment and steal it back if not.
-     */
-    if (env.envp != envp) {
-       size_t evlen;
-       char **ep;
-
-       for (ep = envp; *ep != NULL; ep++)
-           continue;
-       evlen = ep - envp;
-       if (evlen + 1 > env.env_size) {
-           efree(env.envp);
-           env.env_size = evlen + 1 + 128;
-           env.envp = emalloc2(env.env_size, sizeof(char *));
-       }
-       memcpy(env.envp, envp, (evlen + 1) * sizeof(char *));
-       env.env_len = evlen;
-    }
+    /* Make sure we are operating on the current environment. */
+    if (env.envp != environ)
+       sync_env();
 
     /* Add user-specified environment variables. */
     for (cur = env_vars; cur != NULL; cur = cur->next)
-       insert_env(cur->value, &env, 1);
-
-    return(env.envp);
+       insert_env(cur->value, TRUE, TRUE);
 }
 
 /*
@@ -658,12 +705,10 @@ validate_env_vars(env_vars)
     int okvar;
 
     for (var = env_vars; var != NULL; var = var->next) {
-#ifdef SECURE_PATH
-       if (!user_is_exempt() && strncmp(var->value, "PATH=", 5) == 0) {
+       if (def_secure_path && !user_is_exempt() &&
+           strncmp(var->value, "PATH=", 5) == 0) {
            okvar = FALSE;
-       } else
-#endif
-       if (def_env_reset) {
+       } else if (def_env_reset) {
            okvar = matches_env_check(var->value);
            if (okvar == -1)
                okvar = matches_env_keep(var->value);
@@ -700,6 +745,41 @@ validate_env_vars(env_vars)
     }
 }
 
+/*
+ * Read in /etc/environment ala AIX and Linux.
+ * Lines are in the form of NAME=VALUE
+ * Invalid lines, blank lines, or lines consisting solely of a comment
+ * character are skipped.
+ */
+void
+read_env_file(path, replace)
+    const char *path;
+    int replace;
+{
+    FILE *fp;
+    char *cp;
+
+    if ((fp = fopen(path, "r")) == NULL)
+       return;
+
+    /* Make sure we are operating on the current environment. */
+    if (env.envp != environ)
+       sync_env();
+
+    while ((cp = sudo_parseln(fp)) != NULL) {
+       /* Skip blank or comment lines */
+       if (*cp == '\0')
+           continue;
+
+       /* Must be of the form name=value */
+       if (strchr(cp, '=') == NULL)
+           continue;
+
+       insert_env(estrdup(cp), replace ? TRUE : -1, TRUE);
+    }
+    fclose(fp);
+}
+
 void
 init_envtables()
 {
diff --git a/err.c b/err.c
deleted file mode 100644 (file)
index e9a37f6..0000000
--- a/err.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*-
- * Copyright (c) 1993
- *     The Regents of the University of California.  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. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *     @(#)err.c       8.1 (Berkeley) 6/4/93"
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <config.h>
-#include <compat.h>
-#include "emul/err.h"
-
-#ifndef lint
-__unused static const char rcsid[] = "$Sudo: err.c,v 1.2.2.1 2007/06/12 00:56:42 millert Exp $";
-#endif /* lint */
-
-void
-#ifdef __STDC__
-err(int eval, const char *fmt, ...)
-#else
-err(eval, fmt, va_alist)
-       int eval;
-       const char *fmt;
-       va_dcl
-#endif
-{
-       va_list ap;
-#ifdef __STDC__
-       va_start(ap, fmt);
-#else
-       va_start(ap);
-#endif
-       verr(eval, fmt, ap);
-       va_end(ap);
-}
-
-void
-verr(eval, fmt, ap)
-       int eval;
-       const char *fmt;
-       va_list ap;
-{
-       int sverrno;
-
-       sverrno = errno;
-       (void)fprintf(stderr, "%s: ", getprogname());
-       if (fmt != NULL) {
-               (void)vfprintf(stderr, fmt, ap);
-               (void)fprintf(stderr, ": ");
-       }
-       (void)fprintf(stderr, "%s\n", strerror(sverrno));
-       exit(eval);
-}
-
-void
-#ifdef __STDC__
-errx(int eval, const char *fmt, ...)
-#else
-errx(eval, fmt, va_alist)
-       int eval;
-       const char *fmt;
-       va_dcl
-#endif
-{
-       va_list ap;
-#ifdef __STDC__
-       va_start(ap, fmt);
-#else
-       va_start(ap);
-#endif
-       verrx(eval, fmt, ap);
-       va_end(ap);
-}
-
-void
-verrx(eval, fmt, ap)
-       int eval;
-       const char *fmt;
-       va_list ap;
-{
-       (void)fprintf(stderr, "%s: ", getprogname());
-       if (fmt != NULL)
-               (void)vfprintf(stderr, fmt, ap);
-       (void)fprintf(stderr, "\n");
-       exit(eval);
-}
-
-void
-#ifdef __STDC__
-warn(const char *fmt, ...)
-#else
-warn(fmt, va_alist)
-       const char *fmt;
-       va_dcl
-#endif
-{
-       va_list ap;
-#ifdef __STDC__
-       va_start(ap, fmt);
-#else
-       va_start(ap);
-#endif
-       vwarn(fmt, ap);
-       va_end(ap);
-}
-
-void
-vwarn(fmt, ap)
-       const char *fmt;
-       va_list ap;
-{
-       int sverrno;
-
-       sverrno = errno;
-       (void)fprintf(stderr, "%s: ", getprogname());
-       if (fmt != NULL) {
-               (void)vfprintf(stderr, fmt, ap);
-               (void)fprintf(stderr, ": ");
-       }
-       (void)fprintf(stderr, "%s\n", strerror(sverrno));
-}
-
-void
-#ifdef __STDC__
-warnx(const char *fmt, ...)
-#else
-warnx(fmt, va_alist)
-       const char *fmt;
-       va_dcl
-#endif
-{
-       va_list ap;
-#ifdef __STDC__
-       va_start(ap, fmt);
-#else
-       va_start(ap);
-#endif
-       vwarnx(fmt, ap);
-       va_end(ap);
-}
-
-void
-vwarnx(fmt, ap)
-       const char *fmt;
-       va_list ap;
-{
-       (void)fprintf(stderr, "%s: ", getprogname());
-       if (fmt != NULL)
-               (void)vfprintf(stderr, fmt, ap);
-       (void)fprintf(stderr, "\n");
-}
diff --git a/error.c b/error.c
new file mode 100644 (file)
index 0000000..6f8149b
--- /dev/null
+++ b/error.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <config.h>
+#include <compat.h>
+#include "error.h"
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: error.c,v 1.7 2005/11/18 01:39:58 millert Exp $";
+#endif /* lint */
+
+static void _warning   __P((int, const char *, va_list));
+       void cleanup    __P((int));
+
+void
+#ifdef __STDC__
+error(int eval, const char *fmt, ...)
+#else
+error(eval, fmt, va_alist)
+       int eval;
+       const char *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+#ifdef __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       _warning(1, fmt, ap);
+       va_end(ap);
+       cleanup(0);
+       exit(eval);
+}
+
+void
+#ifdef __STDC__
+errorx(int eval, const char *fmt, ...)
+#else
+errorx(eval, fmt, va_alist)
+       int eval;
+       const char *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+#ifdef __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       _warning(0, fmt, ap);
+       va_end(ap);
+       cleanup(0);
+       exit(eval);
+}
+
+void
+#ifdef __STDC__
+warning(const char *fmt, ...)
+#else
+warning(fmt, va_alist)
+       const char *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+#ifdef __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       _warning(1, fmt, ap);
+       va_end(ap);
+}
+
+void
+#ifdef __STDC__
+warningx(const char *fmt, ...)
+#else
+warningx(fmt, va_alist)
+       const char *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+#ifdef __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       _warning(0, fmt, ap);
+       va_end(ap);
+}
+
+static void
+_warning(use_errno, fmt, ap)
+       int use_errno;
+       const char *fmt;
+       va_list ap;
+{
+       int serrno = errno;
+
+       fputs(getprogname(), stderr);
+       if (fmt != NULL) {
+               fputs(": ", stderr);
+               vfprintf(stderr, fmt, ap);
+       }
+       if (use_errno) {
+           fputs(": ", stderr);
+           fputs(strerror(serrno), stderr);
+       }
+       putc('\n', stderr);
+}
diff --git a/error.h b/error.h
new file mode 100644 (file)
index 0000000..e8d7b77
--- /dev/null
+++ b/error.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Sudo: error.h,v 1.2 2004/11/19 17:32:25 millert Exp $
+ */
+
+#ifndef _SUDO_ERROR_H_
+#define        _SUDO_ERROR_H_
+
+#ifdef __STDC__
+# include <stdarg.h>
+void   error(int, const char *, ...) __attribute__((__noreturn__));
+void   errorx(int, const char *, ...) __attribute__((__noreturn__));
+void   warning(const char *, ...);
+void   warningx(const char *, ...);
+#else
+# include <varargs.h>
+void   error() __attribute__((__noreturn__));
+void   errorx() __attribute__((__noreturn__));
+void   warning();
+void   warningx();
+#endif /* __STDC__ */
+
+#endif /* _SUDO_ERROR_H_ */
index e15c512788836cd68f544546145dda265398924e..9f176bd4064220a7c4309648c9b7a00e11c5e675 100644 (file)
--- a/fileops.c
+++ b/fileops.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 # include <sys/file.h>
 #endif /* HAVE_FLOCK */
 #include <stdio.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#include <ctype.h>
+#include <limits.h>
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 
 #include "sudo.h"
 
+#ifndef LINE_MAX
+# define LINE_MAX 2048
+#endif
+
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: fileops.c,v 1.5.2.5 2007/06/12 01:28:41 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: fileops.c,v 1.16 2008/11/09 14:13:12 millert Exp $";
 #endif /* lint */
 
 /*
@@ -139,3 +152,30 @@ lock_file(fd, lockit)
 #endif
 }
 #endif
+
+/*
+ * Read a line of input, remove comments and strip off leading
+ * and trailing spaces.  Returns static storage that is reused.
+ */
+char *
+sudo_parseln(fp)
+    FILE *fp;
+{
+    size_t len;
+    char *cp = NULL;
+    static char buf[LINE_MAX];
+
+    if (fgets(buf, sizeof(buf), fp) != NULL) {
+       /* Remove comments */
+       if ((cp = strchr(buf, '#')) != NULL)
+           *cp = '\0';
+
+       /* Trim leading and trailing whitespace/newline */
+       len = strlen(buf);
+       while (len > 0 && isspace(buf[len - 1]))
+           buf[--len] = '\0';
+       for (cp = buf; isblank(*cp); cp++)
+           continue;
+    }
+    return(cp);
+}
index 3fcf314f91fa98d3b320f1a7773642adbad4efa7..673cd0df55913b3618b00e08706b23e5f0745ccf 100644 (file)
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 
 #include "sudo.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: find_path.c,v 1.108.2.4 2007/06/12 01:43:01 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: find_path.c,v 1.115 2005/03/29 14:29:46 millert Exp $";
 #endif /* lint */
 
 /*
@@ -76,7 +71,7 @@ find_path(infile, outfile, sbp, path)
     int len;                   /* length parameter */
 
     if (strlen(infile) >= PATH_MAX)
-       errx(1, "%s: File name too long", infile);
+       errorx(1, "%s: File name too long", infile);
 
     /*
      * If we were given a fully qualified or relative path
@@ -92,11 +87,9 @@ find_path(infile, outfile, sbp, path)
     }
 
     /* Use PATH passed in unless SECURE_PATH is in effect.  */
-#ifdef SECURE_PATH
-    if (!user_is_exempt())
-       path = SECURE_PATH;
-#endif /* SECURE_PATH */
-    if (path == NULL)
+    if (def_secure_path && !user_is_exempt())
+       path = def_secure_path;
+    else if (path == NULL)
        return(NOT_FOUND);
     path = estrdup(path);
     origpath = path;
@@ -120,7 +113,7 @@ find_path(infile, outfile, sbp, path)
         */
        len = snprintf(command, sizeof(command), "%s/%s", path, infile);
        if (len <= 0 || len >= sizeof(command))
-           errx(1, "%s: File name too long", infile);
+           errorx(1, "%s: File name too long", infile);
        if ((result = sudo_goodpath(command, sbp)))
            break;
 
diff --git a/fnmatch.3 b/fnmatch.3
deleted file mode 100644 (file)
index 652ff93..0000000
--- a/fnmatch.3
+++ /dev/null
@@ -1,144 +0,0 @@
-.\"    $OpenBSD: fnmatch.3,v 1.7 1999/06/05 04:47:41 aaron Exp $
-.\"
-.\" Copyright (c) 1989, 1991, 1993
-.\"    The Regents of the University of California.  All rights reserved.
-.\"
-.\" This code is derived from software contributed to Berkeley by
-.\" Guido van Rossum.
-.\" 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. Neither the name of the University nor the names of its contributors
-.\"    may be used to endorse or promote products derived from this software
-.\"    without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
-.\"
-.\"     @(#)fnmatch.3  8.3 (Berkeley) 4/28/95
-.\"
-.Dd April 28, 1995
-.Dt FNMATCH 3
-.Os
-.Sh NAME
-.Nm fnmatch
-.Nd match filename or pathname using shell globbing rules
-.Sh SYNOPSIS
-.Fd #include <fnmatch.h>
-.Ft int
-.Fn fnmatch "const char *pattern" "const char *string" "int flags"
-.Sh DESCRIPTION
-The
-.Fn fnmatch
-function
-matches patterns according to the globbing rules used by the shell.
-It checks the string specified by the
-.Fa string
-argument to see if it matches the pattern specified by the
-.Fa pattern
-argument.
-.Pp
-The
-.Fa flags
-argument modifies the interpretation of
-.Fa pattern
-and
-.Fa string .
-The value of
-.Fa flags
-is the bitwise inclusive
-.Tn OR
-of any of the following
-constants, which are defined in the include file
-.Aq Pa fnmatch.h .
-.Bl -tag -width FNM_PATHNAME
-.It Dv FNM_NOESCAPE
-Normally, every occurrence of a backslash
-.Pq Sq \e
-followed by a character in
-.Fa pattern
-is replaced by that character.
-This is done to negate any special meaning for the character.
-If the
-.Dv FNM_NOESCAPE
-flag is set, a backslash character is treated as an ordinary character.
-.It Dv FNM_PATHNAME
-Slash characters in
-.Fa string
-must be explicitly matched by slashes in
-.Fa pattern .
-If this flag is not set, then slashes are treated as regular characters.
-.It Dv FNM_PERIOD
-Leading periods in
-.Fa string
-must be explicitly matched by periods in
-.Fa pattern .
-If this flag is not set, then leading periods are treated as regular
-characters.
-The definition of
-.Dq leading
-is related to the specification of
-.Dv FNM_PATHNAME .
-A period is always leading
-if it is the first character in
-.Fa string .
-Additionally, if
-.Dv FNM_PATHNAME
-is set,
-a period is leading
-if it immediately follows a slash.
-.It Dv FNM_LEADING_DIR
-Ignore
-.Nm /*
-rest after successful
-.Fa pattern
-matching.
-.It Dv FNM_CASEFOLD
-Ignore case distinctions in both the
-.Fa pattern
-and the
-.Fa string .
-.El
-.Sh RETURN VALUES
-The
-.Fn fnmatch
-function returns zero if
-.Fa string
-matches the pattern specified by
-.Fa pattern ,
-otherwise, it returns the value
-.Dv FNM_NOMATCH .
-.Sh SEE ALSO
-.Xr sh 1 ,
-.Xr glob 3 ,
-.Xr regex 3
-.Sh STANDARDS
-The
-.Fn fnmatch
-function conforms to
-.St -p1003.2-92 .
-.Sh HISTORY
-The
-.Fn fnmatch
-function first appeared in
-.Bx 4.4 .
-.Sh BUGS
-The pattern
-.Ql *
-matches the empty string, even if
-.Dv FNM_PATHNAME
-is specified.
index bacff5d3210c55ab5ab67b4a531dfd0aa2d10b0c..625d759cbbc055d1ef20a8c31f06a4567859cfb8 100644 (file)
--- a/fnmatch.c
+++ b/fnmatch.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2008 Todd C. Miller <Todd.Miller@courtesan.com>
  * Copyright (c) 1989, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
  *
@@ -49,6 +50,7 @@
 
 #include <compat.h>
 #include "emul/fnmatch.h"
+#include "emul/charclass.h"
 
 #undef EOS
 #define        EOS     '\0'
 #define        RANGE_ERROR     (-1)
 
 #if defined(LIBC_SCCS) && !defined(lint)
-__unused static char rcsid[] = "$OpenBSD: fnmatch.c,v 1.6 1998/03/19 00:29:59 millert Exp $";
+__unused static const char rcsid[] = "$OpenBSD: fnmatch.c,v 1.6 1998/03/19 00:29:59 millert Exp $";
 #endif /* LIBC_SCCS and not lint */
 
-static int rangematch __P((const char *, char, int, char **));
+static int rangematch __P((const char *, int, int, char **));
+static int classmatch __P((const char *, int, int, const char **));
 
 int
 fnmatch(pattern, string, flags)
@@ -167,16 +170,16 @@ fnmatch(pattern, string, flags)
 
 static int
 #ifdef __STDC__
-rangematch(const char *pattern, char test, int flags, char **newp)
+rangematch(const char *pattern, int test, int flags, char **newp)
 #else
 rangematch(pattern, test, flags, newp)
        const char *pattern;
-       char test;
+       int test;
        int flags;
        char **newp;
 #endif
 {
-       int negate, ok;
+       int negate, ok, rv;
        char c, c2;
 
        /*
@@ -190,7 +193,7 @@ rangematch(pattern, test, flags, newp)
                ++pattern;
 
        if (ISSET(flags, FNM_CASEFOLD))
-               test = tolower((unsigned char)test);
+               test = tolower(test);
 
        /*
         * A right bracket shall lose its special meaning and represent
@@ -200,6 +203,17 @@ rangematch(pattern, test, flags, newp)
        ok = 0;
        c = *pattern++;
        do {
+               if (c == '[' && *pattern == ':') {
+                       do {
+                               rv = classmatch(pattern + 1, test,
+                                   (flags & FNM_CASEFOLD), &pattern);
+                               if (rv == RANGE_MATCH)
+                                       ok = 1;
+                               c = *pattern++;
+                       } while (rv != RANGE_ERROR && c == '[' && *pattern == ':');
+                       if (c == ']')
+                       break;
+               }
                if (c == '\\' && !ISSET(flags, FNM_NOESCAPE))
                        c = *pattern++;
                if (c == EOS)
@@ -226,3 +240,43 @@ rangematch(pattern, test, flags, newp)
        *newp = (char *)pattern;
        return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
 }
+
+static int
+#ifdef __STDC__
+classmatch(const char *pattern, int test, int foldcase, const char **ep)
+#else
+classmatch(pattern, test, foldcase, ep)
+       const char *pattern;
+       int test;
+       int foldcase;
+       const char **ep;
+#endif
+{
+       struct cclass *cc;
+       const char *colon;
+       size_t len;
+       int rval = RANGE_NOMATCH;
+
+       if ((colon = strchr(pattern, ':')) == NULL || colon[1] != ']') {
+               *ep = pattern - 2;
+               return(RANGE_ERROR);
+       }
+       *ep = colon + 2;
+       len = (size_t)(colon - pattern);
+
+       if (foldcase && strncmp(pattern, "upper:]", 7) == 0)
+               pattern = "lower:]";
+       for (cc = cclasses; cc->name != NULL; cc++) {
+               if (!strncmp(pattern, cc->name, len) && cc->name[len] == '\0') {
+                       if (cc->isctype(test))
+                               rval = RANGE_MATCH;
+                       break;
+               }
+       }
+       if (cc->name == NULL) {
+               /* invalid character class, return EOS */
+               *ep = colon + strlen(colon);
+               rval = RANGE_ERROR;
+       }
+       return(rval);
+}
index 0478932c467e3237122eb906fc5b5abff871a44c..6b5588a330a79c345a3b3a40c938c7bad57bf021 100644 (file)
--- a/getcwd.c
+++ b/getcwd.c
@@ -79,7 +79,7 @@
            (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: getcwd.c,v 1.25.2.1 2007/06/12 00:56:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: getcwd.c,v 1.28 2005/02/08 03:55:42 millert Exp $";
 #endif /* lint */
 
 char *
index 387416d01e2044c4e758ed8b68ca09563a37597d..bd06d0ea76b51a6caf49eb852dc1b4cdb7d3b11f 100644 (file)
@@ -25,7 +25,7 @@
 #include <compat.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: getprogname.c,v 1.4.2.2 2007/06/12 01:28:41 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: getprogname.c,v 1.7 2005/02/12 22:56:06 millert Exp $";
 #endif /* lint */
 
 const char *
index 07f53088c8d4bed50e2bbe15e362b84abc395e01..c6848a75a457f30f6339d31539f43ec1f4363958 100644 (file)
@@ -46,6 +46,7 @@
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include <pwd.h>
+#include <grp.h>
 #ifdef HAVE_GETSPNAM
 # include <shadow.h>
 #endif /* HAVE_GETSPNAM */
 #include "sudo.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: getspwuid.c,v 1.65.2.2 2007/06/12 01:28:41 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: getspwuid.c,v 1.78 2005/02/12 22:56:06 millert Exp $";
 #endif /* lint */
 
 /*
- * Global variables (yuck)
+ * Exported for auth/secureware.c
  */
 #if defined(HAVE_GETPRPWNAM) && defined(__alpha)
 int crypt_type = INT_MAX;
 #endif /* HAVE_GETPRPWNAM && __alpha */
 
-
 /*
  * Return a copy of the encrypted password for the user described by pw.
  * If shadow passwords are in use, look in the shadow file.
@@ -106,14 +106,12 @@ sudo_getepw(pw)
     {
        struct pr_passwd *spw;
 
-       setprpwent();
        if ((spw = getprpwnam(pw->pw_name)) && spw->ufld.fd_encrypt) {
 # ifdef __alpha
            crypt_type = spw->ufld.fd_oldcrypt;
 # endif /* __alpha */
            epw = estrdup(spw->ufld.fd_encrypt);
        }
-       endprpwent();
        if (epw)
            return(epw);
     }
@@ -122,10 +120,8 @@ sudo_getepw(pw)
     {
        struct spwd *spw;
 
-       setspent();
        if ((spw = getspnam(pw->pw_name)) && spw->sp_pwdp)
            epw = estrdup(spw->sp_pwdp);
-       endspent();
        if (epw)
            return(epw);
     }
@@ -134,10 +130,8 @@ sudo_getepw(pw)
     {
        struct s_passwd *spw;
 
-       setspwent();
        if ((spw = getspwuid(pw->pw_uid)) && spw->pw_passwd)
            epw = estrdup(spw->pw_passwd);
-       endspwent();
        if (epw)
            return(epw);
     }
@@ -146,10 +140,8 @@ sudo_getepw(pw)
     {
        struct passwd_adjunct *spw;
 
-       setpwaent();
        if ((spw = getpwanam(pw->pw_name)) && spw->pwa_passwd)
            epw = estrdup(spw->pwa_passwd);
-       endpwaent();
        if (epw)
            return(epw);
     }
@@ -158,10 +150,8 @@ sudo_getepw(pw)
     {
        AUTHORIZATION *spw;
 
-       setauthent();
        if ((spw = getauthuid(pw->pw_uid)) && spw->a_password)
            epw = estrdup(spw->a_password);
-       endauthent();
        if (epw)
            return(epw);
     }
@@ -171,129 +161,42 @@ sudo_getepw(pw)
     return(estrdup(pw->pw_passwd));
 }
 
-/*
- * Dynamically allocate space for a struct password and the constituent parts
- * that we care about.  Fills in pw_passwd from shadow file if necessary.
- */
-struct passwd *
-sudo_pwdup(pw)
-    const struct passwd *pw;
+void
+sudo_setspent()
 {
-    char *cp;
-    const char *pw_passwd, *pw_shell;
-    size_t nsize, psize, csize, gsize, dsize, ssize, total;
-    struct passwd *newpw;
-
-    /* Get shadow password if available. */
-    pw_passwd = sudo_getepw(pw);
-
-    /* If shell field is empty, expand to _PATH_BSHELL. */
-    pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
-       ? _PATH_BSHELL : pw->pw_shell;
-
-    /* Allocate in one big chunk for easy freeing. */
-    nsize = psize = csize = gsize = dsize = ssize = 0;
-    total = sizeof(struct passwd);
-    if (pw->pw_name) {
-           nsize = strlen(pw->pw_name) + 1;
-           total += nsize;
-    }
-    if (pw_passwd) {
-           psize = strlen(pw_passwd) + 1;
-           total += psize;
-    }
-#ifdef HAVE_LOGIN_CAP_H
-    if (pw->pw_class) {
-           csize = strlen(pw->pw_class) + 1;
-           total += csize;
-    }
+#ifdef HAVE_GETPRPWNAM
+    setprpwent();
 #endif
-    if (pw->pw_gecos) {
-           gsize = strlen(pw->pw_gecos) + 1;
-           total += gsize;
-    }
-    if (pw->pw_dir) {
-           dsize = strlen(pw->pw_dir) + 1;
-           total += dsize;
-    }
-    if (pw_shell) {
-           ssize = strlen(pw_shell) + 1;
-           total += ssize;
-    }
-    if ((cp = malloc(total)) == NULL)
-           return (NULL);
-    newpw = (struct passwd *)cp;
-
-    /*
-     * Copy in passwd contents and make strings relative to space
-     * at the end of the buffer.
-     */
-    (void)memcpy(newpw, pw, sizeof(struct passwd));
-    cp += sizeof(struct passwd);
-    if (nsize) {
-           (void)memcpy(cp, pw->pw_name, nsize);
-           newpw->pw_name = cp;
-           cp += nsize;
-    }
-    if (psize) {
-           (void)memcpy(cp, pw_passwd, psize);
-           newpw->pw_passwd = cp;
-           cp += psize;
-    }
-#ifdef HAVE_LOGIN_CAP_H
-    if (csize) {
-           (void)memcpy(cp, pw->pw_class, csize);
-           newpw->pw_class = cp;
-           cp += csize;
-    }
+#ifdef HAVE_GETSPNAM
+    setspent();
+#endif
+#ifdef HAVE_GETSPWUID
+    setspwent();
+#endif
+#ifdef HAVE_GETPWANAM
+    setpwaent();
+#endif
+#ifdef HAVE_GETAUTHUID
+    setauthent();
 #endif
-    if (gsize) {
-           (void)memcpy(cp, pw->pw_gecos, gsize);
-           newpw->pw_gecos = cp;
-           cp += gsize;
-    }
-    if (dsize) {
-           (void)memcpy(cp, pw->pw_dir, dsize);
-           newpw->pw_dir = cp;
-           cp += dsize;
-    }
-    if (ssize) {
-           (void)memcpy(cp, pw_shell, ssize);
-           newpw->pw_shell = cp;
-           cp += ssize;
-    }
-
-    return (newpw);
-}
-
-/*
- * Get a password entry by uid and allocate space for it.
- * Fills in pw_passwd from shadow file if necessary.
- */
-struct passwd *
-sudo_getpwuid(uid)
-    uid_t uid;
-{
-    struct passwd *pw;
-
-    if ((pw = getpwuid(uid)) == NULL)
-       return(NULL);
-    else
-       return(sudo_pwdup(pw));
 }
 
-/*
- * Get a password entry by name and allocate space for it.
- * Fills in pw_passwd from shadow file if necessary.
- */
-struct passwd *
-sudo_getpwnam(name)
-    const char *name;
+void
+sudo_endspent()
 {
-    struct passwd *pw;
-
-    if ((pw = getpwnam(name)) == NULL)
-       return(NULL);
-    else
-       return(sudo_pwdup(pw));
+#ifdef HAVE_GETPRPWNAM
+    endprpwent();
+#endif
+#ifdef HAVE_GETSPNAM
+    endspent();
+#endif
+#ifdef HAVE_GETSPWUID
+    endspwent();
+#endif
+#ifdef HAVE_GETPWANAM
+    endpwaent();
+#endif
+#ifdef HAVE_GETAUTHUID
+    endauthent();
+#endif
 }
index 2b03f65d17180d3d2b581599db8c6de430a52e2b..c864c9b08ad1d54791e534a764853419f9b776e4 100644 (file)
--- a/gettime.c
+++ b/gettime.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2004-2005, 2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #include <compat.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: gettime.c,v 1.6.2.5 2007/06/12 01:28:41 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: gettime.c,v 1.8 2008/11/09 14:13:12 millert Exp $";
 #endif /* lint */
 
 /*
  * Get the current time via gettimeofday() for systems with
  * timespecs in struct stat or, otherwise, using time().
- * XXX - configure check for gettimeofday() - XXX
  */
 int
 gettime(ts)
diff --git a/glob.c b/glob.c
index 5319c130c306a74c1131a7f6018b697e5c5906bf..46d883b085d86fd4d893241af63c4cd903403e2b 100644 (file)
--- a/glob.c
+++ b/glob.c
@@ -1,6 +1,5 @@
-/*     $OpenBSD: glob.c,v 1.23 2004/05/18 02:05:52 jfb Exp $   */
-
 /*
+ * Copyright (c) 2008 Todd C. Miller <Todd.Miller@courtesan.com>
  * Copyright (c) 1989, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
@@ -99,6 +98,7 @@
 
 #include <compat.h>
 #include "emul/glob.h"
+#include "emul/charclass.h"
 
 #define        DOLLAR          '$'
 #define        DOT             '.'
@@ -147,6 +147,7 @@ typedef char Char;
 #define        M_ONE           META('?')
 #define        M_RNG           META('-')
 #define        M_SET           META('[')
+#define        M_CLASS         META(':')
 #define        ismeta(c)       (((c)&M_QUOTE) != 0)
 
 
@@ -154,7 +155,8 @@ static int   compare __P((const void *, const void *));
 static int      g_Ctoc __P((const Char *, char *, unsigned int));
 static int      g_lstat __P((Char *, struct stat *, glob_t *));
 static DIR     *g_opendir __P((Char *, glob_t *));
-static Char    *g_strchr __P((Char *, int));
+static Char    *g_strchr __P((const Char *, int));
+static int      g_strncmp __P((const Char *, const char *, size_t));
 static int      g_stat __P((Char *, struct stat *, glob_t *));
 static int      glob0 __P((const Char *, glob_t *));
 static int      glob1 __P((Char *, Char *, glob_t *));
@@ -172,6 +174,9 @@ static int   match __P((Char *, Char *, Char *));
 static void     qprintf __P((const char *, Char *));
 #endif
 
+extern struct passwd *sudo_getpwnam __P((const char *));
+extern struct passwd *sudo_getpwuid __P((uid_t));
+
 int
 glob(pattern, flags, errfunc, pglob)
        const char *pattern;
@@ -235,7 +240,7 @@ globexp1(pattern, pglob)
        if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
                return glob0(pattern, pglob);
 
-       while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
+       while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
                if (!globexp2(ptr, pattern, pglob, &rv))
                        return rv;
 
@@ -385,7 +390,7 @@ globtilde(pattern, patbuf, patbuf_len, pglob)
                 * first and then trying the password file
                 */
                if ((h = getenv("HOME")) == NULL) {
-                       if ((pwd = getpwuid(getuid())) == NULL)
+                       if ((pwd = sudo_getpwuid(getuid())) == NULL)
                                return pattern;
                        else
                                h = pwd->pw_dir;
@@ -394,7 +399,7 @@ globtilde(pattern, patbuf, patbuf_len, pglob)
                /*
                 * Expand a ~user
                 */
-               if ((pwd = getpwnam((char*) patbuf)) == NULL)
+               if ((pwd = sudo_getpwnam((char*) patbuf)) == NULL)
                        return pattern;
                else
                        h = pwd->pw_dir;
@@ -412,6 +417,52 @@ globtilde(pattern, patbuf, patbuf_len, pglob)
        return patbuf;
 }
 
+static int
+g_strncmp(s1, s2, n)
+       const Char *s1;
+       const char *s2;
+       size_t n;
+{
+       int rv = 0;
+
+       while (n--) {
+               rv = *(Char *)s1 - *(const unsigned char *)s2++;
+               if (rv)
+                       break;
+               if (*s1++ == '\0')
+                       break;
+       }
+       return rv;
+}
+
+static int
+g_charclass(patternp, bufnextp)
+       const Char **patternp;
+       Char **bufnextp;
+{
+       const Char *pattern = *patternp + 1;
+       Char *bufnext = *bufnextp;
+       const Char *colon;
+       struct cclass *cc;
+       size_t len;
+
+       if ((colon = g_strchr(pattern, ':')) == NULL || colon[1] != ']')
+               return 1;       /* not a character class */
+
+       len = (size_t)(colon - pattern);
+       for (cc = cclasses; cc->name != NULL; cc++) {
+               if (!g_strncmp(pattern, cc->name, len) && cc->name[len] == '\0')
+                       break;
+       }
+       if (cc->name == NULL)
+               return -1;      /* invalid character class */
+       *bufnext++ = M_CLASS;
+       *bufnext++ = (Char)(cc - &cclasses[0]);
+       *bufnextp = bufnext;
+       *patternp += len + 3;
+
+       return 0;
+}
 
 /*
  * The main glob() routine: compiles the pattern (optionally processing
@@ -441,7 +492,7 @@ glob0(pattern, pglob)
                        if (c == NOT)
                                ++qpatnext;
                        if (*qpatnext == EOS ||
-                           g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
+                           g_strchr(qpatnext+1, RBRACKET) == NULL) {
                                *bufnext++ = LBRACKET;
                                if (c == NOT)
                                        --qpatnext;
@@ -452,6 +503,20 @@ glob0(pattern, pglob)
                                *bufnext++ = M_NOT;
                        c = *qpatnext++;
                        do {
+                               if (c == LBRACKET && *qpatnext == ':') {
+                                       do {
+                                               err = g_charclass(&qpatnext,
+                                                   &bufnext);
+                                               if (err)
+                                                       break;
+                                               c = *qpatnext++;
+                                       } while (c == LBRACKET && *qpatnext == ':');
+                                       if (err == -1 &&
+                                           !(pglob->gl_flags & GLOB_NOCHECK))
+                                               return GLOB_NOMATCH;
+                                       if (c == RBRACKET)
+                                               break;
+                               }
                                *bufnext++ = CHAR(c);
                                if (*qpatnext == RANGE &&
                                    (c = qpatnext[1]) != RBRACKET) {
@@ -750,6 +815,13 @@ match(name, pat, patend)
                        if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
                                ++pat;
                        while (((c = *pat++) & M_MASK) != M_END)
+                               if ((c & M_MASK) == M_CLASS) {
+                                       int idx = *pat & M_MASK;
+                                       if (idx < NCCLASSES &&
+                                           cclasses[idx].isctype(k))
+                                               ok = 1;
+                                       ++pat;
+                               }
                                if ((*pat & M_MASK) == M_RNG) {
                                        if (c <= k && k <= pat[1])
                                                ok = 1;
@@ -831,12 +903,12 @@ g_stat(fn, sb, pglob)
 
 static Char *
 g_strchr(str, ch)
-       Char *str;
+       const Char *str;
        int ch;
 {
        do {
                if (*str == ch)
-                       return (str);
+                       return ((Char *)str);
        } while (*str++);
        return (NULL);
 }
index 1b72a66b14139cb696dae6c207c1514702a11db3..1529404555b4e53e5fed91e6c2a627de102b74ef 100644 (file)
@@ -39,7 +39,7 @@
 #include "sudo.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: goodpath.c,v 1.40.2.3 2007/06/12 01:28:41 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: goodpath.c,v 1.44 2005/02/12 22:56:06 millert Exp $";
 #endif /* lint */
 
 /*
diff --git a/gram.c b/gram.c
new file mode 100644 (file)
index 0000000..ed991a7
--- /dev/null
+++ b/gram.c
@@ -0,0 +1,1619 @@
+#ifndef lint
+/*static char yysccsid[] = "from: @(#)yaccpar  1.9 (Berkeley) 02/21/93";*/
+static char yyrcsid[]
+#if __GNUC__ >= 2
+  __attribute__ ((unused))
+#endif /* __GNUC__ >= 2 */
+  = "$OpenBSD: skeleton.c,v 1.29 2008/07/08 15:06:50 otto Exp $";
+#endif
+#include <stdlib.h>
+#include <string.h>
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define YYLEX yylex()
+#define YYEMPTY -1
+#define yyclearin (yychar=(YYEMPTY))
+#define yyerrok (yyerrflag=0)
+#define YYRECOVERING() (yyerrflag!=0)
+#define YYPREFIX "yy"
+#line 2 "gram.y"
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
+# include <alloca.h>
+#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
+#include <limits.h>
+
+#include "sudo.h"
+#include "parse.h"
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: gram.c,v 1.34 2008/11/09 14:15:36 millert Exp $";
+#endif /* lint */
+
+/*
+ * We must define SIZE_MAX for yacc's skeleton.c.
+ * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
+ * could be signed (as it is on SunOS 4.x).
+ */
+#ifndef SIZE_MAX
+# ifdef SIZE_T_MAX
+#  define SIZE_MAX     SIZE_T_MAX
+# else
+#  define SIZE_MAX     INT_MAX
+# endif /* SIZE_T_MAX */
+#endif /* SIZE_MAX */
+
+/*
+ * Globals
+ */
+extern int sudolineno;
+extern char *sudoers;
+int parse_error;
+int pedantic = FALSE;
+int verbose = FALSE;
+int errorlineno = -1;
+char *errorfile = NULL;
+
+struct defaults_list defaults;
+struct userspec_list userspecs;
+
+/*
+ * Local protoypes
+ */
+static void  add_defaults      __P((int, struct member *, struct defaults *));
+static void  add_userspec      __P((struct member *, struct privilege *));
+static struct defaults *new_default __P((char *, char *, int));
+static struct member *new_member __P((char *, int));
+       void  yyerror           __P((const char *));
+
+void
+yyerror(s)
+    const char *s;
+{
+    /* Save the line the first error occurred on. */
+    if (errorlineno == -1) {
+       errorlineno = sudolineno ? sudolineno - 1 : 0;
+       errorfile = estrdup(sudoers);
+    }
+    if (verbose && s != NULL) {
+#ifndef TRACELEXER
+       (void) fprintf(stderr, ">>> %s: %s near line %d <<<\n", sudoers, s,
+           sudolineno ? sudolineno - 1 : 0);
+#else
+       (void) fprintf(stderr, "<*> ");
+#endif
+    }
+    parse_error = TRUE;
+}
+#line 117 "gram.y"
+#ifndef YYSTYPE_DEFINED
+#define YYSTYPE_DEFINED
+typedef union {
+    struct cmndspec *cmndspec;
+    struct defaults *defaults;
+    struct member *member;
+    struct runascontainer *runas;
+    struct privilege *privilege;
+    struct sudo_command command;
+    struct cmndtag tag;
+    struct selinux_info seinfo;
+    char *string;
+    int tok;
+} YYSTYPE;
+#endif /* YYSTYPE_DEFINED */
+#line 151 "y.tab.c"
+#define COMMAND 257
+#define ALIAS 258
+#define DEFVAR 259
+#define NTWKADDR 260
+#define NETGROUP 261
+#define USERGROUP 262
+#define WORD 263
+#define DEFAULTS 264
+#define DEFAULTS_HOST 265
+#define DEFAULTS_USER 266
+#define DEFAULTS_RUNAS 267
+#define DEFAULTS_CMND 268
+#define NOPASSWD 269
+#define PASSWD 270
+#define NOEXEC 271
+#define EXEC 272
+#define SETENV 273
+#define NOSETENV 274
+#define ALL 275
+#define COMMENT 276
+#define HOSTALIAS 277
+#define CMNDALIAS 278
+#define USERALIAS 279
+#define RUNASALIAS 280
+#define ERROR 281
+#define TYPE 282
+#define ROLE 283
+#define YYERRCODE 256
+#if defined(__cplusplus) || defined(__STDC__)
+const short yylhs[] =
+#else
+short yylhs[] =
+#endif
+       {                                        -1,
+    0,    0,   25,   25,   26,   26,   26,   26,   26,   26,
+   26,   26,   26,   26,   26,   26,    4,    4,    3,    3,
+    3,    3,    3,   20,   20,   19,   10,   10,    8,    8,
+    8,    8,    8,    2,    2,    1,    6,    6,   23,   24,
+   22,   22,   22,   22,   22,   17,   17,   18,   18,   18,
+   21,   21,   21,   21,   21,   21,   21,    5,    5,    5,
+   28,   28,   31,    9,    9,   29,   29,   32,    7,    7,
+   30,   30,   33,   27,   27,   34,   13,   13,   11,   11,
+   12,   12,   12,   12,   12,   16,   16,   14,   14,   15,
+   15,   15,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yylen[] =
+#else
+short yylen[] =
+#endif
+       {                                         2,
+    0,    1,    1,    2,    1,    2,    2,    2,    2,    2,
+    2,    2,    3,    3,    3,    3,    1,    3,    1,    2,
+    3,    3,    3,    1,    3,    3,    1,    2,    1,    1,
+    1,    1,    1,    1,    3,    4,    1,    2,    3,    3,
+    0,    1,    1,    2,    2,    0,    3,    1,    3,    2,
+    0,    2,    2,    2,    2,    2,    2,    1,    1,    1,
+    1,    3,    3,    1,    3,    1,    3,    3,    1,    3,
+    1,    3,    3,    1,    3,    3,    1,    3,    1,    2,
+    1,    1,    1,    1,    1,    1,    3,    1,    2,    1,
+    1,    1,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yydefred[] =
+#else
+short yydefred[] =
+#endif
+       {                                      0,
+    0,   81,   83,   84,   85,    0,    0,    0,    0,    0,
+   82,    5,    0,    0,    0,    0,    0,    0,   77,   79,
+    0,    0,    3,    6,    0,    0,   17,    0,   29,   32,
+   31,   33,   30,    0,   27,    0,   64,    0,    0,   60,
+   59,   58,    0,   37,   69,    0,    0,    0,   61,    0,
+    0,   66,    0,    0,   74,    0,    0,   71,   80,    0,
+    0,   24,    0,    4,    0,    0,    0,   20,    0,   28,
+    0,    0,    0,    0,   38,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   78,    0,    0,   21,   22,
+   23,   18,   65,   70,    0,   62,    0,   67,    0,   75,
+    0,   72,    0,   34,    0,    0,   25,    0,    0,    0,
+    0,    0,    0,   51,    0,    0,   90,   92,   91,    0,
+   86,   88,    0,    0,   47,   35,    0,    0,    0,   44,
+   45,   89,    0,    0,   40,   39,   52,   53,   54,   55,
+   56,   57,   36,   87,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yydgoto[] =
+#else
+short yydgoto[] =
+#endif
+       {                                      18,
+  104,  105,   27,   28,   44,   45,   46,   35,   61,   37,
+   19,   20,   21,  121,  122,  123,  106,  110,   62,   63,
+  129,  114,  115,  116,   22,   23,   54,   48,   51,   57,
+   49,   52,   58,   55,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yysindex[] =
+#else
+short yysindex[] =
+#endif
+       {                                    405,
+ -266,    0,    0,    0,    0,   -9,  463,  510,  510,   -2,
+    0,    0, -243, -218, -215, -211, -225,    0,    0,    0,
+  -28,  405,    0,    0,  -36, -210,    0,    4,    0,    0,
+    0,    0,    0, -231,    0,  -33,    0,  -25,  -25,    0,
+    0,    0, -240,    0,    0,  -21,   -6,   -1,    0,    2,
+    6,    0,    7,    8,    0,    9,   11,    0,    0,  510,
+  -22,    0,   13,    0, -203, -201, -198,    0,   -9,    0,
+  463,    4,    4,    4,    0,   -2,    4,  463, -243,   -2,
+ -218,  510, -215,  510, -211,    0,   27,  463,    0,    0,
+    0,    0,    0,    0,   28,    0,   30,    0,   31,    0,
+   31,    0,  141,    0,   32, -262,    0,  -27,  -16,   36,
+   27,   18,   19,    0, -200, -202,    0,    0,    0, -217,
+    0,    0,   39,  -27,    0,    0, -177, -175,  250,    0,
+    0,    0,  -27,   39,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yyrindex[] =
+#else
+short yyrindex[] =
+#endif
+       {                                     90,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,   91,    0,    0,    1,    0,    0,  156,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,  181,    0,    0,
+  206,    0,    0,  237,    0,    0,  274,    0,    0,    0,
+    0,    0,  300,    0,    0,    0,    0,    0,    0,    0,
+    0,  326,  352,  378,    0,    0,  430,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,  -29,    0,    0,    0,
+    0,    0,    0,    0,   26,    0,   52,    0,   78,    0,
+  104,    0,    0,    0,  130,  442,    0,    0,   51,    0,
+  -29,    0,    0,    0,  461,  485,    0,    0,    0,    0,
+    0,    0,   53,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,   54,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yygindex[] =
+#else
+short yygindex[] =
+#endif
+       {                                      0,
+  -18,    0,   29,   15,   56,  -73,   16,   63,   -5,   34,
+   40,   84,    5,  -31,  -17,  -15,    0,    0,   24,    0,
+    0,    0,  -10,   -8,    0,   92,    0,    0,    0,    0,
+   37,   38,   33,   41,
+};
+#define YYTABLESIZE 785
+#if defined(__cplusplus) || defined(__STDC__)
+const short yytable[] =
+#else
+short yytable[] =
+#endif
+       {                                      26,
+   19,   36,   94,   46,   34,  120,   66,   26,   67,   24,
+   71,   26,   38,   39,   47,   60,   40,   41,   60,  112,
+  113,   71,   76,   26,   65,   63,   29,   60,   30,   31,
+   43,   32,    2,   19,   42,    3,    4,    5,   87,   50,
+  117,  124,   53,   33,   19,  118,   56,   69,   68,   11,
+   72,   68,   73,   74,   78,  143,   79,  119,   63,   89,
+   77,   90,   80,   81,   91,   83,  103,   82,   85,   84,
+   88,   71,   95,   76,   60,  111,  125,   76,  127,  128,
+  113,  112,  133,   63,   68,  135,   99,  136,  101,    1,
+    2,   48,  126,   50,   49,   97,   70,   92,   75,   86,
+   59,  144,  132,   73,   93,  131,  130,  109,  134,   68,
+   76,  107,    0,   64,    0,   96,    0,  102,   98,    0,
+    0,    0,    0,  100,    0,    0,    0,    0,    0,   26,
+    0,    0,    0,    0,    0,   76,   73,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   12,    0,    0,    0,    0,
+    0,   73,   26,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,   17,    0,    0,    0,    0,    0,    0,
+    9,    0,    0,    0,    0,    0,    0,   26,   12,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,  108,    0,
+    0,    0,    0,    0,    0,   10,    0,    0,    0,    0,
+    0,    0,    0,    9,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   25,    0,   46,   46,   29,
+  117,   30,   31,   25,   32,  118,    8,   25,   10,   46,
+   46,   46,   46,   46,   46,   46,   33,  119,    0,   25,
+    0,    0,   46,   46,   40,   41,   19,    0,   19,    0,
+    0,   19,   19,   19,   19,   19,   19,   19,   19,    8,
+    0,    0,   42,   11,    0,   19,   19,   19,   19,   19,
+   19,   63,   43,   63,    0,    0,   63,   63,   63,   63,
+   63,   63,   63,   63,    0,    0,    0,    0,    0,    7,
+   63,   63,   63,   63,   63,   63,   11,   68,    0,   68,
+    0,    0,   68,   68,   68,   68,   68,   68,   68,   68,
+    0,    0,    0,    0,    0,   15,   68,   68,   68,   68,
+   68,   68,    7,   76,    0,   76,    0,    0,   76,   76,
+   76,   76,   76,   76,   76,   76,    0,    0,    0,    0,
+    0,   13,   76,   76,   76,   76,   76,   76,   15,   73,
+    0,   73,    0,    0,   73,   73,   73,   73,   73,   73,
+   73,   73,    0,    0,    0,    0,    0,   14,   73,   73,
+   73,   73,   73,   73,   13,   26,    0,   26,    0,    0,
+   26,   26,   26,   26,   26,   26,   26,   26,    2,    0,
+    0,    3,    4,    5,   26,   26,   26,   26,   26,   26,
+   14,   12,    0,   12,    0,   11,   12,   12,   12,   12,
+   12,   12,   12,   12,    0,    0,    0,    0,    0,   16,
+   12,   12,   12,   12,   12,   12,    9,   17,    9,    0,
+    0,    9,    9,    9,    9,    9,    9,    9,    9,    0,
+    0,    0,    0,    0,    0,    9,    9,    9,    9,    9,
+    9,   10,   16,   10,    0,    0,   10,   10,   10,   10,
+   10,   10,   10,   10,   41,    0,    0,    0,    0,    0,
+   10,   10,   10,   10,   10,   10,    0,    0,    0,    0,
+    0,    0,    8,   42,    8,   34,    0,    8,    8,    8,
+    8,    8,    8,    8,    8,    0,   40,   41,    0,    0,
+    0,    8,    8,    8,    8,    8,    8,   43,  137,  138,
+  139,  140,  141,  142,   42,    0,    0,    0,    0,   11,
+    0,   11,    0,    0,   11,   11,   11,   11,   11,   11,
+   11,   11,   17,    0,    0,    0,    0,    0,   11,   11,
+   11,   11,   11,   11,    0,    7,    0,    7,    0,    0,
+    7,    7,    7,    7,    7,    7,    7,    7,    0,    0,
+    0,    0,    0,    0,    7,    7,    7,    7,    7,    7,
+    0,   15,    0,   15,    0,    0,   15,   15,   15,   15,
+   15,   15,   15,   15,    0,    0,    0,    0,    0,    0,
+   15,   15,   15,   15,   15,   15,    0,   13,    0,   13,
+    0,    0,   13,   13,   13,   13,   13,   13,   13,   13,
+    0,    0,    0,    0,    0,    0,   13,   13,   13,   13,
+   13,   13,    0,   14,    0,   14,    0,    0,   14,   14,
+   14,   14,   14,   14,   14,   14,    0,    0,    0,    0,
+    0,    0,   14,   14,   14,   14,   14,   14,    0,    0,
+    1,    0,    2,    0,    0,    3,    4,    5,    6,    7,
+    8,    9,   10,    0,    0,    0,    0,    0,    0,   11,
+   12,   13,   14,   15,   16,   16,    0,   16,    0,    0,
+   16,   16,   16,   16,   16,   16,   16,   16,   41,   41,
+    0,    0,    0,    0,   16,   16,   16,   16,   16,   16,
+   41,   41,   41,   41,   41,   41,   41,   42,   42,    0,
+   29,    0,   30,   31,    0,   32,    0,    0,    0,   42,
+   42,   42,   42,   42,   42,   42,    0,   33,    0,    0,
+    0,   43,   43,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,   43,   43,   43,   43,   43,   43,   43,
+    0,    0,    0,    0,    0,    0,    0,    2,    0,    0,
+    3,    4,    5,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,   11,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yycheck[] =
+#else
+short yycheck[] =
+#endif
+       {                                      33,
+    0,    7,   76,   33,   33,   33,   43,   33,   45,  276,
+   44,   33,    8,    9,  258,   44,  257,  258,   44,  282,
+  283,   44,   44,   33,   61,    0,  258,   44,  260,  261,
+   33,  263,  258,   33,  275,  261,  262,  263,   61,  258,
+  258,   58,  258,  275,   44,  263,  258,   44,  259,  275,
+   36,    0,   38,   39,   61,  129,   58,  275,   33,  263,
+   46,  263,   61,   58,  263,   58,   40,   61,   58,   61,
+   58,   44,   78,   44,   44,   44,   41,    0,   61,   61,
+  283,  282,   44,   58,   33,  263,   82,  263,   84,    0,
+    0,   41,  111,   41,   41,   80,   34,   69,   43,   60,
+   17,  133,  120,    0,   71,  116,  115,  103,  124,   58,
+   33,   88,   -1,   22,   -1,   79,   -1,   85,   81,   -1,
+   -1,   -1,   -1,   83,   -1,   -1,   -1,   -1,   -1,    0,
+   -1,   -1,   -1,   -1,   -1,   58,   33,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,
+   -1,   58,   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   33,   -1,   -1,   -1,   -1,   -1,   -1,
+    0,   -1,   -1,   -1,   -1,   -1,   -1,   58,   33,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   58,   -1,
+   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   33,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  259,   -1,  257,  258,  258,
+  258,  260,  261,  259,  263,  263,    0,  259,   33,  269,
+  270,  271,  272,  273,  274,  275,  275,  275,   -1,  259,
+   -1,   -1,  282,  283,  257,  258,  256,   -1,  258,   -1,
+   -1,  261,  262,  263,  264,  265,  266,  267,  268,   33,
+   -1,   -1,  275,    0,   -1,  275,  276,  277,  278,  279,
+  280,  256,   33,  258,   -1,   -1,  261,  262,  263,  264,
+  265,  266,  267,  268,   -1,   -1,   -1,   -1,   -1,    0,
+  275,  276,  277,  278,  279,  280,   33,  256,   -1,  258,
+   -1,   -1,  261,  262,  263,  264,  265,  266,  267,  268,
+   -1,   -1,   -1,   -1,   -1,    0,  275,  276,  277,  278,
+  279,  280,   33,  256,   -1,  258,   -1,   -1,  261,  262,
+  263,  264,  265,  266,  267,  268,   -1,   -1,   -1,   -1,
+   -1,    0,  275,  276,  277,  278,  279,  280,   33,  256,
+   -1,  258,   -1,   -1,  261,  262,  263,  264,  265,  266,
+  267,  268,   -1,   -1,   -1,   -1,   -1,    0,  275,  276,
+  277,  278,  279,  280,   33,  256,   -1,  258,   -1,   -1,
+  261,  262,  263,  264,  265,  266,  267,  268,  258,   -1,
+   -1,  261,  262,  263,  275,  276,  277,  278,  279,  280,
+   33,  256,   -1,  258,   -1,  275,  261,  262,  263,  264,
+  265,  266,  267,  268,   -1,   -1,   -1,   -1,   -1,    0,
+  275,  276,  277,  278,  279,  280,  256,   33,  258,   -1,
+   -1,  261,  262,  263,  264,  265,  266,  267,  268,   -1,
+   -1,   -1,   -1,   -1,   -1,  275,  276,  277,  278,  279,
+  280,  256,   33,  258,   -1,   -1,  261,  262,  263,  264,
+  265,  266,  267,  268,   33,   -1,   -1,   -1,   -1,   -1,
+  275,  276,  277,  278,  279,  280,   -1,   -1,   -1,   -1,
+   -1,   -1,  256,   33,  258,   33,   -1,  261,  262,  263,
+  264,  265,  266,  267,  268,   -1,  257,  258,   -1,   -1,
+   -1,  275,  276,  277,  278,  279,  280,   33,  269,  270,
+  271,  272,  273,  274,  275,   -1,   -1,   -1,   -1,  256,
+   -1,  258,   -1,   -1,  261,  262,  263,  264,  265,  266,
+  267,  268,   33,   -1,   -1,   -1,   -1,   -1,  275,  276,
+  277,  278,  279,  280,   -1,  256,   -1,  258,   -1,   -1,
+  261,  262,  263,  264,  265,  266,  267,  268,   -1,   -1,
+   -1,   -1,   -1,   -1,  275,  276,  277,  278,  279,  280,
+   -1,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
+  265,  266,  267,  268,   -1,   -1,   -1,   -1,   -1,   -1,
+  275,  276,  277,  278,  279,  280,   -1,  256,   -1,  258,
+   -1,   -1,  261,  262,  263,  264,  265,  266,  267,  268,
+   -1,   -1,   -1,   -1,   -1,   -1,  275,  276,  277,  278,
+  279,  280,   -1,  256,   -1,  258,   -1,   -1,  261,  262,
+  263,  264,  265,  266,  267,  268,   -1,   -1,   -1,   -1,
+   -1,   -1,  275,  276,  277,  278,  279,  280,   -1,   -1,
+  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,  265,
+  266,  267,  268,   -1,   -1,   -1,   -1,   -1,   -1,  275,
+  276,  277,  278,  279,  280,  256,   -1,  258,   -1,   -1,
+  261,  262,  263,  264,  265,  266,  267,  268,  257,  258,
+   -1,   -1,   -1,   -1,  275,  276,  277,  278,  279,  280,
+  269,  270,  271,  272,  273,  274,  275,  257,  258,   -1,
+  258,   -1,  260,  261,   -1,  263,   -1,   -1,   -1,  269,
+  270,  271,  272,  273,  274,  275,   -1,  275,   -1,   -1,
+   -1,  257,  258,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,  269,  270,  271,  272,  273,  274,  275,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,  258,   -1,   -1,
+  261,  262,  263,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,  275,
+};
+#define YYFINAL 18
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 283
+#if YYDEBUG
+#if defined(__cplusplus) || defined(__STDC__)
+const char * const yyname[] =
+#else
+char *yyname[] =
+#endif
+       {
+"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+"'!'",0,0,0,0,0,0,"'('","')'",0,"'+'","','","'-'",0,0,0,0,0,0,0,0,0,0,0,0,"':'",
+0,0,"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+"COMMAND","ALIAS","DEFVAR","NTWKADDR","NETGROUP","USERGROUP","WORD","DEFAULTS",
+"DEFAULTS_HOST","DEFAULTS_USER","DEFAULTS_RUNAS","DEFAULTS_CMND","NOPASSWD",
+"PASSWD","NOEXEC","EXEC","SETENV","NOSETENV","ALL","COMMENT","HOSTALIAS",
+"CMNDALIAS","USERALIAS","RUNASALIAS","ERROR","TYPE","ROLE",
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const char * const yyrule[] =
+#else
+char *yyrule[] =
+#endif
+       {"$accept : file",
+"file :",
+"file : line",
+"line : entry",
+"line : line entry",
+"entry : COMMENT",
+"entry : error COMMENT",
+"entry : userlist privileges",
+"entry : USERALIAS useraliases",
+"entry : HOSTALIAS hostaliases",
+"entry : CMNDALIAS cmndaliases",
+"entry : RUNASALIAS runasaliases",
+"entry : DEFAULTS defaults_list",
+"entry : DEFAULTS_USER userlist defaults_list",
+"entry : DEFAULTS_RUNAS userlist defaults_list",
+"entry : DEFAULTS_HOST hostlist defaults_list",
+"entry : DEFAULTS_CMND cmndlist defaults_list",
+"defaults_list : defaults_entry",
+"defaults_list : defaults_list ',' defaults_entry",
+"defaults_entry : DEFVAR",
+"defaults_entry : '!' DEFVAR",
+"defaults_entry : DEFVAR '=' WORD",
+"defaults_entry : DEFVAR '+' WORD",
+"defaults_entry : DEFVAR '-' WORD",
+"privileges : privilege",
+"privileges : privileges ':' privilege",
+"privilege : hostlist '=' cmndspeclist",
+"ophost : host",
+"ophost : '!' host",
+"host : ALIAS",
+"host : ALL",
+"host : NETGROUP",
+"host : NTWKADDR",
+"host : WORD",
+"cmndspeclist : cmndspec",
+"cmndspeclist : cmndspeclist ',' cmndspec",
+"cmndspec : runasspec selinux cmndtag opcmnd",
+"opcmnd : cmnd",
+"opcmnd : '!' cmnd",
+"rolespec : ROLE '=' WORD",
+"typespec : TYPE '=' WORD",
+"selinux :",
+"selinux : rolespec",
+"selinux : typespec",
+"selinux : rolespec typespec",
+"selinux : typespec rolespec",
+"runasspec :",
+"runasspec : '(' runaslist ')'",
+"runaslist : userlist",
+"runaslist : userlist ':' grouplist",
+"runaslist : ':' grouplist",
+"cmndtag :",
+"cmndtag : cmndtag NOPASSWD",
+"cmndtag : cmndtag PASSWD",
+"cmndtag : cmndtag NOEXEC",
+"cmndtag : cmndtag EXEC",
+"cmndtag : cmndtag SETENV",
+"cmndtag : cmndtag NOSETENV",
+"cmnd : ALL",
+"cmnd : ALIAS",
+"cmnd : COMMAND",
+"hostaliases : hostalias",
+"hostaliases : hostaliases ':' hostalias",
+"hostalias : ALIAS '=' hostlist",
+"hostlist : ophost",
+"hostlist : hostlist ',' ophost",
+"cmndaliases : cmndalias",
+"cmndaliases : cmndaliases ':' cmndalias",
+"cmndalias : ALIAS '=' cmndlist",
+"cmndlist : opcmnd",
+"cmndlist : cmndlist ',' opcmnd",
+"runasaliases : runasalias",
+"runasaliases : runasaliases ':' runasalias",
+"runasalias : ALIAS '=' userlist",
+"useraliases : useralias",
+"useraliases : useraliases ':' useralias",
+"useralias : ALIAS '=' userlist",
+"userlist : opuser",
+"userlist : userlist ',' opuser",
+"opuser : user",
+"opuser : '!' user",
+"user : ALIAS",
+"user : ALL",
+"user : NETGROUP",
+"user : USERGROUP",
+"user : WORD",
+"grouplist : opgroup",
+"grouplist : grouplist ',' opgroup",
+"opgroup : group",
+"opgroup : '!' group",
+"group : ALIAS",
+"group : ALL",
+"group : WORD",
+};
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 10000
+#define YYMAXDEPTH 10000
+#endif
+#endif
+#define YYINITSTACKSIZE 200
+/* LINTUSED */
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+short *yyss;
+short *yysslim;
+YYSTYPE *yyvs;
+int yystacksize;
+#line 590 "gram.y"
+static struct defaults *
+new_default(var, val, op)
+    char *var;
+    char *val;
+    int op;
+{
+    struct defaults *d;
+
+    d = emalloc(sizeof(struct defaults));
+    d->var = var;
+    d->val = val;
+    tq_init(&d->binding);
+    d->type = 0;
+    d->op = op;
+    d->prev = d;
+    d->next = NULL;
+
+    return(d);
+}
+
+static struct member *
+new_member(name, type)
+    char *name;
+    int type;
+{
+    struct member *m;
+
+    m = emalloc(sizeof(struct member));
+    m->name = name;
+    m->type = type;
+    m->prev = m;
+    m->next = NULL;
+
+    return(m);
+}
+
+/*
+ * Add a list of defaults structures to the defaults list.
+ * The binding, if non-NULL, specifies a list of hosts, users, or
+ * runas users the entries apply to (specified by the type).
+ */
+static void
+add_defaults(type, bmem, defs)
+    int type;
+    struct member *bmem;
+    struct defaults *defs;
+{
+    struct defaults *d;
+    struct member_list binding;
+
+    /*
+     * We can only call list2tq once on bmem as it will zero
+     * out the prev pointer when it consumes bmem.
+     */
+    list2tq(&binding, bmem);
+
+    /*
+     * Set type and binding (who it applies to) for new entries.
+     */
+    for (d = defs; d != NULL; d = d->next) {
+       d->type = type;
+       d->binding = binding;
+    }
+    tq_append(&defaults, defs);
+}
+
+/*
+ * Allocate a new struct userspec, populate it, and insert it at the
+ * and of the userspecs list.
+ */
+static void
+add_userspec(members, privs)
+    struct member *members;
+    struct privilege *privs;
+{
+    struct userspec *u;
+
+    u = emalloc(sizeof(*u));
+    list2tq(&u->users, members);
+    list2tq(&u->privileges, privs);
+    u->prev = u;
+    u->next = NULL;
+    tq_append(&userspecs, u);
+}
+
+/*
+ * Free up space used by data structures from a previous parser run and sets
+ * the current sudoers file to path.
+ */
+void
+init_parser(path, quiet)
+    char *path;
+    int quiet;
+{
+    struct defaults *d;
+    struct member *m, *binding;
+    struct userspec *us;
+    struct privilege *priv;
+    struct cmndspec *cs;
+    struct sudo_command *c;
+
+    while ((us = tq_pop(&userspecs)) != NULL) {
+       while ((m = tq_pop(&us->users)) != NULL) {
+           efree(m->name);
+           efree(m);
+       }
+       while ((priv = tq_pop(&us->privileges)) != NULL) {
+           struct member *runasuser = NULL, *runasgroup = NULL;
+#ifdef HAVE_SELINUX
+           char *role = NULL, *type = NULL;
+#endif /* HAVE_SELINUX */
+
+           while ((m = tq_pop(&priv->hostlist)) != NULL) {
+               efree(m->name);
+               efree(m);
+           }
+           while ((cs = tq_pop(&priv->cmndlist)) != NULL) {
+#ifdef HAVE_SELINUX
+               /* Only free the first instance of a role/type. */
+               if (cs->role != role) {
+                   role = cs->role;
+                   efree(cs->role);
+               }
+               if (cs->type != type) {
+                   type = cs->type;
+                   efree(cs->type);
+               }
+#endif /* HAVE_SELINUX */
+               if (tq_last(&cs->runasuserlist) != runasuser) {
+                   runasuser = tq_last(&cs->runasuserlist);
+                   while ((m = tq_pop(&cs->runasuserlist)) != NULL) {
+                       efree(m->name);
+                       efree(m);
+                   }
+               }
+               if (tq_last(&cs->runasgrouplist) != runasgroup) {
+                   runasgroup = tq_last(&cs->runasgrouplist);
+                   while ((m = tq_pop(&cs->runasgrouplist)) != NULL) {
+                       efree(m->name);
+                       efree(m);
+                   }
+               }
+               if (cs->cmnd->type == COMMAND) {
+                       c = (struct sudo_command *) cs->cmnd->name;
+                       efree(c->cmnd);
+                       efree(c->args);
+               }
+               efree(cs->cmnd->name);
+               efree(cs->cmnd);
+               efree(cs);
+           }
+           efree(priv);
+       }
+       efree(us);
+    }
+    tq_init(&userspecs);
+
+    binding = NULL;
+    while ((d = tq_pop(&defaults)) != NULL) {
+       if (tq_last(&d->binding) != binding) {
+           binding = tq_last(&d->binding);
+           while ((m = tq_pop(&d->binding)) != NULL) {
+               if (m->type == COMMAND) {
+                       c = (struct sudo_command *) m->name;
+                       efree(c->cmnd);
+                       efree(c->args);
+               }
+               efree(m->name);
+               efree(m);
+           }
+       }
+       efree(d->var);
+       efree(d->val);
+       efree(d);
+    }
+    tq_init(&defaults);
+
+    init_aliases();
+
+    efree(sudoers);
+    sudoers = path ? estrdup(path) : NULL;
+
+    parse_error = FALSE;
+    errorlineno = -1;
+    sudolineno = 1;
+    verbose = !quiet;
+}
+#line 758 "y.tab.c"
+/* allocate initial stack or double stack size, up to YYMAXDEPTH */
+#if defined(__cplusplus) || defined(__STDC__)
+static int yygrowstack(void)
+#else
+static int yygrowstack()
+#endif
+{
+    int newsize, i;
+    short *newss;
+    YYSTYPE *newvs;
+
+    if ((newsize = yystacksize) == 0)
+        newsize = YYINITSTACKSIZE;
+    else if (newsize >= YYMAXDEPTH)
+        return -1;
+    else if ((newsize *= 2) > YYMAXDEPTH)
+        newsize = YYMAXDEPTH;
+    i = yyssp - yyss;
+#ifdef SIZE_MAX
+#define YY_SIZE_MAX SIZE_MAX
+#else
+#define YY_SIZE_MAX 0x7fffffff
+#endif
+    if (newsize && YY_SIZE_MAX / newsize < sizeof *newss)
+        goto bail;
+    newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) :
+      (short *)malloc(newsize * sizeof *newss); /* overflow check above */
+    if (newss == NULL)
+        goto bail;
+    yyss = newss;
+    yyssp = newss + i;
+    if (newsize && YY_SIZE_MAX / newsize < sizeof *newvs)
+        goto bail;
+    newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) :
+      (YYSTYPE *)malloc(newsize * sizeof *newvs); /* overflow check above */
+    if (newvs == NULL)
+        goto bail;
+    yyvs = newvs;
+    yyvsp = newvs + i;
+    yystacksize = newsize;
+    yysslim = yyss + newsize - 1;
+    return 0;
+bail:
+    if (yyss)
+            free(yyss);
+    if (yyvs)
+            free(yyvs);
+    yyss = yyssp = NULL;
+    yyvs = yyvsp = NULL;
+    yystacksize = 0;
+    return -1;
+}
+
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+#if defined(__cplusplus) || defined(__STDC__)
+yyparse(void)
+#else
+yyparse()
+#endif
+{
+    int yym, yyn, yystate;
+#if YYDEBUG
+#if defined(__cplusplus) || defined(__STDC__)
+    const char *yys;
+#else /* !(defined(__cplusplus) || defined(__STDC__)) */
+    char *yys;
+#endif /* !(defined(__cplusplus) || defined(__STDC__)) */
+
+    if ((yys = getenv("YYDEBUG")))
+    {
+        yyn = *yys;
+        if (yyn >= '0' && yyn <= '9')
+            yydebug = yyn - '0';
+    }
+#endif /* YYDEBUG */
+
+    yynerrs = 0;
+    yyerrflag = 0;
+    yychar = (-1);
+
+    if (yyss == NULL && yygrowstack()) goto yyoverflow;
+    yyssp = yyss;
+    yyvsp = yyvs;
+    *yyssp = yystate = 0;
+
+yyloop:
+    if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
+    if (yychar < 0)
+    {
+        if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, reading %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+    }
+    if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: state %d, shifting to state %d\n",
+                    YYPREFIX, yystate, yytable[yyn]);
+#endif
+        if (yyssp >= yysslim && yygrowstack())
+        {
+            goto yyoverflow;
+        }
+        *++yyssp = yystate = yytable[yyn];
+        *++yyvsp = yylval;
+        yychar = (-1);
+        if (yyerrflag > 0)  --yyerrflag;
+        goto yyloop;
+    }
+    if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+        yyn = yytable[yyn];
+        goto yyreduce;
+    }
+    if (yyerrflag) goto yyinrecovery;
+#if defined(lint) || defined(__GNUC__)
+    goto yynewerror;
+#endif
+yynewerror:
+    yyerror("syntax error");
+#if defined(lint) || defined(__GNUC__)
+    goto yyerrlab;
+#endif
+yyerrlab:
+    ++yynerrs;
+yyinrecovery:
+    if (yyerrflag < 3)
+    {
+        yyerrflag = 3;
+        for (;;)
+        {
+            if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
+                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
+#endif
+                if (yyssp >= yysslim && yygrowstack())
+                {
+                    goto yyoverflow;
+                }
+                *++yyssp = yystate = yytable[yyn];
+                *++yyvsp = yylval;
+                goto yyloop;
+            }
+            else
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: error recovery discarding state %d\n",
+                            YYPREFIX, *yyssp);
+#endif
+                if (yyssp <= yyss) goto yyabort;
+                --yyssp;
+                --yyvsp;
+            }
+        }
+    }
+    else
+    {
+        if (yychar == 0) goto yyabort;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+        yychar = (-1);
+        goto yyloop;
+    }
+yyreduce:
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+                YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+    yym = yylen[yyn];
+    if (yym)
+        yyval = yyvsp[1-yym];
+    else
+        memset(&yyval, 0, sizeof yyval);
+    switch (yyn)
+    {
+case 1:
+#line 188 "gram.y"
+{ ; }
+break;
+case 5:
+#line 196 "gram.y"
+{
+                           ;
+                       }
+break;
+case 6:
+#line 199 "gram.y"
+{
+                           yyerrok;
+                       }
+break;
+case 7:
+#line 202 "gram.y"
+{
+                           add_userspec(yyvsp[-1].member, yyvsp[0].privilege);
+                       }
+break;
+case 8:
+#line 205 "gram.y"
+{
+                           ;
+                       }
+break;
+case 9:
+#line 208 "gram.y"
+{
+                           ;
+                       }
+break;
+case 10:
+#line 211 "gram.y"
+{
+                           ;
+                       }
+break;
+case 11:
+#line 214 "gram.y"
+{
+                           ;
+                       }
+break;
+case 12:
+#line 217 "gram.y"
+{
+                           add_defaults(DEFAULTS, NULL, yyvsp[0].defaults);
+                       }
+break;
+case 13:
+#line 220 "gram.y"
+{
+                           add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults);
+                       }
+break;
+case 14:
+#line 223 "gram.y"
+{
+                           add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults);
+                       }
+break;
+case 15:
+#line 226 "gram.y"
+{
+                           add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults);
+                       }
+break;
+case 16:
+#line 229 "gram.y"
+{
+                           add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults);
+                       }
+break;
+case 18:
+#line 235 "gram.y"
+{
+                           list_append(yyvsp[-2].defaults, yyvsp[0].defaults);
+                           yyval.defaults = yyvsp[-2].defaults;
+                       }
+break;
+case 19:
+#line 241 "gram.y"
+{
+                           yyval.defaults = new_default(yyvsp[0].string, NULL, TRUE);
+                       }
+break;
+case 20:
+#line 244 "gram.y"
+{
+                           yyval.defaults = new_default(yyvsp[0].string, NULL, FALSE);
+                       }
+break;
+case 21:
+#line 247 "gram.y"
+{
+                           yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, TRUE);
+                       }
+break;
+case 22:
+#line 250 "gram.y"
+{
+                           yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+');
+                       }
+break;
+case 23:
+#line 253 "gram.y"
+{
+                           yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-');
+                       }
+break;
+case 25:
+#line 259 "gram.y"
+{
+                           list_append(yyvsp[-2].privilege, yyvsp[0].privilege);
+                           yyval.privilege = yyvsp[-2].privilege;
+                       }
+break;
+case 26:
+#line 265 "gram.y"
+{
+                           struct privilege *p = emalloc(sizeof(*p));
+                           list2tq(&p->hostlist, yyvsp[-2].member);
+                           list2tq(&p->cmndlist, yyvsp[0].cmndspec);
+                           p->prev = p;
+                           p->next = NULL;
+                           yyval.privilege = p;
+                       }
+break;
+case 27:
+#line 275 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = FALSE;
+                       }
+break;
+case 28:
+#line 279 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = TRUE;
+                       }
+break;
+case 29:
+#line 285 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, ALIAS);
+                       }
+break;
+case 30:
+#line 288 "gram.y"
+{
+                           yyval.member = new_member(NULL, ALL);
+                       }
+break;
+case 31:
+#line 291 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, NETGROUP);
+                       }
+break;
+case 32:
+#line 294 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, NTWKADDR);
+                       }
+break;
+case 33:
+#line 297 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, WORD);
+                       }
+break;
+case 35:
+#line 303 "gram.y"
+{
+                           list_append(yyvsp[-2].cmndspec, yyvsp[0].cmndspec);
+#ifdef HAVE_SELINUX
+                           /* propagate role and type */
+                           if (yyvsp[0].cmndspec->role == NULL)
+                               yyvsp[0].cmndspec->role = yyvsp[0].cmndspec->prev->role;
+                           if (yyvsp[0].cmndspec->type == NULL)
+                               yyvsp[0].cmndspec->type = yyvsp[0].cmndspec->prev->type;
+#endif /* HAVE_SELINUX */
+                           /* propagate tags and runas list */
+                           if (yyvsp[0].cmndspec->tags.nopasswd == UNSPEC)
+                               yyvsp[0].cmndspec->tags.nopasswd = yyvsp[0].cmndspec->prev->tags.nopasswd;
+                           if (yyvsp[0].cmndspec->tags.noexec == UNSPEC)
+                               yyvsp[0].cmndspec->tags.noexec = yyvsp[0].cmndspec->prev->tags.noexec;
+                           if (yyvsp[0].cmndspec->tags.setenv == UNSPEC &&
+                               yyvsp[0].cmndspec->prev->tags.setenv != IMPLIED)
+                               yyvsp[0].cmndspec->tags.setenv = yyvsp[0].cmndspec->prev->tags.setenv;
+                           if ((tq_empty(&yyvsp[0].cmndspec->runasuserlist) &&
+                                tq_empty(&yyvsp[0].cmndspec->runasgrouplist)) &&
+                               (!tq_empty(&yyvsp[0].cmndspec->prev->runasuserlist) ||
+                                !tq_empty(&yyvsp[0].cmndspec->prev->runasgrouplist))) {
+                               yyvsp[0].cmndspec->runasuserlist = yyvsp[0].cmndspec->prev->runasuserlist;
+                               yyvsp[0].cmndspec->runasgrouplist = yyvsp[0].cmndspec->prev->runasgrouplist;
+                           }
+                           yyval.cmndspec = yyvsp[-2].cmndspec;
+                       }
+break;
+case 36:
+#line 331 "gram.y"
+{
+                           struct cmndspec *cs = emalloc(sizeof(*cs));
+                           if (yyvsp[-3].runas != NULL) {
+                               list2tq(&cs->runasuserlist, yyvsp[-3].runas->runasusers);
+                               list2tq(&cs->runasgrouplist, yyvsp[-3].runas->runasgroups);
+                               efree(yyvsp[-3].runas);
+                           } else {
+                               tq_init(&cs->runasuserlist);
+                               tq_init(&cs->runasgrouplist);
+                           }
+#ifdef HAVE_SELINUX
+                           cs->role = yyvsp[-2].seinfo.role;
+                           cs->type = yyvsp[-2].seinfo.type;
+#endif
+                           cs->tags = yyvsp[-1].tag;
+                           cs->cmnd = yyvsp[0].member;
+                           cs->prev = cs;
+                           cs->next = NULL;
+                           /* sudo "ALL" implies the SETENV tag */
+                           if (cs->cmnd->type == ALL && !cs->cmnd->negated &&
+                               cs->tags.setenv == UNSPEC)
+                               cs->tags.setenv = IMPLIED;
+                           yyval.cmndspec = cs;
+                       }
+break;
+case 37:
+#line 357 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = FALSE;
+                       }
+break;
+case 38:
+#line 361 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = TRUE;
+                       }
+break;
+case 39:
+#line 367 "gram.y"
+{
+                           yyval.string = yyvsp[0].string;
+                       }
+break;
+case 40:
+#line 372 "gram.y"
+{
+                           yyval.string = yyvsp[0].string;
+                       }
+break;
+case 41:
+#line 377 "gram.y"
+{
+                           yyval.seinfo.role = NULL;
+                           yyval.seinfo.type = NULL;
+                       }
+break;
+case 42:
+#line 381 "gram.y"
+{
+                           yyval.seinfo.role = yyvsp[0].string;
+                           yyval.seinfo.type = NULL;
+                       }
+break;
+case 43:
+#line 385 "gram.y"
+{
+                           yyval.seinfo.type = yyvsp[0].string;
+                           yyval.seinfo.role = NULL;
+                       }
+break;
+case 44:
+#line 389 "gram.y"
+{
+                           yyval.seinfo.role = yyvsp[-1].string;
+                           yyval.seinfo.type = yyvsp[0].string;
+                       }
+break;
+case 45:
+#line 393 "gram.y"
+{
+                           yyval.seinfo.type = yyvsp[-1].string;
+                           yyval.seinfo.role = yyvsp[0].string;
+                       }
+break;
+case 46:
+#line 399 "gram.y"
+{
+                           yyval.runas = NULL;
+                       }
+break;
+case 47:
+#line 402 "gram.y"
+{
+                           yyval.runas = yyvsp[-1].runas;
+                       }
+break;
+case 48:
+#line 407 "gram.y"
+{
+                           yyval.runas = emalloc(sizeof(struct runascontainer));
+                           yyval.runas->runasusers = yyvsp[0].member;
+                           yyval.runas->runasgroups = NULL;
+                       }
+break;
+case 49:
+#line 412 "gram.y"
+{
+                           yyval.runas = emalloc(sizeof(struct runascontainer));
+                           yyval.runas->runasusers = yyvsp[-2].member;
+                           yyval.runas->runasgroups = yyvsp[0].member;
+                       }
+break;
+case 50:
+#line 417 "gram.y"
+{
+                           yyval.runas = emalloc(sizeof(struct runascontainer));
+                           yyval.runas->runasusers = NULL;
+                           yyval.runas->runasgroups = yyvsp[0].member;
+                       }
+break;
+case 51:
+#line 424 "gram.y"
+{
+                           yyval.tag.nopasswd = yyval.tag.noexec = yyval.tag.setenv = UNSPEC;
+                       }
+break;
+case 52:
+#line 427 "gram.y"
+{
+                           yyval.tag.nopasswd = TRUE;
+                       }
+break;
+case 53:
+#line 430 "gram.y"
+{
+                           yyval.tag.nopasswd = FALSE;
+                       }
+break;
+case 54:
+#line 433 "gram.y"
+{
+                           yyval.tag.noexec = TRUE;
+                       }
+break;
+case 55:
+#line 436 "gram.y"
+{
+                           yyval.tag.noexec = FALSE;
+                       }
+break;
+case 56:
+#line 439 "gram.y"
+{
+                           yyval.tag.setenv = TRUE;
+                       }
+break;
+case 57:
+#line 442 "gram.y"
+{
+                           yyval.tag.setenv = FALSE;
+                       }
+break;
+case 58:
+#line 447 "gram.y"
+{
+                           yyval.member = new_member(NULL, ALL);
+                       }
+break;
+case 59:
+#line 450 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, ALIAS);
+                       }
+break;
+case 60:
+#line 453 "gram.y"
+{
+                           struct sudo_command *c = emalloc(sizeof(*c));
+                           c->cmnd = yyvsp[0].command.cmnd;
+                           c->args = yyvsp[0].command.args;
+                           yyval.member = new_member((char *)c, COMMAND);
+                       }
+break;
+case 63:
+#line 465 "gram.y"
+{
+                           char *s;
+                           if ((s = alias_add(yyvsp[-2].string, HOSTALIAS, yyvsp[0].member)) != NULL) {
+                               yyerror(s);
+                               YYERROR;
+                           }
+                       }
+break;
+case 65:
+#line 475 "gram.y"
+{
+                           list_append(yyvsp[-2].member, yyvsp[0].member);
+                           yyval.member = yyvsp[-2].member;
+                       }
+break;
+case 68:
+#line 485 "gram.y"
+{
+                           char *s;
+                           if ((s = alias_add(yyvsp[-2].string, CMNDALIAS, yyvsp[0].member)) != NULL) {
+                               yyerror(s);
+                               YYERROR;
+                           }
+                       }
+break;
+case 70:
+#line 495 "gram.y"
+{
+                           list_append(yyvsp[-2].member, yyvsp[0].member);
+                           yyval.member = yyvsp[-2].member;
+                       }
+break;
+case 73:
+#line 505 "gram.y"
+{
+                           char *s;
+                           if ((s = alias_add(yyvsp[-2].string, RUNASALIAS, yyvsp[0].member)) != NULL) {
+                               yyerror(s);
+                               YYERROR;
+                           }
+                       }
+break;
+case 76:
+#line 518 "gram.y"
+{
+                           char *s;
+                           if ((s = alias_add(yyvsp[-2].string, USERALIAS, yyvsp[0].member)) != NULL) {
+                               yyerror(s);
+                               YYERROR;
+                           }
+                       }
+break;
+case 78:
+#line 528 "gram.y"
+{
+                           list_append(yyvsp[-2].member, yyvsp[0].member);
+                           yyval.member = yyvsp[-2].member;
+                       }
+break;
+case 79:
+#line 534 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = FALSE;
+                       }
+break;
+case 80:
+#line 538 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = TRUE;
+                       }
+break;
+case 81:
+#line 544 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, ALIAS);
+                       }
+break;
+case 82:
+#line 547 "gram.y"
+{
+                           yyval.member = new_member(NULL, ALL);
+                       }
+break;
+case 83:
+#line 550 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, NETGROUP);
+                       }
+break;
+case 84:
+#line 553 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, USERGROUP);
+                       }
+break;
+case 85:
+#line 556 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, WORD);
+                       }
+break;
+case 87:
+#line 562 "gram.y"
+{
+                           list_append(yyvsp[-2].member, yyvsp[0].member);
+                           yyval.member = yyvsp[-2].member;
+                       }
+break;
+case 88:
+#line 568 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = FALSE;
+                       }
+break;
+case 89:
+#line 572 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = TRUE;
+                       }
+break;
+case 90:
+#line 578 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, ALIAS);
+                       }
+break;
+case 91:
+#line 581 "gram.y"
+{
+                           yyval.member = new_member(NULL, ALL);
+                       }
+break;
+case 92:
+#line 584 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, WORD);
+                       }
+break;
+#line 1498 "y.tab.c"
+    }
+    yyssp -= yym;
+    yystate = *yyssp;
+    yyvsp -= yym;
+    yym = yylhs[yyn];
+    if (yystate == 0 && yym == 0)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+        yystate = YYFINAL;
+        *++yyssp = YYFINAL;
+        *++yyvsp = yyval;
+        if (yychar < 0)
+        {
+            if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+            if (yydebug)
+            {
+                yys = 0;
+                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+                if (!yys) yys = "illegal-symbol";
+                printf("%sdebug: state %d, reading %d (%s)\n",
+                        YYPREFIX, YYFINAL, yychar, yys);
+            }
+#endif
+        }
+        if (yychar == 0) goto yyaccept;
+        goto yyloop;
+    }
+    if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+        yystate = yytable[yyn];
+    else
+        yystate = yydgoto[yym];
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yyssp, yystate);
+#endif
+    if (yyssp >= yysslim && yygrowstack())
+    {
+        goto yyoverflow;
+    }
+    *++yyssp = yystate;
+    *++yyvsp = yyval;
+    goto yyloop;
+yyoverflow:
+    yyerror("yacc stack overflow");
+yyabort:
+    if (yyss)
+            free(yyss);
+    if (yyvs)
+            free(yyvs);
+    yyss = yyssp = NULL;
+    yyvs = yyvsp = NULL;
+    yystacksize = 0;
+    return (1);
+yyaccept:
+    if (yyss)
+            free(yyss);
+    if (yyvs)
+            free(yyvs);
+    yyss = yyssp = NULL;
+    yyvs = yyvsp = NULL;
+    yystacksize = 0;
+    return (0);
+}
diff --git a/gram.h b/gram.h
new file mode 100644 (file)
index 0000000..8f05491
--- /dev/null
+++ b/gram.h
@@ -0,0 +1,43 @@
+#define COMMAND 257
+#define ALIAS 258
+#define DEFVAR 259
+#define NTWKADDR 260
+#define NETGROUP 261
+#define USERGROUP 262
+#define WORD 263
+#define DEFAULTS 264
+#define DEFAULTS_HOST 265
+#define DEFAULTS_USER 266
+#define DEFAULTS_RUNAS 267
+#define DEFAULTS_CMND 268
+#define NOPASSWD 269
+#define PASSWD 270
+#define NOEXEC 271
+#define EXEC 272
+#define SETENV 273
+#define NOSETENV 274
+#define ALL 275
+#define COMMENT 276
+#define HOSTALIAS 277
+#define CMNDALIAS 278
+#define USERALIAS 279
+#define RUNASALIAS 280
+#define ERROR 281
+#define TYPE 282
+#define ROLE 283
+#ifndef YYSTYPE_DEFINED
+#define YYSTYPE_DEFINED
+typedef union {
+    struct cmndspec *cmndspec;
+    struct defaults *defaults;
+    struct member *member;
+    struct runascontainer *runas;
+    struct privilege *privilege;
+    struct sudo_command command;
+    struct cmndtag tag;
+    struct selinux_info seinfo;
+    char *string;
+    int tok;
+} YYSTYPE;
+#endif /* YYSTYPE_DEFINED */
+extern YYSTYPE yylval;
diff --git a/gram.y b/gram.y
new file mode 100644 (file)
index 0000000..d39068d
--- /dev/null
+++ b/gram.y
@@ -0,0 +1,776 @@
+%{
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
+# include <alloca.h>
+#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
+#include <limits.h>
+
+#include "sudo.h"
+#include "parse.h"
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: gram.y,v 1.34 2008/11/09 14:13:12 millert Exp $";
+#endif /* lint */
+
+/*
+ * We must define SIZE_MAX for yacc's skeleton.c.
+ * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
+ * could be signed (as it is on SunOS 4.x).
+ */
+#ifndef SIZE_MAX
+# ifdef SIZE_T_MAX
+#  define SIZE_MAX     SIZE_T_MAX
+# else
+#  define SIZE_MAX     INT_MAX
+# endif /* SIZE_T_MAX */
+#endif /* SIZE_MAX */
+
+/*
+ * Globals
+ */
+extern int sudolineno;
+extern char *sudoers;
+int parse_error;
+int pedantic = FALSE;
+int verbose = FALSE;
+int errorlineno = -1;
+char *errorfile = NULL;
+
+struct defaults_list defaults;
+struct userspec_list userspecs;
+
+/*
+ * Local protoypes
+ */
+static void  add_defaults      __P((int, struct member *, struct defaults *));
+static void  add_userspec      __P((struct member *, struct privilege *));
+static struct defaults *new_default __P((char *, char *, int));
+static struct member *new_member __P((char *, int));
+       void  yyerror           __P((const char *));
+
+void
+yyerror(s)
+    const char *s;
+{
+    /* Save the line the first error occurred on. */
+    if (errorlineno == -1) {
+       errorlineno = sudolineno ? sudolineno - 1 : 0;
+       errorfile = estrdup(sudoers);
+    }
+    if (verbose && s != NULL) {
+#ifndef TRACELEXER
+       (void) fprintf(stderr, ">>> %s: %s near line %d <<<\n", sudoers, s,
+           sudolineno ? sudolineno - 1 : 0);
+#else
+       (void) fprintf(stderr, "<*> ");
+#endif
+    }
+    parse_error = TRUE;
+}
+%}
+
+%union {
+    struct cmndspec *cmndspec;
+    struct defaults *defaults;
+    struct member *member;
+    struct runascontainer *runas;
+    struct privilege *privilege;
+    struct sudo_command command;
+    struct cmndtag tag;
+    struct selinux_info seinfo;
+    char *string;
+    int tok;
+}
+
+%start file                            /* special start symbol */
+%token <command> COMMAND               /* absolute pathname w/ optional args */
+%token <string>  ALIAS                 /* an UPPERCASE alias name */
+%token <string>         DEFVAR                 /* a Defaults variable name */
+%token <string>  NTWKADDR              /* ipv4 or ipv6 address */
+%token <string>  NETGROUP              /* a netgroup (+NAME) */
+%token <string>  USERGROUP             /* a usergroup (%NAME) */
+%token <string>  WORD                  /* a word */
+%token <tok>    DEFAULTS               /* Defaults entry */
+%token <tok>    DEFAULTS_HOST          /* Host-specific defaults entry */
+%token <tok>    DEFAULTS_USER          /* User-specific defaults entry */
+%token <tok>    DEFAULTS_RUNAS         /* Runas-specific defaults entry */
+%token <tok>    DEFAULTS_CMND          /* Command-specific defaults entry */
+%token <tok>    NOPASSWD               /* no passwd req for command */
+%token <tok>    PASSWD                 /* passwd req for command (default) */
+%token <tok>    NOEXEC                 /* preload dummy execve() for cmnd */
+%token <tok>    EXEC                   /* don't preload dummy execve() */
+%token <tok>    SETENV                 /* user may set environment for cmnd */
+%token <tok>    NOSETENV               /* user may not set environment */
+%token <tok>    ALL                    /* ALL keyword */
+%token <tok>    COMMENT                /* comment and/or carriage return */
+%token <tok>    HOSTALIAS              /* Host_Alias keyword */
+%token <tok>    CMNDALIAS              /* Cmnd_Alias keyword */
+%token <tok>    USERALIAS              /* User_Alias keyword */
+%token <tok>    RUNASALIAS             /* Runas_Alias keyword */
+%token <tok>    ':' '=' ',' '!' '+' '-' /* union member tokens */
+%token <tok>    '(' ')'                /* runas tokens */
+%token <tok>    ERROR
+%token <tok>    TYPE                   /* SELinux type */
+%token <tok>    ROLE                   /* SELinux role */
+
+%type <cmndspec>  cmndspec
+%type <cmndspec>  cmndspeclist
+%type <defaults>  defaults_entry
+%type <defaults>  defaults_list
+%type <member>   cmnd
+%type <member>   opcmnd
+%type <member>   cmndlist
+%type <member>   host
+%type <member>   hostlist
+%type <member>   ophost
+%type <member>   opuser
+%type <member>   user
+%type <member>   userlist
+%type <member>   opgroup
+%type <member>   group
+%type <member>   grouplist
+%type <runas>    runasspec
+%type <runas>    runaslist
+%type <privilege> privilege
+%type <privilege> privileges
+%type <tag>      cmndtag
+%type <seinfo>   selinux
+%type <string>   rolespec
+%type <string>   typespec
+
+%%
+
+file           :       { ; }
+               |       line
+               ;
+
+line           :       entry
+               |       line entry
+               ;
+
+entry          :       COMMENT {
+                           ;
+                       }
+                |       error COMMENT {
+                           yyerrok;
+                       }
+               |       userlist privileges {
+                           add_userspec($1, $2);
+                       }
+               |       USERALIAS useraliases {
+                           ;
+                       }
+               |       HOSTALIAS hostaliases {
+                           ;
+                       }
+               |       CMNDALIAS cmndaliases {
+                           ;
+                       }
+               |       RUNASALIAS runasaliases {
+                           ;
+                       }
+               |       DEFAULTS defaults_list {
+                           add_defaults(DEFAULTS, NULL, $2);
+                       }
+               |       DEFAULTS_USER userlist defaults_list {
+                           add_defaults(DEFAULTS_USER, $2, $3);
+                       }
+               |       DEFAULTS_RUNAS userlist defaults_list {
+                           add_defaults(DEFAULTS_RUNAS, $2, $3);
+                       }
+               |       DEFAULTS_HOST hostlist defaults_list {
+                           add_defaults(DEFAULTS_HOST, $2, $3);
+                       }
+               |       DEFAULTS_CMND cmndlist defaults_list {
+                           add_defaults(DEFAULTS_CMND, $2, $3);
+                       }
+               ;
+
+defaults_list  :       defaults_entry
+               |       defaults_list ',' defaults_entry {
+                           list_append($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+defaults_entry :       DEFVAR {
+                           $$ = new_default($1, NULL, TRUE);
+                       }
+               |       '!' DEFVAR {
+                           $$ = new_default($2, NULL, FALSE);
+                       }
+               |       DEFVAR '=' WORD {
+                           $$ = new_default($1, $3, TRUE);
+                       }
+               |       DEFVAR '+' WORD {
+                           $$ = new_default($1, $3, '+');
+                       }
+               |       DEFVAR '-' WORD {
+                           $$ = new_default($1, $3, '-');
+                       }
+               ;
+
+privileges     :       privilege
+               |       privileges ':' privilege {
+                           list_append($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+privilege      :       hostlist '=' cmndspeclist {
+                           struct privilege *p = emalloc(sizeof(*p));
+                           list2tq(&p->hostlist, $1);
+                           list2tq(&p->cmndlist, $3);
+                           p->prev = p;
+                           p->next = NULL;
+                           $$ = p;
+                       }
+               ;
+
+ophost         :       host {
+                           $$ = $1;
+                           $$->negated = FALSE;
+                       }
+               |       '!' host {
+                           $$ = $2;
+                           $$->negated = TRUE;
+                       }
+               ;
+
+host           :       ALIAS {
+                           $$ = new_member($1, ALIAS);
+                       }
+               |       ALL {
+                           $$ = new_member(NULL, ALL);
+                       }
+               |       NETGROUP {
+                           $$ = new_member($1, NETGROUP);
+                       }
+               |       NTWKADDR {
+                           $$ = new_member($1, NTWKADDR);
+                       }
+               |       WORD {
+                           $$ = new_member($1, WORD);
+                       }
+               ;
+
+cmndspeclist   :       cmndspec
+               |       cmndspeclist ',' cmndspec {
+                           list_append($1, $3);
+#ifdef HAVE_SELINUX
+                           /* propagate role and type */
+                           if ($3->role == NULL)
+                               $3->role = $3->prev->role;
+                           if ($3->type == NULL)
+                               $3->type = $3->prev->type;
+#endif /* HAVE_SELINUX */
+                           /* propagate tags and runas list */
+                           if ($3->tags.nopasswd == UNSPEC)
+                               $3->tags.nopasswd = $3->prev->tags.nopasswd;
+                           if ($3->tags.noexec == UNSPEC)
+                               $3->tags.noexec = $3->prev->tags.noexec;
+                           if ($3->tags.setenv == UNSPEC &&
+                               $3->prev->tags.setenv != IMPLIED)
+                               $3->tags.setenv = $3->prev->tags.setenv;
+                           if ((tq_empty(&$3->runasuserlist) &&
+                                tq_empty(&$3->runasgrouplist)) &&
+                               (!tq_empty(&$3->prev->runasuserlist) ||
+                                !tq_empty(&$3->prev->runasgrouplist))) {
+                               $3->runasuserlist = $3->prev->runasuserlist;
+                               $3->runasgrouplist = $3->prev->runasgrouplist;
+                           }
+                           $$ = $1;
+                       }
+               ;
+
+cmndspec       :       runasspec selinux cmndtag opcmnd {
+                           struct cmndspec *cs = emalloc(sizeof(*cs));
+                           if ($1 != NULL) {
+                               list2tq(&cs->runasuserlist, $1->runasusers);
+                               list2tq(&cs->runasgrouplist, $1->runasgroups);
+                               efree($1);
+                           } else {
+                               tq_init(&cs->runasuserlist);
+                               tq_init(&cs->runasgrouplist);
+                           }
+#ifdef HAVE_SELINUX
+                           cs->role = $2.role;
+                           cs->type = $2.type;
+#endif
+                           cs->tags = $3;
+                           cs->cmnd = $4;
+                           cs->prev = cs;
+                           cs->next = NULL;
+                           /* sudo "ALL" implies the SETENV tag */
+                           if (cs->cmnd->type == ALL && !cs->cmnd->negated &&
+                               cs->tags.setenv == UNSPEC)
+                               cs->tags.setenv = IMPLIED;
+                           $$ = cs;
+                       }
+               ;
+
+opcmnd         :       cmnd {
+                           $$ = $1;
+                           $$->negated = FALSE;
+                       }
+               |       '!' cmnd {
+                           $$ = $2;
+                           $$->negated = TRUE;
+                       }
+               ;
+
+rolespec       :       ROLE '=' WORD {
+                           $$ = $3;
+                       }
+               ;
+
+typespec       :       TYPE '=' WORD {
+                           $$ = $3;
+                       }
+               ;
+
+selinux                :       /* empty */ {
+                           $$.role = NULL;
+                           $$.type = NULL;
+                       }
+               |       rolespec {
+                           $$.role = $1;
+                           $$.type = NULL;
+                       }
+               |       typespec {
+                           $$.type = $1;
+                           $$.role = NULL;
+                       }
+               |       rolespec typespec {
+                           $$.role = $1;
+                           $$.type = $2;
+                       }
+               |       typespec rolespec {
+                           $$.type = $1;
+                           $$.role = $2;
+                       }
+               ;
+
+runasspec      :       /* empty */ {
+                           $$ = NULL;
+                       }
+               |       '(' runaslist ')' {
+                           $$ = $2;
+                       }
+               ;
+
+runaslist      :       userlist {
+                           $$ = emalloc(sizeof(struct runascontainer));
+                           $$->runasusers = $1;
+                           $$->runasgroups = NULL;
+                       }
+               |       userlist ':' grouplist {
+                           $$ = emalloc(sizeof(struct runascontainer));
+                           $$->runasusers = $1;
+                           $$->runasgroups = $3;
+                       }
+               |       ':' grouplist {
+                           $$ = emalloc(sizeof(struct runascontainer));
+                           $$->runasusers = NULL;
+                           $$->runasgroups = $2;
+                       }
+               ;
+
+cmndtag                :       /* empty */ {
+                           $$.nopasswd = $$.noexec = $$.setenv = UNSPEC;
+                       }
+               |       cmndtag NOPASSWD {
+                           $$.nopasswd = TRUE;
+                       }
+               |       cmndtag PASSWD {
+                           $$.nopasswd = FALSE;
+                       }
+               |       cmndtag NOEXEC {
+                           $$.noexec = TRUE;
+                       }
+               |       cmndtag EXEC {
+                           $$.noexec = FALSE;
+                       }
+               |       cmndtag SETENV {
+                           $$.setenv = TRUE;
+                       }
+               |       cmndtag NOSETENV {
+                           $$.setenv = FALSE;
+                       }
+               ;
+
+cmnd           :       ALL {
+                           $$ = new_member(NULL, ALL);
+                       }
+               |       ALIAS {
+                           $$ = new_member($1, ALIAS);
+                       }
+               |       COMMAND {
+                           struct sudo_command *c = emalloc(sizeof(*c));
+                           c->cmnd = $1.cmnd;
+                           c->args = $1.args;
+                           $$ = new_member((char *)c, COMMAND);
+                       }
+               ;
+
+hostaliases    :       hostalias
+               |       hostaliases ':' hostalias
+               ;
+
+hostalias      :       ALIAS '=' hostlist {
+                           char *s;
+                           if ((s = alias_add($1, HOSTALIAS, $3)) != NULL) {
+                               yyerror(s);
+                               YYERROR;
+                           }
+                       }
+               ;
+
+hostlist       :       ophost
+               |       hostlist ',' ophost {
+                           list_append($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+cmndaliases    :       cmndalias
+               |       cmndaliases ':' cmndalias
+               ;
+
+cmndalias      :       ALIAS '=' cmndlist {
+                           char *s;
+                           if ((s = alias_add($1, CMNDALIAS, $3)) != NULL) {
+                               yyerror(s);
+                               YYERROR;
+                           }
+                       }
+               ;
+
+cmndlist       :       opcmnd
+               |       cmndlist ',' opcmnd {
+                           list_append($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+runasaliases   :       runasalias
+               |       runasaliases ':' runasalias
+               ;
+
+runasalias     :       ALIAS '=' userlist {
+                           char *s;
+                           if ((s = alias_add($1, RUNASALIAS, $3)) != NULL) {
+                               yyerror(s);
+                               YYERROR;
+                           }
+                       }
+               ;
+
+useraliases    :       useralias
+               |       useraliases ':' useralias
+               ;
+
+useralias      :       ALIAS '=' userlist {
+                           char *s;
+                           if ((s = alias_add($1, USERALIAS, $3)) != NULL) {
+                               yyerror(s);
+                               YYERROR;
+                           }
+                       }
+               ;
+
+userlist       :       opuser
+               |       userlist ',' opuser {
+                           list_append($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+opuser         :       user {
+                           $$ = $1;
+                           $$->negated = FALSE;
+                       }
+               |       '!' user {
+                           $$ = $2;
+                           $$->negated = TRUE;
+                       }
+               ;
+
+user           :       ALIAS {
+                           $$ = new_member($1, ALIAS);
+                       }
+               |       ALL {
+                           $$ = new_member(NULL, ALL);
+                       }
+               |       NETGROUP {
+                           $$ = new_member($1, NETGROUP);
+                       }
+               |       USERGROUP {
+                           $$ = new_member($1, USERGROUP);
+                       }
+               |       WORD {
+                           $$ = new_member($1, WORD);
+                       }
+               ;
+
+grouplist      :       opgroup
+               |       grouplist ',' opgroup {
+                           list_append($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+opgroup                :       group {
+                           $$ = $1;
+                           $$->negated = FALSE;
+                       }
+               |       '!' group {
+                           $$ = $2;
+                           $$->negated = TRUE;
+                       }
+               ;
+
+group          :       ALIAS {
+                           $$ = new_member($1, ALIAS);
+                       }
+               |       ALL {
+                           $$ = new_member(NULL, ALL);
+                       }
+               |       WORD {
+                           $$ = new_member($1, WORD);
+                       }
+               ;
+
+%%
+static struct defaults *
+new_default(var, val, op)
+    char *var;
+    char *val;
+    int op;
+{
+    struct defaults *d;
+
+    d = emalloc(sizeof(struct defaults));
+    d->var = var;
+    d->val = val;
+    tq_init(&d->binding);
+    d->type = 0;
+    d->op = op;
+    d->prev = d;
+    d->next = NULL;
+
+    return(d);
+}
+
+static struct member *
+new_member(name, type)
+    char *name;
+    int type;
+{
+    struct member *m;
+
+    m = emalloc(sizeof(struct member));
+    m->name = name;
+    m->type = type;
+    m->prev = m;
+    m->next = NULL;
+
+    return(m);
+}
+
+/*
+ * Add a list of defaults structures to the defaults list.
+ * The binding, if non-NULL, specifies a list of hosts, users, or
+ * runas users the entries apply to (specified by the type).
+ */
+static void
+add_defaults(type, bmem, defs)
+    int type;
+    struct member *bmem;
+    struct defaults *defs;
+{
+    struct defaults *d;
+    struct member_list binding;
+
+    /*
+     * We can only call list2tq once on bmem as it will zero
+     * out the prev pointer when it consumes bmem.
+     */
+    list2tq(&binding, bmem);
+
+    /*
+     * Set type and binding (who it applies to) for new entries.
+     */
+    for (d = defs; d != NULL; d = d->next) {
+       d->type = type;
+       d->binding = binding;
+    }
+    tq_append(&defaults, defs);
+}
+
+/*
+ * Allocate a new struct userspec, populate it, and insert it at the
+ * and of the userspecs list.
+ */
+static void
+add_userspec(members, privs)
+    struct member *members;
+    struct privilege *privs;
+{
+    struct userspec *u;
+
+    u = emalloc(sizeof(*u));
+    list2tq(&u->users, members);
+    list2tq(&u->privileges, privs);
+    u->prev = u;
+    u->next = NULL;
+    tq_append(&userspecs, u);
+}
+
+/*
+ * Free up space used by data structures from a previous parser run and sets
+ * the current sudoers file to path.
+ */
+void
+init_parser(path, quiet)
+    char *path;
+    int quiet;
+{
+    struct defaults *d;
+    struct member *m, *binding;
+    struct userspec *us;
+    struct privilege *priv;
+    struct cmndspec *cs;
+    struct sudo_command *c;
+
+    while ((us = tq_pop(&userspecs)) != NULL) {
+       while ((m = tq_pop(&us->users)) != NULL) {
+           efree(m->name);
+           efree(m);
+       }
+       while ((priv = tq_pop(&us->privileges)) != NULL) {
+           struct member *runasuser = NULL, *runasgroup = NULL;
+#ifdef HAVE_SELINUX
+           char *role = NULL, *type = NULL;
+#endif /* HAVE_SELINUX */
+
+           while ((m = tq_pop(&priv->hostlist)) != NULL) {
+               efree(m->name);
+               efree(m);
+           }
+           while ((cs = tq_pop(&priv->cmndlist)) != NULL) {
+#ifdef HAVE_SELINUX
+               /* Only free the first instance of a role/type. */
+               if (cs->role != role) {
+                   role = cs->role;
+                   efree(cs->role);
+               }
+               if (cs->type != type) {
+                   type = cs->type;
+                   efree(cs->type);
+               }
+#endif /* HAVE_SELINUX */
+               if (tq_last(&cs->runasuserlist) != runasuser) {
+                   runasuser = tq_last(&cs->runasuserlist);
+                   while ((m = tq_pop(&cs->runasuserlist)) != NULL) {
+                       efree(m->name);
+                       efree(m);
+                   }
+               }
+               if (tq_last(&cs->runasgrouplist) != runasgroup) {
+                   runasgroup = tq_last(&cs->runasgrouplist);
+                   while ((m = tq_pop(&cs->runasgrouplist)) != NULL) {
+                       efree(m->name);
+                       efree(m);
+                   }
+               }
+               if (cs->cmnd->type == COMMAND) {
+                       c = (struct sudo_command *) cs->cmnd->name;
+                       efree(c->cmnd);
+                       efree(c->args);
+               }
+               efree(cs->cmnd->name);
+               efree(cs->cmnd);
+               efree(cs);
+           }
+           efree(priv);
+       }
+       efree(us);
+    }
+    tq_init(&userspecs);
+
+    binding = NULL;
+    while ((d = tq_pop(&defaults)) != NULL) {
+       if (tq_last(&d->binding) != binding) {
+           binding = tq_last(&d->binding);
+           while ((m = tq_pop(&d->binding)) != NULL) {
+               if (m->type == COMMAND) {
+                       c = (struct sudo_command *) m->name;
+                       efree(c->cmnd);
+                       efree(c->args);
+               }
+               efree(m->name);
+               efree(m);
+           }
+       }
+       efree(d->var);
+       efree(d->val);
+       efree(d);
+    }
+    tq_init(&defaults);
+
+    init_aliases();
+
+    efree(sudoers);
+    sudoers = path ? estrdup(path) : NULL;
+
+    parse_error = FALSE;
+    errorlineno = -1;
+    sudolineno = 1;
+    verbose = !quiet;
+}
index b8269d84ab39e9e4e2ed259174117b36c35e1a23..db27ed389ffc22766c82667ab9f4dd7dda8dc794 100644 (file)
@@ -1,13 +1,14 @@
--di4
 -br
 -cdb
 -ce
 -d0
+-di1
 -ei
--lp
+-i4
+-nlp
 -npcs
--ps
 -npsl
+-ps
 -sc
 -TYYSTYPE
 -TLIST
index 9eb83d392e632f6489c5f1fa98e0ff7ee5cdc29f..e94d8ae531d80587fff50dea2a080eee084e31d3 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1996, 1998, 1999 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1996, 1998, 1999, 2004
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -13,7 +14,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $Sudo: ins_csops.h,v 1.28.2.1 2007/06/10 16:57:35 millert Exp $
+ * $Sudo: ins_csops.h,v 1.30 2008/11/09 14:13:12 millert Exp $
  */
 
 #ifndef _SUDO_INS_CSOPS_H
index da077192aa5b48d4cb1efd8119af075eafeb3cc2..6dcd300a7bb3c45f0dfb55f756396d31a596e9e0 100755 (executable)
@@ -1,7 +1,7 @@
 #! /bin/sh
 
 ## (From INN-1.4, written by Rich Salz)
-##  $Revision: 1.9.4.1 $
+##  $Revision: 1.10 $
 ##  A script to install files and directories.
 
 PROGNAME=`basename $0`
index 9b0c30fca0104e40cb5470fd2e232d3edd3ee0f2..113fe3611501edd032e01febfd12dee06c3360fd 100644 (file)
--- a/insults.h
+++ b/insults.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1994-1996,1998-1999 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1994-1996, 1998-1999, 2004
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -13,7 +14,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $Sudo: insults.h,v 1.46 2004/02/13 21:36:43 millert Exp $
+ * $Sudo: insults.h,v 1.47 2008/11/09 14:13:12 millert Exp $
  */
 
 #ifndef _SUDO_INSULTS_H
index 87abfaa5229498a5a3d00018081fe7bb891814b1..27ca4382e61be90a7ad65eb53c340409903942c9 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1996, 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1996, 1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -59,11 +60,6 @@ struct rtentry;
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <netdb.h>
 #include <errno.h>
 #ifdef _ISC
@@ -89,7 +85,7 @@ struct rtentry;
 #include "interfaces.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: interfaces.c,v 1.72.2.8 2007/11/27 17:06:53 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: interfaces.c,v 1.84 2008/11/09 14:13:12 millert Exp $";
 #endif /* lint */
 
 
@@ -193,7 +189,7 @@ load_interfaces()
 
     sock = socket(AF_INET, SOCK_DGRAM, 0);
     if (sock < 0)
-       err(1, "cannot open socket");
+       error(1, "cannot open socket");
 
     /*
      * Get interface configuration or return (leaving num_interfaces == 0)
@@ -249,7 +245,7 @@ load_interfaces()
                continue;
 
 #ifdef SIOCGIFFLAGS
-       memset(&ifr_tmp, 0, sizeof(ifr_tmp));
+       zero_bytes(&ifr_tmp, sizeof(ifr_tmp));
        strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
        if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0)
 #endif
@@ -267,7 +263,7 @@ load_interfaces()
        previfname = ifr->ifr_name;
 
        /* Get the netmask. */
-       (void) memset(&ifr_tmp, 0, sizeof(ifr_tmp));
+       zero_bytes(&ifr_tmp, sizeof(ifr_tmp));
        strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
 #ifdef SIOCGIFNETMASK
 #ifdef _ISC
index ddb6f84b7ef06e91863b4d20c85bcd6f1f120895..d4d4dd0d204ba81aca3d6f6019f4428a823ad3ea 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1996, 1998-2005, 2007
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,7 +18,7 @@
  * Agency (DARPA) and Air Force Research Laboratory, Air Force
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  *
- * $Sudo: interfaces.h,v 1.8.2.3 2007/10/24 16:43:27 millert Exp $
+ * $Sudo: interfaces.h,v 1.12 2008/11/09 14:13:12 millert Exp $
  */
 
 #ifndef _SUDO_INTERFACES_H
diff --git a/isblank.c b/isblank.c
new file mode 100644 (file)
index 0000000..02b15fe
--- /dev/null
+++ b/isblank.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: isblank.c,v 1.1 2008/11/06 00:05:24 millert Exp $";
+#endif /* lint */
+
+#undef isblank
+int
+isblank(ch)
+    int ch;
+{
+    return(ch == ' ' || ch == '\t');
+}
diff --git a/lbuf.c b/lbuf.c
new file mode 100644 (file)
index 0000000..ef898eb
--- /dev/null
+++ b/lbuf.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <ctype.h>
+
+#include "sudo.h"
+#include "lbuf.h"
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: lbuf.c,v 1.7 2008/12/09 20:55:49 millert Exp $";
+#endif /* lint */
+
+#if !defined(TIOCGSIZE) && defined(TIOCGWINSZ)
+# define TIOCGSIZE     TIOCGWINSZ
+# define ttysize       winsize
+# define ts_cols       ws_col
+#endif
+
+int
+get_ttycols()
+{
+    char *p;
+    int cols;
+#ifdef TIOCGSIZE
+    struct ttysize win;
+
+    if (ioctl(STDERR_FILENO, TIOCGSIZE, &win) == 0 && win.ts_cols != 0)
+       return((int)win.ts_cols);
+#endif
+
+    /* Fall back on $COLUMNS. */
+    if ((p = getenv("COLUMNS")) == NULL || (cols = atoi(p)) <= 0)
+       cols = 80;
+    return(cols);
+}
+
+/*
+ * TODO: add support for embedded newlines in lbufs
+ */
+
+void
+lbuf_init(lbuf, buf, indent, continuation)
+    struct lbuf *lbuf;
+    char *buf;
+    int indent;
+    int continuation;
+{
+    lbuf->continuation = continuation;
+    lbuf->indent = indent;
+    lbuf->len = 0;
+    lbuf->size = 0;
+    lbuf->buf = NULL;
+}
+
+void
+lbuf_destroy(lbuf)
+    struct lbuf *lbuf;
+{
+    efree(lbuf->buf);
+    lbuf->buf = NULL;
+}
+
+/*
+ * Append strings to the buffer, expanding it as needed.
+ */
+void
+#ifdef __STDC__
+lbuf_append_quoted(struct lbuf *lbuf, const char *set, ...)
+#else
+lbuf_append_quoted(lbuf, set, va_alist)
+       struct lbuf *lbuf;
+       const char *set;
+       va_dcl
+#endif
+{
+    va_list ap;
+    int len = 0;
+    char *cp, *s;
+
+#ifdef __STDC__
+    va_start(ap, set);
+#else
+    va_start(ap);
+#endif
+    while ((s = va_arg(ap, char *)) != NULL) {
+       len += strlen(s);
+       for (cp = s; (cp = strpbrk(cp, set)) != NULL; cp++)
+           len++;
+    }
+    va_end(ap);
+
+    /* Expand buffer as needed. */
+    if (lbuf->len + len >= lbuf->size) {
+       do {
+           lbuf->size += 256;
+       } while (lbuf->len + len >= lbuf->size);
+       lbuf->buf = erealloc(lbuf->buf, lbuf->size);
+    }
+
+#ifdef __STDC__
+    va_start(ap, set);
+#else
+    va_start(ap);
+#endif
+    /* Append each string. */
+    while ((s = va_arg(ap, char *)) != NULL) {
+       while ((cp = strpbrk(s, set)) != NULL) {
+           len = (int)(cp - s);
+           memcpy(lbuf->buf + lbuf->len, s, len);
+           lbuf->len += len;
+           lbuf->buf[lbuf->len++] = '\\';
+           lbuf->buf[lbuf->len++] = *cp;
+           s = cp + 1;
+       }
+       if (*s != '\0') {
+           len = strlen(s);
+           memcpy(lbuf->buf + lbuf->len, s, len);
+           lbuf->len += len;
+       }
+    }
+    lbuf->buf[lbuf->len] = '\0';
+    va_end(ap);
+}
+
+/*
+ * Append strings to the buffer, expanding it as needed.
+ */
+void
+#ifdef __STDC__
+lbuf_append(struct lbuf *lbuf, ...)
+#else
+lbuf_append(lbuf, va_alist)
+       struct lbuf *lbuf;
+       va_dcl
+#endif
+{
+    va_list ap;
+    int len = 0;
+    char *s;
+
+#ifdef __STDC__
+    va_start(ap, lbuf);
+#else
+    va_start(ap);
+#endif
+    while ((s = va_arg(ap, char *)) != NULL)
+       len += strlen(s);
+    va_end(ap);
+
+    /* Expand buffer as needed. */
+    if (lbuf->len + len >= lbuf->size) {
+       do {
+           lbuf->size += 256;
+       } while (lbuf->len + len >= lbuf->size);
+       lbuf->buf = erealloc(lbuf->buf, lbuf->size);
+    }
+
+#ifdef __STDC__
+    va_start(ap, lbuf);
+#else
+    va_start(ap);
+#endif
+    /* Append each string. */
+    while ((s = va_arg(ap, char *)) != NULL) {
+       len = strlen(s);
+       memcpy(lbuf->buf + lbuf->len, s, len);
+       lbuf->len += len;
+    }
+    lbuf->buf[lbuf->len] = '\0';
+    va_end(ap);
+}
+
+/*
+ * Print the buffer with word wrap based on the tty width.
+ * The lbuf is reset on return.
+ */
+void
+lbuf_print(lbuf)
+    struct lbuf *lbuf;
+{
+    char *cp;
+    int i, have, contlen;
+    static int cols = -1;
+
+    if (cols == -1)
+       cols = get_ttycols();
+    contlen = lbuf->continuation ? 2 : 0;
+
+    /* For very small widths just give up... */
+    if (cols <= lbuf->indent + contlen + 20) {
+       puts(lbuf->buf);
+       goto done;
+    }
+
+    /*
+     * Print the buffer, splitting the line as needed on a word
+     * boundary.
+     */
+    cp = lbuf->buf;
+    have = cols;
+    while (cp != NULL && *cp != '\0') {
+       char *ep = NULL;
+       int need = lbuf->len - (int)(cp - lbuf->buf);
+
+       if (need > have) {
+           have -= contlen;            /* subtract for continuation char */
+           if ((ep = memrchr(cp, ' ', have)) == NULL)
+               ep = memchr(cp + have, ' ', need - have);
+           if (ep != NULL)
+               need = (int)(ep - cp);
+       }
+       if (cp != lbuf->buf) {
+           /* indent continued lines */
+           for (i = 0; i < lbuf->indent; i++)
+               putchar(' ');
+       }
+       fwrite(cp, need, 1, stdout);
+       cp = ep;
+
+       /*
+        * If there is more to print, reset have, incremement cp past
+        * the whitespace, and print a line continuaton char if needed.
+        */
+       if (cp != NULL) {
+           have = cols - lbuf->indent;
+           do {
+               cp++;
+           } while (isspace((unsigned char)*cp));
+           if (lbuf->continuation) {
+               putchar(' ');
+               putchar(lbuf->continuation);
+           }
+       }
+       putchar('\n');
+    }
+
+done:
+    lbuf->len = 0;             /* reset the buffer for re-use. */
+}
diff --git a/lbuf.h b/lbuf.h
new file mode 100644 (file)
index 0000000..4633dee
--- /dev/null
+++ b/lbuf.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Sudo: lbuf.h,v 1.2 2007/08/22 22:31:07 millert Exp $"
+ */
+
+#ifndef _SUDO_LBUF_H
+#define _SUDO_LBUF_H
+
+/*
+ * Line buffer struct.
+ */
+struct lbuf {
+    char *buf;
+    int continuation;
+    int indent;
+    int len;
+    int size;
+};
+
+void lbuf_init         __P((struct lbuf *, char *, int, int));
+void lbuf_destroy      __P((struct lbuf *));
+void lbuf_append       __P((struct lbuf *, ...));
+void lbuf_append_quoted        __P((struct lbuf *, const char *, ...));
+void lbuf_print                __P((struct lbuf *));
+
+#endif /* _SUDO_LBUF_H */
diff --git a/ldap.c b/ldap.c
index 8ee0ba73d9c66d7faeea47eec024788210cdd685..c778f3a0b54a30015906ae926756c57040593214 100644 (file)
--- a/ldap.c
+++ b/ldap.c
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include <ctype.h>
-#include <limits.h>
 #include <pwd.h>
 #include <grp.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
-#include <errno.h>
 #ifdef HAVE_LBER_H
 # include <lber.h>
 #endif
 #elif defined(HAVE_MPS_LDAP_SSL_H)
 # include <mps/ldap_ssl.h>
 #endif
+#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
+# ifdef HAVE_SASL_SASL_H
+#  include <sasl/sasl.h>
+# else
+#  include <sasl.h>
+# endif
+# if HAVE_GSS_KRB5_CCACHE_NAME
+#  if defined(HAVE_GSSAPI_GSSAPI_KRB5_H)
+#   include <gssapi/gssapi.h>
+#   include <gssapi/gssapi_krb5.h>
+#  elif defined(HAVE_GSSAPI_GSSAPI_H)
+#   include <gssapi/gssapi.h>
+#  else
+#   include <gssapi.h>
+#  endif
+# endif
+#endif
 
 #include "sudo.h"
 #include "parse.h"
+#include "lbuf.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: ldap.c,v 1.11.2.38 2008/04/11 14:03:51 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: ldap.c,v 1.100 2008/04/23 12:30:07 millert Exp $";
 #endif /* lint */
 
-#ifndef LINE_MAX
-# define LINE_MAX 2048
-#endif
-
 #ifndef LDAP_OPT_SUCCESS
 # define LDAP_OPT_SUCCESS LDAP_SUCCESS
 #endif
@@ -86,7 +93,25 @@ __unused static const char rcsid[] = "$Sudo: ldap.c,v 1.11.2.38 2008/04/11 14:03
 # define LDAPS_PORT 636
 #endif
 
-#define        DPRINTF(args, level)    if (ldap_conf.debug >= level) warnx args
+#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && !defined(LDAP_SASL_QUIET)
+# define LDAP_SASL_QUIET       0
+#endif
+
+#ifndef HAVE_LDAP_UNBIND_EXT_S
+#define ldap_unbind_ext_s(a, b, c)     ldap_unbind_s(a)
+#endif
+
+#ifndef HAVE_LDAP_SEARCH_EXT_S
+#define ldap_search_ext_s(a, b, c, d, e, f, g, h, i, j, k)             \
+       ldap_search_s(a, b, c, d, e, f, k)
+#endif
+
+#define LDAP_FOREACH(var, ld, res)                                     \
+    for ((var) = ldap_first_entry((ld), (res));                                \
+       (var) != NULL;                                                  \
+       (var) = ldap_next_entry((ld), (var)))
+
+#define        DPRINTF(args, level)    if (ldap_conf.debug >= level) warningx args
 
 #define CONF_BOOL      0
 #define CONF_INT       1
@@ -104,7 +129,7 @@ struct ldap_config_table {
 };
 
 /* ldap configuration structure */
-struct ldap_config {
+static struct ldap_config {
     int port;
     int version;
     int debug;
@@ -112,6 +137,8 @@ struct ldap_config {
     int tls_checkpeer;
     int timelimit;
     int bind_timelimit;
+    int use_sasl;
+    int rootuse_sasl;
     int ssl_mode;
     char *host;
     char *uri;
@@ -126,9 +153,13 @@ struct ldap_config {
     char *tls_cipher_suite;
     char *tls_certfile;
     char *tls_keyfile;
+    char *sasl_auth_id;
+    char *rootsasl_auth_id;
+    char *sasl_secprops;
+    char *krb5_ccname;
 } ldap_conf;
 
-struct ldap_config_table ldap_conf_table[] = {
+static struct ldap_config_table ldap_conf_table[] = {
     { "sudoers_debug", CONF_INT, FALSE, -1, &ldap_conf.debug },
     { "host", CONF_STR, FALSE, -1, &ldap_conf.host },
     { "port", CONF_INT, FALSE, -1, &ldap_conf.port },
@@ -188,12 +219,74 @@ struct ldap_config_table ldap_conf_table[] = {
     { "bindpw", CONF_STR, FALSE, -1, &ldap_conf.bindpw },
     { "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },
     { "sudoers_base", CONF_STR, FALSE, -1, &ldap_conf.base },
+#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
+    { "use_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.use_sasl },
+    { "sasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.sasl_auth_id },
+    { "rootuse_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.rootuse_sasl },
+    { "rootsasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.rootsasl_auth_id },
+# ifdef LDAP_OPT_X_SASL_SECPROPS
+    { "sasl_secprops", CONF_STR, TRUE, LDAP_OPT_X_SASL_SECPROPS,
+       &ldap_conf.sasl_secprops },
+# endif
+    { "krb5_ccname", CONF_STR, FALSE, -1, &ldap_conf.krb5_ccname },
+#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
     { NULL }
 };
 
-static void sudo_ldap_update_defaults __P((LDAP *));
-static void sudo_ldap_close __P((LDAP *));
-static LDAP *sudo_ldap_open __P((void));
+struct sudo_nss sudo_nss_ldap = {
+    &sudo_nss_ldap,
+    NULL,
+    sudo_ldap_open,
+    sudo_ldap_close,
+    sudo_ldap_parse,
+    sudo_ldap_setdefs,
+    sudo_ldap_lookup,
+    sudo_ldap_display_cmnd,
+    sudo_ldap_display_defaults,
+    sudo_ldap_display_bound_defaults,
+    sudo_ldap_display_privs
+};
+
+#ifdef HAVE_LDAP_CREATE
+/*
+ * Rebuild the hosts list and include a specific port for each host.
+ * ldap_create() does not take a default port parameter so we must
+ * append one if we want something other than LDAP_PORT.
+ */
+static void
+sudo_ldap_conf_add_ports()
+{
+
+    char *host, *port, defport[13];
+    char hostbuf[LINE_MAX * 2];
+
+    hostbuf[0] = '\0';
+    if (snprintf(defport, sizeof(defport), ":%d", ldap_conf.port) >= sizeof(defport))
+       errorx(1, "sudo_ldap_conf_add_ports: port too large");
+
+    for ((host = strtok(ldap_conf.host, " \t")); host; (host = strtok(NULL, " \t"))) {
+       if (hostbuf[0] != '\0') {
+           if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
+               goto toobig;
+       }
+
+       if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
+           goto toobig;
+       /* Append port if there is not one already. */
+       if ((port = strrchr(host, ':')) == NULL || !isdigit(port[1])) {
+           if (strlcat(hostbuf, defport, sizeof(hostbuf)) >= sizeof(hostbuf))
+               goto toobig;
+       }
+    }
+
+    free(ldap_conf.host);
+    ldap_conf.host = estrdup(hostbuf);
+    return;
+
+toobig:
+    errorx(1, "sudo_ldap_conf_add_ports: out of space expanding hostbuf");
+}
+#endif
 
 #ifndef HAVE_LDAP_INITIALIZE
 /*
@@ -220,7 +313,7 @@ sudo_ldap_parse_uri(uri_list)
            nldaps++;
            host = uri + 8;
        } else {
-           warnx("unsupported LDAP uri type: %s", uri);
+           warningx("unsupported LDAP uri type: %s", uri);
            goto done;
        }
 
@@ -248,17 +341,17 @@ sudo_ldap_parse_uri(uri_list)
        }
     }
     if (hostbuf[0] == '\0') {
-       warnx("invalid uri: %s", uri_list);
+       warningx("invalid uri: %s", uri_list);
        goto done;
     }
 
     if (nldaps != 0) {
        if (nldap != 0) {
-           warnx("cannot mix ldap and ldaps URIs");
+           warningx("cannot mix ldap and ldaps URIs");
            goto done;
        }
        if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
-           warnx("cannot mix ldaps and starttls");
+           warningx("cannot mix ldaps and starttls");
            goto done;
        }
        ldap_conf.ssl_mode = SUDO_LDAP_SSL;
@@ -273,7 +366,7 @@ done:
     return(rc);
 
 toobig:
-    errx(1, "sudo_ldap_parse_uri: out of space building hostbuf");
+    errorx(1, "sudo_ldap_parse_uri: out of space building hostbuf");
 }
 #endif /* HAVE_LDAP_INITIALIZE */
 
@@ -294,22 +387,29 @@ sudo_ldap_init(ldp, host, port)
        rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
            ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
        if (rc != LDAP_SUCCESS) {
-           warnx("unable to initialize SSL cert and key db: %s",
+           warningx("unable to initialize SSL cert and key db: %s",
                ldapssl_err2string(rc));
            goto done;
        }
 
        DPRINTF(("ldapssl_init(%s, %d, 1)", host, port), 2);
-       if ((ld = ldapssl_init(host, port, 1)) == NULL)
-           goto done;
+       if ((ld = ldapssl_init(host, port, 1)) != NULL)
+           rc = LDAP_SUCCESS;
     } else
 #endif
     {
-       DPRINTF(("ldap_init(%s, %d)", host, port), 2);
-       if ((ld = ldap_init(host, port)) == NULL)
+#ifdef HAVE_LDAP_CREATE
+       DPRINTF(("ldap_create()"), 2);
+       if ((rc = ldap_create(&ld)) != LDAP_SUCCESS)
            goto done;
+       DPRINTF(("ldap_set_option(LDAP_OPT_HOST_NAME, %s)", host), 2);
+       rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, host);
+#else
+       DPRINTF(("ldap_init(%s, %d)", host, port), 2);
+       if ((ld = ldap_init(host, port)) != NULL)
+           rc = LDAP_SUCCESS;
+#endif
     }
-    rc = LDAP_SUCCESS;
 
 done:
     *ldp = ld;
@@ -321,30 +421,34 @@ done:
  * netgroup, else FALSE.
  */
 int
-sudo_ldap_check_user_netgroup(ld, entry)
+sudo_ldap_check_user_netgroup(ld, entry, user)
     LDAP *ld;
     LDAPMessage *entry;
+    char *user;
 {
-    char **v = NULL, **p = NULL;
+    struct berval **bv, **p;
+    char *val;
     int ret = FALSE;
 
     if (!entry)
        return(ret);
 
     /* get the values from the entry */
-    v = ldap_get_values(ld, entry, "sudoUser");
+    bv = ldap_get_values_len(ld, entry, "sudoUser");
+    if (bv == NULL)
+       return(ret);
 
     /* walk through values */
-    for (p = v; p && *p && !ret; p++) {
+    for (p = bv; *p != NULL && !ret; p++) {
+       val = (*p)->bv_val;
        /* match any */
-       if (netgr_matches(*p, NULL, NULL, user_name))
+       if (netgr_matches(val, NULL, NULL, user))
            ret = TRUE;
-       DPRINTF(("ldap sudoUser netgroup '%s' ... %s", *p,
+       DPRINTF(("ldap sudoUser netgroup '%s' ... %s", val,
            ret ? "MATCH!" : "not"), 2);
     }
 
-    if (v)
-       ldap_value_free(v);     /* cleanup */
+    ldap_value_free_len(bv);   /* cleanup */
 
     return(ret);
 }
@@ -358,50 +462,51 @@ sudo_ldap_check_host(ld, entry)
     LDAP *ld;
     LDAPMessage *entry;
 {
-    char **v = NULL, **p = NULL;
+    struct berval **bv, **p;
+    char *val;
     int ret = FALSE;
 
     if (!entry)
        return(ret);
 
     /* get the values from the entry */
-    v = ldap_get_values(ld, entry, "sudoHost");
+    bv = ldap_get_values_len(ld, entry, "sudoHost");
+    if (bv == NULL)
+       return(ret);
 
     /* walk through values */
-    for (p = v; p && *p && !ret; p++) {
+    for (p = bv; *p != NULL && !ret; p++) {
+       val = (*p)->bv_val;
        /* match any or address or netgroup or hostname */
-       if (!strcmp(*p, "ALL") || addr_matches(*p) ||
-           netgr_matches(*p, user_host, user_shost, NULL) ||
-           !hostname_matches(user_shost, user_host, *p))
+       if (!strcmp(val, "ALL") || addr_matches(val) ||
+           netgr_matches(val, user_host, user_shost, NULL) ||
+           hostname_matches(user_shost, user_host, val))
            ret = TRUE;
-       DPRINTF(("ldap sudoHost '%s' ... %s", *p,
+       DPRINTF(("ldap sudoHost '%s' ... %s", val,
            ret ? "MATCH!" : "not"), 2);
     }
 
-    if (v)
-       ldap_value_free(v);     /* cleanup */
+    ldap_value_free_len(bv);   /* cleanup */
 
     return(ret);
 }
 
-/*
- * Walk through search results and return TRUE if we have a runas match,
- * else FALSE.
- * Since the runas directive in /etc/sudoers is optional, so is sudoRunAs.
- */
 int
-sudo_ldap_check_runas(ld, entry)
+sudo_ldap_check_runas_user(ld, entry)
     LDAP *ld;
     LDAPMessage *entry;
 {
-    char **v = NULL, **p = NULL;
+    struct berval **bv, **p;
+    char *val;
     int ret = FALSE;
 
-    if (!entry)
-       return(ret);
+    if (!runas_pw)
+       return(UNSPEC);
 
-    /* get the values from the entry */
-    v = ldap_get_values(ld, entry, "sudoRunAs");
+    /* get the runas user from the entry */
+    bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
+    if (bv == NULL)
+       bv = ldap_get_values_len(ld, entry, "sudoRunAs"); /* old style */
 
     /*
      * BUG:
@@ -416,52 +521,104 @@ sudo_ldap_check_runas(ld, entry)
      * For now just require users to always use -u option unless its set
      * in the global defaults. This behaviour is no different than the global
      * /etc/sudoers.
-     *
+     * 
      * Sigh - maybe add this feature later
-     *
      */
 
     /*
      * If there are no runas entries, match runas_default against
      * what the user specified on the command line.
      */
-    if (!v)
-       ret = !strcasecmp(runas_pw->pw_name, def_runas_default);
+    if (bv == NULL)
+       return(!strcasecmp(runas_pw->pw_name, def_runas_default));
 
     /* walk through values returned, looking for a match */
-    for (p = v; p && *p && !ret; p++) {
-       switch (*p[0]) {
+    for (p = bv; *p != NULL && !ret; p++) {
+       val = (*p)->bv_val;
+       switch (val[0]) {
        case '+':
-           if (netgr_matches(*p, NULL, NULL, runas_pw->pw_name))
+           if (netgr_matches(val, NULL, NULL, runas_pw->pw_name))
                ret = TRUE;
            break;
        case '%':
-           if (usergr_matches(*p, runas_pw->pw_name, runas_pw))
+           if (usergr_matches(val, runas_pw->pw_name, runas_pw))
                ret = TRUE;
            break;
        case 'A':
-           if (strcmp(*p, "ALL") == 0) {
+           if (strcmp(val, "ALL") == 0) {
                ret = TRUE;
                break;
            }
            /* FALLTHROUGH */
        default:
-           if (strcasecmp(*p, runas_pw->pw_name) == 0)
+           if (strcasecmp(val, runas_pw->pw_name) == 0)
                ret = TRUE;
            break;
        }
-       DPRINTF(("ldap sudoRunAs '%s' ... %s", *p,
+       DPRINTF(("ldap sudoRunAsUser '%s' ... %s", val,
            ret ? "MATCH!" : "not"), 2);
     }
 
-    if (v)
-       ldap_value_free(v);     /* cleanup */
+    ldap_value_free_len(bv);   /* cleanup */
+
+    return(ret);
+}
+
+int
+sudo_ldap_check_runas_group(ld, entry)
+    LDAP *ld;
+    LDAPMessage *entry;
+{
+    struct berval **bv, **p;
+    char *val;
+    int ret = FALSE;
+
+    /* runas_gr is only set if the user specified the -g flag */
+    if (!runas_gr)
+       return(UNSPEC);
+
+    /* get the values from the entry */
+    bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
+    if (bv == NULL)
+       return(ret);
+
+    /* walk through values returned, looking for a match */
+    for (p = bv; *p != NULL && !ret; p++) {
+       val = (*p)->bv_val;
+       if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
+           ret = TRUE;
+       DPRINTF(("ldap sudoRunAsGroup '%s' ... %s", val,
+           ret ? "MATCH!" : "not"), 2);
+    }
+
+    ldap_value_free_len(bv);   /* cleanup */
 
     return(ret);
 }
 
 /*
- * Walk through search results and return TRUE if we have a command match.
+ * Walk through search results and return TRUE if we have a runas match,
+ * else FALSE.  RunAs info is optional.
+ */
+int
+sudo_ldap_check_runas(ld, entry)
+    LDAP *ld;
+    LDAPMessage *entry;
+{
+    int ret;
+
+    if (!entry)
+       return(FALSE);
+
+    ret = sudo_ldap_check_runas_user(ld, entry) != FALSE &&
+       sudo_ldap_check_runas_group(ld, entry) != FALSE;
+
+    return(ret);
+}
+
+/*
+ * Walk through search results and return TRUE if we have a command match,
+ * FALSE if disallowed and UNSPEC if not matched.
  */
 int
 sudo_ldap_check_command(ld, entry, setenv_implied)
@@ -469,32 +626,35 @@ sudo_ldap_check_command(ld, entry, setenv_implied)
     LDAPMessage *entry;
     int *setenv_implied;
 {
-    char *allowed_cmnd, *allowed_args, **v = NULL, **p = NULL;
-    int foundbang, ret = FALSE;
+    struct berval **bv, **p;
+    char *allowed_cmnd, *allowed_args, *val;
+    int foundbang, ret = UNSPEC;
 
     if (!entry)
        return(ret);
 
-    v = ldap_get_values(ld, entry, "sudoCommand");
+    bv = ldap_get_values_len(ld, entry, "sudoCommand");
+    if (bv == NULL)
+       return(ret);
 
-    /* get_first_entry */
-    for (p = v; p && *p && ret >= 0; p++) {
+    for (p = bv; *p != NULL && ret != FALSE; p++) {
+       val = (*p)->bv_val;
        /* Match against ALL ? */
-       if (!strcmp(*p, "ALL")) {
+       if (!strcmp(val, "ALL")) {
            ret = TRUE;
            if (setenv_implied != NULL)
                *setenv_implied = TRUE;
-           DPRINTF(("ldap sudoCommand '%s' ... MATCH!", *p), 2);
+           DPRINTF(("ldap sudoCommand '%s' ... MATCH!", val), 2);
            continue;
        }
 
        /* check for !command */
-       if (**p == '!') {
+       if (*val == '!') {
            foundbang = TRUE;
-           allowed_cmnd = estrdup(1 + *p);     /* !command */
+           allowed_cmnd = estrdup(1 + val);    /* !command */
        } else {
            foundbang = FALSE;
-           allowed_cmnd = estrdup(*p);         /* command */
+           allowed_cmnd = estrdup(val);        /* command */
        }
 
        /* split optional args away from command */
@@ -508,19 +668,54 @@ sudo_ldap_check_command(ld, entry, setenv_implied)
             * If allowed (no bang) set ret but keep on checking.
             * If disallowed (bang), exit loop.
             */
-           ret = foundbang ? -1 : TRUE;
+           ret = foundbang ? FALSE : TRUE;
        }
-       DPRINTF(("ldap sudoCommand '%s' ... %s", *p,
+       DPRINTF(("ldap sudoCommand '%s' ... %s", val,
            ret == TRUE ? "MATCH!" : "not"), 2);
 
        efree(allowed_cmnd);    /* cleanup */
     }
 
-    if (v)
-       ldap_value_free(v);     /* more cleanup */
+    ldap_value_free_len(bv);   /* more cleanup */
 
-    /* return TRUE if we found at least one ALLOW and no DENY */
-    return(ret > 0);
+    return(ret);
+}
+
+/*
+ * Search for boolean "option" in sudoOption.
+ * Returns TRUE if found and allowed, FALSE if negated, else UNSPEC.
+ */
+int
+sudo_ldap_check_bool(ld, entry, option)
+    LDAP *ld;
+    LDAPMessage *entry;
+    char *option;
+{
+    struct berval **bv, **p;
+    char ch, *var;
+    int ret = UNSPEC;
+
+    if (entry == NULL)
+       return(UNSPEC);
+
+    bv = ldap_get_values_len(ld, entry, "sudoOption");
+    if (bv == NULL)
+       return(ret);
+
+    /* walk through options */
+    for (p = bv; *p != NULL; p++) {
+       var = (*p)->bv_val;;
+       DPRINTF(("ldap sudoOption: '%s'", var), 2);
+
+       if ((ch = *var) == '!')
+           var++;
+       if (strcmp(var, option) == 0)
+           ret = (ch != '!');
+    }
+
+    ldap_value_free_len(bv);
+
+    return(ret);
 }
 
 /*
@@ -532,18 +727,20 @@ sudo_ldap_parse_options(ld, entry)
     LDAP *ld;
     LDAPMessage *entry;
 {
-    char op, *var, *val, **v = NULL, **p = NULL;
+    struct berval **bv, **p;
+    char op, *var, *val;
 
-    if (!entry)
+    if (entry == NULL)
        return;
 
-    v = ldap_get_values(ld, entry, "sudoOption");
+    bv = ldap_get_values_len(ld, entry, "sudoOption");
+    if (bv == NULL)
+       return;
 
     /* walk through options */
-    for (p = v; p && *p; p++) {
-
-       DPRINTF(("ldap sudoOption: '%s'", *p), 2);
-       var = estrdup(*p);
+    for (p = bv; *p != NULL; p++) {
+       var = estrdup((*p)->bv_val);
+       DPRINTF(("ldap sudoOption: '%s'", var), 2);
 
        /* check for equals sign past first char */
        val = strchr(var, '=');
@@ -568,96 +765,63 @@ sudo_ldap_parse_options(ld, entry)
        efree(var);
     }
 
-    if (v)
-       ldap_value_free(v);
-}
-
-/*
- * Concatenate strings, dynamically growing them as necessary.
- * Strings can be arbitrarily long and are allocated/reallocated on
- * the fly.  Make sure to free them when you are done.
- *
- * Usage:
- *
- * char *s=NULL;
- * size_t sz;
- *
- * ncat(&s,&sz,"This ");
- * ncat(&s,&sz,"is ");
- * ncat(&s,&sz,"an ");
- * ncat(&s,&sz,"arbitrarily ");
- * ncat(&s,&sz,"long ");
- * ncat(&s,&sz,"string!");
- *
- * printf("String Value='%s', but has %d bytes allocated\n",s,sz);
- *
- */
-void
-ncat(s, sz, src)
-    char **s;
-    size_t *sz;
-    char *src;
-{
-    size_t nsz;
-
-    /* handle initial alloc */
-    if (*s == NULL) {
-       *s = estrdup(src);
-       *sz = strlen(src) + 1;
-       return;
-    }
-    /* handle realloc */
-    nsz = strlen(*s) + strlen(src) + 1;
-    if (*sz < nsz)
-       *s = erealloc((void *) *s, *sz = nsz * 2);
-    strlcat(*s, src, *sz);
+    ldap_value_free_len(bv);
 }
 
 /*
  * builds together a filter to check against ldap
  */
 char *
-sudo_ldap_build_pass1()
+sudo_ldap_build_pass1(pw)
+    struct passwd *pw;
 {
     struct group *grp;
     size_t sz;
-    char *b = NULL;
+    char *buf;
     int i;
 
-    /* global OR */
-    ncat(&b, &sz, "(|");
+    /* Start with (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
+    sz = 29 + strlen(pw->pw_name);
 
-    /* build filter sudoUser=user_name */
-    ncat(&b, &sz, "(sudoUser=");
-    ncat(&b, &sz, user_name);
-    ncat(&b, &sz, ")");
+    /* Add space for groups */
+    if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL)
+       sz += 12 + strlen(grp->gr_name);        /* primary group */
+    for (i = 0; i < user_ngroups; i++) {
+       if (user_groups[i] == pw->pw_gid)
+           continue;
+       if ((grp = sudo_getgrgid(user_groups[i])) != NULL)
+           sz += 12 + strlen(grp->gr_name);    /* supplementary group */
+    }
+    buf = emalloc(sz);
+
+    /* Global OR + sudoUser=user_name filter */
+    (void) strlcpy(buf, "(|(sudoUser=", sz);
+    (void) strlcat(buf, pw->pw_name, sz);
+    (void) strlcat(buf, ")", sz);
 
     /* Append primary group */
-    grp = getgrgid(user_gid);
-    if (grp != NULL) {
-       ncat(&b, &sz, "(sudoUser=%");
-       ncat(&b, &sz, grp -> gr_name);
-       ncat(&b, &sz, ")");
+    if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
+       (void) strlcat(buf, "(sudoUser=%", sz);
+       (void) strlcat(buf, grp->gr_name, sz);
+       (void) strlcat(buf, ")", sz);
     }
 
     /* Append supplementary groups */
     for (i = 0; i < user_ngroups; i++) {
-       if (user_groups[i] == user_gid)
+       if (user_groups[i] == pw->pw_gid)
            continue;
-       if ((grp = getgrgid(user_groups[i])) != NULL) {
-           ncat(&b, &sz, "(sudoUser=%");
-           ncat(&b, &sz, grp -> gr_name);
-           ncat(&b, &sz, ")");
+       if ((grp = sudo_getgrgid(user_groups[i])) != NULL) {
+           (void) strlcat(buf, "(sudoUser=%", sz);
+           (void) strlcat(buf, grp->gr_name, sz);
+           (void) strlcat(buf, ")", sz);
        }
     }
 
-    /* Add ALL to list */
-    ncat(&b, &sz, "(sudoUser=ALL)");
-
-    /* End of OR List */
-    ncat(&b, &sz, ")");
+    /* Add ALL to list and end the global OR */
+    if (strlcat(buf, "(sudoUser=ALL))", sz) >= sz)
+       errorx(1, "sudo_ldap_build_pass1 allocation mismatch");
 
-    return(b);
+    return(buf);
 }
 
 /*
@@ -699,11 +863,33 @@ _atobool(s)
     return(-1);
 }
 
+static void
+sudo_ldap_read_secret(path)
+    const char *path;
+{
+    FILE *fp;
+    char buf[LINE_MAX], *cp;
+
+    if ((fp = fopen(_PATH_LDAP_SECRET, "r")) != NULL) {
+       if (fgets(buf, sizeof(buf), fp) != NULL) {
+           if ((cp = strchr(buf, '\n')) != NULL)
+               *cp = '\0';
+           /* copy to bindpw and binddn */
+           efree(ldap_conf.bindpw);
+           ldap_conf.bindpw = estrdup(buf);
+           efree(ldap_conf.binddn);
+           ldap_conf.binddn = ldap_conf.rootbinddn;
+           ldap_conf.rootbinddn = NULL;
+       }
+       fclose(fp);
+    }
+}
+
 int
 sudo_ldap_read_config()
 {
-    FILE *f;
-    char buf[LINE_MAX], *c, *keyword, *value;
+    FILE *fp;
+    char *cp, *keyword, *value;
     struct ldap_config_table *cur;
 
     /* defaults */
@@ -712,39 +898,27 @@ sudo_ldap_read_config()
     ldap_conf.tls_checkpeer = -1;
     ldap_conf.timelimit = -1;
     ldap_conf.bind_timelimit = -1;
+    ldap_conf.use_sasl = -1;
+    ldap_conf.rootuse_sasl = -1;
 
-    if ((f = fopen(_PATH_LDAP_CONF, "r")) == NULL)
+    if ((fp = fopen(_PATH_LDAP_CONF, "r")) == NULL)
        return(FALSE);
 
-    while (fgets(buf, sizeof(buf), f)) {
-       /* ignore text after comment character */
-       if ((c = strchr(buf, '#')) != NULL)
-           *c = '\0';
-
-       /* skip leading whitespace */
-       for (c = buf; isspace((unsigned char) *c); c++)
-           /* nothing */;
-
-       if (*c == '\0' || *c == '\n')
+    while ((cp = sudo_parseln(fp)) != NULL) {
+       if (*cp == '\0')
            continue;           /* skip empty line */
 
-       /* properly terminate keyword string */
-       keyword = c;
-       while (*c && !isspace((unsigned char) *c))
-           c++;
-       if (*c)
-           *c++ = '\0';        /* terminate keyword */
+       /* split into keyword and value */
+       keyword = cp;
+       while (*cp && !isblank((unsigned char) *cp))
+           cp++;
+       if (*cp)
+           *cp++ = '\0';       /* terminate keyword */
 
        /* skip whitespace before value */
-       while (isspace((unsigned char) *c))
-           c++;
-       value = c;
-
-       /* trim whitespace after value */
-       while (*c)
-           c++;                /* wind to end */
-       while (--c > value && isspace((unsigned char) *c))
-           *c = '\0';
+       while (isblank((unsigned char) *cp))
+           cp++;
+       value = cp;
 
        /* Look up keyword in config table. */
        for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
@@ -765,10 +939,10 @@ sudo_ldap_read_config()
            }
        }
     }
-    fclose(f);
+    fclose(fp);
 
     if (!ldap_conf.host)
-       ldap_conf.host = "localhost";
+       ldap_conf.host = estrdup("localhost");
 
     if (ldap_conf.bind_timelimit > 0)
        ldap_conf.bind_timelimit *= 1000;       /* convert to ms */
@@ -777,25 +951,25 @@ sudo_ldap_read_config()
        fprintf(stderr, "LDAP Config Summary\n");
        fprintf(stderr, "===================\n");
        if (ldap_conf.uri) {
-           fprintf(stderr, "uri          %s\n", ldap_conf.uri);
+           fprintf(stderr, "uri              %s\n", ldap_conf.uri);
        } else {
-           fprintf(stderr, "host         %s\n", ldap_conf.host ?
+           fprintf(stderr, "host             %s\n", ldap_conf.host ?
                ldap_conf.host : "(NONE)");
-           fprintf(stderr, "port         %d\n", ldap_conf.port);
+           fprintf(stderr, "port             %d\n", ldap_conf.port);
        }
-       fprintf(stderr, "ldap_version %d\n", ldap_conf.version);
+       fprintf(stderr, "ldap_version     %d\n", ldap_conf.version);
 
-       fprintf(stderr, "sudoers_base %s\n", ldap_conf.base ?
+       fprintf(stderr, "sudoers_base     %s\n", ldap_conf.base ?
            ldap_conf.base : "(NONE) <---Sudo will ignore ldap)");
-       fprintf(stderr, "binddn       %s\n", ldap_conf.binddn ?
+       fprintf(stderr, "binddn           %s\n", ldap_conf.binddn ?
            ldap_conf.binddn : "(anonymous)");
-       fprintf(stderr, "bindpw       %s\n", ldap_conf.bindpw ?
+       fprintf(stderr, "bindpw           %s\n", ldap_conf.bindpw ?
            ldap_conf.bindpw : "(anonymous)");
        if (ldap_conf.bind_timelimit > 0)
-           fprintf(stderr, "bind_timelimit  %d\n", ldap_conf.bind_timelimit);
+           fprintf(stderr, "bind_timelimit   %d\n", ldap_conf.bind_timelimit);
        if (ldap_conf.timelimit > 0)
-           fprintf(stderr, "timelimit    %d\n", ldap_conf.timelimit);
-       fprintf(stderr, "ssl          %s\n", ldap_conf.ssl ?
+           fprintf(stderr, "timelimit        %d\n", ldap_conf.timelimit);
+       fprintf(stderr, "ssl              %s\n", ldap_conf.ssl ?
            ldap_conf.ssl : "(no)");
        if (ldap_conf.tls_checkpeer != -1)
            fprintf(stderr, "tls_checkpeer    %s\n", ldap_conf.tls_checkpeer ?
@@ -812,6 +986,21 @@ sudo_ldap_read_config()
            fprintf(stderr, "tls_certfile     %s\n", ldap_conf.tls_certfile);
        if (ldap_conf.tls_keyfile != NULL)
            fprintf(stderr, "tls_keyfile      %s\n", ldap_conf.tls_keyfile);
+#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
+       if (ldap_conf.use_sasl != -1) {
+           fprintf(stderr, "use_sasl         %s\n",
+               ldap_conf.use_sasl ? "yes" : "no");
+           fprintf(stderr, "sasl_auth_id     %s\n", ldap_conf.sasl_auth_id ?
+               ldap_conf.sasl_auth_id : "(NONE)");
+           fprintf(stderr, "rootuse_sasl     %d\n", ldap_conf.rootuse_sasl);
+           fprintf(stderr, "rootsasl_auth_id %s\n", ldap_conf.rootsasl_auth_id ?
+               ldap_conf.rootsasl_auth_id : "(NONE)");
+           fprintf(stderr, "sasl_secprops    %s\n", ldap_conf.sasl_secprops ?
+               ldap_conf.sasl_secprops : "(NONE)");
+           fprintf(stderr, "krb5_ccname      %s\n", ldap_conf.krb5_ccname ?
+               ldap_conf.krb5_ccname : "(NONE)");
+       }
+#endif
        fprintf(stderr, "===================\n");
     }
     if (!ldap_conf.base)
@@ -845,124 +1034,441 @@ sudo_ldap_read_config()
     }
 #endif
 
-    /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */
-    if (!ldap_conf.uri && ldap_conf.port < 0)
-       ldap_conf.port =
-           ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT;
+    if (!ldap_conf.uri) {
+       /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */
+       if (ldap_conf.port < 0)
+           ldap_conf.port =
+               ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT;
+
+#ifdef HAVE_LDAP_CREATE
+       /*
+        * Cannot specify port directly to ldap_create(), each host must
+        * include :port to override the default.
+        */
+       if (ldap_conf.port != LDAP_PORT)
+           sudo_ldap_conf_add_ports();
+#endif
+    }
 
     /* If rootbinddn set, read in /etc/ldap.secret if it exists. */
-    if (ldap_conf.rootbinddn) {
-       if ((f = fopen(_PATH_LDAP_SECRET, "r")) != NULL) {
-           if (fgets(buf, sizeof(buf), f) != NULL) {
-               /* removing trailing newlines */
-               for (c = buf; *c != '\0'; c++)
-                   continue;
-               while (--c > buf && *c == '\n')
-                   *c = '\0';
-               /* copy to bindpw and binddn */
-               efree(ldap_conf.bindpw);
-               ldap_conf.bindpw = estrdup(buf);
-               efree(ldap_conf.binddn);
-               ldap_conf.binddn = ldap_conf.rootbinddn;
-               ldap_conf.rootbinddn = NULL;
+    if (ldap_conf.rootbinddn)
+       sudo_ldap_read_secret(_PATH_LDAP_SECRET);
+
+#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
+    /*
+     * Make sure we can open the file specified by krb5_ccname.
+     */
+    if (ldap_conf.krb5_ccname != NULL) {
+       if (strncasecmp(ldap_conf.krb5_ccname, "FILE:", 5) == 0 ||
+           strncasecmp(ldap_conf.krb5_ccname, "WRFILE:", 7) == 0) {
+           value = ldap_conf.krb5_ccname +
+               (ldap_conf.krb5_ccname[4] == ':' ? 5 : 7);
+           if ((fp = fopen(value, "r")) != NULL) {
+               DPRINTF(("using krb5 credential cache: %s", value), 1);
+               fclose(fp);
+           } else {
+               /* Can't open it, just ignore the entry. */
+               DPRINTF(("unable to open krb5 credential cache: %s", value), 1);
+               efree(ldap_conf.krb5_ccname);
+               ldap_conf.krb5_ccname = NULL;
            }
-           fclose(f);
        }
     }
+#endif
     return(TRUE);
 }
 
 /*
- * like perl's join(sep,@ARGS)
+ * Extract the dn from an entry and return the first rdn from it.
  */
-char *
- _ldap_join_values(sep, v)
-    char *sep;
-    char **v;
+static char *
+sudo_ldap_get_first_rdn(ld, entry)
+    LDAP *ld;
+    LDAPMessage *entry;
 {
-    char *b = NULL, **p = NULL;
-    size_t sz = 0;
-
-    /* paste values together */
-    for (p = v; p && *p; p++) {
-       if (p != v && sep != NULL)
-           ncat(&b, &sz, sep); /* append separator */
-       ncat(&b, &sz, *p);      /* append value */
+#ifdef HAVE_LDAP_STR2DN
+    char *dn, *rdn = NULL;
+    LDAPDN tmpDN;
+
+    if ((dn = ldap_get_dn(ld, entry)) == NULL)
+       return(NULL);
+    if (ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP) == LDAP_SUCCESS) {
+       ldap_rdn2str(tmpDN[0], &rdn, LDAP_DN_FORMAT_UFN);
+       ldap_dnfree(tmpDN);
     }
+    ldap_memfree(dn);
+    return(rdn);
+#else
+    char *dn, **edn;
+
+    if ((dn = ldap_get_dn(ld, entry)) == NULL)
+       return(NULL);
+    edn = ldap_explode_dn(dn, 1);
+    ldap_memfree(dn);
+    return(edn ? edn[0] : NULL);
+#endif
+}
 
-    /* sanity check */
-    if (b[0] == '\0') {
-       /* something went wrong, put something here */
-       ncat(&b, &sz, "(empty list)");  /* append value */
+/*
+ * Fetch and display the global Options.
+ */
+int
+sudo_ldap_display_defaults(nss, pw, lbuf)
+    struct sudo_nss *nss;
+    struct passwd *pw;
+    struct lbuf *lbuf;
+{
+    struct berval **bv, **p;
+    LDAP *ld = (LDAP *) nss->handle;
+    LDAPMessage *entry = NULL, *result = NULL;
+    char *prefix = NULL;
+    int rc, count = 0;
+
+    if (ld == NULL)
+       return(-1);
+
+    rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE,
+       "cn=defaults", NULL, 0, NULL, NULL, NULL, -1, &result);
+    if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
+       bv = ldap_get_values_len(ld, entry, "sudoOption");
+       if (bv != NULL) {
+           if (lbuf->len == 0)
+               prefix = "    ";
+           else
+               prefix = ", ";
+           for (p = bv; *p != NULL; p++) {
+               lbuf_append(lbuf, prefix, (*p)->bv_val, NULL);
+               prefix = ", ";
+               count++;
+           }
+           ldap_value_free_len(bv);
+       }
     }
+    if (result)
+       ldap_msgfree(result);
+    return(count);
+}
 
-    return(b);
+/*
+ * STUB
+ */
+int
+sudo_ldap_display_bound_defaults(nss, pw, lbuf)
+    struct sudo_nss *nss;
+    struct passwd *pw;
+    struct lbuf *lbuf;
+{
+    return(1);
 }
 
-char *sudo_ldap_cm_list = NULL;
-size_t sudo_ldap_cm_list_size;
+/*
+ * Print a record in the short form, ala file sudoers.
+ */
+int
+sudo_ldap_display_entry_short(ld, entry, lbuf)
+    LDAP *ld;
+    LDAPMessage *entry;
+    struct lbuf *lbuf;
+{
+    struct berval **bv, **p;
+    int count = 0;
+
+    lbuf_append(lbuf, "    (", NULL);
+
+    /* get the RunAsUser Values from the entry */
+    bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
+    if (bv == NULL)
+       bv = ldap_get_values_len(ld, entry, "sudoRunAs");
+    if (bv != NULL) {
+       for (p = bv; *p != NULL; p++) {
+           if (p != bv)
+               lbuf_append(lbuf, ", ", NULL);
+           lbuf_append(lbuf, (*p)->bv_val, NULL);
+       }
+       ldap_value_free_len(bv);
+    } else
+       lbuf_append(lbuf, def_runas_default, NULL);
+
+    /* get the RunAsGroup Values from the entry */
+    bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
+    if (bv != NULL) {
+       lbuf_append(lbuf, " : ", NULL);
+       for (p = bv; *p != NULL; p++) {
+           if (p != bv)
+               lbuf_append(lbuf, ", ", NULL);
+           lbuf_append(lbuf, (*p)->bv_val, NULL);
+       }
+       ldap_value_free_len(bv);
+    }
+    lbuf_append(lbuf, ") ", NULL);
+
+    /* get the Option Values from the entry */
+    bv = ldap_get_values_len(ld, entry, "sudoOption");
+    if (bv != NULL) {
+       char *cp, *tag;
+
+       for (p = bv; *p != NULL; p++) {
+           cp = (*p)->bv_val;
+           if (*cp == '!')
+               cp++;
+           tag = NULL;
+           if (strcmp(cp, "authenticate") == 0)
+               tag = (*p)->bv_val[0] == '!' ?
+                   "NOPASSWD: " : "PASSWD: ";
+           else if (strcmp(cp, "noexec") == 0)
+               tag = (*p)->bv_val[0] == '!' ?
+                   "EXEC: " : "NOEXEC: ";
+           else if (strcmp(cp, "setenv") == 0)
+               tag = (*p)->bv_val[0] == '!' ?
+                   "NOSETENV: " : "SETENV: ";
+           if (tag != NULL)
+               lbuf_append(lbuf, tag, NULL);
+           /* XXX - ignores other options */
+       }
+       ldap_value_free_len(bv);
+    }
+
+    /* get the Command Values from the entry */
+    bv = ldap_get_values_len(ld, entry, "sudoCommand");
+    if (bv != NULL) {
+       for (p = bv; *p != NULL; p++) {
+           if (p != bv)
+               lbuf_append(lbuf, ", ", NULL);
+           lbuf_append(lbuf, (*p)->bv_val, NULL);
+           count++;
+       }
+       ldap_value_free_len(bv);
+    }
+
+    lbuf_print(lbuf);          /* forces a newline */
+    return(count);
+}
 
-#define SAVE_LIST(x) ncat(&sudo_ldap_cm_list,&sudo_ldap_cm_list_size,(x))
 /*
- * Walks through search result and returns TRUE if we have a
- * command match
+ * Print a record in the long form.
  */
 int
-sudo_ldap_add_match(ld, entry, pwflag)
+sudo_ldap_display_entry_long(ld, entry, lbuf)
     LDAP *ld;
     LDAPMessage *entry;
-    int pwflag;
+    struct lbuf *lbuf;
 {
-    char *dn, **edn, **v = NULL;
-
-    /* if we are not collecting matches, then don't save them */
-    if (pwflag != I_LISTPW)
-       return(TRUE);
-
-    /* collect the dn, only show the rdn */
-    dn = ldap_get_dn(ld, entry);
-    edn = dn ? ldap_explode_dn(dn, 1) : NULL;
-    SAVE_LIST("\nLDAP Role: ");
-    SAVE_LIST((edn && *edn) ? *edn : "UNKNOWN");
-    SAVE_LIST("\n");
-    if (dn)
-       ldap_memfree(dn);
-    if (edn)
-       ldap_value_free(edn);
-
-    /* get the Runas Values from the entry */
-    v = ldap_get_values(ld, entry, "sudoRunAs");
-    if (v && *v) {
-       SAVE_LIST("  RunAs: (");
-       SAVE_LIST(_ldap_join_values(", ", v));
-       SAVE_LIST(")\n");
+    struct berval **bv, **p;
+    char *rdn;
+    int count = 0;
+
+    /* extract the dn, only show the first rdn */
+    rdn = sudo_ldap_get_first_rdn(ld, entry);
+    lbuf_print(lbuf);  /* force a newline */
+    lbuf_append(lbuf, "LDAP Role: ", rdn ? rdn : "UNKNOWN", NULL);
+    lbuf_print(lbuf);
+    if (rdn)
+       ldap_memfree(rdn);
+
+    /* get the RunAsUser Values from the entry */
+    lbuf_append(lbuf, "    RunAsUsers: ", NULL);
+    bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
+    if (bv == NULL)
+       bv = ldap_get_values_len(ld, entry, "sudoRunAs");
+    if (bv != NULL) {
+       for (p = bv; *p != NULL; p++) {
+           if (p != bv)
+               lbuf_append(lbuf, ", ", NULL);
+           lbuf_append(lbuf, (*p)->bv_val, NULL);
+       }
+       ldap_value_free_len(bv);
+    } else
+       lbuf_append(lbuf, def_runas_default, NULL);
+    lbuf_print(lbuf);
+
+    /* get the RunAsGroup Values from the entry */
+    bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
+    if (bv != NULL) {
+       lbuf_append(lbuf, "    RunAsGroups: ", NULL);
+       for (p = bv; *p != NULL; p++) {
+           if (p != bv)
+               lbuf_append(lbuf, ", ", NULL);
+           lbuf_append(lbuf, (*p)->bv_val, NULL);
+       }
+       ldap_value_free_len(bv);
+       lbuf_print(lbuf);
+    }
+
+    /* get the Option Values from the entry */
+    bv = ldap_get_values_len(ld, entry, "sudoOption");
+    if (bv != NULL) {
+       lbuf_append(lbuf, "    Options: ", NULL);
+       for (p = bv; *p != NULL; p++) {
+           if (p != bv)
+               lbuf_append(lbuf, ", ", NULL);
+           lbuf_append(lbuf, (*p)->bv_val, NULL);
+       }
+       ldap_value_free_len(bv);
+       lbuf_print(lbuf);
     }
-    if (v)
-       ldap_value_free(v);
 
     /* get the Command Values from the entry */
-    v = ldap_get_values(ld, entry, "sudoCommand");
-    if (v && *v) {
-       SAVE_LIST("  Commands:\n    ");
-       SAVE_LIST(_ldap_join_values("\n    ", v));
-       SAVE_LIST("\n");
-    } else {
-       SAVE_LIST("  Commands: NONE\n");
+    bv = ldap_get_values_len(ld, entry, "sudoCommand");
+    if (bv != NULL) {
+       lbuf_append(lbuf, "    Commands:", NULL);
+       lbuf_print(lbuf);
+       for (p = bv; *p != NULL; p++) {
+           lbuf_append(lbuf, "\t", (*p)->bv_val, NULL);
+           lbuf_print(lbuf);
+           count++;
+       }
+       ldap_value_free_len(bv);
     }
-    if (v)
-       ldap_value_free(v);
 
-    return(FALSE);             /* Don't stop at the first match */
+    return(count);
 }
-#undef SAVE_LIST
 
-void
-sudo_ldap_list_matches()
+/*
+ * Like sudo_ldap_lookup(), except we just print entries.
+ */
+int
+sudo_ldap_display_privs(nss, pw, lbuf)
+    struct sudo_nss *nss;
+    struct passwd *pw;
+    struct lbuf *lbuf;
 {
-    if (sudo_ldap_cm_list != NULL)
-       printf("%s", sudo_ldap_cm_list);
+    LDAP *ld = (LDAP *) nss->handle;
+    LDAPMessage *entry = NULL, *result = NULL;
+    char *filt;
+    int rc, do_netgr, count = 0;
+
+    if (ld == NULL)
+       return(-1);
+
+    /*
+     * Okay - time to search for anything that matches this user
+     * Lets limit it to only two queries of the LDAP server
+     *
+     * The first pass will look by the username, groups, and
+     * the keyword ALL.  We will then inspect the results that
+     * came back from the query.  We don't need to inspect the
+     * sudoUser in this pass since the LDAP server already scanned
+     * it for us.
+     *
+     * The second pass will return all the entries that contain
+     * user netgroups.  Then we take the netgroups returned and
+     * try to match them against the username.
+     */
+    for (do_netgr = 0; do_netgr < 2; do_netgr++) {
+       filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
+       DPRINTF(("ldap search '%s'", filt), 1);
+       rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
+           NULL, 0, NULL, NULL, NULL, -1, &result);
+       efree(filt);
+       if (rc != LDAP_SUCCESS)
+           continue;   /* no entries for this pass */
+
+       /* print each matching entry */
+       LDAP_FOREACH(entry, ld, result) {
+           if ((!do_netgr ||
+               sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
+               sudo_ldap_check_host(ld, entry)) {
+
+               if (long_list)
+                   count += sudo_ldap_display_entry_long(ld, entry, lbuf);
+               else
+                   count += sudo_ldap_display_entry_short(ld, entry, lbuf);
+           }
+       }
+       ldap_msgfree(result);
+       result = NULL;
+    }
+    return(count);
 }
 
+int
+sudo_ldap_display_cmnd(nss, pw)
+    struct sudo_nss *nss;
+    struct passwd *pw;
+{
+    LDAP *ld = (LDAP *) nss->handle;
+    LDAPMessage *entry = NULL, *result = NULL; /* used for searches */
+    char *filt;                                        /* used to parse attributes */
+    int rc, found, do_netgr;                   /* temp/final return values */
+
+    if (ld == NULL)
+       return(1);
+
+    /*
+     * Okay - time to search for anything that matches this user
+     * Lets limit it to only two queries of the LDAP server
+     *
+     * The first pass will look by the username, groups, and
+     * the keyword ALL.  We will then inspect the results that
+     * came back from the query.  We don't need to inspect the
+     * sudoUser in this pass since the LDAP server already scanned
+     * it for us.
+     *
+     * The second pass will return all the entries that contain
+     * user netgroups.  Then we take the netgroups returned and
+     * try to match them against the username.
+     */
+    for (found = FALSE, do_netgr = 0; !found && do_netgr < 2; do_netgr++) {
+       filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
+       DPRINTF(("ldap search '%s'", filt), 1);
+       rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
+           NULL, 0, NULL, NULL, NULL, -1, &result);
+       efree(filt);
+       if (rc != LDAP_SUCCESS)
+           continue;   /* no entries for this pass */
+
+       LDAP_FOREACH(entry, ld, result) {
+           if ((!do_netgr ||
+               sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
+               sudo_ldap_check_host(ld, entry) &&
+               sudo_ldap_check_command(ld, entry, NULL) &&
+               sudo_ldap_check_runas(ld, entry)) {
+
+               found = TRUE;
+               break;
+           }
+       }
+       ldap_msgfree(result);
+       result = NULL;
+    }
+
+    if (found)
+       printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
+           user_args ? " " : "", user_args ? user_args : "");
+   return(!found);
+}
+
+#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
+static int
+sudo_ldap_sasl_interact(ld, flags, _auth_id, _interact)
+    LDAP *ld;
+    unsigned int flags;
+    void *_auth_id;
+    void *_interact;
+{
+    char *auth_id = (char *)_auth_id;
+    sasl_interact_t *interact = (sasl_interact_t *)_interact;
+
+    for (; interact->id != SASL_CB_LIST_END; interact++) {
+       if (interact->id != SASL_CB_USER)
+           return(LDAP_PARAM_ERROR);
+
+       if (auth_id != NULL)
+           interact->result = auth_id;
+       else if (interact->defresult != NULL)
+           interact->result = interact->defresult;
+       else
+           interact->result = "";
+
+       interact->len = strlen(interact->result);
+#if SASL_VERSION_MAJOR < 2
+       interact->result = estrdup(interact->result);
+#endif /* SASL_VERSION_MAJOR < 2 */
+    }
+    return(LDAP_SUCCESS);
+}
+#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
+
 /*
  * Set LDAP options based on the config table.
  */
@@ -996,7 +1502,7 @@ sudo_ldap_set_options(ld)
            if (ival >= 0) {
                rc = ldap_set_option(conn, cur->opt_val, &ival);
                if (rc != LDAP_OPT_SUCCESS) {
-                   warnx("ldap_set_option: %s -> %d: %s",
+                   warningx("ldap_set_option: %s -> %d: %s",
                        cur->conf_str, ival, ldap_err2string(rc));
                    return(-1);
                }
@@ -1008,7 +1514,7 @@ sudo_ldap_set_options(ld)
            if (sval != NULL) {
                rc = ldap_set_option(conn, cur->opt_val, sval);
                if (rc != LDAP_OPT_SUCCESS) {
-                   warnx("ldap_set_option: %s -> %s: %s",
+                   warningx("ldap_set_option: %s -> %s: %s",
                        cur->conf_str, sval, ldap_err2string(rc));
                    return(-1);
                }
@@ -1026,7 +1532,7 @@ sudo_ldap_set_options(ld)
        tv.tv_usec = 0;
        rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
        if (rc != LDAP_OPT_SUCCESS) {
-           warnx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",
+           warningx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",
                (long)tv.tv_sec, ldap_err2string(rc));
            return(-1);
        }
@@ -1040,7 +1546,7 @@ sudo_ldap_set_options(ld)
        int val = LDAP_OPT_X_TLS_HARD;
        rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val);
        if (rc != LDAP_SUCCESS) {
-           warnx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",
+           warningx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",
                ldap_err2string(rc));
            return(-1);
        }
@@ -1051,16 +1557,102 @@ sudo_ldap_set_options(ld)
 }
 
 /*
- * Open a connection to the LDAP server.
+ * Connect to the LDAP server specified by ld
  */
-static LDAP *
-sudo_ldap_open()
+static int
+sudo_ldap_bind_s(ld)
+    LDAP *ld;
 {
-    LDAP *ld = NULL;
     int rc;
+    const char *old_ccname = user_ccname;
+#ifdef HAVE_GSS_KRB5_CCACHE_NAME
+    unsigned int status;
+#endif
+
+#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
+    if (ldap_conf.rootuse_sasl == TRUE ||
+       (ldap_conf.rootuse_sasl != FALSE && ldap_conf.use_sasl == TRUE)) {
+       void *auth_id = ldap_conf.rootsasl_auth_id ?
+           ldap_conf.rootsasl_auth_id : ldap_conf.sasl_auth_id;
+
+       if (ldap_conf.krb5_ccname != NULL) {
+#ifdef HAVE_GSS_KRB5_CCACHE_NAME
+           if (gss_krb5_ccache_name(&status, ldap_conf.krb5_ccname, &old_ccname)
+               != GSS_S_COMPLETE) {
+               old_ccname = NULL;
+               DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1);
+           }
+#else
+           sudo_setenv("KRB5CCNAME", ldap_conf.krb5_ccname, TRUE);
+#endif
+       }
+       rc = ldap_sasl_interactive_bind_s(ld, ldap_conf.binddn, "GSSAPI",
+           NULL, NULL, LDAP_SASL_QUIET, sudo_ldap_sasl_interact, auth_id);
+       if (ldap_conf.krb5_ccname != NULL) {
+#ifdef HAVE_GSS_KRB5_CCACHE_NAME
+           if (gss_krb5_ccache_name(&status, old_ccname, NULL) != GSS_S_COMPLETE)
+                   DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1);
+#else
+           if (old_ccname != NULL)
+               sudo_setenv("KRB5CCNAME", old_ccname, TRUE);
+           else
+               sudo_unsetenv("KRB5CCNAME");
+#endif
+       }
+       if (rc != LDAP_SUCCESS) {
+           warningx("ldap_sasl_interactive_bind_s(): %s", ldap_err2string(rc));
+           return(-1);
+       }
+       DPRINTF(("ldap_sasl_interactive_bind_s() ok"), 1);
+    } else
+#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
+#ifdef HAVE_LDAP_SASL_BIND_S
+    {
+       struct berval bv;
+
+       bv.bv_val = ldap_conf.bindpw ? ldap_conf.bindpw : "";
+       bv.bv_len = strlen(bv.bv_val);
+
+       rc = ldap_sasl_bind_s(ld, ldap_conf.binddn, LDAP_SASL_SIMPLE, &bv,
+           NULL, NULL, NULL);
+       if (rc != LDAP_SUCCESS) {
+           warningx("ldap_sasl_bind_s(): %s", ldap_err2string(rc));
+           return(-1);
+       }
+       DPRINTF(("ldap_sasl_bind_s() ok"), 1);
+    }
+#else
+    {
+       rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw);
+       if (rc != LDAP_SUCCESS) {
+           warningx("ldap_simple_bind_s(): %s", ldap_err2string(rc));
+           return(-1);
+       }
+       DPRINTF(("ldap_simple_bind_s() ok"), 1);
+    }
+#endif
+    return(0);
+}
+
+/*
+ * Open a connection to the LDAP server.
+ * Returns 0 on success and non-zero on failure.
+ */
+int
+sudo_ldap_open(nss)
+    struct sudo_nss *nss;
+{
+    LDAP *ld;
+    int rc, ldapnoinit = FALSE;
 
     if (!sudo_ldap_read_config())
-       return(NULL);
+       return(-1);
+
+    /* Prevent reading of user ldaprc and system defaults. */
+    if (getenv("LDAPNOINIT") == NULL) {
+       ldapnoinit = TRUE;
+       sudo_setenv("LDAPNOINIT", "1", TRUE);
+    }
 
     /* Connect to LDAP server */
 #ifdef HAVE_LDAP_INITIALIZE
@@ -1068,51 +1660,55 @@ sudo_ldap_open()
        DPRINTF(("ldap_initialize(ld, %s)", ldap_conf.uri), 2);
        rc = ldap_initialize(&ld, ldap_conf.uri);
     } else
-#endif /* HAVE_LDAP_INITIALIZE */
+#endif
        rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port);
     if (rc != LDAP_SUCCESS) {
-       warnx("unable to initialize LDAP: %s", ldap_err2string(rc));
-       return(NULL);
+       warningx("unable to initialize LDAP: %s", ldap_err2string(rc));
+       return(-1);
     }
 
+    if (ldapnoinit)
+       sudo_unsetenv("LDAPNOINIT");
+
     /* Set LDAP options */
     if (sudo_ldap_set_options(ld) < 0)
-       return(NULL);
+       return(-1);
 
     if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
 #ifdef HAVE_LDAP_START_TLS_S
        rc = ldap_start_tls_s(ld, NULL, NULL);
        if (rc != LDAP_SUCCESS) {
-           warnx("ldap_start_tls_s(): %s", ldap_err2string(rc));
-           ldap_unbind(ld);
-           return(NULL);
+           warningx("ldap_start_tls_s(): %s", ldap_err2string(rc));
+           return(-1);
        }
        DPRINTF(("ldap_start_tls_s() ok"), 1);
 #else
-       warnx("start_tls specified but LDAP libs do not support ldap_start_tls_s()");
+       warningx("start_tls specified but LDAP libs do not support ldap_start_tls_s()");
 #endif /* HAVE_LDAP_START_TLS_S */
     }
 
     /* Actually connect */
-    if ((rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw))) {
-       warnx("ldap_simple_bind_s: %s", ldap_err2string(rc));
-       return(NULL);
-    }
-    DPRINTF(("ldap_simple_bind_s() ok"), 1);
+    if (sudo_ldap_bind_s(ld) != 0)
+       return(-1);
 
-    return(ld);
+    nss->handle = ld;
+    return(0);
 }
 
-static void
-sudo_ldap_update_defaults(ld)
-    LDAP *ld;
+int
+sudo_ldap_setdefs(nss)
+    struct sudo_nss *nss;
 {
+    LDAP *ld = (LDAP *) nss->handle;
     LDAPMessage *entry = NULL, *result = NULL;  /* used for searches */
     int rc;                                     /* temp return value */
 
-    rc = ldap_search_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE,
-       "cn=defaults", NULL, 0, &result);
-    if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
+    if (ld == NULL)
+       return(-1);
+
+    rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE,
+       "cn=defaults", NULL, 0, NULL, NULL, NULL, -1, &result);
+    if (rc == 0 && (entry = ldap_first_entry(ld, result))) {
        DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
        sudo_ldap_parse_options(ld, entry);
     } else
@@ -1120,28 +1716,89 @@ sudo_ldap_update_defaults(ld)
 
     if (result)
        ldap_msgfree(result);
+
+    return(0);
 }
 
 /*
  * like sudoers_lookup() - only LDAP style
  */
 int
-sudo_ldap_check(pwflag)
+sudo_ldap_lookup(nss, ret, pwflag)
+    struct sudo_nss *nss;
+    int ret;
     int pwflag;
 {
-    LDAP *ld;
-    LDAPMessage *entry = NULL, *result = NULL; /* used for searches */
-    char *filt;                                        /* used to parse attributes */
-    int rc, ret = FALSE, do_netgr;             /* temp/final return values */
+    LDAP *ld = (LDAP *) nss->handle;
+    LDAPMessage *entry = NULL, *result = NULL;
+    char *filt;
+    int do_netgr, rc, matched;
     int setenv_implied;
-    int ldap_user_matches = FALSE, ldap_host_matches = FALSE; /* flags */
+    int ldap_user_matches = FALSE, ldap_host_matches = FALSE;
+    struct passwd *pw = list_pw ? list_pw : sudo_user.pw;
+
+    if (ld == NULL)
+       return(ret);
 
-    /* Open a connection to the LDAP server. */
-    if ((ld = sudo_ldap_open()) == NULL)
-       return(VALIDATE_ERROR);
+    if (pwflag) {
+       int doauth = UNSPEC;
+       enum def_tupple pwcheck = 
+           (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
+
+       for (matched = 0, do_netgr = 0; !matched && do_netgr < 2; do_netgr++) {
+           filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
+           rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
+               NULL, 0, NULL, NULL, NULL, -1, &result);
+           efree(filt);
+           if (rc != LDAP_SUCCESS)
+               continue;
+
+           LDAP_FOREACH(entry, ld, result) {
+               /* only verify netgroup matches in pass 2 */
+               if (do_netgr && !sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name))
+                   continue;
 
-    /* Parse Default options. */
-    sudo_ldap_update_defaults(ld);
+               ldap_user_matches = TRUE;
+               if (sudo_ldap_check_host(ld, entry)) {
+                   ldap_host_matches = TRUE;
+                   if ((pwcheck == any && doauth != FALSE) ||
+                       (pwcheck == all && doauth == FALSE))
+                       doauth = sudo_ldap_check_bool(ld, entry, "authenticate");
+                   /* Only check the command when listing another user. */
+                   if (user_uid == 0 || list_pw == NULL ||
+                       user_uid == list_pw->pw_uid ||
+                       sudo_ldap_check_command(ld, entry, NULL)) {
+                       matched = 1;
+                       break;  /* end foreach */
+                   }
+               }
+           }
+           ldap_msgfree(result);
+           result = NULL;
+       }
+       if (matched || user_uid == 0) {
+           SET(ret, VALIDATE_OK);
+           CLR(ret, VALIDATE_NOT_OK);
+           if (def_authenticate) {
+               switch (pwcheck) {
+                   case always:
+                       SET(ret, FLAG_CHECK_USER);
+                       break;
+                   case all:
+                   case any:
+                       if (doauth == FALSE)
+                           def_authenticate = FALSE;
+                       break;
+                   case never:
+                       def_authenticate = FALSE;
+                       break;
+                   default:
+                       break;
+               }
+           }
+       }
+       goto done;
+    }
 
     /*
      * Okay - time to search for anything that matches this user
@@ -1158,112 +1815,78 @@ sudo_ldap_check(pwflag)
      * try to match them against the username.
      */
     setenv_implied = FALSE;
-    for (do_netgr = 0; !ret && do_netgr < 2; do_netgr++) {
-       filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1();
+    for (matched = 0, do_netgr = 0; !matched && do_netgr < 2; do_netgr++) {
+       filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
        DPRINTF(("ldap search '%s'", filt), 1);
-       rc = ldap_search_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
-           NULL, 0, &result);
+       rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
+           NULL, 0, NULL, NULL, NULL, -1, &result);
        if (rc != LDAP_SUCCESS)
            DPRINTF(("nothing found for '%s'", filt), 1);
        efree(filt);
 
        /* parse each entry returned from this most recent search */
-       entry = rc ? NULL : ldap_first_entry(ld, result);
-       while (entry != NULL) {
-           DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
-           if (
-           /* first verify user netgroup matches - only if in pass 2 */
-               (!do_netgr || sudo_ldap_check_user_netgroup(ld, entry)) &&
-           /* remember that user matched */
-               (ldap_user_matches = -1) &&
-           /* verify host match */
-               sudo_ldap_check_host(ld, entry) &&
-           /* remember that host matched */
-               (ldap_host_matches = -1) &&
-           /* add matches for listing later */
-               sudo_ldap_add_match(ld, entry, pwflag) &&
-           /* verify command match */
-               sudo_ldap_check_command(ld, entry, &setenv_implied) &&
-           /* verify runas match */
-               sudo_ldap_check_runas(ld, entry)
-               ) {
-               /* We have a match! */
-               DPRINTF(("Perfect Matched!"), 1);
-               /* pick up any options */
-               if (setenv_implied)
-                   def_setenv = TRUE;
-               sudo_ldap_parse_options(ld, entry);
+       if (rc == LDAP_SUCCESS) {
+           LDAP_FOREACH(entry, ld, result) {
+               DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
+               if (
+               /* first verify user netgroup matches - only if in pass 2 */
+                   (!do_netgr || sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
+               /* remember that user matched */
+                   (ldap_user_matches = TRUE) &&
+               /* verify host match */
+                   sudo_ldap_check_host(ld, entry) &&
+               /* remember that host matched */
+                   (ldap_host_matches = TRUE) &&
+               /* verify runas match */
+                   sudo_ldap_check_runas(ld, entry) &&
+               /* verify command match */
+                   (rc = sudo_ldap_check_command(ld, entry, &setenv_implied)) != UNSPEC
+                   ) {
+                   /* We have a match! */
+                   DPRINTF(("Command %sallowed", rc == TRUE ? "" : "NOT "), 1);
+                   matched = TRUE;
+                   if (rc == TRUE) {
+                       /* pick up any options */
+                       if (setenv_implied)
+                           def_setenv = TRUE;
+                       sudo_ldap_parse_options(ld, entry);
 #ifdef HAVE_SELINUX
-               /* Set role and type if not specified on command line. */
-               if (user_role == NULL)
-                   user_role = def_role;
-               if (user_type == NULL)
-                   user_type = def_type;
+                       /* Set role and type if not specified on command line. */
+                       if (user_role == NULL)
+                           user_role = def_role;
+                       if (user_type == NULL)
+                           user_type = def_type;
 #endif /* HAVE_SELINUX */
-               /* make sure we don't reenter loop */
-               ret = VALIDATE_OK;
-               /* break from inside for loop */
-               break;
+                       /* make sure we don't reenter loop */
+                       SET(ret, VALIDATE_OK);
+                       CLR(ret, VALIDATE_NOT_OK);
+                   } else {
+                       SET(ret, VALIDATE_NOT_OK);
+                       CLR(ret, VALIDATE_OK);
+                   }
+                   /* break from inside for loop */
+                   break;
+               }
            }
-           entry = ldap_next_entry(ld, entry);
-       }
-       if (result)
            ldap_msgfree(result);
-       result = NULL;
+           result = NULL;
+       }
     }
 
-    sudo_ldap_close(ld);               /* shut down connection */
-
+done:
     DPRINTF(("user_matches=%d", ldap_user_matches), 1);
     DPRINTF(("host_matches=%d", ldap_host_matches), 1);
 
-    /* Check for special case for -v, -k, -l options */
-    if (pwflag && ldap_user_matches && ldap_host_matches) {
-       /*
-         * Handle verifypw & listpw
-         *
-         * To be extra paranoid, since we haven't read any NOPASSWD options
-         * in /etc/sudoers yet, but we have to make the decission now, lets
-         * assume the worst and prefer to prompt for password unless the setting
-         * is "never". (example verifypw=never or listpw=never)
-         *
-         */
-       ret = VALIDATE_OK;
-       if (pwflag == -1) {
-           SET(ret, FLAG_NOPASS);              /* -k or -K */
-       } else {
-           switch (sudo_defs_table[pwflag].sd_un.tuple) {
-           case never:
-               SET(ret, FLAG_NOPASS);
-               break;
-           case always:
-               if (def_authenticate)
-                   SET(ret, FLAG_CHECK_USER);
-               break;
-           default:
-               break;
-           }
-       }
-    }
-    if (ISSET(ret, VALIDATE_OK)) {
-       /* we have a match, should we check the password? */
-       if (!def_authenticate)
-           SET(ret, FLAG_NOPASS);
-       if (def_noexec)
-           SET(ret, FLAG_NOEXEC);
-       if (def_setenv)
-           SET(ret, FLAG_SETENV);
-    } else {
+    if (!ISSET(ret, VALIDATE_OK)) {
        /* we do not have a match */
-       ret = VALIDATE_NOT_OK;
-       if (pwflag)
+       if (pwflag && list_pw == NULL)
            SET(ret, FLAG_NO_CHECK);
-       else if (!ldap_user_matches)
-           SET(ret, FLAG_NO_USER);
-       else if (!ldap_host_matches)
-           SET(ret, FLAG_NO_HOST);
     }
-    DPRINTF(("sudo_ldap_check(%d)=0x%02x", pwflag, ret), 1);
+    if (ldap_user_matches)
+       CLR(ret, FLAG_NO_USER);
+    if (ldap_host_matches)
+       CLR(ret, FLAG_NO_HOST);
+    DPRINTF(("sudo_ldap_lookup(%d)=0x%02x", pwflag, ret), 1);
 
     return(ret);
 }
@@ -1271,9 +1894,23 @@ sudo_ldap_check(pwflag)
 /*
  * shut down LDAP connection
  */
-static void
-sudo_ldap_close(LDAP *ld)
+int
+sudo_ldap_close(nss)
+    struct sudo_nss *nss;
 {
-    if (ld)
-       ldap_unbind_s(ld);
+    if (nss->handle != NULL) {
+       ldap_unbind_ext_s((LDAP *) nss->handle, NULL, NULL);
+       nss->handle = NULL;
+    }
+    return(0);
+}
+
+/*
+ * STUB
+ */
+int
+sudo_ldap_parse(nss)
+    struct sudo_nss *nss;
+{
+    return(0);
 }
diff --git a/lex.yy.c b/lex.yy.c
deleted file mode 100644 (file)
index b05dd92..0000000
--- a/lex.yy.c
+++ /dev/null
@@ -1,3281 +0,0 @@
-/*     $OpenBSD: flex.skl,v 1.10 2007/01/26 14:38:19 tsi Exp $ */
-
-/* A lexical scanner generated by flex */
-
-/* Scanner skeleton version:
- * $Header: /home/cvs/courtesan/sudo/Attic/lex.yy.c,v 1.46.2.11 2008/06/26 11:53:49 millert Exp $
- */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-
-#include <stdio.h>
-#include <errno.h>
-
-
-/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
-#ifdef c_plusplus
-#ifndef __cplusplus
-#define __cplusplus
-#endif
-#endif
-
-
-#ifdef __cplusplus
-
-#include <stdlib.h>
-#include <unistd.h>
-
-/* Use prototypes in function declarations. */
-#define YY_USE_PROTOS
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else  /* ! __cplusplus */
-
-#ifdef __STDC__
-
-#define YY_USE_PROTOS
-#define YY_USE_CONST
-
-#endif /* __STDC__ */
-#endif /* ! __cplusplus */
-
-#ifdef __TURBOC__
- #pragma warn -rch
- #pragma warn -use
-#include <io.h>
-#include <stdlib.h>
-#define YY_USE_CONST
-#define YY_USE_PROTOS
-#endif
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-
-#ifdef YY_USE_PROTOS
-#define YY_PROTO(proto) proto
-#else
-#define YY_PROTO(proto) ()
-#endif
-
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index.  If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
- */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
-
-/* Enter a start condition.  This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN yy_start = 1 + 2 *
-
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state.  The YYSTATE alias is for lex
- * compatibility.
- */
-#define YY_START ((yy_start - 1) / 2)
-#define YYSTATE YY_START
-
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
-/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart( yyin )
-
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#define YY_BUF_SIZE 16384
-
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-
-extern int yyleng;
-extern FILE *yyin, *yyout;
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-
-/* The funky do-while in the following #define is used to turn the definition
- * int a single C statement (which needs a semi-colon terminator).  This
- * avoids problems with code like:
- *
- *     if ( condition_holds )
- *             yyless( 5 );
- *     else
- *             do_something_else();
- *
- * Prior to using the do-while the compiler would get upset at the
- * "else" because it interpreted the "if" statement as being all
- * done when it reached the ';' after the yyless() call.
- */
-
-/* Return all but the first 'n' matched characters back to the input stream. */
-
-#define yyless(n) \
-       do \
-               { \
-               /* Undo effects of setting up yytext. */ \
-               *yy_cp = yy_hold_char; \
-               YY_RESTORE_YY_MORE_OFFSET \
-               yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
-               YY_DO_BEFORE_ACTION; /* set up yytext again */ \
-               } \
-       while ( 0 )
-
-#define unput(c) yyunput( c, yytext_ptr )
-
-/* The following is because we cannot portably get our hands on size_t
- * (without autoconf's help, which isn't available because we want
- * flex-generated scanners to compile on their own).
- */
-typedef unsigned int yy_size_t;
-
-
-struct yy_buffer_state
-       {
-       FILE *yy_input_file;
-
-       char *yy_ch_buf;                /* input buffer */
-       char *yy_buf_pos;               /* current position in input buffer */
-
-       /* Size of input buffer in bytes, not including room for EOB
-        * characters.
-        */
-       yy_size_t yy_buf_size;
-
-       /* Number of characters read into yy_ch_buf, not including EOB
-        * characters.
-        */
-       int yy_n_chars;
-
-       /* Whether we "own" the buffer - i.e., we know we created it,
-        * and can realloc() it to grow it, and should free() it to
-        * delete it.
-        */
-       int yy_is_our_buffer;
-
-       /* Whether this is an "interactive" input source; if so, and
-        * if we're using stdio for input, then we want to use getc()
-        * instead of fread(), to make sure we stop fetching input after
-        * each newline.
-        */
-       int yy_is_interactive;
-
-       /* Whether we're considered to be at the beginning of a line.
-        * If so, '^' rules will be active on the next match, otherwise
-        * not.
-        */
-       int yy_at_bol;
-
-       /* Whether to try to fill the input buffer when we reach the
-        * end of it.
-        */
-       int yy_fill_buffer;
-
-       int yy_buffer_status;
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
-       /* When an EOF's been seen but there's still some text to process
-        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
-        * shouldn't try reading from the input source any more.  We might
-        * still have a bunch of tokens to match, though, because of
-        * possible backing-up.
-        *
-        * When we actually see the EOF, we change the status to "new"
-        * (via yyrestart()), so that the user can continue scanning by
-        * just pointing yyin at a new input file.
-        */
-#define YY_BUFFER_EOF_PENDING 2
-       };
-
-static YY_BUFFER_STATE yy_current_buffer = 0;
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- */
-#define YY_CURRENT_BUFFER yy_current_buffer
-
-
-/* yy_hold_char holds the character lost when yytext is formed. */
-static char yy_hold_char;
-
-static int yy_n_chars;         /* number of characters read into yy_ch_buf */
-
-
-int yyleng;
-
-/* Points to current character in buffer. */
-static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 1;                /* whether we need to initialize */
-static int yy_start = 0;       /* start state number */
-
-/* Flag which is used to allow yywrap()'s to do buffer switches
- * instead of setting up a fresh yyin.  A bit of a hack ...
- */
-static int yy_did_buffer_switch_on_eof;
-
-void yyrestart YY_PROTO(( FILE *input_file ));
-
-void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
-void yy_load_buffer_state YY_PROTO(( void ));
-YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
-void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
-void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
-void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
-#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
-
-YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
-YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
-YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
-
-static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
-static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
-static void yy_flex_free YY_PROTO(( void * ));
-
-#define yy_new_buffer yy_create_buffer
-
-#define yy_set_interactive(is_interactive) \
-       { \
-       if ( ! yy_current_buffer ) \
-               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
-       yy_current_buffer->yy_is_interactive = is_interactive; \
-       }
-
-#define yy_set_bol(at_bol) \
-       { \
-       if ( ! yy_current_buffer ) \
-               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
-       yy_current_buffer->yy_at_bol = at_bol; \
-       }
-
-#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
-
-typedef unsigned char YY_CHAR;
-FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
-typedef int yy_state_type;
-extern char *yytext;
-#define yytext_ptr yytext
-
-static yy_state_type yy_get_previous_state YY_PROTO(( void ));
-static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
-static int yy_get_next_buffer YY_PROTO(( void ));
-static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
- */
-#define YY_DO_BEFORE_ACTION \
-       yytext_ptr = yy_bp; \
-       yyleng = (int) (yy_cp - yy_bp); \
-       yy_hold_char = *yy_cp; \
-       *yy_cp = '\0'; \
-       yy_c_buf_p = yy_cp;
-
-#define YY_NUM_RULES 48
-#define YY_END_OF_BUFFER 49
-static yyconst short int yy_accept[610] =
-    {   0,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,   49,   38,   44,   43,   42,   47,
-       38,   31,   47,   38,   39,   38,   38,   38,   38,   41,
-       40,   32,   32,   32,   32,   32,   32,   47,   38,   38,
-       32,   32,   32,   32,   32,   33,   47,   33,   35,   33,
-       33,   33,   33,   33,   32,   32,   32,   32,   32,   32,
-       47,   33,   33,    1,   16,   15,   16,   15,   15,   47,
-       47,    2,    8,    7,    8,    3,    8,    4,   47,   12,
-       12,   12,   10,   11,   38,    0,   44,   42,    0,   46,
-       26,    0,   25,    0,   37,   37,    0,   38,   38,    0,
-
-       38,   38,   38,   38,    0,   29,   32,   32,   32,   32,
-       32,   32,   38,   45,   38,   38,   38,   38,   38,   38,
-       33,    0,    0,   33,   26,    0,   25,    0,   33,    0,
-       33,   33,   33,   33,   33,   33,   32,   32,   32,   32,
-       32,   32,   33,   33,    1,   16,   16,   14,   13,   14,
-        0,    2,    8,    0,    5,    6,    8,    8,   12,    0,
-       12,   12,    0,    9,    0,   38,   38,   38,   38,   38,
-        0,    0,   29,   29,   32,   32,   32,   32,   32,   32,
-       32,   38,   38,   38,   38,   38,   38,    0,   34,   33,
-       33,   33,   33,   33,   32,   32,   32,   32,   32,   32,
-
-       32,   33,    9,   38,   38,   38,   38,   38,   38,    0,
-       30,   30,   30,    0,    0,   29,   29,   29,   29,   29,
-       29,   29,   32,   32,   32,   32,   32,   32,   32,   38,
-       38,   38,   38,   33,   33,   33,   33,   33,   33,   32,
-       32,   32,   32,   32,   32,   32,   33,   38,   38,   38,
-        0,    0,   30,   30,   30,    0,   29,   29,    0,   29,
-       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
-        0,   22,   32,   32,   32,   32,   32,   38,   38,   38,
-       33,   33,   33,   32,   32,   32,   32,   32,   33,   38,
-       38,   38,   38,   38,    0,   30,    0,   29,   29,   29,
-
-        0,    0,    0,   29,   29,   29,   29,   29,   29,   29,
-       29,   29,   29,   29,   29,   29,   32,   32,   32,   32,
-       32,   38,   38,   38,   33,   33,   33,   33,   33,   32,
-       32,   32,   32,   32,   33,   27,   27,   27,    0,    0,
-       29,   29,   29,   29,   29,   29,   29,    0,    0,    0,
-        0,    0,   29,   29,   29,   29,   29,   29,   29,   29,
-       29,   29,   29,   29,   29,   29,    0,   21,   32,   32,
-        0,   20,    0,   23,   38,   38,   38,   27,   27,   27,
-       32,   32,   33,   38,   27,   27,   27,   27,    0,   29,
-        0,   29,   29,   29,   29,   29,   29,   29,   29,   29,
-
-       29,   29,    0,    0,    0,   29,   29,   29,   29,   29,
-       29,   29,   29,   29,   29,   29,   29,   29,   32,   32,
-       36,   38,   17,   33,   27,   27,   27,   27,   32,   32,
-       33,   38,   28,   28,   28,   29,    0,    0,    0,   29,
-       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
-       29,   29,    0,    0,    0,    0,    0,   29,   29,   29,
-       29,   29,   29,   29,   29,    0,   19,    0,   24,   38,
-       17,   33,   28,   28,   28,   38,   38,   28,   28,   28,
-       28,   28,    0,    0,    0,    0,    0,   29,   29,   29,
-       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
-
-       29,   29,   29,   29,   29,   29,   29,   18,   33,   33,
-       28,   28,   28,   28,   28,   38,   38,   38,   28,   28,
-        0,    0,    0,   29,   29,   29,   29,   29,   29,   29,
-       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
-       29,   33,   33,   33,   28,   28,   38,   38,   38,   38,
-       38,    0,    0,    0,    0,    0,   29,   29,   29,   29,
-       29,   29,   29,   29,   33,   33,   33,   33,   33,   38,
-       38,   38,   29,   29,   29,   29,   29,   29,   33,   33,
-       33,   38,   38,   38,   38,   38,   29,   29,   29,   29,
-       29,   33,   33,   33,   33,   33,   27,   27,   27,   27,
-
-       27,   27,   27,   27,   27,   27,   27,   27,    0
-    } ;
-
-static yyconst int yy_ec[256] =
-    {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    2,    4,    5,    6,    1,    7,    1,    1,    8,
-        9,   10,   11,   12,   13,   14,   15,   16,   17,   18,
-       19,   20,   21,   22,   22,   22,   23,   24,    1,    1,
-       25,   26,   10,   26,   27,   28,   29,   30,   31,   28,
-       32,   33,   32,   32,   32,   32,   32,   34,   35,   36,
-       32,   37,   38,   39,   40,   41,   42,   43,   32,   32,
-       10,   44,   10,    1,   45,    1,   46,   47,   47,   48,
-
-       49,   50,   51,   51,   52,   51,   51,   53,   54,   55,
-       56,   51,   51,   57,   58,   59,   60,   51,   51,   51,
-       51,   51,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1
-    } ;
-
-static yyconst int yy_meta[61] =
-    {   0,
-        1,    2,    3,    4,    5,    6,    1,    4,    4,    1,
-        1,    2,    7,    8,    9,   10,   10,   10,   10,   10,
-       10,   10,   10,   11,    6,    4,   12,   12,   12,   12,
-       12,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,   13,   14,   15,   15,   15,   15,   15,
-       14,   14,   14,   14,   14,   14,   14,   14,   14,   14
-    } ;
-
-static yyconst short int yy_base[681] =
-    {   0,
-        0,   32,   72,    0,   62,  131,  132,  139,  182,  241,
-      300,  343,  145,  150, 3097, 3052, 3093, 3790, 3068, 3059,
-     3008, 3790, 3790, 2996, 3790,  161,  374,  179,  161, 3015,
-     3790,  424, 2995,  469, 3002, 3009, 2982,  518,  190,  102,
-     2949, 2944, 2927, 2913, 2905, 2909,  201, 2873, 3790, 2864,
-      306,  531,  232,  240,  581, 2855,  626, 2855, 2852, 2838,
-      675,  248,  114, 2847,    0, 3790, 2844,    0, 3790,  314,
-       64,    0, 2803, 3790,  115, 3790,  146, 3790,  158, 2802,
-      171,  275, 3790,  270, 2801,  355, 2836, 2818, 2808, 3790,
-     2757,  684, 2739,  709,  325, 2729,  718,  355,  729, 2739,
-
-     2739,  390,  485,  493, 2675,  151,  764,    0, 2665,  245,
-     2657, 2649,  338, 3790,  124,  148,  232,  219,  287,  278,
-     2633,  794, 2656,    0, 2605,  819, 2593,  828,  530,  853,
-      549,  864, 2622,  642,  745,  650,  899,    0, 2604,  292,
-     2596, 2571,  382,  230, 2566,    0, 2548,  305, 3790, 3790,
-      333,    0, 2507,  700, 3790, 3790, 2505,  492, 2489, 2527,
-      384,  339,  350, 2529,  844,  936,  880,  720,  967, 2484,
-     2460, 1002,  201, 1038, 1073, 2454, 2433, 2438, 2431, 2409,
-     2403,  265,  236, 2369,  356,  147,  370, 2411, 3790, 1110,
-      915,  753, 1141, 2399, 1176, 2354, 2315, 2302, 2283, 2275,
-
-     2281,  479, 2293,  947,  375,    0,    0,  343,  392, 2270,
-     2236,  955,  515, 2222, 2221,  513,  983, 1213, 1018,  854,
-     1249, 1056, 2214,  539, 2196, 2186, 2153, 2149, 2125,  540,
-      388,  764,  529, 1090,  532,    0,    0,  427,  661, 2133,
-      583, 2110, 2101, 2084, 2080, 2087,  645, 1121, 1159, 1194,
-     2095, 2080, 1129, 2080, 2033, 2032, 2021,  667, 1229,  683,
-     1265,  775, 1286,    0, 1304, 1323, 1339,  888, 1359, 1377,
-      729, 3790, 2009, 1999, 1972, 1972, 1948,  481,  513,  651,
-     1396, 1406, 1416, 1959, 1919, 1925, 1925, 1913,  675, 1424,
-      791, 1434, 1444, 1455, 1926, 1873, 1856, 1819, 1484,  792,
-
-     1811, 1810, 1463,  802,  824,  827, 1471,  852, 1521,    0,
-     1502, 1558, 1537,  923, 1594, 1576,  730, 1745, 1737,  958,
-     1040,   19,  805,  670, 1610,  819, 1639, 1649, 1631, 1081,
-     1711, 1718, 1112, 1251,  318, 1661, 1669,  991, 1694, 1677,
-     1615, 1677, 1692, 1708, 1273, 1727, 1745, 1762, 1624, 1621,
-     1620, 1772, 1056, 1101, 1387, 1622, 1778, 1788, 1799,    0,
-     1817, 1836, 1788, 1347, 1872, 1854, 1324, 3790, 1590, 1578,
-     1325, 3790, 1522, 3790,  984,  757,  771, 1908, 1888, 1545,
-     1572, 1543, 1038, 1916,  636,    0,    0,  866, 1559, 1505,
-     1924,  937, 1945, 1142, 1955,    0, 1966, 1977, 1993, 1716,
-
-     2012, 2030, 1496, 1482, 2049, 1150, 1185, 1934, 2040, 2057,
-     2067, 2078,    0, 2096, 2115, 2067, 1896, 2133, 1523, 1837,
-     1434,  879, 1194, 2150, 1377,    0,    0,  970, 1838, 1957,
-     1426, 2181, 2158, 2166, 1028, 1407, 1390, 1389, 2191, 1306,
-     1435, 1577, 2199, 1650, 2212,    0, 2223, 2234, 2250, 2001,
-     2269, 2287, 2304, 1260, 1244, 1225, 2314, 1745, 1854, 2322,
-     1084, 1103, 2333,    0, 2324, 1968, 3790, 2116, 3790, 1451,
-     3790, 2343, 2351, 2359, 1167, 2372,  846, 2380, 2388, 2401,
-     2409, 2419, 2422, 1172, 1153, 1101, 2432, 1057, 1039, 1693,
-     2134, 2438, 2182, 2450,    0, 2461, 2472, 2488, 2258, 2507,
-
-     2525, 1032, 1012, 2543, 2287,  947, 1187,  880, 2553, 1483,
-     2561, 2569, 2577, 2585, 2595, 2600, 2610, 2624, 2634, 2368,
-      850,  833, 2644,  798,  780, 2235, 2473, 2652, 2526, 2662,
-        0, 2673, 2684, 2700, 2496, 2721,  782,  740,  713, 2730,
-      701, 2738, 2748, 2758, 2768, 2692, 2776, 1484, 2786, 2796,
-     2807, 2813,  689,  638,  592, 2823,  566,  559, 2601,  550,
-      416, 2836,    0, 1232, 2844, 1659, 2854, 2864, 2875, 2883,
-     2893, 2904, 2912, 2920, 2928,  393,    0,  346, 2938, 2948,
-     2958, 2968, 2146, 2978, 2988, 2998, 3790, 3004, 3012, 2708,
-     3790, 3027, 2179, 3037, 3047, 3057, 3063, 3071, 3100, 3108,
-
-     3116, 3145,  293, 3153, 3137,  123, 3182, 3166, 3790, 3226,
-     3241, 3256, 3271, 3286, 3301, 3316, 3331, 3346, 3352, 3367,
-     3382, 3397, 3412, 3427, 3442, 1242, 3457, 3472, 3487, 3502,
-     3508, 3515, 3530, 1593, 3536, 3543, 3549, 3555, 3561, 3568,
-     3574, 3580, 3586, 3593, 3601, 3607, 3613, 3619, 1211, 1321,
-     3626, 3634, 3640, 3646, 3653, 3661, 3667, 3675, 1694, 1762,
-     3682, 3690, 1834, 1871, 3696, 3704, 3711, 3719, 3725, 3733,
-     1302, 1375, 3740, 1888, 1943, 3746, 3754, 3760, 3768, 3774
-    } ;
-
-static yyconst short int yy_def[681] =
-    {   0,
-      609,    1,  609,    3,    1,    1,  610,  610,  611,  611,
-      612,  612,  613,  613,  609,  614,  609,  609,  609,  615,
-      616,  609,  609,  617,  609,  618,  614,   27,   27,  619,
-      609,  609,   32,   32,   34,   34,   34,  614,   27,  614,
-       32,   32,   34,   34,   34,  620,  621,  622,  609,  623,
-      624,  620,   52,   52,  609,   55,   55,   57,   57,   57,
-      620,   52,  620,  609,  625,  609,  625,  625,  609,  609,
-      609,  626,  627,  609,  627,  609,  627,  609,  628,  629,
-      629,  629,  609,  609,  614,  614,  609,  609,  615,  609,
-      616,  616,  617,  617,  618,  630,  614,  614,   27,  619,
-
-       99,   99,   99,   99,  631,  632,   32,   34,   34,   34,
-       34,   34,  614,  609,  614,  614,   99,  614,  614,  614,
-      620,  620,  633,  634,  622,  622,  623,  623,  624,  620,
-      620,   52,  132,  132,  132,  132,   55,   57,   57,   57,
-       57,   57,  620,  620,  609,  625,  625,  609,  609,  609,
-      609,  626,  627,  627,  609,  609,  627,  627,  629,  609,
-      629,  629,  609,  609,  609,  614,  166,  166,   99,  169,
-      635,  609,  636,  609,   32,   34,   34,   34,   34,   34,
-       34,  614,  614,  169,  614,  614,  614,  633,  609,  620,
-      190,  190,  132,  193,   55,   57,   57,   57,   57,   57,
-
-       57,  620,  609,  614,  614,  166,  166,  166,  614,  637,
-      638,  638,  212,  639,  638,  640,  174,  609,  218,  218,
-      609,  218,   34,   34,   34,   34,   34,   34,   34,  614,
-      614,  614,  614,  620,  620,  190,  190,  190,  620,   57,
-       57,   57,   57,   57,   57,   57,  620,  166,  166,  166,
-      609,  641,  641,  253,  641,  642,  643,  644,  609,  645,
-      221,  645,  609,  263,  645,  609,  266,  266,  609,  266,
-      609,  609,   34,   34,   34,   34,   34,  614,  614,  614,
-      190,  190,  190,   57,   57,   57,   57,   57,  620,  614,
-      614,  166,  166,  614,  646,  646,  647,  648,  609,  609,
-
-      649,  650,  609,  651,  651,  652,  269,  652,  609,  309,
-      652,  609,  312,  312,  609,  312,   34,   34,   34,   34,
-       34,  614,  614,  614,  620,  620,  190,  190,  620,   57,
-       57,   57,   57,   57,  620,  614,  336,  336,  609,  653,
-      654,  299,  609,  343,  343,  609,  343,  609,  609,  649,
-      649,  609,  609,  655,  655,  656,  315,  656,  609,  359,
-      656,  609,  362,  362,  609,  362,  609,  609,   34,   34,
-      609,  609,  609,  609,  614,  614,  614,  620,  378,  378,
-       57,   57,  620,  614,  614,  336,  336,  336,  609,  657,
-      609,  658,  346,  658,  658,  395,  658,  609,  398,  398,
-
-      609,  398,  659,  660,  609,  609,  661,  661,  662,  365,
-      662,  609,  412,  662,  609,  415,  415,  415,   34,   34,
-      614,  614,  614,  620,  620,  378,  378,  378,   57,   57,
-      620,  614,  432,  432,  432,  609,  663,  664,  609,  665,
-      665,  666,  401,  666,  666,  445,  666,  609,  448,  448,
-      609,  448,  609,  609,  659,  659,  609,  609,  667,  667,
-      668,  668,  668,  463,  668,  609,  609,  609,  609,  614,
-      609,  620,  472,  472,  472,  614,  614,  432,  432,  432,
-      432,  614,  609,  609,  663,  663,  609,  609,  669,  669,
-      670,  451,  670,  670,  494,  670,  609,  497,  497,  609,
-
-      497,  671,  672,  609,  609,  673,  673,  614,  472,  620,
-      472,  472,  472,  472,  620,  432,  432,  432,  432,  614,
-      674,  675,  609,  609,  676,  676,  677,  500,  677,  677,
-      530,  677,  609,  533,  533,  533,  609,  671,  671,  609,
-      609,  472,  472,  472,  472,  620,  614,  614,  432,  432,
-      614,  609,  609,  674,  674,  609,  609,  678,  678,  679,
-      679,  679,  562,  562,  620,  620,  472,  472,  620,  432,
-      432,  432,  609,  609,  609,  609,  680,  680,  472,  472,
-      472,  432,  614,  432,  432,  614,  609,  609,  609,  609,
-      609,  472,  620,  472,  472,  620,  614,  614,  614,  620,
-
-      620,  620,  614,  614,  614,  620,  620,  620,    0,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609
-    } ;
-
-static yyconst short int yy_nxt[3851] =
-    {   0,
-       16,   17,   18,   19,   16,   20,   21,   22,   23,   16,
-       24,   25,   16,   16,   26,   27,   28,   29,   27,   27,
-       27,   27,   27,   30,   31,   23,   32,   32,   32,   32,
-       33,   34,   34,   35,   34,   36,   34,   37,   34,   34,
-       34,   34,   34,   38,   16,   39,   39,   39,   39,   39,
-       16,   16,   16,   16,   16,   16,   16,   40,   16,   16,
-       41,   42,   86,   64,   43,  151,  114,   23,   44,   23,
-      375,   45,   46,   17,   18,   19,   46,   47,   48,   23,
-       49,   46,   50,   25,   46,   46,   51,   52,   53,   54,
-       52,   52,   52,   52,   52,   30,   31,   23,   55,   55,
-
-       55,   55,   56,   57,   57,   58,   57,   59,   57,   60,
-       57,   57,   57,   57,   57,   61,   46,   62,   62,   62,
-       62,   62,   46,   46,   46,   46,   46,   46,   46,   63,
-       46,   46,   64,   17,   66,   67,   23,   68,   23,  155,
-       17,   66,   67,   69,   68,   86,   81,   18,   82,   83,
-       69,   81,   18,   82,   83,   69,   68,  122,  154,  158,
-      114,  115,   69,   68,   96,  172,  122,   86,   96,   96,
-      156,  182,  161,  144,  174,   70,  103,  103,  103,  103,
-      103,  104,   70,   17,   18,   19,   96,   20,   84,  154,
-       86,   86,  233,   84,  102,  102,  102,  102,  102,  102,
-
-      102,  102,  183,   85,   97,  101,  101,  101,  101,  101,
-      101,  101,  101,  124,  160,  172,  124,  124,  124,  124,
-      124,  124,  124,  124,  217,   71,   72,   72,   72,   72,
-       72,   72,   72,   72,   72,   72,   72,   72,   72,   72,
-       72,   72,   17,   18,   19,   85,   20,  134,  134,  134,
-      134,  134,  134,  134,  134,  135,  135,  135,  135,  135,
-      136,  121,   86,  133,  133,  133,  133,  133,  133,  133,
-      133,  163,  164,  122,  159,  177,  185,  202,  162,   86,
-      178,  184,  179,  231,   71,   72,   72,   72,   72,   72,
-       72,   72,   72,   72,   72,   72,   72,   72,   72,   72,
-
-       72,   17,   18,   19,   74,   20,  151,  114,   86,   96,
-       75,   76,   77,   96,   96,  148,  114,  149,  160,  150,
-      230,   86,  197,  149,   78,  150,  187,  198,   96,  199,
-       86,   96,   96,   96,  151,  114,   86,  150,  150,  151,
-      114,  186,  162,   79,   17,   18,   19,   74,   20,  130,
-       96,  163,  164,   75,   76,   77,   85,  150,   85,  391,
-       85,  122,   85,   85,   85,   85,   85,   78,   97,  383,
-      166,  167,  168,  166,  166,  166,  166,  166,   85,   85,
-       85,   86,  160,  151,  114,  161,   79,   98,  204,   99,
-       99,   99,   99,   99,   99,   99,   99,  100,   86,   86,
-
-      101,  101,  101,  101,  101,  170,  170,  170,  170,  170,
-      170,  170,  170,   86,  231,  100,  528,   86,   86,  101,
-      101,  101,  101,  101,   85,  122,  231,  160,   85,  609,
-       85,   86,  279,   85,   85,   86,   85,   85,   85,  107,
-      107,  107,  107,  107,  107,  107,  107,  100,  121,  121,
-      107,  107,  107,  107,  107,  108,  108,  108,  108,  108,
-      108,  108,  108,  108,  108,  108,  108,   86,  108,  101,
-      101,  101,  101,  101,   85,   85,   85,   85,   85,   85,
-       85,   85,   85,   85,  108,  108,  108,  108,  108,  108,
-      108,  108,  609,  151,  114,  108,  108,  108,  108,  108,
-
-      170,  170,  170,  170,  170,  170,  170,  170,  170,  170,
-      170,  170,  170,  170,   85,   85,   85,   85,   85,  113,
-      114,   85,  122,   85,   86,   85,   85,  172,  322,   85,
-      255,  255,  255,   96,  247,  154,  217,   96,   96,  323,
-      271,   85,   85,   85,  131,  234,  132,  132,  132,  132,
-      132,  132,  132,  132,  100,   96,   86,  133,  133,  133,
-      133,  133,  272,  391,  190,  191,  192,  190,  190,  190,
-      190,  190,   86,  130,  122,  122,  133,  133,  133,  133,
-      133,  121,  528,   86,  271,  121,  231,  121,  278,  492,
-      121,  121,  122,  121,  121,  121,  137,  137,  137,  137,
-
-      137,  137,  137,  137,  100,  552,  272,  137,  137,  137,
-      137,  137,  138,  138,  138,  138,  138,  138,  138,  138,
-      138,  138,  138,  138,  122,  138,  133,  133,  133,  133,
-      133,  121,  121,  121,  121,  121,  121,  121,  121,  121,
-      121,  138,  138,  138,  138,  138,  138,  138,  138,  609,
-      384,  552,  138,  138,  138,  138,  138,  194,  194,  194,
-      194,  194,  194,  194,  194,  194,  194,  194,  194,  194,
-      194,  121,  121,  121,  121,  121,  143,  114,  121,   86,
-      121,  172,  121,  121,  100,   91,  121,   91,  122,   91,
-      217,   91,   91,  289,   86,   91,  259,  172,  121,  121,
-
-      121,  153,  552,  324,  122,  153,  261,   91,   91,   91,
-       93,  153,   93,   86,   93,  172,   93,   93,  122,   95,
-       93,   85,  335,   95,  153,   85,   85,  172,  377,   95,
-      271,  367,   93,   93,   93,  207,  207,  207,  207,  207,
-      208,   95,   95,   85,  169,  169,  169,  169,  169,  169,
-      169,  169,  272,  368,  172,  169,  169,  169,  169,  169,
-      194,  194,  194,  194,  194,  194,  194,  194,  237,  237,
-      237,  237,  237,  238,  169,  169,  169,  169,  169,  175,
-      175,  175,  175,  175,  175,  175,  175,  100,  609,  172,
-      175,  175,  175,  175,  175,  121,  172,  121,  261,  121,
-
-       86,  121,  121,  492,  290,  121,  172,   86,  422,  169,
-      169,  169,  169,  169,   86,  217,  172,  121,  121,  121,
-      125,  443,  125,  280,  125,  261,  125,  125,  423,  127,
-      125,  127,  325,  127,   86,  127,  127,  259,  172,  127,
-      259,  172,  125,  125,  125,   96,  552,  261,   86,   96,
-      307,  127,  127,  127,  129,   96,  121,  376,  129,  476,
-      121,  121,  122,  552,  129,  609,  172,   96,   96,  264,
-      264,  264,  264,  264,  265,  307,  129,  129,  121,  193,
-      193,  193,  193,  193,  193,  193,  193,   85,   85,   86,
-      193,  193,  193,  193,  193,  206,  206,  206,  206,  206,
-
-      206,  206,  206,  310,  310,  310,  310,  310,  311,  193,
-      193,  193,  193,  193,  195,  195,  195,  195,  195,  195,
-      195,  195,   86,   86,  470,  195,  195,  195,  195,  195,
-      236,  236,  236,  236,  236,  236,  236,  236,  360,  360,
-      360,  360,  360,  361,  193,  193,  193,  193,  193,  204,
-      391,  205,  205,  205,  205,  205,  205,  205,  205,  371,
-      393,  172,  248,  249,  250,  248,  248,  248,  248,  248,
-      253,  253,  254,  255,  255,  255,  255,  255,  214,   86,
-       85,  372,  209,  209,  209,  209,  209,  209,  209,  209,
-       86,  121,  121,  209,  209,  209,  209,  209,  222,  222,
-
-      222,  222,  222,  222,  222,  222,  387,  387,  387,  387,
-      387,  388,  209,  209,  209,  209,  209,  211,  212,  213,
-      213,  213,  213,  213,  213,  214,  172,   86,  215,  215,
-      215,  215,  215,  263,  263,  263,  263,  263,  263,  263,
-      263,  373,  421,  482,  482,  482,  172,  215,  215,  215,
-      215,  215,  172,  218,  219,  220,  218,  218,  218,  218,
-      218,  221,  443,  374,  222,  222,  222,  222,  222,  609,
-      172,  262,  262,  262,  262,  262,  262,  262,  262,  261,
-      393,  122,  367,  222,  222,  222,  222,  222,  223,  223,
-      223,  223,  223,  223,  223,  223,  431,  259,  172,  223,
-
-      223,  223,  223,  223,  368,  281,  282,  283,  281,  281,
-      281,  281,  281,  371,  483,  172,  609,  172,  209,  209,
-      209,  209,  209,  234,  307,  235,  235,  235,  235,  235,
-      235,  235,  235,  122,  290,  372,  291,  291,  291,  291,
-      291,  291,  291,  291,  296,  296,  296,  296,  296,  296,
-      296,  296,  214,  122,  121,  609,  239,  239,  239,  239,
-      239,  239,  239,  239,  172,  393,  483,  239,  239,  239,
-      239,  239,  290,  307,  292,  292,  292,  292,  292,  292,
-      292,  292,  515,  515,  515,  483,  239,  239,  239,  239,
-      239,  240,  240,  240,  240,  240,  240,  240,  240,  172,
-
-      259,  172,  240,  240,  240,  240,  240,  290,  357,  293,
-      293,  293,  293,  293,  294,  291,  291,  471,  349,  471,
-      349,  239,  239,  239,  239,  239,  259,  172,  260,  260,
-      260,  260,  260,  260,  260,  260,  261,   86,  453,  262,
-      262,  262,  262,  262,  301,  302,  303,  301,  301,  301,
-      301,  301,  373,  577,  577,  152,  152,  453,  262,  262,
-      262,  262,  262,  172,  266,  267,  268,  266,  266,  266,
-      266,  266,  269,  453,  374,  270,  270,  270,  270,  270,
-      270,  270,  270,  270,  270,  270,  270,  270,  396,  396,
-      396,  396,  396,  397,  270,  270,  270,  270,  270,  259,
-
-      172,  305,  305,  305,  305,  305,  305,  305,  305,  261,
-      537,  537,  304,  304,  304,  304,  304,  259,  172,  305,
-      305,  305,  305,  305,  305,  367,  371,  261,  350,  393,
-      350,  304,  304,  304,  304,  304,  259,  172,  306,  306,
-      306,  306,  306,  306,  306,  306,  307,  368,  372,  308,
-      308,  308,  308,  308,  309,  309,  309,  309,  309,  309,
-      309,  309,  413,  413,  413,  413,  413,  414,  308,  308,
-      308,  308,  308,  172,  312,  313,  314,  312,  312,  312,
-      312,  312,  315,  538,  538,  316,  316,  316,  316,  316,
-      609,  424,  308,  308,  308,  308,  308,  308,  308,  308,
-
-      259,  172,  483,  483,  316,  316,  316,  316,  316,  325,
-      307,  326,  326,  326,  326,  326,  326,  326,  326,  325,
-      122,  327,  327,  327,  327,  327,  327,  327,  327,  325,
-      342,  328,  328,  328,  328,  328,  329,  326,  326,  336,
-      337,  338,  336,  336,  336,  336,  336,  290,  391,  291,
-      291,  291,  291,  291,  291,  291,  291,  290,  393,  291,
-      291,  291,  291,  291,  291,  291,  291,   86,  290,  122,
-      291,  291,  291,  291,  291,  291,  348,   86,  351,  351,
-      351,  351,  351,  352,  349,  349,  316,  316,  316,  316,
-      316,  316,  316,  316,   86,  453,  509,  547,   86,  343,
-
-      344,  345,  343,  343,  343,  343,  343,  346,  508,  453,
-      347,  347,  347,  347,  347,  259,  172,  355,  355,  355,
-      355,  355,  355,  373,  466,  307,  122,   86,  342,  347,
-      347,  347,  347,  347,  259,  172,  355,  355,  355,  355,
-      355,  355,  355,  355,  307,  374,  467,  354,  354,  354,
-      354,  354,  359,  359,  359,  359,  359,  359,  359,  359,
-      427,  427,  427,  427,  427,  428,  354,  354,  354,  354,
-      354,  259,  172,  356,  356,  356,  356,  356,  356,  356,
-      356,  357,  257,  430,  358,  358,  358,  358,  358,  609,
-      391,  358,  358,  358,  358,  358,  358,  358,  358,  124,
-
-      443,  429,  124,  358,  358,  358,  358,  358,  172,  362,
-      363,  364,  362,  362,  362,  362,  362,  365,  420,  419,
-      366,  366,  366,  366,  366,  378,  379,  380,  378,  378,
-      378,  378,  378,  348,  348,  259,  172,  348,  342,  366,
-      366,  366,  366,  366,  325,  357,  326,  326,  326,  326,
-      326,  326,  325,  122,  326,  326,  326,  326,  326,  326,
-      326,  326,  325,  609,  326,  326,  326,  326,  326,  326,
-      326,  326,  565,  443,  122,  384,  385,  385,  385,  385,
-      385,  385,  385,  385,  386,  386,  386,  386,  386,  386,
-      386,  386,  347,  347,  347,  347,  347,  347,  347,  347,
-
-      257,  454,  122,  454,   86,  391,  391,  392,  392,  392,
-      392,  392,  392,  392,  392,  393,  443,  214,  394,  394,
-      394,  394,  394,  395,  395,  395,  395,  395,  395,  395,
-      395,  446,  446,  446,  446,  446,  447,  394,  394,  394,
-      394,  394,  398,  399,  400,  398,  398,  398,  398,  398,
-      401,  382,  381,  402,  402,  402,  402,  402,  609,  172,
-      394,  394,  394,  394,  394,  394,  394,  394,  357,  455,
-      370,  455,  402,  402,  402,  402,  402,  403,  404,  405,
-      403,  403,  403,  403,  403,  348,  369,  349,  349,  349,
-      349,  349,  349,  366,  366,  366,  366,  366,  366,  366,
-
-      366,  609,  172,  412,  412,  412,  412,  412,  412,  412,
-      412,  357,  259,  172,  408,  408,  408,  408,  408,  408,
-      408,  408,  357,  348,  348,  407,  407,  407,  407,  407,
-      259,  172,  408,  408,  408,  408,  408,  408,  468,  466,
-      357,  484,  342,  484,  407,  407,  407,  407,  407,  259,
-      172,  409,  409,  409,  409,  409,  409,  409,  409,  410,
-      469,  467,  411,  411,  411,  411,  411,  609,  172,  411,
-      411,  411,  411,  411,  411,  411,  411,  410,  485,  257,
-      485,  411,  411,  411,  411,  411,  172,  415,  416,  417,
-      415,  415,  415,  415,  415,  553,  214,  553,  418,  418,
-
-      418,  418,  418,  426,  426,  426,  426,  426,  426,  426,
-      426,  464,  464,  464,  464,  464,  465,  418,  418,  418,
-      418,  418,  424,  425,  425,  425,  425,  425,  425,  425,
-      425,  432,  433,  434,  435,  432,  432,  432,  432,  437,
-      438,  439,  437,  437,  437,  437,  437,  259,  172,  214,
-      554,  122,  554,  334,  333,  332,  331,  357,  468,   86,
-      402,  402,  402,  402,  402,  402,  402,  402,  391,  466,
-      441,  441,  441,  441,  441,  441,  441,  441,  393,  391,
-      469,  441,  441,  441,  441,  441,  441,  330,  321,  393,
-      391,  467,  442,  442,  442,  442,  442,  442,  442,  442,
-
-      443,  320,  319,  444,  444,  444,  444,  444,  445,  445,
-      445,  445,  445,  445,  445,  445,  495,  495,  495,  495,
-      495,  496,  444,  444,  444,  444,  444,  448,  449,  450,
-      448,  448,  448,  448,  448,  451,  318,  317,  452,  452,
-      452,  452,  452,  609,  299,  444,  444,  444,  444,  444,
-      444,  444,  444,  259,  172,  257,  214,  452,  452,  452,
-      452,  452,  453,  410,  456,  456,  456,  456,  456,  457,
-      454,  454,  418,  418,  418,  418,  418,  418,  418,  418,
-      609,  172,  463,  463,  463,  463,  463,  463,  463,  463,
-      410,  259,  172,  460,  460,  460,  460,  460,  460,  460,
-
-      460,  410,  295,  214,  459,  459,  459,  459,  459,  259,
-      172,  460,  460,  460,  460,  460,  460,  468,  106,  410,
-      288,  287,  286,  459,  459,  459,  459,  459,  259,  172,
-      461,  461,  461,  461,  461,  461,  461,  461,  285,  469,
-      284,  462,  462,  462,  462,  462,  609,  391,  462,  462,
-      462,  462,  462,  462,  462,  462,  100,  492,  277,  582,
-      462,  462,  462,  462,  462,  472,  473,  474,  475,  472,
-      472,  472,  472,  478,  478,  478,  478,  478,  478,  478,
-      478,  479,  479,  479,  479,  479,  480,  481,  481,   86,
-      276,  275,  592,  122,  476,  609,  477,  477,  477,  477,
-
-      477,  477,  477,  477,  483,  492,  486,  486,  486,  486,
-      486,  487,  484,  484,  452,  452,  452,  452,  452,  452,
-      452,  452,  122,  274,   86,  391,  273,  490,  490,  490,
-      490,  490,  490,  490,  490,  443,  391,  100,  490,  490,
-      490,  490,  490,  490,  214,  257,  443,  391,  391,  491,
-      491,  491,  491,  491,  491,  491,  491,  492,  492,  214,
-      493,  493,  493,  493,  493,  494,  494,  494,  494,  494,
-      494,  494,  494,  531,  531,  531,  531,  531,  532,  493,
-      493,  493,  493,  493,  497,  498,  499,  497,  497,  497,
-      497,  497,  500,  106,  203,  501,  501,  501,  501,  501,
-
-      609,  172,  493,  493,  493,  493,  493,  493,  493,  493,
-      410,  246,  245,  244,  501,  501,  501,  501,  501,  502,
-      503,  504,  502,  502,  502,  502,  502,  453,  243,  454,
-      454,  454,  454,  454,  454,  259,  172,  259,  172,  507,
-      507,  507,  507,  507,  507,  410,  259,  172,  507,  507,
-      507,  507,  507,  507,  507,  507,  509,  242,  510,  510,
-      510,  510,  510,  510,  510,  510,  511,  511,  511,  511,
-      511,  511,  511,  511,  512,  512,  512,  512,  512,  513,
-      514,  514,  241,  520,  520,  520,  122,  516,  517,  518,
-      516,  516,  516,  516,  516,  481,  481,  481,  481,  481,
-
-      481,  481,  481,  481,  481,  481,  481,  481,  481,  481,
-      481,   86,  131,  189,  232,   86,  481,  481,  481,  481,
-      481,  481,  519,  519,  519,  519,  519,  519,  519,  519,
-      519,  519,  476,  229,  520,  520,  520,  521,  522,  523,
-      521,  521,  521,  521,  521,  483,  228,  484,  484,  484,
-      484,  484,  484,  501,  501,  501,  501,  501,  501,  501,
-      501,  227,   86,  391,  226,  526,  526,  526,  526,  526,
-      526,  526,  526,  492,  391,  225,  526,  526,  526,  526,
-      526,  526,  224,  106,  492,  391,  391,  527,  527,  527,
-      527,  527,  527,  527,  527,  528,  528,   98,  529,  529,
-
-      529,  529,  529,  530,  530,  530,  530,  530,  530,  530,
-      530,  563,  563,  563,  563,  563,  564,  529,  529,  529,
-      529,  529,  533,  534,  535,  533,  533,  533,  533,  533,
-      203,  159,  160,  536,  536,  536,  536,  536,  609,  609,
-      529,  529,  529,  529,  529,  529,  529,  529,  154,  528,
-      154,  147,  536,  536,  536,  536,  536,  172,  539,  539,
-      539,  539,  539,  540,  537,  537,  121,  145,  542,  543,
-      544,  542,  542,  542,  542,  542,  514,  514,  514,  514,
-      514,  514,  514,  514,  514,  514,  514,  514,  514,  514,
-      514,  514,  514,  514,  514,  514,  514,  514,  545,  545,
-
-      545,  545,  545,  545,  545,  545,  545,  545,  509,  201,
-      546,  546,  546,  547,  391,  548,  548,  548,  548,  548,
-      548,  548,  548,  547,  528,  549,  549,  549,  549,  549,
-      549,  549,  549,  200,  196,  121,  128,  547,  122,  550,
-      550,  550,  550,  550,  551,  548,  548,   85,  126,  519,
-      519,  519,  519,  519,  519,  519,  519,  552,  189,  555,
-      555,  555,  555,  555,  556,  553,  553,  536,  536,  536,
-      536,  536,  536,  536,  536,  391,  122,  559,  559,  559,
-      559,  559,  559,  559,  559,  528,  391,  181,  559,  559,
-      559,  559,  559,  559,  180,  176,  528,  391,  106,  560,
-
-      560,  560,  560,  560,  560,  560,  560,  546,  546,  546,
-      561,  561,  561,  561,  561,  562,  562,  562,  562,  562,
-      562,  562,  562,  587,  587,  587,  587,  587,  587,  561,
-      561,  561,  561,  561,  609,  122,  561,  561,  561,  561,
-      561,  561,  561,  561,  172,  537,  537,  537,  537,  537,
-      537,  565,   85,  566,  566,  566,  566,  566,  566,  566,
-      566,  565,  106,  567,  567,  567,  567,  567,  567,  567,
-      567,  565,  165,  568,  568,  568,  568,  568,  569,  566,
-      566,  121,   94,  545,  545,  545,  545,  545,  545,  545,
-      545,  570,  571,  572,  570,  570,  570,  570,  570,  547,
-
-       92,  548,  548,  548,  548,  548,  548,  548,  548,  547,
-       90,  548,  548,  548,  548,  548,  548,  548,  548,   86,
-      547,   88,  548,  548,  548,  548,  548,  548,  573,  574,
-      575,  573,  573,  573,  573,  573,  552,   87,  553,  553,
-      553,  553,  553,  553,   86,  160,  154,  147,  145,  391,
-       86,  578,  578,  578,  578,  578,  578,  578,  578,  579,
-      580,  581,  579,  579,  579,  579,  579,  565,  142,  566,
-      566,  566,  566,  566,  566,  566,  566,  565,  141,  566,
-      566,  566,  566,  566,  566,  566,  566,  122,  565,  140,
-      566,  566,  566,  566,  566,  566,  582,  139,  583,  583,
-
-      583,  583,  583,  583,  583,  583,  582,  128,  584,  584,
-      584,  584,  584,  584,  584,  584,  126,  582,  122,  585,
-      585,  585,  585,  585,  586,  583,  583,  587,  587,  587,
-      587,  587,  587,  587,  587,  588,  588,  588,  588,  588,
-      588,  588,  588,  589,  589,  589,  589,  589,  590,  587,
-      587,  592,  122,  593,  593,  593,  593,  593,  593,  593,
-      593,  592,  120,  594,  594,  594,  594,  594,  594,  594,
-      594,  592,  119,  595,  595,  595,  595,  595,  596,  593,
-      593,   85,  118,  597,  598,  599,  597,  597,  597,  597,
-      597,  582,  117,  583,  583,  583,  583,  583,  583,  583,
-
-      583,  582,  116,  583,  583,  583,  583,  583,  583,  583,
-      583,  582,  112,  583,  583,  583,  583,  583,  583,  587,
-      587,  587,  587,  587,  587,  587,  587,  587,  587,  587,
-      587,  587,  587,  587,  587,  111,  110,  109,  106,   94,
-      121,   86,  600,  601,  602,  600,  600,  600,  600,  600,
-      592,   92,  593,  593,  593,  593,  593,  593,  593,  593,
-      592,   90,  593,  593,  593,  593,  593,  593,  593,  593,
-      592,   88,  593,  593,  593,  593,  593,  593,  603,  603,
-      603,  603,  603,  603,  603,  603,  597,  597,  597,  597,
-      597,  597,  597,  597,   87,   86,  609,  609,  609,  609,
-
-      122,  609,  609,  609,  609,  609,   86,  609,  609,  609,
-      609,  609,  609,  609,   86,  604,  604,  604,  604,  604,
-      605,  603,  603,  606,  606,  606,  606,  606,  606,  606,
-      606,  600,  600,  600,  600,  600,  600,  600,  600,  609,
-      609,  609,  609,   86,  609,  609,  609,  609,  609,  609,
-      609,  122,  603,  603,  603,  603,  603,  603,  609,  122,
-      607,  607,  607,  607,  607,  608,  606,  606,  603,  603,
-      603,  603,  603,  603,  603,  603,  609,  609,  609,  609,
-       86,  606,  606,  606,  606,  606,  606,  609,  122,  609,
-      609,  609,  609,  609,  609,  609,   86,  606,  606,  606,
-
-      606,  606,  606,  606,  606,  609,  609,  609,  609,  122,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  122,   65,   65,   65,   65,
-       65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
-       65,   23,   23,   23,   23,   23,   23,   23,   23,   23,
-       23,   23,   23,   23,   23,   23,   73,   73,   73,   73,
-       73,   73,   73,   73,   73,   73,   73,   73,   73,   73,
-       73,   80,   80,   80,   80,   80,   80,   80,   80,   80,
-       80,   80,   80,   80,   80,   80,   85,  609,  609,  609,
-       85,  609,   85,   85,   85,   85,  609,   85,   85,   85,
-
-       85,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   91,  609,  609,  609,
-       91,  609,   91,   91,   91,   91,  609,   91,   91,   91,
-       91,   93,  609,  609,  609,   93,  609,   93,   93,   93,
-       93,  609,   93,   93,   93,   93,   95,  609,  609,   95,
-       95,  609,   95,   95,   95,   95,  609,   95,   95,   95,
-       95,  105,  105,  105,  609,  609,  105,  121,  609,  609,
-      609,  121,  609,  121,  121,  121,  121,  609,  121,  121,
-      121,  121,  123,  123,  123,  123,  123,  123,  123,  123,
-      123,  123,  123,  123,  123,  123,  123,  125,  609,  609,
-
-      609,  125,  609,  125,  125,  125,  125,  609,  125,  125,
-      125,  125,  127,  609,  609,  609,  127,  609,  127,  127,
-      127,  127,  609,  127,  127,  127,  127,  129,  609,  609,
-      129,  129,  609,  129,  129,  129,  129,  609,  129,  129,
-      129,  129,  146,  609,  609,  146,  146,  146,  146,  146,
-      146,  146,  609,  146,  609,  146,  146,  153,  609,  609,
-      153,  153,  609,  153,  153,  153,  153,  153,  153,  153,
-      153,  153,  157,  157,  157,  157,  157,  157,  157,  157,
-      157,  157,  157,  157,  157,  157,  157,  159,  159,  609,
-      159,  609,  159,  159,  159,  159,  159,  159,  159,  159,
-
-      159,  159,   96,  609,  609,   96,   96,  609,   96,   96,
-       96,   96,  609,   96,   96,   96,   96,  171,  171,  171,
-      609,  609,  171,  173,  173,  173,  173,  609,  609,  173,
-      188,  188,  188,  188,  188,  188,  188,  188,  188,  188,
-      188,  188,  188,  188,  188,  210,  210,  210,  609,  609,
-      210,  216,  216,  216,  216,  609,  609,  216,  251,  251,
-      251,  609,  609,  251,  252,  252,  252,  609,  609,  252,
-      256,  256,  256,  609,  609,  256,  258,  258,  258,  258,
-      609,  609,  258,  295,  295,  295,  609,  609,  295,  297,
-      297,  297,  609,  609,  297,  298,  298,  298,  609,  609,
-
-      298,  300,  300,  300,  300,  609,  609,  300,  304,  304,
-      304,  304,  304,  609,  609,  304,  339,  339,  339,  609,
-      609,  339,  340,  340,  340,  609,  609,  340,  341,  341,
-      341,  609,  609,  341,  353,  353,  353,  353,  609,  609,
-      353,  354,  354,  354,  354,  354,  609,  609,  354,  389,
-      389,  389,  609,  609,  389,  390,  390,  390,  609,  609,
-      390,  406,  406,  406,  406,  609,  609,  406,  407,  407,
-      407,  407,  407,  609,  609,  407,  436,  436,  436,  609,
-      609,  436,  440,  609,  440,  440,  440,  609,  609,  440,
-      458,  458,  458,  458,  609,  609,  458,  459,  459,  459,
-
-      459,  459,  609,  609,  459,  488,  488,  488,  609,  609,
-      488,  489,  609,  489,  489,  489,  609,  609,  489,  505,
-      505,  505,  505,  609,  609,  505,  506,  506,  506,  609,
-      506,  609,  609,  506,  524,  524,  524,  609,  609,  524,
-      525,  609,  525,  525,  525,  609,  609,  525,  541,  541,
-      609,  541,  609,  609,  541,  557,  557,  557,  609,  609,
-      557,  558,  609,  558,  558,  558,  609,  609,  558,  576,
-      576,  576,  609,  609,  576,  577,  609,  577,  609,  577,
-      609,  609,  577,  591,  609,  591,  609,  609,  591,   15,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609
-    } ;
-
-static yyconst short int yy_chk[3851] =
-    {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        2,    2,  322,    5,    2,   71,   71,    5,    2,    5,
-      322,    2,    3,    3,    3,    3,    3,    3,    3,    3,
-        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-
-        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-        3,    3,    6,    7,    7,    7,    6,    7,    6,   75,
-        8,    8,    8,    7,    8,   40,   13,   13,   13,   13,
-        8,   14,   14,   14,   14,    7,    7,   63,   75,   79,
-       79,   40,    8,    8,   26,  106,  606,  115,   26,   26,
-       77,  115,   81,   63,  106,    7,   29,   29,   29,   29,
-       29,   29,    8,    9,    9,    9,   26,    9,   13,   77,
-      186,  116,  186,   14,   28,   28,   28,   28,   28,   28,
-
-       28,   28,  116,   39,   26,   39,   39,   39,   39,   39,
-       39,   39,   39,   47,   81,  173,   47,   47,   47,   47,
-       47,   47,   47,   47,  173,    9,    9,    9,    9,    9,
-        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
-        9,    9,   10,   10,   10,  117,   10,   53,   53,   53,
-       53,   53,   53,   53,   53,   54,   54,   54,   54,   54,
-       54,   62,  118,   62,   62,   62,   62,   62,   62,   62,
-       62,   84,   84,  144,   84,  110,  118,  144,   82,  183,
-      110,  117,  110,  183,   10,   10,   10,   10,   10,   10,
-       10,   10,   10,   10,   10,   10,   10,   10,   10,   10,
-
-       10,   11,   11,   11,   11,   11,  148,  148,  182,   51,
-       11,   11,   11,   51,   51,   70,   70,   70,   82,   70,
-      182,  120,  140,   70,   11,   70,  120,  140,   95,  140,
-      119,   51,   95,   95,  151,  151,  603,   70,   70,  113,
-      113,  119,  162,   11,   12,   12,   12,   12,   12,   51,
-       95,  163,  163,   12,   12,   12,   86,   70,   86,  578,
-       86,  335,   86,   86,  208,  208,   86,   12,   95,  335,
-       98,   98,   98,   98,   98,   98,   98,   98,   86,   86,
-       86,  113,  162,  143,  143,  161,   12,   27,  205,   27,
-       27,   27,   27,   27,   27,   27,   27,   27,   98,  185,
-
-       27,   27,   27,   27,   27,  102,  102,  102,  102,  102,
-      102,  102,  102,  187,  185,  209,  576,   27,  205,   27,
-       27,   27,   27,   27,   32,  143,  187,  161,   32,  561,
-       32,  231,  231,   32,   32,  209,   32,   32,   32,   32,
-       32,   32,   32,   32,   32,   32,   32,   32,  238,  238,
-       32,   32,   32,   32,   32,   32,   32,   32,   32,   32,
-       32,   32,   32,   32,   32,   32,   32,   32,   32,   32,
-       32,   32,   32,   32,   32,   32,   32,   32,   32,   32,
-       32,   32,   32,   32,   34,   34,   34,   34,   34,   34,
-       34,   34,   34,  158,  158,   34,   34,   34,   34,   34,
-
-      103,  103,  103,  103,  103,  103,  103,  103,  104,  104,
-      104,  104,  104,  104,   34,   34,   34,   34,   34,   38,
-       38,   38,  202,   38,  278,   38,   38,  216,  278,   38,
-      213,  213,  213,  129,  202,  158,  216,  129,  129,  279,
-      224,   38,   38,   38,   52,  235,   52,   52,   52,   52,
-       52,   52,   52,   52,   52,  129,  279,   52,   52,   52,
-       52,   52,  224,  560,  131,  131,  131,  131,  131,  131,
-      131,  131,  233,  129,   52,  235,   52,   52,   52,   52,
-       52,   55,  558,  230,  241,   55,  233,   55,  230,  557,
-       55,   55,  131,   55,   55,   55,   55,   55,   55,   55,
-
-       55,   55,   55,   55,   55,  555,  241,   55,   55,   55,
-       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
-       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
-       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
-       55,   57,   57,   57,   57,   57,   57,   57,   57,   57,
-      385,  554,   57,   57,   57,   57,   57,  134,  134,  134,
-      134,  134,  134,  134,  134,  136,  136,  136,  136,  136,
-      136,   57,   57,   57,   57,   57,   61,   61,   61,  385,
-       61,  258,   61,   61,  239,   92,   61,   92,  247,   92,
-      258,   92,   92,  247,  280,   92,  260,  260,   61,   61,
-
-       61,  154,  553,  280,  239,  154,  260,   92,   92,   92,
-       94,  154,   94,  324,   94,  541,   94,   94,  289,   97,
-       94,   97,  289,   97,  154,   97,   97,  539,  324,   97,
-      271,  317,   94,   94,   94,  168,  168,  168,  168,  168,
-      168,   97,   97,   97,   99,   99,   99,   99,   99,   99,
-       99,   99,  271,  317,  538,   99,   99,   99,   99,   99,
-      135,  135,  135,  135,  135,  135,  135,  135,  192,  192,
-      192,  192,  192,  192,   99,   99,   99,   99,   99,  107,
-      107,  107,  107,  107,  107,  107,  107,  232,  262,  262,
-      107,  107,  107,  107,  107,  122,  537,  122,  262,  122,
-
-      376,  122,  122,  525,  291,  122,  300,  232,  376,  107,
-      107,  107,  107,  107,  377,  300,  304,  122,  122,  122,
-      126,  524,  126,  232,  126,  304,  126,  126,  377,  128,
-      126,  128,  326,  128,  291,  128,  128,  305,  305,  128,
-      306,  306,  126,  126,  126,  165,  522,  305,  323,  165,
-      306,  128,  128,  128,  130,  165,  130,  323,  130,  477,
-      130,  130,  326,  521,  130,  308,  308,  165,  165,  220,
-      220,  220,  220,  220,  220,  308,  130,  130,  130,  132,
-      132,  132,  132,  132,  132,  132,  132,  388,  388,  477,
-      132,  132,  132,  132,  132,  167,  167,  167,  167,  167,
-
-      167,  167,  167,  268,  268,  268,  268,  268,  268,  132,
-      132,  132,  132,  132,  137,  137,  137,  137,  137,  137,
-      137,  137,  422,  508,  422,  137,  137,  137,  137,  137,
-      191,  191,  191,  191,  191,  191,  191,  191,  314,  314,
-      314,  314,  314,  314,  137,  137,  137,  137,  137,  166,
-      392,  166,  166,  166,  166,  166,  166,  166,  166,  320,
-      392,  506,  204,  204,  204,  204,  204,  204,  204,  204,
-      212,  212,  212,  212,  212,  212,  212,  212,  212,  166,
-      169,  320,  169,  169,  169,  169,  169,  169,  169,  169,
-      204,  428,  428,  169,  169,  169,  169,  169,  217,  217,
-
-      217,  217,  217,  217,  217,  217,  338,  338,  338,  338,
-      338,  338,  169,  169,  169,  169,  169,  172,  172,  172,
-      172,  172,  172,  172,  172,  172,  503,  375,  172,  172,
-      172,  172,  172,  219,  219,  219,  219,  219,  219,  219,
-      219,  321,  375,  435,  435,  435,  502,  172,  172,  172,
-      172,  172,  174,  174,  174,  174,  174,  174,  174,  174,
-      174,  174,  489,  321,  174,  174,  174,  174,  174,  222,
-      353,  222,  222,  222,  222,  222,  222,  222,  222,  353,
-      488,  383,  330,  174,  174,  174,  174,  174,  175,  175,
-      175,  175,  175,  175,  175,  175,  383,  461,  461,  175,
-
-      175,  175,  175,  175,  330,  234,  234,  234,  234,  234,
-      234,  234,  234,  333,  486,  354,  462,  462,  175,  175,
-      175,  175,  175,  190,  354,  190,  190,  190,  190,  190,
-      190,  190,  190,  234,  248,  333,  248,  248,  248,  248,
-      248,  248,  248,  248,  253,  253,  253,  253,  253,  253,
-      253,  253,  253,  190,  193,  394,  193,  193,  193,  193,
-      193,  193,  193,  193,  406,  394,  485,  193,  193,  193,
-      193,  193,  249,  406,  249,  249,  249,  249,  249,  249,
-      249,  249,  475,  475,  475,  484,  193,  193,  193,  193,
-      193,  195,  195,  195,  195,  195,  195,  195,  195,  407,
-
-      507,  507,  195,  195,  195,  195,  195,  250,  407,  250,
-      250,  250,  250,  250,  250,  250,  250,  423,  649,  423,
-      649,  195,  195,  195,  195,  195,  218,  218,  218,  218,
-      218,  218,  218,  218,  218,  218,  218,  423,  456,  218,
-      218,  218,  218,  218,  259,  259,  259,  259,  259,  259,
-      259,  259,  334,  564,  564,  626,  626,  455,  218,  218,
-      218,  218,  218,  221,  221,  221,  221,  221,  221,  221,
-      221,  221,  221,  454,  334,  221,  221,  221,  221,  221,
-      261,  261,  261,  261,  261,  261,  261,  261,  345,  345,
-      345,  345,  345,  345,  221,  221,  221,  221,  221,  263,
-
-      263,  263,  263,  263,  263,  263,  263,  263,  263,  263,
-      671,  671,  263,  263,  263,  263,  263,  265,  265,  265,
-      265,  265,  265,  265,  265,  367,  371,  265,  650,  440,
-      650,  263,  263,  263,  263,  263,  266,  266,  266,  266,
-      266,  266,  266,  266,  266,  266,  266,  367,  371,  266,
-      266,  266,  266,  266,  267,  267,  267,  267,  267,  267,
-      267,  267,  364,  364,  364,  364,  364,  364,  266,  266,
-      266,  266,  266,  269,  269,  269,  269,  269,  269,  269,
-      269,  269,  269,  672,  672,  269,  269,  269,  269,  269,
-      270,  425,  270,  270,  270,  270,  270,  270,  270,  270,
-
-      355,  355,  438,  437,  269,  269,  269,  269,  269,  281,
-      355,  281,  281,  281,  281,  281,  281,  281,  281,  282,
-      425,  282,  282,  282,  282,  282,  282,  282,  282,  283,
-      436,  283,  283,  283,  283,  283,  283,  283,  283,  290,
-      290,  290,  290,  290,  290,  290,  290,  292,  441,  292,
-      292,  292,  292,  292,  292,  292,  292,  293,  441,  293,
-      293,  293,  293,  293,  293,  293,  293,  290,  294,  431,
-      294,  294,  294,  294,  294,  294,  303,  421,  303,  303,
-      303,  303,  303,  303,  303,  303,  307,  307,  307,  307,
-      307,  307,  307,  307,  470,  404,  510,  548,  294,  299,
-
-      299,  299,  299,  299,  299,  299,  299,  299,  470,  403,
-      299,  299,  299,  299,  299,  311,  311,  311,  311,  311,
-      311,  311,  311,  373,  419,  311,  510,  548,  390,  299,
-      299,  299,  299,  299,  309,  309,  309,  309,  309,  309,
-      309,  309,  309,  309,  309,  373,  419,  309,  309,  309,
-      309,  309,  313,  313,  313,  313,  313,  313,  313,  313,
-      380,  380,  380,  380,  380,  380,  309,  309,  309,  309,
-      309,  312,  312,  312,  312,  312,  312,  312,  312,  312,
-      312,  312,  389,  382,  312,  312,  312,  312,  312,  316,
-      442,  316,  316,  316,  316,  316,  316,  316,  316,  634,
-
-      442,  381,  634,  312,  312,  312,  312,  312,  315,  315,
-      315,  315,  315,  315,  315,  315,  315,  315,  370,  369,
-      315,  315,  315,  315,  315,  325,  325,  325,  325,  325,
-      325,  325,  325,  351,  350,  356,  356,  349,  341,  315,
-      315,  315,  315,  315,  329,  356,  329,  329,  329,  329,
-      329,  329,  327,  325,  327,  327,  327,  327,  327,  327,
-      327,  327,  328,  444,  328,  328,  328,  328,  328,  328,
-      328,  328,  566,  444,  329,  336,  336,  336,  336,  336,
-      336,  336,  336,  336,  337,  337,  337,  337,  337,  337,
-      337,  337,  342,  342,  342,  342,  342,  342,  342,  342,
-
-      340,  659,  566,  659,  336,  343,  490,  343,  343,  343,
-      343,  343,  343,  343,  343,  343,  490,  339,  343,  343,
-      343,  343,  343,  344,  344,  344,  344,  344,  344,  344,
-      344,  400,  400,  400,  400,  400,  400,  343,  343,  343,
-      343,  343,  346,  346,  346,  346,  346,  346,  346,  346,
-      346,  332,  331,  346,  346,  346,  346,  346,  347,  458,
-      347,  347,  347,  347,  347,  347,  347,  347,  458,  660,
-      319,  660,  346,  346,  346,  346,  346,  348,  348,  348,
-      348,  348,  348,  348,  348,  352,  318,  352,  352,  352,
-      352,  352,  352,  357,  357,  357,  357,  357,  357,  357,
-
-      357,  358,  358,  363,  363,  363,  363,  363,  363,  363,
-      363,  358,  359,  359,  359,  359,  359,  359,  359,  359,
-      359,  359,  359,  302,  301,  359,  359,  359,  359,  359,
-      361,  361,  361,  361,  361,  361,  361,  361,  420,  429,
-      361,  663,  298,  663,  359,  359,  359,  359,  359,  362,
-      362,  362,  362,  362,  362,  362,  362,  362,  362,  362,
-      420,  429,  362,  362,  362,  362,  362,  366,  459,  366,
-      366,  366,  366,  366,  366,  366,  366,  459,  664,  297,
-      664,  362,  362,  362,  362,  362,  365,  365,  365,  365,
-      365,  365,  365,  365,  365,  674,  296,  674,  365,  365,
-
-      365,  365,  365,  379,  379,  379,  379,  379,  379,  379,
-      379,  417,  417,  417,  417,  417,  417,  365,  365,  365,
-      365,  365,  378,  378,  378,  378,  378,  378,  378,  378,
-      378,  384,  384,  384,  384,  384,  384,  384,  384,  391,
-      391,  391,  391,  391,  391,  391,  391,  408,  408,  295,
-      675,  378,  675,  288,  287,  286,  285,  408,  430,  384,
-      393,  393,  393,  393,  393,  393,  393,  393,  395,  466,
-      395,  395,  395,  395,  395,  395,  395,  395,  395,  397,
-      430,  397,  397,  397,  397,  397,  397,  284,  277,  397,
-      398,  466,  398,  398,  398,  398,  398,  398,  398,  398,
-
-      398,  276,  275,  398,  398,  398,  398,  398,  399,  399,
-      399,  399,  399,  399,  399,  399,  450,  450,  450,  450,
-      450,  450,  398,  398,  398,  398,  398,  401,  401,  401,
-      401,  401,  401,  401,  401,  401,  274,  273,  401,  401,
-      401,  401,  401,  402,  257,  402,  402,  402,  402,  402,
-      402,  402,  402,  409,  409,  256,  255,  401,  401,  401,
-      401,  401,  405,  409,  405,  405,  405,  405,  405,  405,
-      405,  405,  410,  410,  410,  410,  410,  410,  410,  410,
-      411,  411,  416,  416,  416,  416,  416,  416,  416,  416,
-      411,  412,  412,  412,  412,  412,  412,  412,  412,  412,
-
-      412,  412,  254,  252,  412,  412,  412,  412,  412,  414,
-      414,  414,  414,  414,  414,  414,  414,  468,  251,  414,
-      246,  245,  244,  412,  412,  412,  412,  412,  415,  415,
-      415,  415,  415,  415,  415,  415,  415,  415,  243,  468,
-      242,  415,  415,  415,  415,  415,  418,  491,  418,  418,
-      418,  418,  418,  418,  418,  418,  240,  491,  229,  583,
-      415,  415,  415,  415,  415,  424,  424,  424,  424,  424,
-      424,  424,  424,  433,  433,  433,  433,  433,  433,  433,
-      433,  434,  434,  434,  434,  434,  434,  434,  434,  583,
-      228,  227,  593,  424,  432,  493,  432,  432,  432,  432,
-
-      432,  432,  432,  432,  439,  493,  439,  439,  439,  439,
-      439,  439,  439,  439,  443,  443,  443,  443,  443,  443,
-      443,  443,  593,  226,  432,  445,  225,  445,  445,  445,
-      445,  445,  445,  445,  445,  445,  447,  223,  447,  447,
-      447,  447,  447,  447,  215,  214,  447,  448,  526,  448,
-      448,  448,  448,  448,  448,  448,  448,  448,  526,  211,
-      448,  448,  448,  448,  448,  449,  449,  449,  449,  449,
-      449,  449,  449,  499,  499,  499,  499,  499,  499,  448,
-      448,  448,  448,  448,  451,  451,  451,  451,  451,  451,
-      451,  451,  451,  210,  203,  451,  451,  451,  451,  451,
-
-      452,  505,  452,  452,  452,  452,  452,  452,  452,  452,
-      505,  201,  200,  199,  451,  451,  451,  451,  451,  453,
-      453,  453,  453,  453,  453,  453,  453,  457,  198,  457,
-      457,  457,  457,  457,  457,  460,  460,  465,  465,  465,
-      465,  465,  465,  465,  465,  460,  463,  463,  463,  463,
-      463,  463,  463,  463,  463,  463,  472,  197,  472,  472,
-      472,  472,  472,  472,  472,  472,  473,  473,  473,  473,
-      473,  473,  473,  473,  474,  474,  474,  474,  474,  474,
-      474,  474,  196,  520,  520,  520,  472,  476,  476,  476,
-      476,  476,  476,  476,  476,  478,  478,  478,  478,  478,
-
-      478,  478,  478,  479,  479,  479,  479,  479,  479,  479,
-      479,  520,  194,  188,  184,  476,  480,  480,  480,  480,
-      480,  480,  480,  480,  481,  481,  481,  481,  481,  481,
-      481,  481,  482,  181,  482,  482,  482,  483,  483,  483,
-      483,  483,  483,  483,  483,  487,  180,  487,  487,  487,
-      487,  487,  487,  492,  492,  492,  492,  492,  492,  492,
-      492,  179,  482,  494,  178,  494,  494,  494,  494,  494,
-      494,  494,  494,  494,  496,  177,  496,  496,  496,  496,
-      496,  496,  176,  171,  496,  497,  527,  497,  497,  497,
-      497,  497,  497,  497,  497,  497,  527,  170,  497,  497,
-
-      497,  497,  497,  498,  498,  498,  498,  498,  498,  498,
-      498,  535,  535,  535,  535,  535,  535,  497,  497,  497,
-      497,  497,  500,  500,  500,  500,  500,  500,  500,  500,
-      164,  160,  159,  500,  500,  500,  500,  500,  501,  529,
-      501,  501,  501,  501,  501,  501,  501,  501,  157,  529,
-      153,  147,  500,  500,  500,  500,  500,  504,  504,  504,
-      504,  504,  504,  504,  504,  504,  509,  145,  509,  509,
-      509,  509,  509,  509,  509,  509,  511,  511,  511,  511,
-      511,  511,  511,  511,  512,  512,  512,  512,  512,  512,
-      512,  512,  513,  513,  513,  513,  513,  513,  513,  513,
-
-      514,  514,  514,  514,  514,  514,  514,  514,  515,  142,
-      515,  515,  515,  516,  559,  516,  516,  516,  516,  516,
-      516,  516,  516,  517,  559,  517,  517,  517,  517,  517,
-      517,  517,  517,  141,  139,  133,  127,  518,  515,  518,
-      518,  518,  518,  518,  518,  518,  518,  519,  125,  519,
-      519,  519,  519,  519,  519,  519,  519,  523,  123,  523,
-      523,  523,  523,  523,  523,  523,  523,  528,  528,  528,
-      528,  528,  528,  528,  528,  530,  121,  530,  530,  530,
-      530,  530,  530,  530,  530,  530,  532,  112,  532,  532,
-      532,  532,  532,  532,  111,  109,  532,  533,  105,  533,
-
-      533,  533,  533,  533,  533,  533,  533,  546,  546,  546,
-      533,  533,  533,  533,  533,  534,  534,  534,  534,  534,
-      534,  534,  534,  590,  590,  590,  590,  590,  590,  533,
-      533,  533,  533,  533,  536,  546,  536,  536,  536,  536,
-      536,  536,  536,  536,  540,  540,  540,  540,  540,  540,
-      540,  542,  101,  542,  542,  542,  542,  542,  542,  542,
-      542,  543,  100,  543,  543,  543,  543,  543,  543,  543,
-      543,  544,   96,  544,  544,  544,  544,  544,  544,  544,
-      544,  545,   93,  545,  545,  545,  545,  545,  545,  545,
-      545,  547,  547,  547,  547,  547,  547,  547,  547,  549,
-
-       91,  549,  549,  549,  549,  549,  549,  549,  549,  550,
-       89,  550,  550,  550,  550,  550,  550,  550,  550,  547,
-      551,   88,  551,  551,  551,  551,  551,  551,  552,  552,
-      552,  552,  552,  552,  552,  552,  556,   87,  556,  556,
-      556,  556,  556,  556,   85,   80,   73,   67,   64,  562,
-      551,  562,  562,  562,  562,  562,  562,  562,  562,  565,
-      565,  565,  565,  565,  565,  565,  565,  567,   60,  567,
-      567,  567,  567,  567,  567,  567,  567,  568,   59,  568,
-      568,  568,  568,  568,  568,  568,  568,  565,  569,   58,
-      569,  569,  569,  569,  569,  569,  570,   56,  570,  570,
-
-      570,  570,  570,  570,  570,  570,  571,   50,  571,  571,
-      571,  571,  571,  571,  571,  571,   48,  572,  569,  572,
-      572,  572,  572,  572,  572,  572,  572,  573,  573,  573,
-      573,  573,  573,  573,  573,  574,  574,  574,  574,  574,
-      574,  574,  574,  575,  575,  575,  575,  575,  575,  575,
-      575,  579,   46,  579,  579,  579,  579,  579,  579,  579,
-      579,  580,   45,  580,  580,  580,  580,  580,  580,  580,
-      580,  581,   44,  581,  581,  581,  581,  581,  581,  581,
-      581,  582,   43,  582,  582,  582,  582,  582,  582,  582,
-      582,  584,   42,  584,  584,  584,  584,  584,  584,  584,
-
-      584,  585,   41,  585,  585,  585,  585,  585,  585,  585,
-      585,  586,   37,  586,  586,  586,  586,  586,  586,  588,
-      588,  588,  588,  588,  588,  588,  588,  589,  589,  589,
-      589,  589,  589,  589,  589,   36,   35,   33,   30,   24,
-      592,  586,  592,  592,  592,  592,  592,  592,  592,  592,
-      594,   21,  594,  594,  594,  594,  594,  594,  594,  594,
-      595,   20,  595,  595,  595,  595,  595,  595,  595,  595,
-      596,   19,  596,  596,  596,  596,  596,  596,  597,  597,
-      597,  597,  597,  597,  597,  597,  598,  598,  598,  598,
-      598,  598,  598,  598,   17,   16,   15,    0,    0,    0,
-
-      596,    0,    0,    0,    0,    0,  597,    0,    0,    0,
-        0,    0,    0,    0,  598,  599,  599,  599,  599,  599,
-      599,  599,  599,  600,  600,  600,  600,  600,  600,  600,
-      600,  601,  601,  601,  601,  601,  601,  601,  601,    0,
-        0,    0,    0,  599,    0,    0,    0,    0,    0,    0,
-        0,  600,  605,  605,  605,  605,  605,  605,    0,  601,
-      602,  602,  602,  602,  602,  602,  602,  602,  604,  604,
-      604,  604,  604,  604,  604,  604,    0,    0,    0,    0,
-      605,  608,  608,  608,  608,  608,  608,    0,  602,    0,
-        0,    0,    0,    0,    0,    0,  604,  607,  607,  607,
-
-      607,  607,  607,  607,  607,    0,    0,    0,    0,  608,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,  607,  610,  610,  610,  610,
-      610,  610,  610,  610,  610,  610,  610,  610,  610,  610,
-      610,  611,  611,  611,  611,  611,  611,  611,  611,  611,
-      611,  611,  611,  611,  611,  611,  612,  612,  612,  612,
-      612,  612,  612,  612,  612,  612,  612,  612,  612,  612,
-      612,  613,  613,  613,  613,  613,  613,  613,  613,  613,
-      613,  613,  613,  613,  613,  613,  614,    0,    0,    0,
-      614,    0,  614,  614,  614,  614,    0,  614,  614,  614,
-
-      614,  615,  615,  615,  615,  615,  615,  615,  615,  615,
-      615,  615,  615,  615,  615,  615,  616,    0,    0,    0,
-      616,    0,  616,  616,  616,  616,    0,  616,  616,  616,
-      616,  617,    0,    0,    0,  617,    0,  617,  617,  617,
-      617,    0,  617,  617,  617,  617,  618,    0,    0,  618,
-      618,    0,  618,  618,  618,  618,    0,  618,  618,  618,
-      618,  619,  619,  619,    0,    0,  619,  620,    0,    0,
-        0,  620,    0,  620,  620,  620,  620,    0,  620,  620,
-      620,  620,  621,  621,  621,  621,  621,  621,  621,  621,
-      621,  621,  621,  621,  621,  621,  621,  622,    0,    0,
-
-        0,  622,    0,  622,  622,  622,  622,    0,  622,  622,
-      622,  622,  623,    0,    0,    0,  623,    0,  623,  623,
-      623,  623,    0,  623,  623,  623,  623,  624,    0,    0,
-      624,  624,    0,  624,  624,  624,  624,    0,  624,  624,
-      624,  624,  625,    0,    0,  625,  625,  625,  625,  625,
-      625,  625,    0,  625,    0,  625,  625,  627,    0,    0,
-      627,  627,    0,  627,  627,  627,  627,  627,  627,  627,
-      627,  627,  628,  628,  628,  628,  628,  628,  628,  628,
-      628,  628,  628,  628,  628,  628,  628,  629,  629,    0,
-      629,    0,  629,  629,  629,  629,  629,  629,  629,  629,
-
-      629,  629,  630,    0,    0,  630,  630,    0,  630,  630,
-      630,  630,    0,  630,  630,  630,  630,  631,  631,  631,
-        0,    0,  631,  632,  632,  632,  632,    0,    0,  632,
-      633,  633,  633,  633,  633,  633,  633,  633,  633,  633,
-      633,  633,  633,  633,  633,  635,  635,  635,    0,    0,
-      635,  636,  636,  636,  636,    0,    0,  636,  637,  637,
-      637,    0,    0,  637,  638,  638,  638,    0,    0,  638,
-      639,  639,  639,    0,    0,  639,  640,  640,  640,  640,
-        0,    0,  640,  641,  641,  641,    0,    0,  641,  642,
-      642,  642,    0,    0,  642,  643,  643,  643,    0,    0,
-
-      643,  644,  644,  644,  644,    0,    0,  644,  645,  645,
-      645,  645,  645,    0,    0,  645,  646,  646,  646,    0,
-        0,  646,  647,  647,  647,    0,    0,  647,  648,  648,
-      648,    0,    0,  648,  651,  651,  651,  651,    0,    0,
-      651,  652,  652,  652,  652,  652,    0,    0,  652,  653,
-      653,  653,    0,    0,  653,  654,  654,  654,    0,    0,
-      654,  655,  655,  655,  655,    0,    0,  655,  656,  656,
-      656,  656,  656,    0,    0,  656,  657,  657,  657,    0,
-        0,  657,  658,    0,  658,  658,  658,    0,    0,  658,
-      661,  661,  661,  661,    0,    0,  661,  662,  662,  662,
-
-      662,  662,    0,    0,  662,  665,  665,  665,    0,    0,
-      665,  666,    0,  666,  666,  666,    0,    0,  666,  667,
-      667,  667,  667,    0,    0,  667,  668,  668,  668,    0,
-      668,    0,    0,  668,  669,  669,  669,    0,    0,  669,
-      670,    0,  670,  670,  670,    0,    0,  670,  673,  673,
-        0,  673,    0,    0,  673,  676,  676,  676,    0,    0,
-      676,  677,    0,  677,  677,  677,    0,    0,  677,  678,
-      678,  678,    0,    0,  678,  679,    0,  679,    0,  679,
-        0,    0,  679,  680,    0,  680,    0,    0,  680,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  609,  609,  609,  609,  609,  609,  609
-    } ;
-
-static yy_state_type yy_last_accepting_state;
-static char *yy_last_accepting_cpos;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
-#define yymore() yymore_used_but_not_detected
-#define YY_MORE_ADJ 0
-#define YY_RESTORE_YY_MORE_OFFSET
-char *yytext;
-#line 1 "parse.lex"
-#define INITIAL 0
-#line 2 "parse.lex"
-/*
- * Copyright (c) 1996, 1998-2004, 2007
- *     Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- * 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.
- *
- * Sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F39502-99-1-0512.
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <stdio.h>
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif /* STDC_HEADERS */
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# ifdef HAVE_STRINGS_H
-#  include <strings.h>
-# endif
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
-# include <malloc.h>
-#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
-#include <ctype.h>
-#include "sudo.h"
-#include "parse.h"
-#include <sudo.tab.h>
-
-#ifndef lint
-__unused static const char rcsid[] = "$Sudo: lex.yy.c,v 1.46.2.11 2008/06/26 11:53:49 millert Exp $";
-#endif /* lint */
-
-#undef yywrap          /* guard against a yywrap macro */
-
-extern YYSTYPE yylval;
-extern int clearaliases;
-int sudolineno = 1;
-static int sawspace = 0;
-static int arg_len = 0;
-static int arg_size = 0;
-
-static int ipv6_valid          __P((const char *s));
-static void _fill              __P((char *, int, int));
-static void append             __P((char *, int));
-static void fill_cmnd          __P((char *, int));
-static void fill_args          __P((char *, int, int));
-extern void reset_aliases      __P((void));
-extern void yyerror            __P((char *));
-
-#define fill(a, b)             _fill(a, b, 0)
-
-/* realloc() to size + COMMANDARGINC to make room for command args */
-#define COMMANDARGINC  64
-
-#ifdef TRACELEXER
-#define LEXTRACE(msg)  fputs(msg, stderr)
-#else
-#define LEXTRACE(msg)
-#endif
-/* XXX - convert GOTRUNAS to exclusive state (GOTDEFS cannot be) */
-#define GOTRUNAS 1
-
-#define GOTDEFS 2
-
-#define GOTCMND 3
-
-#define STARTDEFS 4
-
-#define INDEFS 5
-
-#define INSTR 6
-
-#line 1527 "lex.yy.c"
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int yywrap YY_PROTO(( void ));
-#else
-extern int yywrap YY_PROTO(( void ));
-#endif
-#endif
-
-#ifndef YY_NO_UNPUT
-static void yyunput YY_PROTO(( int c, char *buf_ptr ));
-#endif
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen YY_PROTO(( yyconst char * ));
-#endif
-
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
-static int yyinput YY_PROTO(( void ));
-#else
-static int input YY_PROTO(( void ));
-#endif
-#endif
-
-#if defined(YY_STACK_USED) && YY_STACK_USED
-static int yy_start_stack_ptr = 0;
-static int yy_start_stack_depth = 0;
-static int *yy_start_stack = 0;
-#ifndef YY_NO_PUSH_STATE
-static void yy_push_state YY_PROTO(( int new_state ));
-#endif
-#ifndef YY_NO_POP_STATE
-static void yy_pop_state YY_PROTO(( void ));
-#endif
-#ifndef YY_NO_TOP_STATE
-static int yy_top_state YY_PROTO(( void ));
-#endif
-
-#else
-#define YY_NO_PUSH_STATE 1
-#define YY_NO_POP_STATE 1
-#define YY_NO_TOP_STATE 1
-#endif
-
-#ifdef YY_MALLOC_DECL
-YY_MALLOC_DECL
-#else
-#ifdef __STDC__
-#ifndef __cplusplus
-#include <stdlib.h>
-#endif
-#else
-/* Just try to get by without declaring the routines.  This will fail
- * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
- * or sizeof(void*) != sizeof(int).
- */
-#endif
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#define YY_READ_BUF_SIZE 8192
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-
-#ifndef ECHO
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
-#endif
-
-/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
-       if ( yy_current_buffer->yy_is_interactive ) \
-               { \
-               int c = '*', n; \
-               for ( n = 0; n < max_size && \
-                            (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
-                       buf[n] = (char) c; \
-               if ( c == '\n' ) \
-                       buf[n++] = (char) c; \
-               if ( c == EOF && ferror( yyin ) ) \
-                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
-               result = n; \
-               } \
-       else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
-                 && ferror( yyin ) ) \
-               YY_FATAL_ERROR( "input in flex scanner failed" );
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
-#endif
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL int yylex YY_PROTO(( void ))
-#endif
-
-/* Code executed at the beginning of each rule, after yytext and yyleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK break;
-#endif
-
-#define YY_RULE_SETUP \
-       if ( yyleng > 0 ) \
-               yy_current_buffer->yy_at_bol = \
-                               (yytext[yyleng - 1] == '\n'); \
-       YY_USER_ACTION
-
-YY_DECL
-       {
-       register yy_state_type yy_current_state;
-       register char *yy_cp, *yy_bp;
-       register int yy_act;
-
-#line 108 "parse.lex"
-
-#line 1683 "lex.yy.c"
-
-       if ( yy_init )
-               {
-               yy_init = 0;
-
-#ifdef YY_USER_INIT
-               YY_USER_INIT;
-#endif
-
-               if ( ! yy_start )
-                       yy_start = 1;   /* first start state */
-
-               if ( ! yyin )
-                       yyin = stdin;
-
-               if ( ! yyout )
-                       yyout = stdout;
-
-               if ( ! yy_current_buffer )
-                       yy_current_buffer =
-                               yy_create_buffer( yyin, YY_BUF_SIZE );
-
-               yy_load_buffer_state();
-               }
-
-       while ( 1 )             /* loops until end-of-file is reached */
-               {
-               yy_cp = yy_c_buf_p;
-
-               /* Support of yytext. */
-               *yy_cp = yy_hold_char;
-
-               /* yy_bp points to the position in yy_ch_buf of the start of
-                * the current run.
-                */
-               yy_bp = yy_cp;
-
-               yy_current_state = yy_start;
-               yy_current_state += YY_AT_BOL();
-yy_match:
-               do
-                       {
-                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
-                       if ( yy_accept[yy_current_state] )
-                               {
-                               yy_last_accepting_state = yy_current_state;
-                               yy_last_accepting_cpos = yy_cp;
-                               }
-                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-                               {
-                               yy_current_state = (int) yy_def[yy_current_state];
-                               if ( yy_current_state >= 610 )
-                                       yy_c = yy_meta[(unsigned int) yy_c];
-                               }
-                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-                       ++yy_cp;
-                       }
-               while ( yy_base[yy_current_state] != 3790 );
-
-yy_find_action:
-               yy_act = yy_accept[yy_current_state];
-               if ( yy_act == 0 )
-                       { /* have to back up */
-                       yy_cp = yy_last_accepting_cpos;
-                       yy_current_state = yy_last_accepting_state;
-                       yy_act = yy_accept[yy_current_state];
-                       }
-
-               YY_DO_BEFORE_ACTION;
-
-
-do_action:     /* This label is used only to access EOF actions. */
-
-
-               switch ( yy_act )
-       { /* beginning of action switch */
-                       case 0: /* must back up */
-                       /* undo the effects of YY_DO_BEFORE_ACTION */
-                       *yy_cp = yy_hold_char;
-                       yy_cp = yy_last_accepting_cpos;
-                       yy_current_state = yy_last_accepting_state;
-                       goto yy_find_action;
-
-case 1:
-YY_RULE_SETUP
-#line 109 "parse.lex"
-BEGIN STARTDEFS;
-       YY_BREAK
-case 2:
-YY_RULE_SETUP
-#line 111 "parse.lex"
-{
-                           BEGIN INDEFS;
-                           LEXTRACE("DEFVAR ");
-                           fill(yytext, yyleng);
-                           return(DEFVAR);
-                       }
-       YY_BREAK
-
-case 3:
-YY_RULE_SETUP
-#line 119 "parse.lex"
-{
-                           BEGIN STARTDEFS;
-                           LEXTRACE(", ");
-                           return(',');
-                       }                       /* return ',' */
-       YY_BREAK
-case 4:
-YY_RULE_SETUP
-#line 125 "parse.lex"
-{
-                           LEXTRACE("= ");
-                           return('=');
-                       }                       /* return '=' */
-       YY_BREAK
-case 5:
-YY_RULE_SETUP
-#line 130 "parse.lex"
-{
-                           LEXTRACE("+= ");
-                           return('+');
-                       }                       /* return '+' */
-       YY_BREAK
-case 6:
-YY_RULE_SETUP
-#line 135 "parse.lex"
-{
-                           LEXTRACE("-= ");
-                           return('-');
-                       }                       /* return '-' */
-       YY_BREAK
-case 7:
-YY_RULE_SETUP
-#line 140 "parse.lex"
-{
-                           LEXTRACE("BEGINSTR ");
-                           yylval.string = NULL;
-                           BEGIN INSTR;
-                       }
-       YY_BREAK
-case 8:
-YY_RULE_SETUP
-#line 146 "parse.lex"
-{
-                           LEXTRACE("WORD(2) ");
-                           fill(yytext, yyleng);
-                           return(WORD);
-                       }
-       YY_BREAK
-
-
-case 9:
-YY_RULE_SETUP
-#line 154 "parse.lex"
-{
-                           /* Line continuation char followed by newline. */
-                           ++sudolineno;
-                           LEXTRACE("\n");
-                       }
-       YY_BREAK
-case 10:
-YY_RULE_SETUP
-#line 160 "parse.lex"
-{
-                           LEXTRACE("ENDSTR ");
-                           BEGIN INDEFS;
-                           return(WORD);
-                       }
-       YY_BREAK
-case 11:
-YY_RULE_SETUP
-#line 166 "parse.lex"
-{
-                           LEXTRACE("BACKSLASH ");
-                           append(yytext, yyleng);
-                       }
-       YY_BREAK
-case 12:
-YY_RULE_SETUP
-#line 171 "parse.lex"
-{
-                           LEXTRACE("STRBODY ");
-                           append(yytext, yyleng);
-                       }
-       YY_BREAK
-
-
-case 13:
-YY_RULE_SETUP
-#line 178 "parse.lex"
-{
-                           /* quoted fnmatch glob char, pass verbatim */
-                           LEXTRACE("QUOTEDCHAR ");
-                           fill_args(yytext, 2, sawspace);
-                           sawspace = FALSE;
-                       }
-       YY_BREAK
-case 14:
-YY_RULE_SETUP
-#line 185 "parse.lex"
-{
-                           /* quoted sudoers special char, strip backslash */
-                           LEXTRACE("QUOTEDCHAR ");
-                           fill_args(yytext + 1, 1, sawspace);
-                           sawspace = FALSE;
-                       }
-       YY_BREAK
-case 15:
-YY_RULE_SETUP
-#line 192 "parse.lex"
-{
-                           BEGIN INITIAL;
-                           unput(*yytext);
-                           return(COMMAND);
-                       }                       /* end of command line args */
-       YY_BREAK
-case 16:
-YY_RULE_SETUP
-#line 198 "parse.lex"
-{
-                           LEXTRACE("ARG ");
-                           fill_args(yytext, yyleng, sawspace);
-                           sawspace = FALSE;
-                       }                       /* a command line arg */
-       YY_BREAK
-
-case 17:
-YY_RULE_SETUP
-#line 205 "parse.lex"
-{
-                           BEGIN GOTDEFS;
-                           switch (yytext[8]) {
-                               case ':':
-                                   LEXTRACE("DEFAULTS_USER ");
-                                   return(DEFAULTS_USER);
-                               case '>':
-                                   LEXTRACE("DEFAULTS_RUNAS ");
-                                   return(DEFAULTS_RUNAS);
-                               case '@':
-                                   LEXTRACE("DEFAULTS_HOST ");
-                                   return(DEFAULTS_HOST);
-                               default:
-                                   LEXTRACE("DEFAULTS ");
-                                   return(DEFAULTS);
-                           }
-                       }
-       YY_BREAK
-case 18:
-YY_RULE_SETUP
-#line 223 "parse.lex"
-{
-                           fill(yytext, yyleng);
-                           switch (*yytext) {
-                               case 'H':
-                                   LEXTRACE("HOSTALIAS ");
-                                   return(HOSTALIAS);
-                               case 'C':
-                                   LEXTRACE("CMNDALIAS ");
-                                   return(CMNDALIAS);
-                               case 'U':
-                                   LEXTRACE("USERALIAS ");
-                                   return(USERALIAS);
-                               case 'R':
-                                   LEXTRACE("RUNASALIAS ");
-                                   BEGIN GOTRUNAS;
-                                   return(RUNASALIAS);
-                           }
-                       }
-       YY_BREAK
-case 19:
-YY_RULE_SETUP
-#line 242 "parse.lex"
-{
-                               /* cmnd does not require passwd for this user */
-                               LEXTRACE("NOPASSWD ");
-                               return(NOPASSWD);
-                       }
-       YY_BREAK
-case 20:
-YY_RULE_SETUP
-#line 248 "parse.lex"
-{
-                               /* cmnd requires passwd for this user */
-                               LEXTRACE("PASSWD ");
-                               return(PASSWD);
-                       }
-       YY_BREAK
-case 21:
-YY_RULE_SETUP
-#line 254 "parse.lex"
-{
-                               LEXTRACE("NOEXEC ");
-                               return(NOEXEC);
-                       }
-       YY_BREAK
-case 22:
-YY_RULE_SETUP
-#line 259 "parse.lex"
-{
-                               LEXTRACE("EXEC ");
-                               return(EXEC);
-                       }
-       YY_BREAK
-case 23:
-YY_RULE_SETUP
-#line 264 "parse.lex"
-{
-                               LEXTRACE("SETENV ");
-                               return(SETENV);
-                       }
-       YY_BREAK
-case 24:
-YY_RULE_SETUP
-#line 269 "parse.lex"
-{
-                               LEXTRACE("NOSETENV ");
-                               return(NOSETENV);
-                       }
-       YY_BREAK
-case 25:
-YY_RULE_SETUP
-#line 274 "parse.lex"
-{
-                           /* netgroup */
-                           fill(yytext, yyleng);
-                           LEXTRACE("NETGROUP ");
-                           return(NETGROUP);
-                       }
-       YY_BREAK
-case 26:
-YY_RULE_SETUP
-#line 281 "parse.lex"
-{
-                           /* UN*X group */
-                           fill(yytext, yyleng);
-                           LEXTRACE("GROUP ");
-                           return(USERGROUP);
-                       }
-       YY_BREAK
-case 27:
-YY_RULE_SETUP
-#line 288 "parse.lex"
-{
-                           fill(yytext, yyleng);
-                           LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
-                       }
-       YY_BREAK
-case 28:
-YY_RULE_SETUP
-#line 294 "parse.lex"
-{
-                           fill(yytext, yyleng);
-                           LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
-                       }
-       YY_BREAK
-case 29:
-YY_RULE_SETUP
-#line 300 "parse.lex"
-{
-                           if (!ipv6_valid(yytext)) {
-                               LEXTRACE("ERROR ");
-                               return(ERROR);
-                           }
-                           fill(yytext, yyleng);
-                           LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
-                       }
-       YY_BREAK
-case 30:
-YY_RULE_SETUP
-#line 310 "parse.lex"
-{
-                           if (!ipv6_valid(yytext)) {
-                               LEXTRACE("ERROR ");
-                               return(ERROR);
-                           }
-                           fill(yytext, yyleng);
-                           LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
-                       }
-       YY_BREAK
-case 31:
-YY_RULE_SETUP
-#line 320 "parse.lex"
-{
-                               BEGIN GOTRUNAS;
-                               LEXTRACE("RUNAS ");
-                               return (RUNAS);
-                       }
-       YY_BREAK
-case 32:
-YY_RULE_SETUP
-#line 326 "parse.lex"
-{
-                           if (strcmp(yytext, "ALL") == 0) {
-                               LEXTRACE("ALL ");
-                               return(ALL);
-                           }
-#ifdef HAVE_SELINUX
-                           /* XXX - restrict type/role to initial state */
-                           if (strcmp(yytext, "TYPE") == 0) {
-                               LEXTRACE("TYPE ");
-                               return(TYPE);
-                           }
-                           if (strcmp(yytext, "ROLE") == 0) {
-                               LEXTRACE("ROLE ");
-                               return(ROLE);
-                           }
-#endif /* HAVE_SELINUX */
-                           fill(yytext, yyleng);
-                           LEXTRACE("ALIAS ");
-                           return(ALIAS);
-                       }
-       YY_BREAK
-case 33:
-YY_RULE_SETUP
-#line 347 "parse.lex"
-{
-                           /* username/uid that user can run command as */
-                           fill(yytext, yyleng);
-                           LEXTRACE("WORD(3) ");
-                           return(WORD);
-                       }
-       YY_BREAK
-case 34:
-YY_RULE_SETUP
-#line 354 "parse.lex"
-{
-                           BEGIN INITIAL;
-                           ++sudolineno;
-                           LEXTRACE("\n");
-                           return(COMMENT);
-                       }
-       YY_BREAK
-case 35:
-YY_RULE_SETUP
-#line 361 "parse.lex"
-{
-                           BEGIN INITIAL;
-                       }
-       YY_BREAK
-case 36:
-YY_RULE_SETUP
-#line 365 "parse.lex"
-{
-                           BEGIN GOTCMND;
-                           LEXTRACE("COMMAND ");
-                           fill_cmnd(yytext, yyleng);
-                       }                       /* sudo -e */
-       YY_BREAK
-case 37:
-YY_RULE_SETUP
-#line 371 "parse.lex"
-{
-                           /* directories can't have args... */
-                           if (yytext[yyleng - 1] == '/') {
-                               LEXTRACE("COMMAND ");
-                               fill_cmnd(yytext, yyleng);
-                               return(COMMAND);
-                           } else {
-                               BEGIN GOTCMND;
-                               LEXTRACE("COMMAND ");
-                               fill_cmnd(yytext, yyleng);
-                           }
-                       }                       /* a pathname */
-       YY_BREAK
-case 38:
-YY_RULE_SETUP
-#line 384 "parse.lex"
-{
-                           /* a word */
-                           fill(yytext, yyleng);
-                           LEXTRACE("WORD(4) ");
-                           return(WORD);
-                       }
-       YY_BREAK
-case 39:
-YY_RULE_SETUP
-#line 391 "parse.lex"
-{
-                           LEXTRACE(", ");
-                           return(',');
-                       }                       /* return ',' */
-       YY_BREAK
-case 40:
-YY_RULE_SETUP
-#line 396 "parse.lex"
-{
-                           LEXTRACE("= ");
-                           return('=');
-                       }                       /* return '=' */
-       YY_BREAK
-case 41:
-YY_RULE_SETUP
-#line 401 "parse.lex"
-{
-                           LEXTRACE(": ");
-                           return(':');
-                       }                       /* return ':' */
-       YY_BREAK
-case 42:
-YY_RULE_SETUP
-#line 406 "parse.lex"
-{
-                           if (yyleng % 2 == 1)
-                               return('!');    /* return '!' */
-                       }
-       YY_BREAK
-case 43:
-YY_RULE_SETUP
-#line 411 "parse.lex"
-{
-                           BEGIN INITIAL;
-                           ++sudolineno;
-                           LEXTRACE("\n");
-                           return(COMMENT);
-                       }                       /* return newline */
-       YY_BREAK
-case 44:
-YY_RULE_SETUP
-#line 418 "parse.lex"
-{                      /* throw away space/tabs */
-                           sawspace = TRUE;    /* but remember for fill_args */
-                       }
-       YY_BREAK
-case 45:
-YY_RULE_SETUP
-#line 422 "parse.lex"
-{
-                           sawspace = TRUE;    /* remember for fill_args */
-                           ++sudolineno;
-                           LEXTRACE("\n\t");
-                       }                       /* throw away EOL after \ */
-       YY_BREAK
-case 46:
-YY_RULE_SETUP
-#line 428 "parse.lex"
-{
-                           BEGIN INITIAL;
-                           ++sudolineno;
-                           LEXTRACE("\n");
-                           return(COMMENT);
-                       }                       /* return comments */
-       YY_BREAK
-case 47:
-YY_RULE_SETUP
-#line 435 "parse.lex"
-{
-                           LEXTRACE("ERROR ");
-                           return(ERROR);
-                       }       /* parse error */
-       YY_BREAK
-case YY_STATE_EOF(INITIAL):
-case YY_STATE_EOF(GOTRUNAS):
-case YY_STATE_EOF(GOTDEFS):
-case YY_STATE_EOF(GOTCMND):
-case YY_STATE_EOF(STARTDEFS):
-case YY_STATE_EOF(INDEFS):
-case YY_STATE_EOF(INSTR):
-#line 440 "parse.lex"
-{
-                           if (YY_START != INITIAL) {
-                               BEGIN INITIAL;
-                               LEXTRACE("ERROR ");
-                               return(ERROR);
-                           }
-                           yyterminate();
-                       }
-       YY_BREAK
-case 48:
-YY_RULE_SETUP
-#line 449 "parse.lex"
-ECHO;
-       YY_BREAK
-#line 2261 "lex.yy.c"
-
-       case YY_END_OF_BUFFER:
-               {
-               /* Amount of text matched not including the EOB char. */
-               int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
-
-               /* Undo the effects of YY_DO_BEFORE_ACTION. */
-               *yy_cp = yy_hold_char;
-               YY_RESTORE_YY_MORE_OFFSET
-
-               if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
-                       {
-                       /* We're scanning a new file or input source.  It's
-                        * possible that this happened because the user
-                        * just pointed yyin at a new source and called
-                        * yylex().  If so, then we have to assure
-                        * consistency between yy_current_buffer and our
-                        * globals.  Here is the right place to do so, because
-                        * this is the first action (other than possibly a
-                        * back-up) that will match for the new input source.
-                        */
-                       yy_n_chars = yy_current_buffer->yy_n_chars;
-                       yy_current_buffer->yy_input_file = yyin;
-                       yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
-                       }
-
-               /* Note that here we test for yy_c_buf_p "<=" to the position
-                * of the first EOB in the buffer, since yy_c_buf_p will
-                * already have been incremented past the NUL character
-                * (since all states make transitions on EOB to the
-                * end-of-buffer state).  Contrast this with the test
-                * in input().
-                */
-               if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
-                       { /* This was really a NUL. */
-                       yy_state_type yy_next_state;
-
-                       yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
-
-                       yy_current_state = yy_get_previous_state();
-
-                       /* Okay, we're now positioned to make the NUL
-                        * transition.  We couldn't have
-                        * yy_get_previous_state() go ahead and do it
-                        * for us because it doesn't know how to deal
-                        * with the possibility of jamming (and we don't
-                        * want to build jamming into it because then it
-                        * will run more slowly).
-                        */
-
-                       yy_next_state = yy_try_NUL_trans( yy_current_state );
-
-                       yy_bp = yytext_ptr + YY_MORE_ADJ;
-
-                       if ( yy_next_state )
-                               {
-                               /* Consume the NUL. */
-                               yy_cp = ++yy_c_buf_p;
-                               yy_current_state = yy_next_state;
-                               goto yy_match;
-                               }
-
-                       else
-                               {
-                               yy_cp = yy_c_buf_p;
-                               goto yy_find_action;
-                               }
-                       }
-
-               else switch ( yy_get_next_buffer() )
-                       {
-                       case EOB_ACT_END_OF_FILE:
-                               {
-                               yy_did_buffer_switch_on_eof = 0;
-
-                               if ( yywrap() )
-                                       {
-                                       /* Note: because we've taken care in
-                                        * yy_get_next_buffer() to have set up
-                                        * yytext, we can now set up
-                                        * yy_c_buf_p so that if some total
-                                        * hoser (like flex itself) wants to
-                                        * call the scanner after we return the
-                                        * YY_NULL, it'll still work - another
-                                        * YY_NULL will get returned.
-                                        */
-                                       yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
-
-                                       yy_act = YY_STATE_EOF(YY_START);
-                                       goto do_action;
-                                       }
-
-                               else
-                                       {
-                                       if ( ! yy_did_buffer_switch_on_eof )
-                                               YY_NEW_FILE;
-                                       }
-                               break;
-                               }
-
-                       case EOB_ACT_CONTINUE_SCAN:
-                               yy_c_buf_p =
-                                       yytext_ptr + yy_amount_of_matched_text;
-
-                               yy_current_state = yy_get_previous_state();
-
-                               yy_cp = yy_c_buf_p;
-                               yy_bp = yytext_ptr + YY_MORE_ADJ;
-                               goto yy_match;
-
-                       case EOB_ACT_LAST_MATCH:
-                               yy_c_buf_p =
-                               &yy_current_buffer->yy_ch_buf[yy_n_chars];
-
-                               yy_current_state = yy_get_previous_state();
-
-                               yy_cp = yy_c_buf_p;
-                               yy_bp = yytext_ptr + YY_MORE_ADJ;
-                               goto yy_find_action;
-                       }
-               break;
-               }
-
-       default:
-               YY_FATAL_ERROR(
-                       "fatal flex scanner internal error--no action found" );
-       } /* end of action switch */
-               } /* end of scanning one token */
-       } /* end of yylex */
-
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- *     EOB_ACT_LAST_MATCH -
- *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- *     EOB_ACT_END_OF_FILE - end of file
- */
-
-static int yy_get_next_buffer()
-       {
-       register char *dest = yy_current_buffer->yy_ch_buf;
-       register char *source = yytext_ptr;
-       register int number_to_move, i;
-       int ret_val;
-
-       if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
-               YY_FATAL_ERROR(
-               "fatal flex scanner internal error--end of buffer missed" );
-
-       if ( yy_current_buffer->yy_fill_buffer == 0 )
-               { /* Don't try to fill the buffer, so this is an EOF. */
-               if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
-                       {
-                       /* We matched a single character, the EOB, so
-                        * treat this as a final EOF.
-                        */
-                       return EOB_ACT_END_OF_FILE;
-                       }
-
-               else
-                       {
-                       /* We matched some text prior to the EOB, first
-                        * process it.
-                        */
-                       return EOB_ACT_LAST_MATCH;
-                       }
-               }
-
-       /* Try to read more data. */
-
-       /* First move last chars to start of buffer. */
-       number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
-
-       for ( i = 0; i < number_to_move; ++i )
-               *(dest++) = *(source++);
-
-       if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
-               /* don't do the read, it's not guaranteed to return an EOF,
-                * just force an EOF
-                */
-               yy_current_buffer->yy_n_chars = yy_n_chars = 0;
-
-       else
-               {
-               int num_to_read =
-                       yy_current_buffer->yy_buf_size - number_to_move - 1;
-
-               while ( num_to_read <= 0 )
-                       { /* Not enough room in the buffer - grow it. */
-#ifdef YY_USES_REJECT
-                       YY_FATAL_ERROR(
-"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
-#else
-
-                       /* just a shorter name for the current buffer */
-                       YY_BUFFER_STATE b = yy_current_buffer;
-
-                       int yy_c_buf_p_offset =
-                               (int) (yy_c_buf_p - b->yy_ch_buf);
-
-                       if ( b->yy_is_our_buffer )
-                               {
-                               int new_size = b->yy_buf_size * 2;
-
-                               if ( new_size <= 0 )
-                                       b->yy_buf_size += b->yy_buf_size / 8;
-                               else
-                                       b->yy_buf_size *= 2;
-
-                               b->yy_ch_buf = (char *)
-                                       /* Include room in for 2 EOB chars. */
-                                       yy_flex_realloc( (void *) b->yy_ch_buf,
-                                                        b->yy_buf_size + 2 );
-                               }
-                       else
-                               /* Can't grow it, we don't own it. */
-                               b->yy_ch_buf = 0;
-
-                       if ( ! b->yy_ch_buf )
-                               YY_FATAL_ERROR(
-                               "fatal error - scanner input buffer overflow" );
-
-                       yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
-
-                       num_to_read = yy_current_buffer->yy_buf_size -
-                                               number_to_move - 1;
-#endif
-                       }
-
-               if ( num_to_read > YY_READ_BUF_SIZE )
-                       num_to_read = YY_READ_BUF_SIZE;
-
-               /* Read in more data. */
-               YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
-                       yy_n_chars, num_to_read );
-
-               yy_current_buffer->yy_n_chars = yy_n_chars;
-               }
-
-       if ( yy_n_chars == 0 )
-               {
-               if ( number_to_move == YY_MORE_ADJ )
-                       {
-                       ret_val = EOB_ACT_END_OF_FILE;
-                       yyrestart( yyin );
-                       }
-
-               else
-                       {
-                       ret_val = EOB_ACT_LAST_MATCH;
-                       yy_current_buffer->yy_buffer_status =
-                               YY_BUFFER_EOF_PENDING;
-                       }
-               }
-
-       else
-               ret_val = EOB_ACT_CONTINUE_SCAN;
-
-       yy_n_chars += number_to_move;
-       yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
-       yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
-
-       yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
-
-       return ret_val;
-       }
-
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
-static yy_state_type yy_get_previous_state()
-       {
-       register yy_state_type yy_current_state;
-       register char *yy_cp;
-
-       yy_current_state = yy_start;
-       yy_current_state += YY_AT_BOL();
-
-       for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
-               {
-               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
-               if ( yy_accept[yy_current_state] )
-                       {
-                       yy_last_accepting_state = yy_current_state;
-                       yy_last_accepting_cpos = yy_cp;
-                       }
-               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-                       {
-                       yy_current_state = (int) yy_def[yy_current_state];
-                       if ( yy_current_state >= 610 )
-                               yy_c = yy_meta[(unsigned int) yy_c];
-                       }
-               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-               }
-
-       return yy_current_state;
-       }
-
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- *     next_state = yy_try_NUL_trans( current_state );
- */
-
-#ifdef YY_USE_PROTOS
-static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
-#else
-static yy_state_type yy_try_NUL_trans( yy_current_state )
-yy_state_type yy_current_state;
-#endif
-       {
-       register int yy_is_jam;
-       register char *yy_cp = yy_c_buf_p;
-
-       register YY_CHAR yy_c = 1;
-       if ( yy_accept[yy_current_state] )
-               {
-               yy_last_accepting_state = yy_current_state;
-               yy_last_accepting_cpos = yy_cp;
-               }
-       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-               {
-               yy_current_state = (int) yy_def[yy_current_state];
-               if ( yy_current_state >= 610 )
-                       yy_c = yy_meta[(unsigned int) yy_c];
-               }
-       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-       yy_is_jam = (yy_current_state == 609);
-
-       return yy_is_jam ? 0 : yy_current_state;
-       }
-
-
-#ifndef YY_NO_UNPUT
-#ifdef YY_USE_PROTOS
-static void yyunput( int c, register char *yy_bp )
-#else
-static void yyunput( c, yy_bp )
-int c;
-register char *yy_bp;
-#endif
-       {
-       register char *yy_cp = yy_c_buf_p;
-
-       /* undo effects of setting up yytext */
-       *yy_cp = yy_hold_char;
-
-       if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
-               { /* need to shift things up to make room */
-               /* +2 for EOB chars. */
-               register int number_to_move = yy_n_chars + 2;
-               register char *dest = &yy_current_buffer->yy_ch_buf[
-                                       yy_current_buffer->yy_buf_size + 2];
-               register char *source =
-                               &yy_current_buffer->yy_ch_buf[number_to_move];
-
-               while ( source > yy_current_buffer->yy_ch_buf )
-                       *--dest = *--source;
-
-               yy_cp += (int) (dest - source);
-               yy_bp += (int) (dest - source);
-               yy_current_buffer->yy_n_chars =
-                       yy_n_chars = yy_current_buffer->yy_buf_size;
-
-               if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
-                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
-               }
-
-       *--yy_cp = (char) c;
-
-
-       yytext_ptr = yy_bp;
-       yy_hold_char = *yy_cp;
-       yy_c_buf_p = yy_cp;
-       }
-#endif /* ifndef YY_NO_UNPUT */
-
-
-#ifdef __cplusplus
-static int yyinput()
-#else
-static int input()
-#endif
-       {
-       int c;
-
-       *yy_c_buf_p = yy_hold_char;
-
-       if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
-               {
-               /* yy_c_buf_p now points to the character we want to return.
-                * If this occurs *before* the EOB characters, then it's a
-                * valid NUL; if not, then we've hit the end of the buffer.
-                */
-               if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
-                       /* This was really a NUL. */
-                       *yy_c_buf_p = '\0';
-
-               else
-                       { /* need more input */
-                       int offset = yy_c_buf_p - yytext_ptr;
-                       ++yy_c_buf_p;
-
-                       switch ( yy_get_next_buffer() )
-                               {
-                               case EOB_ACT_LAST_MATCH:
-                                       /* This happens because yy_g_n_b()
-                                        * sees that we've accumulated a
-                                        * token and flags that we need to
-                                        * try matching the token before
-                                        * proceeding.  But for input(),
-                                        * there's no matching to consider.
-                                        * So convert the EOB_ACT_LAST_MATCH
-                                        * to EOB_ACT_END_OF_FILE.
-                                        */
-
-                                       /* Reset buffer status. */
-                                       yyrestart( yyin );
-
-                                       /* fall through */
-
-                               case EOB_ACT_END_OF_FILE:
-                                       {
-                                       if ( yywrap() )
-                                               return EOF;
-
-                                       if ( ! yy_did_buffer_switch_on_eof )
-                                               YY_NEW_FILE;
-#ifdef __cplusplus
-                                       return yyinput();
-#else
-                                       return input();
-#endif
-                                       }
-
-                               case EOB_ACT_CONTINUE_SCAN:
-                                       yy_c_buf_p = yytext_ptr + offset;
-                                       break;
-                               }
-                       }
-               }
-
-       c = *(unsigned char *) yy_c_buf_p;      /* cast for 8-bit char's */
-       *yy_c_buf_p = '\0';     /* preserve yytext */
-       yy_hold_char = *++yy_c_buf_p;
-
-       yy_current_buffer->yy_at_bol = (c == '\n');
-
-       return c;
-       }
-
-
-#ifdef YY_USE_PROTOS
-void yyrestart( FILE *input_file )
-#else
-void yyrestart( input_file )
-FILE *input_file;
-#endif
-       {
-       if ( ! yy_current_buffer )
-               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
-
-       yy_init_buffer( yy_current_buffer, input_file );
-       yy_load_buffer_state();
-       }
-
-
-#ifdef YY_USE_PROTOS
-void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
-#else
-void yy_switch_to_buffer( new_buffer )
-YY_BUFFER_STATE new_buffer;
-#endif
-       {
-       if ( yy_current_buffer == new_buffer )
-               return;
-
-       if ( yy_current_buffer )
-               {
-               /* Flush out information for old buffer. */
-               *yy_c_buf_p = yy_hold_char;
-               yy_current_buffer->yy_buf_pos = yy_c_buf_p;
-               yy_current_buffer->yy_n_chars = yy_n_chars;
-               }
-
-       yy_current_buffer = new_buffer;
-       yy_load_buffer_state();
-
-       /* We don't actually know whether we did this switch during
-        * EOF (yywrap()) processing, but the only time this flag
-        * is looked at is after yywrap() is called, so it's safe
-        * to go ahead and always set it.
-        */
-       yy_did_buffer_switch_on_eof = 1;
-       }
-
-
-#ifdef YY_USE_PROTOS
-void yy_load_buffer_state( void )
-#else
-void yy_load_buffer_state()
-#endif
-       {
-       yy_n_chars = yy_current_buffer->yy_n_chars;
-       yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
-       yyin = yy_current_buffer->yy_input_file;
-       yy_hold_char = *yy_c_buf_p;
-       }
-
-
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
-#else
-YY_BUFFER_STATE yy_create_buffer( file, size )
-FILE *file;
-int size;
-#endif
-       {
-       YY_BUFFER_STATE b;
-
-       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
-       if ( ! b )
-               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
-       b->yy_buf_size = size;
-
-       /* yy_ch_buf has to be 2 characters longer than the size given because
-        * we need to put in 2 end-of-buffer characters.
-        */
-       b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
-       if ( ! b->yy_ch_buf )
-               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
-       b->yy_is_our_buffer = 1;
-
-       yy_init_buffer( b, file );
-
-       return b;
-       }
-
-
-#ifdef YY_USE_PROTOS
-void yy_delete_buffer( YY_BUFFER_STATE b )
-#else
-void yy_delete_buffer( b )
-YY_BUFFER_STATE b;
-#endif
-       {
-       if ( ! b )
-               return;
-
-       if ( b == yy_current_buffer )
-               yy_current_buffer = (YY_BUFFER_STATE) 0;
-
-       if ( b->yy_is_our_buffer )
-               yy_flex_free( (void *) b->yy_ch_buf );
-
-       yy_flex_free( (void *) b );
-       }
-
-
-#ifndef YY_ALWAYS_INTERACTIVE
-#ifndef YY_NEVER_INTERACTIVE
-#include <unistd.h>
-#endif
-#endif
-
-#ifdef YY_USE_PROTOS
-void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
-#else
-void yy_init_buffer( b, file )
-YY_BUFFER_STATE b;
-FILE *file;
-#endif
-
-
-       {
-       int oerrno = errno;
-
-       yy_flush_buffer( b );
-
-       b->yy_input_file = file;
-       b->yy_fill_buffer = 1;
-
-#if defined(YY_ALWAYS_INTERACTIVE) && YY_ALWAYS_INTERACTIVE
-       b->yy_is_interactive = 1;
-#else
-#if defined(YY_NEVER_INTERACTIVE) && YY_NEVER_INTERACTIVE
-       b->yy_is_interactive = 0;
-#else
-       b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
-#endif
-#endif
-       errno = oerrno;
-       }
-
-
-#ifdef YY_USE_PROTOS
-void yy_flush_buffer( YY_BUFFER_STATE b )
-#else
-void yy_flush_buffer( b )
-YY_BUFFER_STATE b;
-#endif
-
-       {
-       if ( ! b )
-               return;
-
-       b->yy_n_chars = 0;
-
-       /* We always need two end-of-buffer characters.  The first causes
-        * a transition to the end-of-buffer state.  The second causes
-        * a jam in that state.
-        */
-       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
-       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
-
-       b->yy_buf_pos = &b->yy_ch_buf[0];
-
-       b->yy_at_bol = 1;
-       b->yy_buffer_status = YY_BUFFER_NEW;
-
-       if ( b == yy_current_buffer )
-               yy_load_buffer_state();
-       }
-
-
-#ifndef YY_NO_SCAN_BUFFER
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
-#else
-YY_BUFFER_STATE yy_scan_buffer( base, size )
-char *base;
-yy_size_t size;
-#endif
-       {
-       YY_BUFFER_STATE b;
-
-       if ( size < 2 ||
-            base[size-2] != YY_END_OF_BUFFER_CHAR ||
-            base[size-1] != YY_END_OF_BUFFER_CHAR )
-               /* They forgot to leave room for the EOB's. */
-               return 0;
-
-       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
-       if ( ! b )
-               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
-
-       b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
-       b->yy_buf_pos = b->yy_ch_buf = base;
-       b->yy_is_our_buffer = 0;
-       b->yy_input_file = 0;
-       b->yy_n_chars = b->yy_buf_size;
-       b->yy_is_interactive = 0;
-       b->yy_at_bol = 1;
-       b->yy_fill_buffer = 0;
-       b->yy_buffer_status = YY_BUFFER_NEW;
-
-       yy_switch_to_buffer( b );
-
-       return b;
-       }
-#endif
-
-
-#ifndef YY_NO_SCAN_STRING
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
-#else
-YY_BUFFER_STATE yy_scan_string( yy_str )
-yyconst char *yy_str;
-#endif
-       {
-       int len;
-       for ( len = 0; yy_str[len]; ++len )
-               ;
-
-       return yy_scan_bytes( yy_str, len );
-       }
-#endif
-
-
-#ifndef YY_NO_SCAN_BYTES
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
-#else
-YY_BUFFER_STATE yy_scan_bytes( bytes, len )
-yyconst char *bytes;
-int len;
-#endif
-       {
-       YY_BUFFER_STATE b;
-       char *buf;
-       yy_size_t n;
-       int i;
-
-       /* Get memory for full buffer, including space for trailing EOB's. */
-       n = len + 2;
-       buf = (char *) yy_flex_alloc( n );
-       if ( ! buf )
-               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
-
-       for ( i = 0; i < len; ++i )
-               buf[i] = bytes[i];
-
-       buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
-
-       b = yy_scan_buffer( buf, n );
-       if ( ! b )
-               YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
-
-       /* It's okay to grow etc. this buffer, and we should throw it
-        * away when we're done.
-        */
-       b->yy_is_our_buffer = 1;
-
-       return b;
-       }
-#endif
-
-
-#ifndef YY_NO_PUSH_STATE
-#ifdef YY_USE_PROTOS
-static void yy_push_state( int new_state )
-#else
-static void yy_push_state( new_state )
-int new_state;
-#endif
-       {
-       if ( yy_start_stack_ptr >= yy_start_stack_depth )
-               {
-               yy_size_t new_size;
-
-               yy_start_stack_depth += YY_START_STACK_INCR;
-               new_size = yy_start_stack_depth * sizeof( int );
-
-               if ( ! yy_start_stack )
-                       yy_start_stack = (int *) yy_flex_alloc( new_size );
-
-               else
-                       yy_start_stack = (int *) yy_flex_realloc(
-                                       (void *) yy_start_stack, new_size );
-
-               if ( ! yy_start_stack )
-                       YY_FATAL_ERROR(
-                       "out of memory expanding start-condition stack" );
-               }
-
-       yy_start_stack[yy_start_stack_ptr++] = YY_START;
-
-       BEGIN(new_state);
-       }
-#endif
-
-
-#ifndef YY_NO_POP_STATE
-static void yy_pop_state()
-       {
-       if ( --yy_start_stack_ptr < 0 )
-               YY_FATAL_ERROR( "start-condition stack underflow" );
-
-       BEGIN(yy_start_stack[yy_start_stack_ptr]);
-       }
-#endif
-
-
-#ifndef YY_NO_TOP_STATE
-static int yy_top_state()
-       {
-       return yy_start_stack[yy_start_stack_ptr - 1];
-       }
-#endif
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
-
-#ifdef YY_USE_PROTOS
-static void yy_fatal_error( yyconst char msg[] )
-#else
-static void yy_fatal_error( msg )
-char msg[];
-#endif
-       {
-       (void) fprintf( stderr, "%s\n", msg );
-       exit( YY_EXIT_FAILURE );
-       }
-
-
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
-       do \
-               { \
-               /* Undo effects of setting up yytext. */ \
-               yytext[yyleng] = yy_hold_char; \
-               yy_c_buf_p = yytext + n; \
-               yy_hold_char = *yy_c_buf_p; \
-               *yy_c_buf_p = '\0'; \
-               yyleng = n; \
-               } \
-       while ( 0 )
-
-
-/* Internal utility routines. */
-
-#ifndef yytext_ptr
-#ifdef YY_USE_PROTOS
-static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
-#else
-static void yy_flex_strncpy( s1, s2, n )
-char *s1;
-yyconst char *s2;
-int n;
-#endif
-       {
-       register int i;
-       for ( i = 0; i < n; ++i )
-               s1[i] = s2[i];
-       }
-#endif
-
-#ifdef YY_NEED_STRLEN
-#ifdef YY_USE_PROTOS
-static int yy_flex_strlen( yyconst char *s )
-#else
-static int yy_flex_strlen( s )
-yyconst char *s;
-#endif
-       {
-       register int n;
-       for ( n = 0; s[n]; ++n )
-               ;
-
-       return n;
-       }
-#endif
-
-
-#ifdef YY_USE_PROTOS
-static void *yy_flex_alloc( yy_size_t size )
-#else
-static void *yy_flex_alloc( size )
-yy_size_t size;
-#endif
-       {
-       return (void *) malloc( size );
-       }
-
-#ifdef YY_USE_PROTOS
-static void *yy_flex_realloc( void *ptr, yy_size_t size )
-#else
-static void *yy_flex_realloc( ptr, size )
-void *ptr;
-yy_size_t size;
-#endif
-       {
-       /* The cast to (char *) in the following accommodates both
-        * implementations that use char* generic pointers, and those
-        * that use void* generic pointers.  It works with the latter
-        * because both ANSI C and C++ allow castless assignment from
-        * any pointer type to void*, and deal with argument conversions
-        * as though doing an assignment.
-        */
-       return (void *) realloc( (char *) ptr, size );
-       }
-
-#ifdef YY_USE_PROTOS
-static void yy_flex_free( void *ptr )
-#else
-static void yy_flex_free( ptr )
-void *ptr;
-#endif
-       {
-       free( ptr );
-       }
-
-#if defined(YY_MAIN) && YY_MAIN
-int main()
-       {
-       yylex();
-       return 0;
-       }
-#endif
-#line 449 "parse.lex"
-
-static void
-_fill(src, len, olen)
-    char *src;
-    int len, olen;
-{
-    int i, j;
-    char *dst;
-
-    dst = olen ? realloc(yylval.string, olen + len + 1) : malloc(len + 1);
-    if (dst == NULL) {
-       yyerror("unable to allocate memory");
-       return;
-    }
-    yylval.string = dst;
-
-    /* Copy the string and collapse any escaped characters. */
-    dst += olen;
-    for (i = 0, j = 0; i < len; i++, j++) {
-       if (src[i] == '\\' && i != len - 1)
-           dst[j] = src[++i];
-       else
-           dst[j] = src[i];
-    }
-    dst[j] = '\0';
-}
-
-static void
-append(src, len)
-    char *src;
-    int len;
-{
-    int olen = 0;
-
-    if (yylval.string != NULL)
-       olen = strlen(yylval.string);
-
-    _fill(src, len, olen);
-}
-
-static void
-fill_cmnd(s, len)
-    char *s;
-    int len;
-{
-    arg_len = arg_size = 0;
-
-    yylval.command.cmnd = (char *) malloc(++len);
-    if (yylval.command.cmnd == NULL) {
-       yyerror("unable to allocate memory");
-       return;
-    }
-
-    /* copy the string and NULL-terminate it (escapes handled by fnmatch) */
-    (void) strlcpy(yylval.command.cmnd, s, len);
-
-    yylval.command.args = NULL;
-}
-
-static void
-fill_args(s, len, addspace)
-    char *s;
-    int len;
-    int addspace;
-{
-    int new_len;
-    char *p;
-
-    if (yylval.command.args == NULL) {
-       addspace = 0;
-       new_len = len;
-    } else
-       new_len = arg_len + len + addspace;
-
-    if (new_len >= arg_size) {
-       /* Allocate more space than we need for subsequent args */
-       while (new_len >= (arg_size += COMMANDARGINC))
-           ;
-
-       p = yylval.command.args ?
-           (char *) realloc(yylval.command.args, arg_size) :
-           (char *) malloc(arg_size);
-       if (p == NULL) {
-           efree(yylval.command.args);
-           yyerror("unable to allocate memory");
-           return;
-       } else
-           yylval.command.args = p;
-    }
-
-    /* Efficiently append the arg (with a leading space if needed). */
-    p = yylval.command.args + arg_len;
-    if (addspace)
-       *p++ = ' ';
-    if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len)
-       yyerror("fill_args: buffer overflow");  /* paranoia */
-    arg_len = new_len;
-}
-
-/*
- * Check to make sure an IPv6 address does not contain multiple instances
- * of the string "::".  Assumes strlen(s) >= 1.
- * Returns TRUE if address is valid else FALSE.
- */
-static int
-ipv6_valid(s)
-    const char *s;
-{
-    int nmatch = 0;
-
-    for (; *s != '\0'; s++) {
-       if (s[0] == ':' && s[1] == ':') {
-           if (++nmatch > 1)
-               break;
-       }
-       if (s[0] == '/')
-           nmatch = 0;                 /* reset if we hit netmask */
-    }
-
-    return (nmatch <= 1);
-}
-
-int
-yywrap()
-{
-
-    /* Free space used by the aliases unless called by testsudoers. */
-    if (clearaliases)
-       reset_aliases();
-
-    return(TRUE);
-}
diff --git a/list.c b/list.c
new file mode 100644 (file)
index 0000000..2e6482a
--- /dev/null
+++ b/list.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 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 <sys/types.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+
+#include "sudo.h"
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: list.c,v 1.6 2008/11/09 14:13:12 millert Exp $";
+#endif /* lint */
+
+struct list_proto {
+    struct list_proto *prev;
+    struct list_proto *next;
+};
+
+struct list_head_proto {
+    struct list_proto *first;
+    struct list_proto *last;
+};
+
+/*
+ * Pop the last element off the end of vh.
+ * Returns the popped element.
+ */
+void *
+tq_pop(vh)
+    void *vh;
+{
+    struct list_head_proto *h = (struct list_head_proto *)vh;
+    void *last = NULL;
+
+    if (!tq_empty(h)) {
+       last = (void *)h->last;
+       if (h->first == h->last) {
+           h->first = NULL;
+           h->last = NULL;
+       } else {
+           h->last = h->last->prev;
+           h->last->next = NULL;
+       }
+    }
+    return (last);
+}
+
+/*
+ * Convert from a semi-circle queue to normal doubly-linked list
+ * with a head node.
+ */
+void
+list2tq(vh, vl)
+    void *vh;
+    void *vl;
+{
+    struct list_head_proto *h = (struct list_head_proto *)vh;
+    struct list_proto *l = (struct list_proto *)vl;
+
+    if (l != NULL) {
+#ifdef DEBUG
+       if (l->prev == NULL) {
+           warningx("list2tq called with non-semicircular list");
+           abort();
+       }
+#endif
+       h->first = l;
+       h->last = l->prev;      /* l->prev points to the last member of l */
+       l->prev = NULL;         /* zero last ptr now that we have a head */
+    } else {
+       h->first = NULL;
+       h->last = NULL;
+    }
+}
+
+/*
+ * Append one queue (or single entry) to another using the
+ * circular properties of the prev pointer to simplify the logic.
+ */
+void
+list_append(vl1, vl2)
+    void *vl1;
+    void *vl2;
+{
+    struct list_proto *l1 = (struct list_proto *)vl1;
+    struct list_proto *l2 = (struct list_proto *)vl2;
+    void *tail = l2->prev;
+
+    l1->prev->next = l2;
+    l2->prev = l1->prev;
+    l1->prev = tail;
+}
+
+/*
+ * Append the list of entries to the head node and convert 
+ * e from a semi-circle queue to normal doubly-linked list. 
+ */
+void
+tq_append(vh, vl)
+    void *vh;
+    void *vl;
+{
+    struct list_head_proto *h = (struct list_head_proto *)vh;
+    struct list_proto *l = (struct list_proto *)vl;
+    void *tail = l->prev;
+
+    if (h->first == NULL)
+       h->first = l;
+    else
+       h->last->next = l;
+    l->prev = h->last;
+    h->last = tail;
+}
diff --git a/list.h b/list.h
new file mode 100644 (file)
index 0000000..ddf610a
--- /dev/null
+++ b/list.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Sudo: list.h,v 1.3 2007/09/11 19:42:48 millert Exp $
+ */
+
+#ifndef _SUDO_LIST_H
+#define _SUDO_LIST_H
+
+/*
+ * Convenience macro for declaring a list head.
+ */
+#ifdef __STDC__
+#define TQ_DECLARE(n)                                  \
+struct n##_list {                                      \
+    struct n *first;                                   \
+    struct n *last;                                    \
+};
+#else
+#define TQ_DECLARE(n)                                  \
+struct n/**/_list {                                    \
+    struct n *first;                                   \
+    struct n *last;                                    \
+};
+#endif
+
+/*
+ * Foreach loops: forward and reverse
+ */
+#undef tq_foreach_fwd
+#define tq_foreach_fwd(h, v)                           \
+    for ((v) = (h)->first; (v) != NULL; (v) = (v)->next)
+
+#undef tq_foreach_rev
+#define tq_foreach_rev(h, v)                           \
+    for ((v) = (h)->last; (v) != NULL; (v) = (v)->prev)
+
+/*
+ * Init a list head.
+ */
+#undef tq_init
+#define tq_init(h) do {                                        \
+    (h)->first = NULL;                                 \
+    (h)->last = NULL;                                  \
+} while (0)
+
+/*
+ * Simple macros to avoid exposing first/last and prev/next.
+ */
+#undef tq_empty
+#define tq_empty(h)    ((h)->first == NULL)
+
+#undef tq_first
+#define tq_first(h)    ((h)->first)
+
+#undef tq_last
+#define tq_last(h)     ((h)->last)
+
+#undef list_next
+#define list_next(e)   ((e)->next)
+
+#undef list_prev
+#define list_prev(e)   ((e)->prev)
+
+/*
+ * Prototypes for list.c
+ */
+void *tq_pop           __P((void *));
+void tq_append         __P((void *, void *));
+void list_append       __P((void *, void *));
+void list2tq           __P((void *, void *));
+
+#endif /* _SUDO_LIST_H */
index 80d0f5a37d12a728b3027debf9428b93ecf5f3c7..b536305dfd0cada0f3ab2360f62d0ee9d99a2f9e 100644 (file)
--- a/logging.c
+++ b/logging.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994-1996,1998-2007 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1994-1996, 1998-2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <pwd.h>
+#include <grp.h>
 #include <signal.h>
 #include <time.h>
 #include <errno.h>
 #include "sudo.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: logging.c,v 1.168.2.16 2008/06/22 20:23:57 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: logging.c,v 1.203 2008/11/09 14:13:12 millert Exp $";
 #endif /* lint */
 
 static void do_syslog          __P((int, char *));
 static void do_logfile         __P((char *));
 static void send_mail          __P((char *));
-static void mail_auth          __P((int, char *));
+static int should_mail         __P((int));
 static char *get_timestr       __P((void));
 static void mysyslog           __P((int, const char *, ...));
+static char *new_logline       __P((const char *, int));
 
 #define MAXSYSLOGTRIES 16      /* num of retries for broken syslogs */
 
@@ -273,56 +270,31 @@ do_logfile(msg)
 }
 
 /*
- * Two main functions, log_error() to log errors and log_auth() to
- * log allow/deny messages.
+ * Log and mail the denial message, optionally informing the user.
  */
 void
-log_auth(status, inform_user)
+log_denial(status, inform_user)
     int status;
     int inform_user;
 {
-    char *evstr = NULL;
     char *message;
     char *logline;
-    int pri;
 
-    if (ISSET(status, VALIDATE_OK))
-       pri = def_syslog_goodpri;
-    else
-       pri = def_syslog_badpri;
-
-    /* Set error message, if any. */
-    if (ISSET(status, VALIDATE_OK))
-       message = "";
-    else if (ISSET(status, FLAG_NO_USER))
-       message = "user NOT in sudoers ; ";
+    /* Set error message. */
+    if (ISSET(status, FLAG_NO_USER))
+       message = "user NOT in sudoers";
     else if (ISSET(status, FLAG_NO_HOST))
-       message = "user NOT authorized on host ; ";
-    else if (ISSET(status, VALIDATE_NOT_OK))
-       message = "command not allowed ; ";
+       message = "user NOT authorized on host";
     else
-       message = "unknown error ; ";
+       message = "command not allowed";
 
-    if (sudo_user.env_vars != NULL) {
-       size_t len = 7; /* " ; ENV=" */
-       struct list_member *cur;
-       for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next)
-           len += strlen(cur->value) + 1;
-       evstr = emalloc(len);
-       strlcpy(evstr, " ; ENV=", len);
-       for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next) {
-           strlcat(evstr, cur->value, len);
-           strlcat(evstr, " ", len);           /* NOTE: last one will fail */
-       }
-    }
-    easprintf(&logline, "%sTTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s%s%s",
-       message, user_tty, user_cwd, *user_runas, evstr ? evstr : "",
-       user_cmnd, user_args ? " " : "", user_args ? user_args : "");
+    logline = new_logline(message, 0);
 
-    mail_auth(status, logline);                /* send mail based on status */
+    if (should_mail(status))
+       send_mail(logline);     /* send mail based on status */
 
     /* Inform the user if they failed to authenticate.  */
-    if (inform_user && ISSET(status, VALIDATE_NOT_OK)) {
+    if (inform_user) {
        if (ISSET(status, FLAG_NO_USER))
            (void) fprintf(stderr, "%s is not in the sudoers file.  %s",
                user_name, "This incident will be reported.\n");
@@ -334,20 +306,47 @@ log_auth(status, inform_user)
                user_name, user_shost);
        else
            (void) fprintf(stderr,
-               "Sorry, user %s is not allowed to execute '%s%s%s' as %s on %s.\n",
+               "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n",
                user_name, user_cmnd, user_args ? " " : "",
-               user_args ? user_args : "", *user_runas, user_host);
+               user_args ? user_args : "",
+               list_pw ? list_pw->pw_name : runas_pw ?
+               runas_pw->pw_name : user_name, runas_gr ? ":" : "",
+               runas_gr ? runas_gr->gr_name : "", user_host);
     }
 
     /*
      * Log via syslog and/or a file.
      */
     if (def_syslog)
-       do_syslog(pri, logline);
+       do_syslog(def_syslog_badpri, logline);
+    if (def_logfile)
+       do_logfile(logline);
+
+    efree(logline);
+}
+
+/*
+ * Log and potentially mail the allowed command.
+ */
+void
+log_allowed(status)
+    int status;
+{
+    char *logline;
+
+    logline = new_logline(NULL, 0);
+
+    if (should_mail(status))
+       send_mail(logline);     /* send mail based on status */
+
+    /*
+     * Log via syslog and/or a file.
+     */
+    if (def_syslog)
+       do_syslog(def_syslog_goodpri, logline);
     if (def_logfile)
        do_logfile(logline);
 
-    efree(evstr);
     efree(logline);
 }
 
@@ -364,7 +363,6 @@ log_error(flags, fmt, va_alist)
     int serrno = errno;
     char *message;
     char *logline;
-    char *evstr = NULL;
     va_list ap;
 #ifdef __STDC__
     va_start(ap, fmt);
@@ -379,53 +377,21 @@ log_error(flags, fmt, va_alist)
     evasprintf(&message, fmt, ap);
     va_end(ap);
 
-    if (sudo_user.env_vars != NULL) {
-       size_t len = 7; /* " ; ENV=" */
-       struct list_member *cur;
-       for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next)
-           len += strlen(cur->value) + 1;
-       evstr = emalloc(len);
-       strlcpy(evstr, " ; ENV=", len);
-       for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next) {
-           strlcat(evstr, cur->value, len);
-           strlcat(evstr, " ", len);           /* NOTE: last one will fail */
-       }
-    }
-
     if (ISSET(flags, MSG_ONLY))
        logline = message;
-    else if (ISSET(flags, USE_ERRNO)) {
-       if (user_args) {
-           easprintf(&logline,
-               "%s: %s ; TTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s %s",
-               message, strerror(serrno), user_tty, user_cwd, *user_runas,
-               evstr ? evstr : "", user_cmnd, user_args);
-       } else {
-           easprintf(&logline,
-               "%s: %s ; TTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s", message,
-               strerror(serrno), user_tty, user_cwd, *user_runas,
-               evstr ? evstr : "", user_cmnd);
-       }
-    } else {
-       if (user_args) {
-           easprintf(&logline,
-               "%s ; TTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s %s", message,
-               user_tty, user_cwd, *user_runas, evstr ? evstr : "",
-               user_cmnd, user_args);
-       } else {
-           easprintf(&logline,
-               "%s ; TTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s", message,
-               user_tty, user_cwd, *user_runas, evstr ? evstr : "", user_cmnd);
-       }
-    }
+    else
+       logline = new_logline(message, ISSET(flags, USE_ERRNO) ? serrno : 0);
 
     /*
      * Tell the user.
      */
-    if (ISSET(flags, USE_ERRNO))
-       warn("%s", message);
-    else
-       warnx("%s", message);
+    if (!ISSET(flags, NO_STDERR)) {
+       if (ISSET(flags, USE_ERRNO))
+           warning("%s", message);
+       else
+           warningx("%s", message);
+    }
+    efree(message);
 
     /*
      * Send a copy of the error via mail.
@@ -441,12 +407,13 @@ log_error(flags, fmt, va_alist)
     if (def_logfile)
        do_logfile(logline);
 
-    efree(message);
     if (logline != message)
        efree(logline);
 
-    if (!ISSET(flags, NO_EXIT))
+    if (!ISSET(flags, NO_EXIT)) {
+       cleanup(0);
        exit(1);
+    }
 }
 
 #define MAX_MAILFLAGS  63
@@ -481,11 +448,11 @@ send_mail(line)
     /* Fork and return, child will daemonize. */
     switch (pid = fork()) {
        case -1:
-           /* Error */
-           err(1, "cannot fork");
+           /* Error. */
+           error(1, "cannot fork");
            break;
        case 0:
-           /* Child */
+           /* Child. */
            switch (pid = fork()) {
                case -1:
                    /* Error. */
@@ -500,7 +467,7 @@ send_mail(line)
            }
            break;
        default:
-           /* Parent */
+           /* Parent. */
            do {
 #ifdef HAVE_WAITPID
                rv = waitpid(pid, &status, 0);
@@ -514,7 +481,7 @@ send_mail(line)
     /* Daemonize - disassociate from session/tty. */
 #ifdef HAVE_SETSID
     if (setsid() == -1)
-      warn("setsid");
+      warning("setsid");
 #else
     setpgrp(0, 0);
 # ifdef TIOCNOTTY
@@ -531,11 +498,13 @@ send_mail(line)
        (void) dup2(fd, STDERR_FILENO);
     }
 
-    /* Close password and other fds so we don't leak. */
-    endpwent();
+    /* Close password, group and other fds so we don't leak. */
+    sudo_endpwent();
+    sudo_endgrent();
     closefrom(STDERR_FILENO + 1);
 
     /* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */
+    zero_bytes(&sa, sizeof(sa));
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = 0;
     sa.sa_handler = SIG_IGN;
@@ -601,9 +570,9 @@ send_mail(line)
     (void) close(pfd[0]);
     mail = fdopen(pfd[1], "w");
 
-    /* Pipes are all setup, send message via sendmail. */
+    /* Pipes are all setup, send message. */
     (void) fprintf(mail, "To: %s\nFrom: %s\nAuto-Submitted: %s\nSubject: ",
-       def_mailto, user_name, "auto-generated");
+       def_mailto, def_mailfrom ? def_mailfrom : user_name, "auto-generated");
     for (p = def_mailsub; *p; p++) {
        /* Expand escapes in the subject */
        if (*p == '%' && *(p+1) != '%') {
@@ -626,40 +595,26 @@ send_mail(line)
     fclose(mail);
     do {
 #ifdef HAVE_WAITPID
-       rv = waitpid(pid, &status, 0);
+        rv = waitpid(pid, &status, 0);
 #else
-       rv = wait(&status);
+        rv = wait(&status);
 #endif
     } while (rv == -1 && errno == EINTR);
     _exit(0);
 }
 
 /*
- * Send mail based on the value of "status" and compile-time options.
+ * Determine whether we should send mail based on "status" and defaults options.
  */
-static void
-mail_auth(status, line)
+static int
+should_mail(status)
     int status;
-    char *line;
 {
-    int mail_mask;
-
-    /* If any of these bits are set in status, we send mail. */
-    if (def_mail_always)
-       mail_mask =
-           VALIDATE_ERROR|VALIDATE_OK|FLAG_NO_USER|FLAG_NO_HOST|VALIDATE_NOT_OK;
-    else {
-       mail_mask = VALIDATE_ERROR;
-       if (def_mail_no_user)
-           SET(mail_mask, FLAG_NO_USER);
-       if (def_mail_no_host)
-           SET(mail_mask, FLAG_NO_HOST);
-       if (def_mail_no_perms)
-           SET(mail_mask, VALIDATE_NOT_OK);
-    }
 
-    if ((status & mail_mask) != 0)
-       send_mail(line);
+    return(def_mail_always || ISSET(status, VALIDATE_ERROR) ||
+       (def_mail_no_user && ISSET(status, FLAG_NO_USER)) ||
+       (def_mail_no_host && ISSET(status, FLAG_NO_HOST)) ||
+       (def_mail_no_perms && !ISSET(status, VALIDATE_OK)));
 }
 
 /*
@@ -696,3 +651,112 @@ get_timestr()
 
     return(s);
 }
+
+#define        LL_TTY_STR      "TTY="
+#define        LL_CWD_STR      "PWD="          /* XXX - should be CWD= */
+#define        LL_USER_STR     "USER="
+#define        LL_GROUP_STR    "GROUP="
+#define        LL_ENV_STR      "ENV="
+#define        LL_CMND_STR     "COMMAND="
+
+/*
+ * Allocate and fill in a new logline.
+ */
+static char *
+new_logline(message, serrno)
+    const char *message;
+    int serrno;
+{
+    size_t len = 0;
+    char *evstr = NULL;
+    char *errstr = NULL;
+    char *line;
+
+    /*
+     * Compute line length
+     */
+    if (message != NULL)
+       len += strlen(message) + 3;
+    if (serrno) {
+       errstr = strerror(serrno);
+       len += strlen(errstr) + 3;
+    }
+    len += sizeof(LL_TTY_STR) + 2 + strlen(user_tty);
+    len += sizeof(LL_CWD_STR) + 2 + strlen(user_cwd);
+    if (runas_pw != NULL)
+       len += sizeof(LL_USER_STR) + 2 + strlen(runas_pw->pw_name);
+    if (runas_gr != NULL)
+       len += sizeof(LL_GROUP_STR) + 2 + strlen(runas_gr->gr_name);
+    if (sudo_user.env_vars != NULL) {
+       size_t evlen = 0;
+       struct list_member *cur;
+       for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next)
+           evlen += strlen(cur->value) + 1;
+       evstr = emalloc(evlen);
+       evstr[0] = '\0';
+       for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next) {
+           strlcat(evstr, cur->value, evlen);
+           strlcat(evstr, " ", evlen); /* NOTE: last one will fail */
+       }
+       len += sizeof(LL_ENV_STR) + 2 + evlen;
+    }
+    len += sizeof(LL_CMND_STR) - 1 + strlen(user_cmnd);
+    if (user_args != NULL)
+       len += strlen(user_args) + 1;
+
+    /*
+     * Allocate and build up the line.
+     */
+    line = emalloc(++len);
+    line[0] = '\0';
+
+    if (message != NULL) {
+       if (strlcat(line, message, len) >= len ||
+           strlcat(line, errstr ? " : " : " ; ", len) >= len)
+           goto toobig;
+    }
+    if (serrno) {
+       if (strlcat(line, errstr, len) >= len ||
+           strlcat(line, " ; ", len) >= len)
+           goto toobig;
+    }
+    if (strlcat(line, LL_TTY_STR, len) >= len ||
+       strlcat(line, user_tty, len) >= len ||
+       strlcat(line, " ; ", len) >= len)
+       goto toobig;
+    if (strlcat(line, LL_CWD_STR, len) >= len ||
+       strlcat(line, user_cwd, len) >= len ||
+       strlcat(line, " ; ", len) >= len)
+       goto toobig;
+    if (runas_pw != NULL) {
+       if (strlcat(line, LL_USER_STR, len) >= len ||
+           strlcat(line, runas_pw->pw_name, len) >= len ||
+           strlcat(line, " ; ", len) >= len)
+           goto toobig;
+    }
+    if (runas_gr != NULL) {
+       if (strlcat(line, LL_GROUP_STR, len) >= len ||
+           strlcat(line, runas_gr->gr_name, len) >= len ||
+           strlcat(line, " ; ", len) >= len)
+           goto toobig;
+    }
+    if (evstr != NULL) {
+       if (strlcat(line, LL_ENV_STR, len) >= len ||
+           strlcat(line, evstr, len) >= len ||
+           strlcat(line, " ; ", len) >= len)
+           goto toobig;
+       efree(evstr);
+    }
+    if (strlcat(line, LL_CMND_STR, len) >= len ||
+       strlcat(line, user_cmnd, len) >= len)
+       goto toobig;
+    if (user_args != NULL) {
+       if (strlcat(line, " ", len) >= len ||
+           strlcat(line, user_args, len) >= len)
+           goto toobig;
+    }
+
+    return (line);
+toobig:
+    errorx(1, "internal error: insufficient space for log line");
+}
index 77196fa471d07a44c678bfa9c497b68d6f57e8c8..b3f49412ecc82088fb2404437afee4f020b033be 100644 (file)
--- a/logging.h
+++ b/logging.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1999, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -12,6 +13,8 @@
  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Sudo: logging.h,v 1.13 2008/11/09 14:13:12 millert Exp $
  */
 
 #ifndef _LOGGING_H
@@ -34,6 +37,7 @@
 #define USE_ERRNO              0x02
 #define NO_MAIL                        0x04
 #define NO_EXIT                        0x08
+#define NO_STDERR              0x10
 
 /*
  * Maximum number of characters to log per entry.  The syslogger
@@ -45,7 +49,8 @@
 # define MAXSYSLOGLEN          960
 #endif
 
-void log_auth                  __P((int, int));
+void log_allowed               __P((int));
+void log_denial                        __P((int, int));
 void log_error                 __P((int flags, const char *fmt, ...))
                                    __printflike(2, 3);
 RETSIGTYPE reapchild           __P((int));
diff --git a/lsearch.c b/lsearch.c
deleted file mode 100644 (file)
index fa3f491..0000000
--- a/lsearch.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 1989, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Roger L. Snyder.
- *
- * 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. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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 <sys/types.h>
-#include <stdio.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-
-#include <compat.h>
-#include "emul/search.h"
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static const char sccsid[] = "@(#)lsearch.c    8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#ifndef lint
-__unused static const char rcsid[] = "$Sudo: lsearch.c,v 1.18.4.1 2007/06/12 00:56:42 millert Exp $";
-#endif /* lint */
-
-typedef int (*cmp_fn_t) __P((const VOID *, const VOID *));
-static VOID *linear_base __P((const VOID *, const VOID *, size_t *, size_t,
-                            cmp_fn_t, int));
-
-VOID *
-lsearch(key, base, nelp, width, compar)
-       const VOID *key, *base;
-       size_t *nelp, width;
-       cmp_fn_t compar;
-{
-       return(linear_base(key, base, nelp, width, compar, 1));
-}
-
-VOID *
-lfind(key, base, nelp, width, compar)
-       const VOID *key, *base;
-       size_t *nelp, width;
-       cmp_fn_t compar;
-{
-       return(linear_base(key, base, nelp, width, compar, 0));
-}
-
-static VOID *
-linear_base(key, base, nelp, width, compar, add_flag)
-       const VOID *key, *base;
-       size_t *nelp, width;
-       cmp_fn_t compar;
-       int add_flag;
-{
-       /* Strict ANSI does not allow pointer arithmetic on void *'s */
-       const char *element, *end;
-
-       end = (const char *) base + *nelp * width;
-       for (element = (const char *) base; element < end; element += width)
-               if (!compar(key, (VOID *) element))     /* key found */
-                       return((VOID *) element);
-       if (!add_flag)                                  /* key not found */
-               return(NULL);
-
-       /*
-        * The UNIX System User's Manual, 1986 edition claims that
-        * a NULL pointer is returned by lsearch with errno set
-        * appropriately, if there is not enough room in the table
-        * to add a new item.  This can't be done as none of these
-        * routines have any method of determining the size of the
-        * table.  This comment was isn't in the 1986-87 System V
-        * manual.
-        */
-       ++*nelp;
-       (void) memcpy((VOID *)end, key, width);
-       return((VOID *) end);
-}
diff --git a/match.c b/match.c
new file mode 100644 (file)
index 0000000..b3b7f9a
--- /dev/null
+++ b/match.c
@@ -0,0 +1,845 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FNMATCH
+# include <fnmatch.h>
+#endif /* HAVE_FNMATCH */
+#ifdef HAVE_EXTENDED_GLOB
+# include <glob.h>
+#endif /* HAVE_EXTENDED_GLOB */
+#ifdef HAVE_NETGROUP_H
+# include <netgroup.h>
+#endif /* HAVE_NETGROUP_H */
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# ifdef HAVE_SYS_NDIR_H
+#  include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+#  include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+#  include <ndir.h>
+# endif
+#endif
+
+#include "sudo.h"
+#include "interfaces.h"
+#include "parse.h"
+#include <gram.h>
+
+#ifndef HAVE_FNMATCH
+# include "emul/fnmatch.h"
+#endif /* HAVE_FNMATCH */
+#ifndef HAVE_EXTENDED_GLOB
+# include "emul/glob.h"
+#endif /* HAVE_EXTENDED_GLOB */
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: match.c,v 1.38 2008/11/02 14:35:37 millert Exp $";
+#endif /* lint */
+
+static struct member_list empty;
+
+static int command_matches_dir __P((char *, size_t));
+
+/*
+ * Returns TRUE if string 's' contains meta characters.
+ */
+#define has_meta(s)    (strpbrk(s, "\\?*[]") != NULL)
+
+/*
+ * Check for user described by pw in a list of members.
+ * Returns ALLOW, DENY or UNSPEC.
+ */
+static int
+_userlist_matches(pw, list)
+    struct passwd *pw;
+    struct member_list *list;
+{
+    struct member *m;
+    struct alias *a;
+    int rval, matched = UNSPEC;
+
+    tq_foreach_rev(list, m) {
+       switch (m->type) {
+           case ALL:
+               matched = !m->negated;
+               break;
+           case NETGROUP:
+               if (netgr_matches(m->name, NULL, NULL, pw->pw_name))
+                   matched = !m->negated;
+               break;
+           case USERGROUP:
+               if (usergr_matches(m->name, pw->pw_name, pw))
+                   matched = !m->negated;
+               break;
+           case ALIAS:
+               if ((a = find_alias(m->name, USERALIAS)) != NULL) {
+                   rval = _userlist_matches(pw, &a->members);
+                   if (rval != UNSPEC)
+                       matched = m->negated ? !rval : rval;
+                   break;
+               }
+               /* FALLTHROUGH */
+           case WORD:
+               if (userpw_matches(m->name, pw->pw_name, pw))
+                   matched = !m->negated;
+               break;
+       }
+       if (matched != UNSPEC)
+           break;
+    }
+    return(matched);
+}
+
+int
+userlist_matches(pw, list)
+    struct passwd *pw;
+    struct member_list *list;
+{
+    alias_seqno++;
+    return(_userlist_matches(pw, list));
+}
+
+/*
+ * Check for user described by pw in a list of members.
+ * If both lists are empty compare against def_runas_default.
+ * Returns ALLOW, DENY or UNSPEC.
+ */
+static int
+_runaslist_matches(user_list, group_list)
+    struct member_list *user_list;
+    struct member_list *group_list;
+{
+    struct member *m;
+    struct alias *a;
+    int rval, matched = UNSPEC;
+
+    /* Deny if user specified a group but there is no group in sudoers */
+    if (runas_gr != NULL && tq_empty(group_list))
+       return(DENY);
+
+    if (tq_empty(user_list) && tq_empty(group_list))
+       return(userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw));
+
+    if (runas_pw != NULL) {
+       tq_foreach_rev(user_list, m) {
+           switch (m->type) {
+               case ALL:
+                   matched = !m->negated;
+                   break;
+               case NETGROUP:
+                   if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name))
+                       matched = !m->negated;
+                   break;
+               case USERGROUP:
+                   if (usergr_matches(m->name, runas_pw->pw_name, runas_pw))
+                       matched = !m->negated;
+                   break;
+               case ALIAS:
+                   if ((a = find_alias(m->name, RUNASALIAS)) != NULL) {
+                       rval = _runaslist_matches(&a->members, &empty);
+                       if (rval != UNSPEC)
+                           matched = m->negated ? !rval : rval;
+                       break;
+                   }
+                   /* FALLTHROUGH */
+               case WORD:
+                   if (userpw_matches(m->name, runas_pw->pw_name, runas_pw))
+                       matched = !m->negated;
+                   break;
+           }
+           if (matched != UNSPEC)
+               break;
+       }
+    }
+
+    if (runas_gr != NULL) {
+       tq_foreach_rev(group_list, m) {
+           switch (m->type) {
+               case ALL:
+                   matched = !m->negated;
+                   break;
+               case ALIAS:
+                   if ((a = find_alias(m->name, RUNASALIAS)) != NULL) {
+                       rval = _runaslist_matches(&a->members, &empty);
+                       if (rval != UNSPEC)
+                           matched = m->negated ? !rval : rval;
+                       break;
+                   }
+                   /* FALLTHROUGH */
+               case WORD:
+                   if (group_matches(m->name, runas_gr))
+                       matched = !m->negated;
+                   break;
+           }
+           if (matched != UNSPEC)
+               break;
+       }
+    }
+
+    return(matched);
+}
+
+int
+runaslist_matches(user_list, group_list)
+    struct member_list *user_list;
+    struct member_list *group_list;
+{
+    alias_seqno++;
+    return(_runaslist_matches(user_list ? user_list : &empty,
+       group_list ? group_list : &empty));
+}
+
+/*
+ * Check for host and shost in a list of members.
+ * Returns ALLOW, DENY or UNSPEC.
+ */
+static int
+_hostlist_matches(list)
+    struct member_list *list;
+{
+    struct member *m;
+    struct alias *a;
+    int rval, matched = UNSPEC;
+
+    tq_foreach_rev(list, m) {
+       switch (m->type) {
+           case ALL:
+               matched = !m->negated;
+               break;
+           case NETGROUP:
+               if (netgr_matches(m->name, user_host, user_shost, NULL))
+                   matched = !m->negated;
+               break;
+           case NTWKADDR:
+               if (addr_matches(m->name))
+                   matched = !m->negated;
+               break;
+           case ALIAS:
+               if ((a = find_alias(m->name, HOSTALIAS)) != NULL) {
+                   rval = _hostlist_matches(&a->members);
+                   if (rval != UNSPEC)
+                       matched = m->negated ? !rval : rval;
+                   break;
+               }
+               /* FALLTHROUGH */
+           case WORD:
+               if (hostname_matches(user_shost, user_host, m->name))
+                   matched = !m->negated;
+               break;
+       }
+       if (matched != UNSPEC)
+           break;
+    }
+    return(matched);
+}
+
+int
+hostlist_matches(list)
+    struct member_list *list;
+{
+    alias_seqno++;
+    return(_hostlist_matches(list));
+}
+
+/*
+ * Check for cmnd and args in a list of members.
+ * Returns ALLOW, DENY or UNSPEC.
+ */
+static int
+_cmndlist_matches(list)
+    struct member_list *list;
+{
+    struct member *m;
+    int rval, matched = UNSPEC;
+
+    tq_foreach_rev(list, m) {
+       rval = cmnd_matches(m);
+       if (rval != UNSPEC) {
+           matched = m->negated ? !rval : rval;
+           break;
+       }
+    }
+    return(matched);
+}
+
+int
+cmndlist_matches(list)
+    struct member_list *list;
+{
+    alias_seqno++;
+    return(_cmndlist_matches(list));
+}
+
+/*
+ * Check cmnd and args.
+ * Returns ALLOW, DENY or UNSPEC.
+ */
+int
+cmnd_matches(m)
+    struct member *m;
+{
+    struct alias *a;
+    struct sudo_command *c;
+    int rval, matched = UNSPEC;
+
+    switch (m->type) {
+       case ALL:
+           matched = !m->negated;
+           break;
+       case ALIAS:
+           alias_seqno++;
+           if ((a = find_alias(m->name, CMNDALIAS)) != NULL) {
+               rval = _cmndlist_matches(&a->members);
+               if (rval != UNSPEC)
+                   matched = m->negated ? !rval : rval;
+           }
+           break;
+       case COMMAND:
+           c = (struct sudo_command *)m->name;
+           if (command_matches(c->cmnd, c->args))
+               matched = !m->negated;
+           break;
+    }
+    return(matched);
+}
+
+/*
+ * If path doesn't end in /, return TRUE iff cmnd & path name the same inode;
+ * otherwise, return TRUE if user_cmnd names one of the inodes in path.
+ */
+int
+command_matches(sudoers_cmnd, sudoers_args)
+    char *sudoers_cmnd;
+    char *sudoers_args;
+{
+    struct stat sudoers_stat;
+    char **ap, *base, *cp;
+    glob_t gl;
+    size_t dlen;
+
+    /* Check for pseudo-commands */
+    if (strchr(user_cmnd, '/') == NULL) {
+       /*
+        * Return true if both sudoers_cmnd and user_cmnd are "sudoedit" AND
+        *  a) there are no args in sudoers OR
+        *  b) there are no args on command line and none req by sudoers OR
+        *  c) there are args in sudoers and on command line and they match
+        */
+       if (strcmp(sudoers_cmnd, "sudoedit") != 0 ||
+           strcmp(user_cmnd, "sudoedit") != 0)
+           return(FALSE);
+       if (!sudoers_args ||
+           (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
+           (sudoers_args &&
+            fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
+           efree(safe_cmnd);
+           safe_cmnd = estrdup(sudoers_cmnd);
+           return(TRUE);
+       } else
+           return(FALSE);
+    }
+    dlen = strlen(sudoers_cmnd);
+
+    /*
+     * If sudoers_cmnd has meta characters in it, we may need to
+     * use glob(3) and fnmatch(3) to do the matching.
+     */
+    if (has_meta(sudoers_cmnd)) {
+       /*
+        * First check to see if we can avoid the call to glob(3).
+        * Short circuit if there are no meta chars in the command itself
+        * and user_base and basename(sudoers_cmnd) don't match.
+        */
+       if (sudoers_cmnd[dlen - 1] != '/') {
+           if ((base = strrchr(sudoers_cmnd, '/')) != NULL) {
+               base++;
+               if (!has_meta(base) && strcmp(user_base, base) != 0)
+                   return(FALSE);
+           }
+       }
+       /*
+        * Return true if we find a match in the glob(3) results AND
+        *  a) there are no args in sudoers OR
+        *  b) there are no args on command line and none required by sudoers OR
+        *  c) there are args in sudoers and on command line and they match
+        * else return false.
+        */
+#define GLOB_FLAGS     (GLOB_NOSORT | GLOB_MARK | GLOB_BRACE | GLOB_TILDE)
+       if (glob(sudoers_cmnd, GLOB_FLAGS, NULL, &gl) != 0) {
+           globfree(&gl);
+           return(FALSE);
+       }
+       /* For each glob match, compare basename, st_dev and st_ino. */
+       for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) {
+           /* If it ends in '/' it is a directory spec. */
+           dlen = strlen(cp);
+           if (cp[dlen - 1] == '/') {
+               if (command_matches_dir(cp, dlen))
+                   return(TRUE);
+               continue;
+           }
+
+           /* Only proceed if user_base and basename(cp) match */
+           if ((base = strrchr(cp, '/')) != NULL)
+               base++;
+           else
+               base = cp;
+           if (strcmp(user_base, base) != 0 ||
+               stat(cp, &sudoers_stat) == -1)
+               continue;
+           if (user_stat == NULL ||
+               (user_stat->st_dev == sudoers_stat.st_dev &&
+               user_stat->st_ino == sudoers_stat.st_ino)) {
+               efree(safe_cmnd);
+               safe_cmnd = estrdup(cp);
+               break;
+           }
+       }
+       globfree(&gl);
+       if (cp == NULL)
+           return(FALSE);
+
+       if (!sudoers_args ||
+           (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
+           (sudoers_args &&
+            fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
+           efree(safe_cmnd);
+           safe_cmnd = estrdup(user_cmnd);
+           return(TRUE);
+       }
+       return(FALSE);
+    } else {
+       /* If it ends in '/' it is a directory spec. */
+       if (sudoers_cmnd[dlen - 1] == '/')
+           return(command_matches_dir(sudoers_cmnd, dlen));
+
+       /* Only proceed if user_base and basename(sudoers_cmnd) match */
+       if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
+           base = sudoers_cmnd;
+       else
+           base++;
+       if (strcmp(user_base, base) != 0 ||
+           stat(sudoers_cmnd, &sudoers_stat) == -1)
+           return(FALSE);
+
+       /*
+        * Return true if inode/device matches AND
+        *  a) there are no args in sudoers OR
+        *  b) there are no args on command line and none req by sudoers OR
+        *  c) there are args in sudoers and on command line and they match
+        */
+       if (user_stat != NULL &&
+           (user_stat->st_dev != sudoers_stat.st_dev ||
+           user_stat->st_ino != sudoers_stat.st_ino))
+           return(FALSE);
+       if (!sudoers_args ||
+           (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
+           (sudoers_args &&
+            fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
+           efree(safe_cmnd);
+           safe_cmnd = estrdup(sudoers_cmnd);
+           return(TRUE);
+       }
+       return(FALSE);
+    }
+}
+
+/*
+ * Return TRUE if user_cmnd names one of the inodes in dir, else FALSE.
+ */
+static int
+command_matches_dir(sudoers_dir, dlen)
+    char *sudoers_dir;
+    size_t dlen;
+{
+    struct stat sudoers_stat;
+    struct dirent *dent;
+    char buf[PATH_MAX];
+    DIR *dirp;
+
+    /*
+     * Grot through directory entries, looking for user_base.
+     */
+    dirp = opendir(sudoers_dir);
+    if (dirp == NULL)
+       return(FALSE);
+
+    if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf))
+       return(FALSE);
+    while ((dent = readdir(dirp)) != NULL) {
+       /* ignore paths > PATH_MAX (XXX - log) */
+       buf[dlen] = '\0';
+       if (strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf))
+           continue;
+
+       /* only stat if basenames are the same */
+       if (strcmp(user_base, dent->d_name) != 0 ||
+           stat(buf, &sudoers_stat) == -1)
+           continue;
+       if (user_stat->st_dev == sudoers_stat.st_dev &&
+           user_stat->st_ino == sudoers_stat.st_ino) {
+           efree(safe_cmnd);
+           safe_cmnd = estrdup(buf);
+           break;
+       }
+    }
+
+    closedir(dirp);
+    return(dent != NULL);
+}
+
+static int
+addr_matches_if(n)
+    char *n;
+{
+    int i;
+    struct in_addr addr;
+    struct interface *ifp;
+#ifdef HAVE_IN6_ADDR
+    struct in6_addr addr6;
+    int j;
+#endif
+    int family;
+
+#ifdef HAVE_IN6_ADDR
+    if (inet_pton(AF_INET6, n, &addr6) > 0) {
+       family = AF_INET6;
+    } else
+#endif
+    {
+       family = AF_INET;
+       addr.s_addr = inet_addr(n);
+    }
+
+    for (i = 0; i < num_interfaces; i++) {
+       ifp = &interfaces[i];
+       if (ifp->family != family)
+           continue;
+       switch(family) {
+           case AF_INET:
+               if (ifp->addr.ip4.s_addr == addr.s_addr ||
+                   (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr)
+                   == addr.s_addr)
+                   return(TRUE);
+               break;
+#ifdef HAVE_IN6_ADDR
+           case AF_INET6:
+               if (memcmp(ifp->addr.ip6.s6_addr, addr6.s6_addr,
+                   sizeof(addr6.s6_addr)) == 0)
+                   return(TRUE);
+               for (j = 0; j < sizeof(addr6.s6_addr); j++) {
+                   if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr6.s6_addr[j])
+                       break;
+               }
+               if (j == sizeof(addr6.s6_addr))
+                   return(TRUE);
+#endif
+       }
+    }
+
+    return(FALSE);
+}
+
+static int
+addr_matches_if_netmask(n, m)
+    char *n;
+    char *m;
+{
+    int i;
+    struct in_addr addr, mask;
+    struct interface *ifp;
+#ifdef HAVE_IN6_ADDR
+    struct in6_addr addr6, mask6;
+    int j;
+#endif
+    int family;
+
+#ifdef HAVE_IN6_ADDR
+    if (inet_pton(AF_INET6, n, &addr6) > 0)
+       family = AF_INET6;
+    else
+#endif
+    {
+       family = AF_INET;
+       addr.s_addr = inet_addr(n);
+    }
+
+    if (family == AF_INET) {
+       if (strchr(m, '.'))
+           mask.s_addr = inet_addr(m);
+       else {
+           i = 32 - atoi(m);
+           mask.s_addr = 0xffffffff;
+           mask.s_addr >>= i;
+           mask.s_addr <<= i;
+           mask.s_addr = htonl(mask.s_addr);
+       }
+    }
+#ifdef HAVE_IN6_ADDR
+    else {
+       if (inet_pton(AF_INET6, m, &mask6) <= 0) {
+           j = atoi(m);
+           for (i = 0; i < 16; i++) {
+               if (j < i * 8)
+                   mask6.s6_addr[i] = 0;
+               else if (i * 8 + 8 <= j)
+                   mask6.s6_addr[i] = 0xff;
+               else
+                   mask6.s6_addr[i] = 0xff00 >> (j - i * 8);
+           }
+       }
+    }
+#endif /* HAVE_IN6_ADDR */
+
+    for (i = 0; i < num_interfaces; i++) {
+       ifp = &interfaces[i];
+       if (ifp->family != family)
+           continue;
+       switch(family) {
+           case AF_INET:
+               if ((ifp->addr.ip4.s_addr & mask.s_addr) == addr.s_addr)
+                   return(TRUE);
+#ifdef HAVE_IN6_ADDR
+           case AF_INET6:
+               for (j = 0; j < sizeof(addr6.s6_addr); j++) {
+                   if ((ifp->addr.ip6.s6_addr[j] & mask6.s6_addr[j]) != addr6.s6_addr[j])
+                       break;
+               }
+               if (j == sizeof(addr6.s6_addr))
+                   return(TRUE);
+#endif /* HAVE_IN6_ADDR */
+       }
+    }
+
+    return(FALSE);
+}
+
+/*
+ * Returns TRUE if "n" is one of our ip addresses or if
+ * "n" is a network that we are on, else returns FALSE.
+ */
+int
+addr_matches(n)
+    char *n;
+{
+    char *m;
+    int retval;
+
+    /* If there's an explicit netmask, use it. */
+    if ((m = strchr(n, '/'))) {
+       *m++ = '\0';
+       retval = addr_matches_if_netmask(n, m);
+       *(m - 1) = '/';
+    } else
+       retval = addr_matches_if(n);
+
+    return(retval);
+}
+
+/*
+ * Returns TRUE if the hostname matches the pattern, else FALSE
+ */
+int
+hostname_matches(shost, lhost, pattern)
+    char *shost;
+    char *lhost;
+    char *pattern;
+{
+    if (has_meta(pattern)) {
+       if (strchr(pattern, '.'))
+           return(!fnmatch(pattern, lhost, FNM_CASEFOLD));
+       else
+           return(!fnmatch(pattern, shost, FNM_CASEFOLD));
+    } else {
+       if (strchr(pattern, '.'))
+           return(!strcasecmp(lhost, pattern));
+       else
+           return(!strcasecmp(shost, pattern));
+    }
+}
+
+/*
+ *  Returns TRUE if the user/uid from sudoers matches the specified user/uid,
+ *  else returns FALSE.
+ */
+int
+userpw_matches(sudoers_user, user, pw)
+    char *sudoers_user;
+    char *user;
+    struct passwd *pw;
+{
+    if (pw != NULL && *sudoers_user == '#') {
+       uid_t uid = (uid_t) atoi(sudoers_user + 1);
+       if (uid == pw->pw_uid)
+           return(TRUE);
+    }
+    return(strcmp(sudoers_user, user) == 0);
+}
+
+/*
+ *  Returns TRUE if the group/gid from sudoers matches the specified group/gid,
+ *  else returns FALSE.
+ */
+int
+group_matches(sudoers_group, gr)
+    char *sudoers_group;
+    struct group *gr;
+{
+    if (*sudoers_group == '#') {
+       gid_t gid = (gid_t) atoi(sudoers_group + 1);
+       if (gid == gr->gr_gid)
+           return(TRUE);
+    }
+    return(strcmp(gr->gr_name, sudoers_group) == 0);
+}
+
+/*
+ *  Returns TRUE if the given user belongs to the named group,
+ *  else returns FALSE.
+ *  XXX - reduce the number of group lookups
+ */
+int
+usergr_matches(group, user, pw)
+    char *group;
+    char *user;
+    struct passwd *pw;
+{
+    struct group *grp;
+    char **cur;
+    int i;
+
+    /* make sure we have a valid usergroup, sudo style */
+    if (*group++ != '%')
+       return(FALSE);
+
+    /* look up user's primary gid in the passwd file */
+    if (pw == NULL && (pw = sudo_getpwnam(user)) == NULL)
+       return(FALSE);
+
+    if ((grp = sudo_getgrnam(group)) == NULL)
+       return(FALSE);
+
+    /* check against user's primary (passwd file) gid */
+    if (grp->gr_gid == pw->pw_gid)
+       return(TRUE);
+
+    /*
+     * If we are matching the invoking or list user and that user has a
+     * supplementary group vector, check it first.
+     */
+    if (strcmp(user, list_pw ? list_pw->pw_name : user_name) == 0) {
+       for (i = 0; i < user_ngroups; i++)
+           if (grp->gr_gid == user_groups[i])
+               return(TRUE);
+    }
+    if (grp->gr_mem != NULL) {
+       for (cur = grp->gr_mem; *cur; cur++)
+           if (strcmp(*cur, user) == 0)
+               return(TRUE);
+    }
+
+    return(FALSE);
+}
+
+/*
+ * Returns TRUE if "host" and "user" belong to the netgroup "netgr",
+ * else return FALSE.  Either of "host", "shost" or "user" may be NULL
+ * in which case that argument is not checked...
+ *
+ * XXX - swap order of host & shost
+ */
+int
+netgr_matches(netgr, lhost, shost, user)
+    char *netgr;
+    char *lhost;
+    char *shost;
+    char *user;
+{
+    static char *domain;
+#ifdef HAVE_GETDOMAINNAME
+    static int initialized;
+#endif
+
+    /* make sure we have a valid netgroup, sudo style */
+    if (*netgr++ != '+')
+       return(FALSE);
+
+#ifdef HAVE_GETDOMAINNAME
+    /* get the domain name (if any) */
+    if (!initialized) {
+       domain = (char *) emalloc(MAXHOSTNAMELEN + 1);
+       if (getdomainname(domain, MAXHOSTNAMELEN + 1) == -1 || *domain == '\0') {
+           efree(domain);
+           domain = NULL;
+       }
+       initialized = 1;
+    }
+#endif /* HAVE_GETDOMAINNAME */
+
+#ifdef HAVE_INNETGR
+    if (innetgr(netgr, lhost, user, domain))
+       return(TRUE);
+    else if (lhost != shost && innetgr(netgr, shost, user, domain))
+       return(TRUE);
+#endif /* HAVE_INNETGR */
+
+    return(FALSE);
+}
index 7d0554df3e2879863977bb480725c2f2eb796879..f66f8a05cd583bd83b5618867f3f5d1504c8765e 100644 (file)
--- a/memrchr.c
+++ b/memrchr.c
@@ -19,7 +19,7 @@
 #include <compat.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: memrchr.c,v 1.1.2.3 2007/11/27 17:06:54 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: memrchr.c,v 1.4 2007/11/27 17:13:03 millert Exp $";
 #endif /* lint */
 
 #include <sys/types.h>
@@ -29,9 +29,9 @@ __unused static const char rcsid[] = "$Sudo: memrchr.c,v 1.1.2.3 2007/11/27 17:0
  * Reverse memchr()
  * Find the last occurrence of 'c' in the buffer 's' of size 'n'.
  */
-VOID *
+void *
 memrchr(s, c, n)
-    const VOID *s;
+    const void *s;
     int c;
     size_t n;
 {
@@ -41,8 +41,8 @@ memrchr(s, c, n)
        cp = (unsigned char *)s + n;
        do {
            if (*(--cp) == (unsigned char)c)
-               return((VOID *)cp);
+               return((void *)cp);
        } while (--n != 0);
     }
-    return((VOID *)0);
+    return((void *)0);
 }
index 71126f899f006bd9d080bb3683784f2ce9690744..1c9b6d495c8aecaf0236940a664ee2fd2257a271 100644 (file)
--- a/mkstemp.c
+++ b/mkstemp.c
@@ -1,44 +1,25 @@
-/*     $OpenBSD: mktemp.c,v 1.19 2005/08/08 08:05:36 espie Exp $       */
-
 /*
- * Copyright (c) 2000, 2001, 2005 Todd C. Miller <Todd.Miller@courtesan.com>
- * Copyright (c) 1987, 1993
- *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 2001, 2003, 2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
- * 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. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #include "config.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
-#if defined(TIME_WITH_SYS_TIME) || defined(HAVE_SYS_TIME_H)
-# include <sys/time.h>
-#endif
-#include <fcntl.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <stdio.h>
 #ifdef HAVE_STDLIB_H
 # include <stdlib.h>
@@ -51,7 +32,7 @@
 #include "sudo.h"
 
 #ifndef lint
-static const char rcsid[] = "$Sudo: mkstemp.c,v 1.1.2.1 2007/06/12 17:06:20 millert Exp $";
+static const char rcsid[] = "$Sudo: mkstemp.c,v 1.2 2008/08/20 11:40:15 millert Exp $";
 #endif /* not lint */
 
 static unsigned int get_random __P((void));
@@ -61,98 +42,31 @@ int
 mkstemp(path)
        char *path;
 {
-       char *start, *trv;
-       struct stat sbuf;
-       int fd, rval;
-       pid_t pid;
+       char *start, *cp;
+       int fd, r;
        char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 
        if (*path == '\0') {
                errno = EINVAL;
-               return (-1);            /* zero length path */
-       }
-       pid = getpid();
-       for (trv = path; *trv; ++trv)
-               ;
-       --trv;
-       while (trv >= path && *trv == 'X' && pid != 0) {
-               *trv-- = (pid % 10) + '0';
-               pid /= 10;
-       }
-       while (trv >= path && *trv == 'X') {
-               char c;
-
-               /* assumes pid_t is at least 16 bits */
-               pid = (get_random() & 0xffff) % (26 + 26);
-               c = alphabet[pid];
-               *trv-- = c;
+               return(0);
        }
-       start = trv + 1;
 
-       /*
-        * check the target directory; if you have six X's and it
-        * doesn't exist this runs for a *very* long time.
-        */
-       for (;; --trv) {
-               if (trv <= path)
-                       break;
-               if (*trv == '/') {
-                       *trv = '\0';
-                       rval = stat(path, &sbuf);
-                       *trv = '/';
-                       if (rval != 0)
-                               return (-1);
-                       if (!S_ISDIR(sbuf.st_mode)) {
-                               errno = ENOTDIR;
-                               return (-1);
-                       }
-                       break;
-               }
-       }
+       for (cp = path; *cp; cp++)
+               ;
+       do {
+               cp--;
+       } while (cp >= path && *cp == 'X');
+       start = cp + 1;
 
        for (;;) {
-               if ((fd = open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
-                       return (fd);
-               if (errno != EEXIST)
-                       return (-1);
-
-               /* tricky little algorithm for backward compatibility */
-               for (trv = start;;) {
-                       if (!*trv)
-                               return (-1);
-                       if (*trv == 'Z')
-                               *trv++ = 'a';
-                       else {
-                               if (isdigit((unsigned char)(*trv)))
-                                       *trv = 'a';
-                               else if (*trv == 'z')   /* wrap from z to A */
-                                       *trv = 'A';
-                               else {
-#ifdef HAVE_EBCDIC
-                                       switch(*trv) {
-                                       case 'i':
-                                               *trv = 'j';
-                                               break;
-                                       case 'r':
-                                               *trv = 's';
-                                               break;
-                                       case 'I':
-                                               *trv = 'J';
-                                               break;
-                                       case 'R':
-                                               *trv = 'S';
-                                               break;
-                                       default:
-                                               ++*trv;
-                                               break;
-                                       }
-#else
-                                       ++*trv;
-#endif
-                               }
-                               break;
-                       }
+               for (cp = start; *cp; cp++) {
+                       r = get_random % (26 + 26);
+                       *cp = alphabet[r];
                }
+
+               fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
+               if (fd != -1 || errno != EEXIST)
+                       return(fd);
        }
        /*NOTREACHED*/
 }
diff --git a/parse.c b/parse.c
index 8c4a1e5bb5935d0ab172bfafe51a0b253d175149..ef4a4959945abf4864f2a759994402e508d2d0d6 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -1,6 +1,5 @@
 /*
- * Copyright (c) 1996, 1998-2005, 2007
- *     Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2004-2005, 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  */
 
 #include <config.h>
 
 #include <sys/types.h>
 #include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
 #include <stdio.h>
 #ifdef STDC_HEADERS
 # include <stdlib.h>
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_FNMATCH
-# include <fnmatch.h>
-#endif /* HAVE_FNMATCH */
-#ifdef HAVE_EXTENDED_GLOB
-# include <glob.h>
-#endif /* HAVE_EXTENDED_GLOB */
-#ifdef HAVE_NETGROUP_H
-# include <netgroup.h>
-#endif /* HAVE_NETGROUP_H */
 #include <ctype.h>
 #include <pwd.h>
 #include <grp.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#ifdef HAVE_DIRENT_H
-# include <dirent.h>
-# define NAMLEN(dirent) strlen((dirent)->d_name)
-#else
-# define dirent direct
-# define NAMLEN(dirent) (dirent)->d_namlen
-# ifdef HAVE_SYS_NDIR_H
-#  include <sys/ndir.h>
-# endif
-# ifdef HAVE_SYS_DIR_H
-#  include <sys/dir.h>
-# endif
-# ifdef HAVE_NDIR_H
-#  include <ndir.h>
-# endif
-#endif
 
 #include "sudo.h"
 #include "parse.h"
-#include "interfaces.h"
-
-#ifndef HAVE_FNMATCH
-# include "emul/fnmatch.h"
-#endif /* HAVE_FNMATCH */
-#ifndef HAVE_EXTENDED_GLOB
-# include "emul/glob.h"
-#endif /* HAVE_EXTENDED_GLOB */
+#include "lbuf.h"
+#include <gram.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: parse.c,v 1.160.2.16 2008/02/09 14:44:48 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: parse.c,v 1.238 2008/12/09 13:49:55 millert Exp $";
 #endif /* lint */
 
-/*
- * Globals
- */
-int parse_error = FALSE;
-extern int keepall;
-extern FILE *yyin, *yyout;
+/* Characters that must be quoted in sudoers */
+#define SUDOERS_QUOTED ":\\,=#\""
+
+/* sudoers nsswitch routines */
+struct sudo_nss sudo_nss_file = {
+    &sudo_nss_file,
+    NULL,
+    sudo_file_open,
+    sudo_file_close,
+    sudo_file_parse,
+    sudo_file_setdefs,
+    sudo_file_lookup,
+    sudo_file_display_cmnd,
+    sudo_file_display_defaults,
+    sudo_file_display_bound_defaults,
+    sudo_file_display_privs
+};
 
 /*
- * Prototypes
+ * Parser externs.
  */
-static int has_meta    __P((char *));
-       void init_parser        __P((void));
+extern FILE *yyin;
+extern char *errorfile;
+extern int errorlineno, parse_error;
 
 /*
- * Look up the user in the sudoers file and check to see if they are
- * allowed to run the specified command on this host as the target user.
+ * Local prototypes.
  */
+static void print_member       __P((struct lbuf *, char *, int, int, int));
+static int display_bound_defaults __P((int, struct lbuf *));
+
 int
-sudoers_lookup(pwflag)
-    int pwflag;
+sudo_file_open(nss)
+    struct sudo_nss *nss;
 {
-    int error, nopass;
-
-    /* We opened _PATH_SUDOERS in check_sudoers() so just rewind it. */
-    rewind(sudoers_fp);
-    yyin = sudoers_fp;
-    yyout = stdout;
+    if (def_ignore_local_sudoers)
+       return(-1);
+    nss->handle = open_sudoers(_PATH_SUDOERS, NULL);
+    return(nss->handle ? 0 : -1);
+}
 
-    /* Allocate space for data structures in the parser. */
-    init_parser();
+int
+sudo_file_close(nss)
+    struct sudo_nss *nss;
+{
+    /* Free parser data structures and close sudoers file. */
+    init_parser(NULL, 0);
+    if (nss->handle != NULL) {
+       fclose(nss->handle);
+       nss->handle = NULL;
+       yyin = NULL;
+    }
+    return(0);
+}
 
-    /* Keep more state for pseudo-commands so that listpw and verifypw work */
-    if (pwflag > 0)
-       keepall = TRUE;
+/*
+ * Parse the specified sudoers file.
+ */
+int
+sudo_file_parse(nss)
+    struct sudo_nss *nss;
+{
+    if (nss->handle == NULL)
+       return(-1);
+
+    init_parser(_PATH_SUDOERS, 0);
+    yyin = nss->handle;
+    if (yyparse() != 0 || parse_error) {
+       log_error(NO_EXIT, "parse error in %s near line %d",
+           errorfile, errorlineno);
+       return(-1);
+    }
+    return(0);
+}
 
-    /* Need to be runas user while stat'ing things in the parser. */
-    set_perms(PERM_RUNAS);
-    error = yyparse();
+/*
+ * Wrapper around update_defaults() for nsswitch code.
+ */
+int
+sudo_file_setdefs(nss)
+    struct sudo_nss *nss;
+{
+    if (nss->handle == NULL)
+       return(-1);
 
-    /* Close the sudoers file now that we are done with it. */
-    (void) fclose(sudoers_fp);
-    sudoers_fp = NULL;
+    if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER))
+       return(-1);
+    return(0);
+}
 
-    if (error || parse_error) {
-       set_perms(PERM_ROOT);
-       return(VALIDATE_ERROR);
-    }
+/*
+ * Look up the user in the parsed sudoers file and check to see if they are
+ * allowed to run the specified command on this host as the target user.
+ */
+int
+sudo_file_lookup(nss, validated, pwflag)
+    struct sudo_nss *nss;
+    int validated;
+    int pwflag;
+{
+    int match, host_match, runas_match, cmnd_match;
+    struct cmndspec *cs;
+    struct cmndtag *tags = NULL;
+    struct privilege *priv;
+    struct userspec *us;
 
-    /*
-     * Assume the worst.  If the stack is empty the user was
-     * not mentioned at all.
-     */
-    if (def_authenticate)
-       error = VALIDATE_NOT_OK;
-    else
-       error = VALIDATE_NOT_OK | FLAG_NOPASS;
-    if (pwflag) {
-       SET(error, FLAG_NO_CHECK);
-    } else {
-       SET(error, FLAG_NO_HOST);
-       if (!top)
-           SET(error, FLAG_NO_USER);
-    }
+    if (nss->handle == NULL)
+       return(validated);
 
     /*
      * Only check the actual command if pwflag is not set.
      * It is set for the "validate", "list" and "kill" pseudo-commands.
      * Always check the host and user.
      */
-    nopass = -1;
     if (pwflag) {
-       int found;
+       int nopass;
        enum def_tupple pwcheck;
 
        pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
-
-       if (pwcheck == always && def_authenticate)
-           nopass = FLAG_CHECK_USER;
-       else if (pwcheck == never || !def_authenticate)
-           nopass = FLAG_NOPASS;
-       found = 0;
-       while (top) {
-           if (host_matches == TRUE) {
-               found = 1;
-               if (pwcheck == any && no_passwd == TRUE)
-                   nopass = FLAG_NOPASS;
-               else if (pwcheck == all && nopass != 0)
-                   nopass = (no_passwd == TRUE) ? FLAG_NOPASS : 0;
-           }
-           top--;
-       }
-       if (found) {
-           set_perms(PERM_ROOT);
-           if (nopass == -1)
-               nopass = 0;
-           return(VALIDATE_OK | nopass);
-       }
-    } else {
-       while (top) {
-           if (host_matches == TRUE) {
-               CLR(error, FLAG_NO_HOST);
-               if (runas_matches == TRUE && cmnd_matches == TRUE) {
-                   /*
-                    * User was granted access to cmnd on host as user.
-                    */
-#ifdef HAVE_SELINUX
-                   /* Set role and type if not specified on command line. */
-                   if (user_role == NULL) {
-                       if (match[top-1].role != NULL)
-                           user_role = match[top-1].role;
-                       else
-                           user_role = def_role;
-                   }
-                   if (user_type == NULL) {
-                       if (match[top-1].type != NULL)
-                           user_type = match[top-1].type;
-                       else
-                           user_type = def_type;
-                   }
-#endif
-                   set_perms(PERM_ROOT);
-                   return(VALIDATE_OK |
-                       (no_passwd == TRUE ? FLAG_NOPASS : 0) |
-                       (no_execve == TRUE ? FLAG_NOEXEC : 0) |
-                       (setenv_ok >= TRUE ? FLAG_SETENV : 0));
-               } else if ((runas_matches == TRUE && cmnd_matches == FALSE) ||
-                   (runas_matches == FALSE && cmnd_matches == TRUE)) {
-                   /*
-                    * 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) |
-                       (setenv_ok >= TRUE ? FLAG_SETENV : 0));
+       nopass = (pwcheck == all) ? TRUE : FALSE;
+
+       if (list_pw == NULL)
+           SET(validated, FLAG_NO_CHECK);
+       CLR(validated, FLAG_NO_USER);
+       CLR(validated, FLAG_NO_HOST);
+       match = DENY;
+       tq_foreach_fwd(&userspecs, us) {
+           if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
+               continue;
+           tq_foreach_fwd(&us->privileges, priv) {
+               if (hostlist_matches(&priv->hostlist) != ALLOW)
+                   continue;
+               tq_foreach_fwd(&priv->cmndlist, cs) {
+                   /* Only check the command when listing another user. */
+                   if (user_uid == 0 || list_pw == NULL ||
+                       user_uid == list_pw->pw_uid ||
+                       cmnd_matches(cs->cmnd) == ALLOW)
+                           match = ALLOW;
+                   if ((pwcheck == any && cs->tags.nopasswd == TRUE) ||
+                       (pwcheck == all && cs->tags.nopasswd != TRUE))
+                       nopass = cs->tags.nopasswd;
                }
            }
-           top--;
        }
+       if (match == ALLOW || user_uid == 0) {
+           /* User has an entry for this host. */
+           SET(validated, VALIDATE_OK);
+       } else if (match == DENY)
+           SET(validated, VALIDATE_NOT_OK);
+       if (pwcheck == always && def_authenticate)
+           SET(validated, FLAG_CHECK_USER);
+       else if (pwcheck == never || nopass == TRUE)
+           def_authenticate = FALSE;
+       return(validated);
     }
-    set_perms(PERM_ROOT);
 
-    /*
-     * The user was neither explicitly granted nor denied access.
-     */
-    if (nopass == -1)
-       nopass = 0;
-    return(error | nopass);
-}
-
-/*
- * If path doesn't end in /, return TRUE iff cmnd & path name the same inode;
- * otherwise, return TRUE if user_cmnd names one of the inodes in path.
- */
-int
-command_matches(sudoers_cmnd, sudoers_args)
-    char *sudoers_cmnd;
-    char *sudoers_args;
-{
-    struct stat sudoers_stat;
-    struct dirent *dent;
-    char **ap, *base, buf[PATH_MAX];
-    glob_t gl;
-    DIR *dirp;
-
-    /* Check for pseudo-commands */
-    if (strchr(user_cmnd, '/') == NULL) {
-       /*
-        * Return true if both sudoers_cmnd and user_cmnd are "sudoedit" AND
-        *  a) there are no args in sudoers OR
-        *  b) there are no args on command line and none req by sudoers OR
-        *  c) there are args in sudoers and on command line and they match
-        */
-       if (strcmp(sudoers_cmnd, "sudoedit") != 0 ||
-           strcmp(user_cmnd, "sudoedit") != 0)
-           return(FALSE);
-       if (!sudoers_args ||
-           (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-           (sudoers_args &&
-            fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
-           efree(safe_cmnd);
-           safe_cmnd = estrdup(sudoers_cmnd);
-           return(TRUE);
-       } else
-           return(FALSE);
-    }
+    /* Need to be runas user while stat'ing things. */
+    set_perms(PERM_RUNAS);
 
-    /*
-     * If sudoers_cmnd has meta characters in it, use fnmatch(3)
-     * to do the matching.
-     */
-    if (has_meta(sudoers_cmnd)) {
-       /*
-        * Return true if we find a match in the glob(3) results AND
-        *  a) there are no args in sudoers OR
-        *  b) there are no args on command line and none required by sudoers OR
-        *  c) there are args in sudoers and on command line and they match
-        * else return false.
-        *
-        * Could optimize patterns ending in "/*" to "/user_base"
-        */
-#define GLOB_FLAGS     (GLOB_NOSORT | GLOB_MARK | GLOB_BRACE | GLOB_TILDE)
-       if (glob(sudoers_cmnd, GLOB_FLAGS, NULL, &gl) != 0) {
-           globfree(&gl);
-           return(FALSE);
-       }
-       /* For each glob match, compare basename, st_dev and st_ino. */
-       for (ap = gl.gl_pathv; *ap != NULL; ap++) {
-           /* only stat if basenames are the same */
-           if ((base = strrchr(*ap, '/')) != NULL)
-               base++;
+    match = UNSPEC;
+    tq_foreach_rev(&userspecs, us) {
+       if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
+           continue;
+       CLR(validated, FLAG_NO_USER);
+       tq_foreach_rev(&us->privileges, priv) {
+           host_match = hostlist_matches(&priv->hostlist);
+           if (host_match == ALLOW)
+               CLR(validated, FLAG_NO_HOST);
            else
-               base = *ap;
-           if (strcmp(user_base, base) != 0 ||
-               stat(*ap, &sudoers_stat) == -1)
                continue;
-           if (user_stat->st_dev == sudoers_stat.st_dev &&
-               user_stat->st_ino == sudoers_stat.st_ino) {
-               efree(safe_cmnd);
-               safe_cmnd = estrdup(*ap);
-               break;
+           tq_foreach_rev(&priv->cmndlist, cs) {
+               runas_match = runaslist_matches(&cs->runasuserlist,
+                   &cs->runasgrouplist);
+               if (runas_match == ALLOW) {
+                   cmnd_match = cmnd_matches(cs->cmnd);
+                   if (cmnd_match != UNSPEC) {
+                       match = cmnd_match;
+                       tags = &cs->tags;
+#ifdef HAVE_SELINUX
+                       /* Set role and type if not specified on command line. */
+                       if (user_role == NULL)
+                           user_role = cs->role ? estrdup(cs->role) : def_role;
+                       if (user_type == NULL)
+                           user_type = cs->type ? estrdup(cs->type) : def_type;
+#endif /* HAVE_SELINUX */
+                       goto matched2;
+                   }
+               }
            }
        }
-       globfree(&gl);
-       if (*ap == NULL)
-           return(FALSE);
-
-       if (!sudoers_args ||
-           (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-           (sudoers_args &&
-            fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
-           efree(safe_cmnd);
-           safe_cmnd = estrdup(user_cmnd);
-           return(TRUE);
-       } else
-           return(FALSE);
-    } else {
-       size_t dlen = strlen(sudoers_cmnd);
-
-       /*
-        * No meta characters
-        * Check to make sure this is not a directory spec (doesn't end in '/')
-        */
-       if (sudoers_cmnd[dlen - 1] != '/') {
-           /* Only proceed if user_base and basename(sudoers_cmnd) match */
-           if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
-               base = sudoers_cmnd;
-           else
-               base++;
-           if (strcmp(user_base, base) != 0 ||
-               stat(sudoers_cmnd, &sudoers_stat) == -1)
-               return(FALSE);
-
-           /*
-            * Return true if inode/device matches AND
-            *  a) there are no args in sudoers OR
-            *  b) there are no args on command line and none req by sudoers OR
-            *  c) there are args in sudoers and on command line and they match
-            */
-           if (user_stat->st_dev != sudoers_stat.st_dev ||
-               user_stat->st_ino != sudoers_stat.st_ino)
-               return(FALSE);
-           if (!sudoers_args ||
-               (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-               (sudoers_args &&
-                fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
-               efree(safe_cmnd);
-               safe_cmnd = estrdup(sudoers_cmnd);
-               return(TRUE);
-           } else
-               return(FALSE);
+    }
+    matched2:
+    if (match == ALLOW) {
+       SET(validated, VALIDATE_OK);
+       CLR(validated, VALIDATE_NOT_OK);
+       if (tags != NULL) {
+           if (tags->nopasswd != UNSPEC)
+               def_authenticate = !tags->nopasswd;
+           if (tags->noexec != UNSPEC)
+               def_noexec = tags->noexec;
+           if (tags->setenv != UNSPEC)
+               def_setenv = tags->setenv;
        }
+    } else if (match == DENY) {
+       SET(validated, VALIDATE_NOT_OK);
+       CLR(validated, VALIDATE_OK);
+    }
+    set_perms(PERM_ROOT);
+    return(validated);
+}
 
-       /*
-        * Grot through sudoers_cmnd's directory entries, looking for user_base.
-        */
-       dirp = opendir(sudoers_cmnd);
-       if (dirp == NULL)
-           return(FALSE);
-
-       if (strlcpy(buf, sudoers_cmnd, sizeof(buf)) >= sizeof(buf))
-           return(FALSE);
-       while ((dent = readdir(dirp)) != NULL) {
-           /* ignore paths > PATH_MAX (XXX - log) */
-           buf[dlen] = '\0';
-           if (strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf))
-               continue;
+#define        TAG_CHANGED(t) \
+       (cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags->t)
 
-           /* only stat if basenames are the same */
-           if (strcmp(user_base, dent->d_name) != 0 ||
-               stat(buf, &sudoers_stat) == -1)
-               continue;
-           if (user_stat->st_dev == sudoers_stat.st_dev &&
-               user_stat->st_ino == sudoers_stat.st_ino) {
-               efree(safe_cmnd);
-               safe_cmnd = estrdup(buf);
-               break;
-           }
-       }
+static void
+sudo_file_append_cmnd(cs, tags, lbuf)
+    struct cmndspec *cs;
+    struct cmndtag *tags;
+    struct lbuf *lbuf;
+{
+    struct member *m;
 
-       closedir(dirp);
-       return(dent != NULL);
+#ifdef HAVE_SELINUX
+    if (cs->role)
+       lbuf_append(lbuf, "ROLE=", cs->role, " ", NULL);
+    if (cs->type)
+       lbuf_append(lbuf, "TYPE=", cs->type, " ", NULL);
+#endif /* HAVE_SELINUX */
+    if (TAG_CHANGED(setenv)) {
+       lbuf_append(lbuf, cs->tags.setenv ? "SETENV: " :
+           "NOSETENV: ", NULL);
+       tags->setenv = cs->tags.setenv;
+    }
+    if (TAG_CHANGED(noexec)) {
+       lbuf_append(lbuf, cs->tags.noexec ? "NOEXEC: " :
+           "EXEC: ", NULL);
+       tags->noexec = cs->tags.noexec;
+    }
+    if (TAG_CHANGED(nopasswd)) {
+       lbuf_append(lbuf, cs->tags.nopasswd ? "NOPASSWD: " :
+           "PASSWD: ", NULL);
+       tags->nopasswd = cs->tags.nopasswd;
     }
+    m = cs->cmnd;
+    print_member(lbuf, m->name, m->type, m->negated,
+       CMNDALIAS);
 }
 
 static int
-addr_matches_if(n)
-    char *n;
+sudo_file_display_priv_short(pw, us, lbuf)
+    struct passwd *pw;
+    struct userspec *us;
+    struct lbuf *lbuf;
 {
-    int i;
-    struct in_addr addr;
-    struct interface *ifp;
-#ifdef HAVE_IN6_ADDR
-    struct in6_addr addr6;
-    int j;
-#endif
-    int family;
-
-#ifdef HAVE_IN6_ADDR
-    if (inet_pton(AF_INET6, n, &addr6) > 0) {
-       family = AF_INET6;
-    } else
-#endif
-    {
-       family = AF_INET;
-       addr.s_addr = inet_addr(n);
-    }
-
-    for (i = 0; i < num_interfaces; i++) {
-       ifp = &interfaces[i];
-       if (ifp->family != family)
-           continue;
-       switch(family) {
-           case AF_INET:
-               if (ifp->addr.ip4.s_addr == addr.s_addr ||
-                   (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr)
-                   == addr.s_addr)
-                   return(TRUE);
-               break;
-#ifdef HAVE_IN6_ADDR
-           case AF_INET6:
-               if (memcmp(ifp->addr.ip6.s6_addr, addr6.s6_addr,
-                   sizeof(addr6.s6_addr)) == 0)
-                   return(TRUE);
-               for (j = 0; j < sizeof(addr6.s6_addr); j++) {
-                   if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr6.s6_addr[j])
-                       break;
+    struct cmndspec *cs;
+    struct member *m;
+    struct privilege *priv;
+    struct cmndtag tags;
+    int nfound = 0;
+
+    tq_foreach_fwd(&us->privileges, priv) {
+       tags.noexec = UNSPEC;
+       tags.setenv = UNSPEC;
+       tags.nopasswd = UNSPEC;
+       lbuf_append(lbuf, "    ", NULL);
+       tq_foreach_fwd(&priv->cmndlist, cs) {
+           if (cs != tq_first(&priv->cmndlist))
+               lbuf_append(lbuf, ", ", NULL);
+           lbuf_append(lbuf, "(", NULL);
+           if (!tq_empty(&cs->runasuserlist)) {
+               tq_foreach_fwd(&cs->runasuserlist, m) {
+                   if (m != tq_first(&cs->runasuserlist))
+                       lbuf_append(lbuf, ", ", NULL);
+                   print_member(lbuf, m->name, m->type, m->negated,
+                       RUNASALIAS);
                }
-               if (j == sizeof(addr6.s6_addr))
-                   return(TRUE);
-#endif /* HAVE_IN6_ADDR */
+           } else {
+               lbuf_append(lbuf, def_runas_default, NULL);
+           }
+           if (!tq_empty(&cs->runasgrouplist)) {
+               lbuf_append(lbuf, " : ", NULL);
+               tq_foreach_fwd(&cs->runasgrouplist, m) {
+                   if (m != tq_first(&cs->runasgrouplist))
+                       lbuf_append(lbuf, ", ", NULL);
+                   print_member(lbuf, m->name, m->type, m->negated,
+                       RUNASALIAS);
+               }
+           }
+           lbuf_append(lbuf, ") ", NULL);
+           sudo_file_append_cmnd(cs, &tags, lbuf);
+           nfound++;
        }
+       lbuf_print(lbuf);               /* forces a newline */
     }
-
-    return(FALSE);
+    return(nfound);
 }
 
 static int
-addr_matches_if_netmask(n, m)
-    char *n;
-    char *m;
+sudo_file_display_priv_long(pw, us, lbuf)
+    struct passwd *pw;
+    struct userspec *us;
+    struct lbuf *lbuf;
 {
-    int i;
-    struct in_addr addr, mask;
-    struct interface *ifp;
-#ifdef HAVE_IN6_ADDR
-    struct in6_addr addr6, mask6;
-    int j;
-#endif
-    int family;
-
-#ifdef HAVE_IN6_ADDR
-    if (inet_pton(AF_INET6, n, &addr6) > 0)
-       family = AF_INET6;
-    else
-#endif
-    {
-       family = AF_INET;
-       addr.s_addr = inet_addr(n);
-    }
-
-    if (family == AF_INET) {
-       if (strchr(m, '.'))
-           mask.s_addr = inet_addr(m);
-       else {
-           i = 32 - atoi(m);
-           mask.s_addr = 0xffffffff;
-           mask.s_addr >>= i;
-           mask.s_addr <<= i;
-           mask.s_addr = htonl(mask.s_addr);
-       }
-    }
-#ifdef HAVE_IN6_ADDR
-    else {
-       if (inet_pton(AF_INET6, m, &mask6) <= 0) {
-           j = atoi(m);
-           for (i = 0; i < 16; i++) {
-               if (j < i * 8)
-                   mask6.s6_addr[i] = 0;
-               else if (i * 8 + 8 <= j)
-                   mask6.s6_addr[i] = 0xff;
-               else
-                   mask6.s6_addr[i] = 0xff00 >> (j - i * 8);
+    struct cmndspec *cs;
+    struct member *m;
+    struct privilege *priv;
+    struct cmndtag tags;
+    int nfound = 0;
+
+    tq_foreach_fwd(&us->privileges, priv) {
+       tags.noexec = UNSPEC;
+       tags.setenv = UNSPEC;
+       tags.nopasswd = UNSPEC;
+       lbuf_print(lbuf);       /* force a newline */
+       lbuf_append(lbuf, "Sudoers entry:", NULL);
+       lbuf_print(lbuf);
+       tq_foreach_fwd(&priv->cmndlist, cs) {
+           lbuf_append(lbuf, "    RunAsUsers: ", NULL);
+           if (!tq_empty(&cs->runasuserlist)) {
+               tq_foreach_fwd(&cs->runasuserlist, m) {
+                   if (m != tq_first(&cs->runasuserlist))
+                       lbuf_append(lbuf, ", ", NULL);
+                   print_member(lbuf, m->name, m->type, m->negated,
+                       RUNASALIAS);
+               }
+           } else {
+               lbuf_append(lbuf, def_runas_default, NULL);
            }
-       }
-    }
-#endif /* HAVE_IN6_ADDR */
-
-    for (i = 0; i < num_interfaces; i++) {
-       ifp = &interfaces[i];
-       if (ifp->family != family)
-           continue;
-       switch(family) {
-           case AF_INET:
-               if ((ifp->addr.ip4.s_addr & mask.s_addr) == addr.s_addr)
-                   return(TRUE);
-#ifdef HAVE_IN6_ADDR
-           case AF_INET6:
-               for (j = 0; j < sizeof(addr6.s6_addr); j++) {
-                   if ((ifp->addr.ip6.s6_addr[j] & mask6.s6_addr[j]) != addr6.s6_addr[j])
-                       break;
+           lbuf_print(lbuf);
+           if (!tq_empty(&cs->runasgrouplist)) {
+               lbuf_append(lbuf, "    RunAsGroups: ", NULL);
+               tq_foreach_fwd(&cs->runasgrouplist, m) {
+                   if (m != tq_first(&cs->runasgrouplist))
+                       lbuf_append(lbuf, ", ", NULL);
+                   print_member(lbuf, m->name, m->type, m->negated,
+                       RUNASALIAS);
                }
-               if (j == sizeof(addr6.s6_addr))
-                   return(TRUE);
-#endif /* HAVE_IN6_ADDR */
+               lbuf_print(lbuf);
+           }
+           lbuf_append(lbuf, "    Commands: ", NULL);
+           lbuf_print(lbuf);
+           lbuf_append(lbuf, "\t", NULL);
+           sudo_file_append_cmnd(cs, &tags, lbuf);
+           lbuf_print(lbuf);
+           nfound++;
        }
     }
-
-    return(FALSE);
+    return(nfound);
 }
 
-/*
- * Returns TRUE if "n" is one of our ip addresses or if
- * "n" is a network that we are on, else returns FALSE.
- */
 int
-addr_matches(n)
-    char *n;
+sudo_file_display_privs(nss, pw, lbuf)
+    struct sudo_nss *nss;
+    struct passwd *pw;
+    struct lbuf *lbuf;
 {
-    char *m;
-    int retval;
-
-    /* If there's an explicit netmask, use it. */
-    if ((m = strchr(n, '/'))) {
-       *m++ = '\0';
-       retval = addr_matches_if_netmask(n, m);
-       *(m - 1) = '/';
-    } else
-       retval = addr_matches_if(n);
-
-    return(retval);
-}
+    struct userspec *us;
+    int nfound = 0;
 
-/*
- * Returns 0 if the hostname matches the pattern and non-zero otherwise.
- */
-int
-hostname_matches(shost, lhost, pattern)
-    char *shost;
-    char *lhost;
-    char *pattern;
-{
-    if (has_meta(pattern)) {
-       if (strchr(pattern, '.'))
-           return(fnmatch(pattern, lhost, FNM_CASEFOLD));
-       else
-           return(fnmatch(pattern, shost, FNM_CASEFOLD));
-    } else {
-       if (strchr(pattern, '.'))
-           return(strcasecmp(lhost, pattern));
+    if (nss->handle == NULL)
+       return(-1);
+
+    tq_foreach_fwd(&userspecs, us) {
+       /* XXX - why only check the first privilege here? */
+       if (userlist_matches(pw, &us->users) != ALLOW ||
+           hostlist_matches(&us->privileges.first->hostlist) != ALLOW)
+           continue;
+
+       if (long_list)
+           nfound += sudo_file_display_priv_long(pw, us, lbuf);
        else
-           return(strcasecmp(shost, pattern));
+           nfound += sudo_file_display_priv_short(pw, us, lbuf);
     }
+    return(nfound);
 }
 
 /*
- *  Returns TRUE if the user/uid from sudoers matches the specified user/uid,
- *  else returns FALSE.
+ * Display matching Defaults entries for the given user on this host.
  */
 int
-userpw_matches(sudoers_user, user, pw)
-    char *sudoers_user;
-    char *user;
+sudo_file_display_defaults(nss, pw, lbuf)
+    struct sudo_nss *nss;
     struct passwd *pw;
+    struct lbuf *lbuf;
 {
-    if (pw != NULL && *sudoers_user == '#') {
-       uid_t uid = atoi(sudoers_user + 1);
-       if (uid == pw->pw_uid)
-           return(1);
+    struct defaults *d;
+    char *prefix = NULL;
+    int nfound = 0;
+
+    if (nss->handle == NULL)
+       return(-1);
+
+    if (lbuf->len == 0)
+       prefix = "    ";
+    else
+       prefix = ", ";
+
+    tq_foreach_fwd(&defaults, d) {
+       switch (d->type) {
+           case DEFAULTS_HOST:
+               if (hostlist_matches(&d->binding) != ALLOW)
+                   continue;
+               break;
+           case DEFAULTS_USER:
+               if (userlist_matches(pw, &d->binding) != ALLOW)
+                   continue;
+               break;
+           case DEFAULTS_RUNAS:
+           case DEFAULTS_CMND:
+               continue;
+       }
+       lbuf_append(lbuf, prefix, NULL);
+       if (d->val != NULL) {
+           lbuf_append(lbuf, d->var, d->op == '+' ? "+=" :
+               d->op == '-' ? "-=" : "=", NULL);
+           if (strpbrk(d->val, " \t") != NULL) {
+               lbuf_append(lbuf, "\"", NULL);
+               lbuf_append_quoted(lbuf, "\"", d->val, NULL);
+               lbuf_append(lbuf, "\"", NULL);
+           } else
+               lbuf_append_quoted(lbuf, SUDOERS_QUOTED, d->val, NULL);
+       } else
+           lbuf_append(lbuf, d->op == FALSE ? "!" : "", d->var, NULL);
+       prefix = ", ";
+       nfound++;
     }
-    return(strcmp(sudoers_user, user) == 0);
+
+    return(nfound);
 }
 
 /*
- *  Returns TRUE if the given user belongs to the named group,
- *  else returns FALSE.
- *  XXX - reduce the number of passwd/group lookups
+ * Display Defaults entries that are per-runas or per-command
  */
 int
-usergr_matches(group, user, pw)
-    char *group;
-    char *user;
+sudo_file_display_bound_defaults(nss, pw, lbuf)
+    struct sudo_nss *nss;
     struct passwd *pw;
+    struct lbuf *lbuf;
 {
-    struct group *grp;
-    gid_t pw_gid;
-    char **cur;
-    int i;
+    int nfound = 0;
 
-    /* make sure we have a valid usergroup, sudo style */
-    if (*group++ != '%')
-       return(FALSE);
+    /* XXX - should only print ones that match what the user can do. */
+    nfound += display_bound_defaults(DEFAULTS_RUNAS, lbuf);
+    nfound += display_bound_defaults(DEFAULTS_CMND, lbuf);
 
-    /* look up user's primary gid in the passwd file */
-    if (pw == NULL && (pw = getpwnam(user)) == NULL)
-       return(FALSE);
-    pw_gid = pw->pw_gid;
-
-    if ((grp = getgrnam(group)) == NULL)
-       return(FALSE);
-
-    /* check against user's primary (passwd file) gid */
-    if (grp->gr_gid == pw_gid)
-       return(TRUE);
+    return(nfound);
+}
 
-    /*
-     * If the user has a supplementary group vector, check it first.
-     */
-    for (i = 0; i < user_ngroups; i++) {
-       if (grp->gr_gid == user_groups[i])
-           return(TRUE);
+/*
+ * Display Defaults entries of the given type.
+ */
+static int
+display_bound_defaults(dtype, lbuf)
+    int dtype;
+    struct lbuf *lbuf;
+{
+    struct defaults *d;
+    struct member *m, *binding = NULL;
+    char *dname, *dsep;
+    int atype, nfound = 0;
+
+    switch (dtype) {
+       case DEFAULTS_HOST:
+           atype = HOSTALIAS;
+           dname = "host";
+           dsep = "@";
+           break;
+       case DEFAULTS_USER:
+           atype = USERALIAS;
+           dname = "user";
+           dsep = ":";
+           break;
+       case DEFAULTS_RUNAS:
+           atype = RUNASALIAS;
+           dname = "runas";
+           dsep = ">";
+           break;
+       case DEFAULTS_CMND:
+           atype = CMNDALIAS;
+           dname = "cmnd";
+           dsep = "!";
+           break;
+       default:
+           return(-1);
     }
-    if (grp->gr_mem != NULL) {
-       for (cur = grp->gr_mem; *cur; cur++) {
-           if (strcmp(*cur, user) == 0)
-               return(TRUE);
-       }
+    /* printf("Per-%s Defaults entries:\n", dname); */
+    tq_foreach_fwd(&defaults, d) {
+       if (d->type != dtype)
+           continue;
+
+       nfound++;
+       if (binding != tq_first(&d->binding)) {
+           binding = tq_first(&d->binding);
+           lbuf_append(lbuf, "    Defaults", dsep, NULL);
+           for (m = binding; m != NULL; m = m->next) {
+               if (m != binding)
+                   lbuf_append(lbuf, ",", NULL);
+               print_member(lbuf, m->name, m->type, m->negated, atype);
+               lbuf_append(lbuf, " ", NULL);
+           }
+       } else
+           lbuf_append(lbuf, ", ", NULL);
+       if (d->val != NULL) {
+           lbuf_append(lbuf, d->var, d->op == '+' ? "+=" :
+               d->op == '-' ? "-=" : "=", d->val, NULL);
+       } else
+           lbuf_append(lbuf, d->op == FALSE ? "!" : "", d->var, NULL);
     }
 
-    return(FALSE);
+    return(nfound);
 }
 
-/*
- * Returns TRUE if "host" and "user" belong to the netgroup "netgr",
- * else return FALSE.  Either of "host", "shost" or "user" may be NULL
- * in which case that argument is not checked...
- */
 int
-netgr_matches(netgr, host, shost, user)
-    char *netgr;
-    char *host;
-    char *shost;
-    char *user;
+sudo_file_display_cmnd(nss, pw)
+    struct sudo_nss *nss;
+    struct passwd *pw;
 {
-    static char *domain;
-#ifdef HAVE_GETDOMAINNAME
-    static int initialized;
-#endif
-
-    /* make sure we have a valid netgroup, sudo style */
-    if (*netgr++ != '+')
-       return(FALSE);
-
-#ifdef HAVE_GETDOMAINNAME
-    /* get the domain name (if any) */
-    if (!initialized) {
-       domain = (char *) emalloc(MAXHOSTNAMELEN);
-       if (getdomainname(domain, MAXHOSTNAMELEN) == -1 || *domain == '\0') {
-           efree(domain);
-           domain = NULL;
+    struct cmndspec *cs;
+    struct member *match;
+    struct privilege *priv;
+    struct userspec *us;
+    int rval = 1;
+    int host_match, runas_match, cmnd_match;
+
+    if (nss->handle == NULL)
+       return(rval);
+
+    match = NULL;
+    tq_foreach_rev(&userspecs, us) {
+       if (userlist_matches(pw, &us->users) != ALLOW)
+           continue;
+
+       tq_foreach_rev(&us->privileges, priv) {
+           host_match = hostlist_matches(&priv->hostlist);
+           if (host_match != ALLOW)
+               continue;
+           tq_foreach_rev(&priv->cmndlist, cs) {
+               runas_match = runaslist_matches(&cs->runasuserlist,
+                   &cs->runasgrouplist);
+               if (runas_match == ALLOW) {
+                   cmnd_match = cmnd_matches(cs->cmnd);
+                   if (cmnd_match != UNSPEC) {
+                       match = host_match && runas_match ?
+                           cs->cmnd : NULL;
+                       goto matched;
+                   }
+               }
+           }
        }
-       initialized = 1;
     }
-#endif /* HAVE_GETDOMAINNAME */
-
-#ifdef HAVE_INNETGR
-    if (innetgr(netgr, host, user, domain))
-       return(TRUE);
-    else if (host != shost && innetgr(netgr, shost, user, domain))
-       return(TRUE);
-#endif /* HAVE_INNETGR */
-
-    return(FALSE);
+    matched:
+    if (match != NULL && !match->negated) {
+       printf("%s%s%s\n", safe_cmnd, user_args ? " " : "",
+           user_args ? user_args : "");
+       rval = 0;
+    }
+    return(rval);
 }
 
 /*
- * Returns TRUE if "s" has shell meta characters in it,
- * else returns FALSE.
+ * Print the contents of a struct member to stdout
  */
-static int
-has_meta(s)
-    char *s;
+static void
+_print_member(lbuf, name, type, negated, alias_type)
+    struct lbuf *lbuf;
+    char *name;
+    int type, negated, alias_type;
 {
-    char *t;
-    for (t = s; *t; t++) {
-       if (*t == '\\' || *t == '?' || *t == '*' || *t == '[' || *t == ']')
-           return(TRUE);
+    struct alias *a;
+    struct member *m;
+    struct sudo_command *c;
+
+    switch (type) {
+       case ALL:
+           lbuf_append(lbuf, negated ? "!ALL" : "ALL", NULL);
+           break;
+       case COMMAND:
+           c = (struct sudo_command *) name;
+           if (negated)
+               lbuf_append(lbuf, "!", NULL);
+           lbuf_append_quoted(lbuf, SUDOERS_QUOTED, c->cmnd, NULL);
+           if (c->args) {
+               lbuf_append(lbuf, " ", NULL);
+               lbuf_append_quoted(lbuf, SUDOERS_QUOTED, c->args, NULL);
+           }
+           break;
+       case ALIAS:
+           if ((a = find_alias(name, alias_type)) != NULL) {
+               tq_foreach_fwd(&a->members, m) {
+                   if (m != tq_first(&a->members))
+                       lbuf_append(lbuf, ", ", NULL);
+                   _print_member(lbuf, m->name, m->type,
+                       negated ? !m->negated : m->negated, alias_type);
+               }
+               break;
+           }
+           /* FALLTHROUGH */
+       default:
+           lbuf_append(lbuf, negated ? "!" : "", name, NULL);
+           break;
     }
-    return(FALSE);
+}
+
+static void
+print_member(lbuf, name, type, negated, alias_type)
+    struct lbuf *lbuf;
+    char *name;
+    int type, negated, alias_type;
+{
+    alias_seqno++;
+    _print_member(lbuf, name, type, negated, alias_type);
 }
diff --git a/parse.h b/parse.h
index a9bbc8e0e7a40910688cce66cab347b3cfebdf07..16388582565b946aa01669b83339d723ccee5e01 100644 (file)
--- a/parse.h
+++ b/parse.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 1998-2000, 2004, 2007
+ * Copyright (c) 1996, 1998-2000, 2004, 2007-2008
  *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $Sudo: parse.h,v 1.14.2.2 2008/02/09 14:44:48 millert Exp $
+ * $Sudo: parse.h,v 1.44 2008/11/09 14:13:12 millert Exp $
  */
 
 #ifndef _SUDO_PARSE_H
 #define _SUDO_PARSE_H
 
-/*
- * Data structure used in parsing sudoers;
- * top of stack values are the ones that
- * apply when parsing is done & can be
- * accessed by *_matches macros
- */
-#define STACKINCREMENT (32)
-struct matchstack {
-       int user;
-       int cmnd;
-       int host;
-       int runas;
-       int nopass;
-       int noexec;
-       int setenv;
-       char *role;
-       char *type;
-};
+#undef UNSPEC
+#define UNSPEC -1
+#undef DENY
+#define DENY    0
+#undef ALLOW
+#define ALLOW   1
+#undef IMPLIED
+#define IMPLIED         2
 
 /*
- * Data structure describing a command in the
- * sudoers file.
+ * A command with args. XXX - merge into struct member.
  */
 struct sudo_command {
     char *cmnd;
     char *args;
 };
 
+/*
+ * Tags associated with a command.
+ * Possible valus: TRUE, FALSE, UNSPEC.
+ */
+struct cmndtag {
+    __signed char nopasswd;
+    __signed char noexec;
+    __signed char setenv;
+    __signed char extra;
+};
+
 /*
  * SELinux-specific container struct.
  * Currently just contains a role and type.
@@ -57,67 +57,133 @@ struct selinux_info {
     char *type;
 };
 
-#define user_matches   (match[top-1].user)
-#define cmnd_matches   (match[top-1].cmnd)
-#define host_matches   (match[top-1].host)
-#define runas_matches  (match[top-1].runas)
-#define no_passwd      (match[top-1].nopass)
-#define no_execve      (match[top-1].noexec)
-#define setenv_ok      (match[top-1].setenv)
+/*
+ * The parses sudoers file is stored as a collection of linked lists,
+ * modelled after the yacc grammar.
+ *
+ * Other than the alias struct, which is stored in a red-black tree,
+ * the data structure used is basically a doubly-linked tail queue without
+ * a separate head struct--the first entry acts as the head where the prev
+ * pointer does double duty as the tail pointer.  This makes it possible
+ * to trivally append sub-lists.  In addition, the prev pointer is always
+ * valid (even if it points to itself).  Unlike a circle queue, the next
+ * pointer of the last entry is NULL and does not point back to the head.
+ *
+ * Note that each list struct must contain a "prev" and "next" pointer as
+ * the first two members of the struct (in that order).
+ */
+
+/*
+ * Tail queue list head structure.
+ */
+TQ_DECLARE(defaults)
+TQ_DECLARE(userspec)
+TQ_DECLARE(member)
+TQ_DECLARE(privilege)
+TQ_DECLARE(cmndspec)
 
 /*
- * Structure containing command matches if "sudo -l" is used.
+ * Structure describing a user specification and list thereof.
  */
-struct command_match {
-    char *runas;
-    size_t runas_len;
-    size_t runas_size;
-    char *cmnd;
-    size_t cmnd_len;
-    size_t cmnd_size;
-    char *role;
-    size_t role_len;
-    size_t role_size;
-    char *type;
-    size_t type_len;
-    size_t type_size;
-    int nopasswd;
-    int noexecve;
-    int setenv;
+struct userspec {
+    struct userspec *prev, *next;
+    struct member_list users;          /* list of users */
+    struct privilege_list privileges;  /* list of privileges */
 };
 
 /*
- * Structure describing an alias match in parser.
+ * Structure describing a privilege specification.
  */
-typedef struct {
-    int type;
-    char *name;
-    int val;
-} aliasinfo;
+struct privilege {
+    struct privilege *prev, *next;
+    struct member_list hostlist;       /* list of hosts */
+    struct cmndspec_list cmndlist;     /* list of Cmnd_Specs */
+};
 
 /*
- * Structure containing Cmnd_Alias's if "sudo -l" is used.
+ * Structure describing a linked list of Cmnd_Specs.
  */
-struct generic_alias {
-    int type;
-    char *alias;
-    char *entries;
-    size_t entries_size;
-    size_t entries_len;
+struct cmndspec {
+    struct cmndspec *prev, *next;
+    struct member_list runasuserlist;  /* list of runas users */
+    struct member_list runasgrouplist; /* list of runas groups */
+    struct member *cmnd;               /* command to allow/deny */
+    struct cmndtag tags;               /* tag specificaion */
+#ifdef HAVE_SELINUX
+    char *role, *type;                 /* SELinux role and type */
+#endif
 };
 
-/* The matching stack and number of entries on it. */
-extern struct matchstack *match;
-extern int top;
+/*
+ * Generic structure to hold users, hosts, commands.
+ */
+struct member {
+    struct member *prev, *next;
+    char *name;                                /* member name */
+    short type;                                /* type (see gram.h) */
+    short negated;                     /* negated via '!'? */
+};
+
+struct runascontainer {
+    struct member *runasusers;
+    struct member *runasgroups;
+};
+
+/*
+ * Generic structure to hold {User,Host,Runas,Cmnd}_Alias
+ * Aliases are stored in a red-black tree, sorted by name and type.
+ */
+struct alias {
+    char *name;                                /* alias name */
+    unsigned short type;               /* {USER,HOST,RUNAS,CMND}ALIAS */
+    unsigned short seqno;              /* sequence number */
+    struct member_list members;                /* list of alias members */
+};
+
+/*
+ * Structure describing a Defaults entry and a list thereof.
+ */
+struct defaults {
+    struct defaults *prev, *next;
+    char *var;                         /* variable name */
+    char *val;                         /* variable value */
+    struct member_list binding;                /* user/host/runas binding */
+    int type;                          /* DEFAULTS{,_USER,_RUNAS,_HOST} */
+    int op;                            /* TRUE, FALSE, '+', '-' */
+};
+
+/*
+ * Parsed sudoers info.
+ */
+extern struct userspec_list userspecs;
+extern struct defaults_list defaults;
+
+/*
+ * Alias sequence number to avoid loops.
+ */
+extern unsigned int alias_seqno;
 
 /*
  * Prototypes
  */
+char *alias_add                __P((char *, int, struct member *));
 int addr_matches       __P((char *));
+int alias_remove       __P((char *, int));
+int cmnd_matches       __P((struct member *));
+int cmndlist_matches   __P((struct member_list *));
 int command_matches    __P((char *, char *));
+int hostlist_matches   __P((struct member_list *));
 int hostname_matches   __P((char *, char *, char *));
 int netgr_matches      __P((char *, char *, char *, char *));
-int userpw_matches     __P((char *, char *, struct passwd *));
+int no_aliases         __P((void));
+int runaslist_matches  __P((struct member_list *, struct member_list *));
+int userlist_matches   __P((struct passwd *, struct member_list *));
 int usergr_matches     __P((char *, char *, struct passwd *));
+int userpw_matches     __P((char *, char *, struct passwd *));
+int group_matches      __P((char *, struct group *));
+struct alias *find_alias __P((char *, int));
+void alias_apply       __P((int (*)(void *, void *), void *));
+void init_aliases      __P((void));
+void init_parser       __P((char *, int));
 
 #endif /* _SUDO_PARSE_H */
diff --git a/parse.lex b/parse.lex
deleted file mode 100644 (file)
index 41eba10..0000000
--- a/parse.lex
+++ /dev/null
@@ -1,580 +0,0 @@
-%{
-/*
- * Copyright (c) 1996, 1998-2004, 2007
- *     Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- * 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.
- *
- * Sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F39502-99-1-0512.
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <stdio.h>
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif /* STDC_HEADERS */
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# ifdef HAVE_STRINGS_H
-#  include <strings.h>
-# endif
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
-# include <malloc.h>
-#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
-#include <ctype.h>
-#include "sudo.h"
-#include "parse.h"
-#include <sudo.tab.h>
-
-#ifndef lint
-__unused static const char rcsid[] = "$Sudo: parse.lex,v 1.132.2.10 2008/06/26 11:53:50 millert Exp $";
-#endif /* lint */
-
-#undef yywrap          /* guard against a yywrap macro */
-
-extern YYSTYPE yylval;
-extern int clearaliases;
-int sudolineno = 1;
-static int sawspace = 0;
-static int arg_len = 0;
-static int arg_size = 0;
-
-static int ipv6_valid          __P((const char *s));
-static void _fill              __P((char *, int, int));
-static void append             __P((char *, int));
-static void fill_cmnd          __P((char *, int));
-static void fill_args          __P((char *, int, int));
-extern void reset_aliases      __P((void));
-extern void yyerror            __P((char *));
-
-#define fill(a, b)             _fill(a, b, 0)
-
-/* realloc() to size + COMMANDARGINC to make room for command args */
-#define COMMANDARGINC  64
-
-#ifdef TRACELEXER
-#define LEXTRACE(msg)  fputs(msg, stderr)
-#else
-#define LEXTRACE(msg)
-#endif
-%}
-
-HEX16                  [0-9A-Fa-f]{1,4}
-OCTET                  (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5])
-IPV4ADDR               {OCTET}(\.{OCTET}){3}
-IPV6ADDR               ({HEX16}?:){2,7}{HEX16}?|({HEX16}?:){2,6}:{IPV4ADDR}
-
-HOSTNAME               [[:alnum:]_-]+
-WORD                   ([^#>@!=:,\(\) \t\n\\]|\\[^\n])+
-ENVAR                  ([^#!=, \t\n\\\"]|\\[^\n])([^#=, \t\n\\]|\\[^\n])*
-DEFVAR                 [a-z_]+
-
-/* XXX - convert GOTRUNAS to exclusive state (GOTDEFS cannot be) */
-%s     GOTRUNAS
-%s     GOTDEFS
-%x     GOTCMND
-%x     STARTDEFS
-%x     INDEFS
-%x     INSTR
-
-%%
-<GOTDEFS>[[:blank:]]+  BEGIN STARTDEFS;
-
-<STARTDEFS>{DEFVAR}    {
-                           BEGIN INDEFS;
-                           LEXTRACE("DEFVAR ");
-                           fill(yytext, yyleng);
-                           return(DEFVAR);
-                       }
-
-<INDEFS>{
-    ,                  {
-                           BEGIN STARTDEFS;
-                           LEXTRACE(", ");
-                           return(',');
-                       }                       /* return ',' */
-
-    =                  {
-                           LEXTRACE("= ");
-                           return('=');
-                       }                       /* return '=' */
-
-    \+=                        {
-                           LEXTRACE("+= ");
-                           return('+');
-                       }                       /* return '+' */
-
-    -=                 {
-                           LEXTRACE("-= ");
-                           return('-');
-                       }                       /* return '-' */
-
-    \"                 {
-                           LEXTRACE("BEGINSTR ");
-                           yylval.string = NULL;
-                           BEGIN INSTR;
-                       }
-
-    {ENVAR}            {
-                           LEXTRACE("WORD(2) ");
-                           fill(yytext, yyleng);
-                           return(WORD);
-                       }
-}
-
-<INSTR>{
-    \\[[:blank:]]*\n[[:blank:]]*       {
-                           /* Line continuation char followed by newline. */
-                           ++sudolineno;
-                           LEXTRACE("\n");
-                       }
-
-    \"                 {
-                           LEXTRACE("ENDSTR ");
-                           BEGIN INDEFS;
-                           return(WORD);
-                       }
-
-    \\                 {
-                           LEXTRACE("BACKSLASH ");
-                           append(yytext, yyleng);
-                       }
-
-    ([^\"\n\\]|\\\")+  {
-                           LEXTRACE("STRBODY ");
-                           append(yytext, yyleng);
-                       }
-}
-
-<GOTCMND>{
-    \\[\*\?\[\]\!]     {
-                           /* quoted fnmatch glob char, pass verbatim */
-                           LEXTRACE("QUOTEDCHAR ");
-                           fill_args(yytext, 2, sawspace);
-                           sawspace = FALSE;
-                       }
-
-    \\[:\\,= \t#]      {
-                           /* quoted sudoers special char, strip backslash */
-                           LEXTRACE("QUOTEDCHAR ");
-                           fill_args(yytext + 1, 1, sawspace);
-                           sawspace = FALSE;
-                       }
-
-    [#:\,=\n]          {
-                           BEGIN INITIAL;
-                           unput(*yytext);
-                           return(COMMAND);
-                       }                       /* end of command line args */
-
-    [^\\:, \t\n]+      {
-                           LEXTRACE("ARG ");
-                           fill_args(yytext, yyleng, sawspace);
-                           sawspace = FALSE;
-                       }                       /* a command line arg */
-}
-
-<INITIAL>^Defaults[:@>]? {
-                           BEGIN GOTDEFS;
-                           switch (yytext[8]) {
-                               case ':':
-                                   LEXTRACE("DEFAULTS_USER ");
-                                   return(DEFAULTS_USER);
-                               case '>':
-                                   LEXTRACE("DEFAULTS_RUNAS ");
-                                   return(DEFAULTS_RUNAS);
-                               case '@':
-                                   LEXTRACE("DEFAULTS_HOST ");
-                                   return(DEFAULTS_HOST);
-                               default:
-                                   LEXTRACE("DEFAULTS ");
-                                   return(DEFAULTS);
-                           }
-                       }
-
-<INITIAL>^(Host|Cmnd|User|Runas)_Alias {
-                           fill(yytext, yyleng);
-                           switch (*yytext) {
-                               case 'H':
-                                   LEXTRACE("HOSTALIAS ");
-                                   return(HOSTALIAS);
-                               case 'C':
-                                   LEXTRACE("CMNDALIAS ");
-                                   return(CMNDALIAS);
-                               case 'U':
-                                   LEXTRACE("USERALIAS ");
-                                   return(USERALIAS);
-                               case 'R':
-                                   LEXTRACE("RUNASALIAS ");
-                                   BEGIN GOTRUNAS;
-                                   return(RUNASALIAS);
-                           }
-                       }
-
-NOPASSWD[[:blank:]]*:  {
-                               /* cmnd does not require passwd for this user */
-                               LEXTRACE("NOPASSWD ");
-                               return(NOPASSWD);
-                       }
-
-PASSWD[[:blank:]]*:    {
-                               /* cmnd requires passwd for this user */
-                               LEXTRACE("PASSWD ");
-                               return(PASSWD);
-                       }
-
-NOEXEC[[:blank:]]*:    {
-                               LEXTRACE("NOEXEC ");
-                               return(NOEXEC);
-                       }
-
-EXEC[[:blank:]]*:      {
-                               LEXTRACE("EXEC ");
-                               return(EXEC);
-                       }
-
-SETENV[[:blank:]]*:    {
-                               LEXTRACE("SETENV ");
-                               return(SETENV);
-                       }
-
-NOSETENV[[:blank:]]*:  {
-                               LEXTRACE("NOSETENV ");
-                               return(NOSETENV);
-                       }
-
-\+{WORD}               {
-                           /* netgroup */
-                           fill(yytext, yyleng);
-                           LEXTRACE("NETGROUP ");
-                           return(NETGROUP);
-                       }
-
-\%{WORD}               {
-                           /* UN*X group */
-                           fill(yytext, yyleng);
-                           LEXTRACE("GROUP ");
-                           return(USERGROUP);
-                       }
-
-{IPV4ADDR}(\/{IPV4ADDR})? {
-                           fill(yytext, yyleng);
-                           LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
-                       }
-
-{IPV4ADDR}\/([12][0-9]*|3[0-2]*) {
-                           fill(yytext, yyleng);
-                           LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
-                       }
-
-{IPV6ADDR}(\/{IPV6ADDR})? {
-                           if (!ipv6_valid(yytext)) {
-                               LEXTRACE("ERROR ");
-                               return(ERROR);
-                           }
-                           fill(yytext, yyleng);
-                           LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
-                       }
-
-{IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) {
-                           if (!ipv6_valid(yytext)) {
-                               LEXTRACE("ERROR ");
-                               return(ERROR);
-                           }
-                           fill(yytext, yyleng);
-                           LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
-                       }
-
-<INITIAL>\(            {
-                               BEGIN GOTRUNAS;
-                               LEXTRACE("RUNAS ");
-                               return (RUNAS);
-                       }
-
-[[:upper:]][[:upper:][:digit:]_]* {
-                           if (strcmp(yytext, "ALL") == 0) {
-                               LEXTRACE("ALL ");
-                               return(ALL);
-                           }
-#ifdef HAVE_SELINUX
-                           /* XXX - restrict type/role to initial state */
-                           if (strcmp(yytext, "TYPE") == 0) {
-                               LEXTRACE("TYPE ");
-                               return(TYPE);
-                           }
-                           if (strcmp(yytext, "ROLE") == 0) {
-                               LEXTRACE("ROLE ");
-                               return(ROLE);
-                           }
-#endif /* HAVE_SELINUX */
-                           fill(yytext, yyleng);
-                           LEXTRACE("ALIAS ");
-                           return(ALIAS);
-                       }
-
-<GOTRUNAS>(#[0-9-]+|{WORD}) {
-                           /* username/uid that user can run command as */
-                           fill(yytext, yyleng);
-                           LEXTRACE("WORD(3) ");
-                           return(WORD);
-                       }
-
-<GOTRUNAS>#[^0-9-].*\n {
-                           BEGIN INITIAL;
-                           ++sudolineno;
-                           LEXTRACE("\n");
-                           return(COMMENT);
-                       }
-
-<GOTRUNAS>\)           {
-                           BEGIN INITIAL;
-                       }
-
-sudoedit               {
-                           BEGIN GOTCMND;
-                           LEXTRACE("COMMAND ");
-                           fill_cmnd(yytext, yyleng);
-                       }                       /* sudo -e */
-
-\/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+      {
-                           /* directories can't have args... */
-                           if (yytext[yyleng - 1] == '/') {
-                               LEXTRACE("COMMAND ");
-                               fill_cmnd(yytext, yyleng);
-                               return(COMMAND);
-                           } else {
-                               BEGIN GOTCMND;
-                               LEXTRACE("COMMAND ");
-                               fill_cmnd(yytext, yyleng);
-                           }
-                       }                       /* a pathname */
-
-<INITIAL,GOTDEFS>{WORD} {
-                           /* a word */
-                           fill(yytext, yyleng);
-                           LEXTRACE("WORD(4) ");
-                           return(WORD);
-                       }
-
-,                      {
-                           LEXTRACE(", ");
-                           return(',');
-                       }                       /* return ',' */
-
-=                      {
-                           LEXTRACE("= ");
-                           return('=');
-                       }                       /* return '=' */
-
-:                      {
-                           LEXTRACE(": ");
-                           return(':');
-                       }                       /* return ':' */
-
-<*>!+                  {
-                           if (yyleng % 2 == 1)
-                               return('!');    /* return '!' */
-                       }
-
-<*>\n                  {
-                           BEGIN INITIAL;
-                           ++sudolineno;
-                           LEXTRACE("\n");
-                           return(COMMENT);
-                       }                       /* return newline */
-
-<*>[[:blank:]]+                {                       /* throw away space/tabs */
-                           sawspace = TRUE;    /* but remember for fill_args */
-                       }
-
-<*>\\[[:blank:]]*\n    {
-                           sawspace = TRUE;    /* remember for fill_args */
-                           ++sudolineno;
-                           LEXTRACE("\n\t");
-                       }                       /* throw away EOL after \ */
-
-<INITIAL,STARTDEFS,INDEFS>#.*\n        {
-                           BEGIN INITIAL;
-                           ++sudolineno;
-                           LEXTRACE("\n");
-                           return(COMMENT);
-                       }                       /* return comments */
-
-<*>.                   {
-                           LEXTRACE("ERROR ");
-                           return(ERROR);
-                       }       /* parse error */
-
-<*><<EOF>>             {
-                           if (YY_START != INITIAL) {
-                               BEGIN INITIAL;
-                               LEXTRACE("ERROR ");
-                               return(ERROR);
-                           }
-                           yyterminate();
-                       }
-
-%%
-static void
-_fill(src, len, olen)
-    char *src;
-    int len, olen;
-{
-    int i, j;
-    char *dst;
-
-    dst = olen ? realloc(yylval.string, olen + len + 1) : malloc(len + 1);
-    if (dst == NULL) {
-       yyerror("unable to allocate memory");
-       return;
-    }
-    yylval.string = dst;
-
-    /* Copy the string and collapse any escaped characters. */
-    dst += olen;
-    for (i = 0, j = 0; i < len; i++, j++) {
-       if (src[i] == '\\' && i != len - 1)
-           dst[j] = src[++i];
-       else
-           dst[j] = src[i];
-    }
-    dst[j] = '\0';
-}
-
-static void
-append(src, len)
-    char *src;
-    int len;
-{
-    int olen = 0;
-
-    if (yylval.string != NULL)
-       olen = strlen(yylval.string);
-
-    _fill(src, len, olen);
-}
-
-static void
-fill_cmnd(s, len)
-    char *s;
-    int len;
-{
-    arg_len = arg_size = 0;
-
-    yylval.command.cmnd = (char *) malloc(++len);
-    if (yylval.command.cmnd == NULL) {
-       yyerror("unable to allocate memory");
-       return;
-    }
-
-    /* copy the string and NULL-terminate it (escapes handled by fnmatch) */
-    (void) strlcpy(yylval.command.cmnd, s, len);
-
-    yylval.command.args = NULL;
-}
-
-static void
-fill_args(s, len, addspace)
-    char *s;
-    int len;
-    int addspace;
-{
-    int new_len;
-    char *p;
-
-    if (yylval.command.args == NULL) {
-       addspace = 0;
-       new_len = len;
-    } else
-       new_len = arg_len + len + addspace;
-
-    if (new_len >= arg_size) {
-       /* Allocate more space than we need for subsequent args */
-       while (new_len >= (arg_size += COMMANDARGINC))
-           ;
-
-       p = yylval.command.args ?
-           (char *) realloc(yylval.command.args, arg_size) :
-           (char *) malloc(arg_size);
-       if (p == NULL) {
-           efree(yylval.command.args);
-           yyerror("unable to allocate memory");
-           return;
-       } else
-           yylval.command.args = p;
-    }
-
-    /* Efficiently append the arg (with a leading space if needed). */
-    p = yylval.command.args + arg_len;
-    if (addspace)
-       *p++ = ' ';
-    if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len)
-       yyerror("fill_args: buffer overflow");  /* paranoia */
-    arg_len = new_len;
-}
-
-/*
- * Check to make sure an IPv6 address does not contain multiple instances
- * of the string "::".  Assumes strlen(s) >= 1.
- * Returns TRUE if address is valid else FALSE.
- */
-static int
-ipv6_valid(s)
-    const char *s;
-{
-    int nmatch = 0;
-
-    for (; *s != '\0'; s++) {
-       if (s[0] == ':' && s[1] == ':') {
-           if (++nmatch > 1)
-               break;
-       }
-       if (s[0] == '/')
-           nmatch = 0;                 /* reset if we hit netmask */
-    }
-
-    return (nmatch <= 1);
-}
-
-int
-yywrap()
-{
-
-    /* Free space used by the aliases unless called by testsudoers. */
-    if (clearaliases)
-       reset_aliases();
-
-    return(TRUE);
-}
diff --git a/parse.yacc b/parse.yacc
deleted file mode 100644 (file)
index 93871b2..0000000
+++ /dev/null
@@ -1,1418 +0,0 @@
-%{
-/*
- * Copyright (c) 1996, 1998-2004, 2007
- *     Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F39502-99-1-0512.
- */
-
-/*
- * XXX - the whole opFOO naming thing is somewhat bogus.
- *
- * XXX - the way things are stored for printmatches is stupid,
- *       they should be stored as elements in an array and then
- *       list_matches() can format things the way it wants.
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <stdio.h>
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif /* STDC_HEADERS */
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# ifdef HAVE_STRINGS_H
-#  include <strings.h>
-# endif
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
-# include <alloca.h>
-#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
-#ifdef HAVE_LSEARCH
-# include <search.h>
-#endif /* HAVE_LSEARCH */
-#include <limits.h>
-
-#include "sudo.h"
-#include "parse.h"
-
-#ifndef HAVE_LSEARCH
-#include "emul/search.h"
-#endif /* HAVE_LSEARCH */
-
-#ifndef lint
-__unused static const char rcsid[] = "$Sudo: parse.yacc,v 1.204.2.13 2008/02/27 20:34:42 millert Exp $";
-#endif /* lint */
-
-/*
- * We must define SIZE_MAX for yacc's skeleton.c.
- * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
- * could be signed (as it is on SunOS 4.x).
- */
-#ifndef SIZE_MAX
-# ifdef SIZE_T_MAX
-#  define SIZE_MAX     SIZE_T_MAX
-# else
-#  define SIZE_MAX     INT_MAX
-# endif /* SIZE_T_MAX */
-#endif /* SIZE_MAX */
-
-/*
- * Globals
- */
-extern int sudolineno, parse_error;
-int errorlineno = -1;
-int clearaliases = TRUE;
-int printmatches = FALSE;
-int pedantic = FALSE;
-int keepall = FALSE;
-int quiet = FALSE;
-int used_runas = FALSE;
-
-/*
- * Alias types
- */
-#define HOST_ALIAS              1
-#define CMND_ALIAS              2
-#define USER_ALIAS              3
-#define RUNAS_ALIAS             4
-
-#define SETMATCH(_var, _val)   do { \
-       if ((_var) == UNSPEC || (_val) != NOMATCH) \
-           (_var) = (_val); \
-} while (0)
-
-#define SETNMATCH(_var, _val)  do { \
-       if ((_val) != NOMATCH) \
-           (_var) = ! (_val); \
-       else if ((_var) == UNSPEC) \
-           (_var) = NOMATCH; \
-} while (0)
-
-#define        SETENV_RESET \
-       if (setenv_ok == IMPLIED) setenv_ok = def_setenv ? TRUE : UNSPEC
-
-/*
- * The matching stack, initial space allocated in init_parser().
- */
-struct matchstack *match;
-int top = 0, stacksize = 0;
-
-#define push \
-    do { \
-       if (top >= stacksize) { \
-           while ((stacksize += STACKINCREMENT) < top); \
-           match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
-       } \
-       match[top].user   = UNSPEC; \
-       match[top].cmnd   = UNSPEC; \
-       match[top].host   = UNSPEC; \
-       match[top].runas  = UNSPEC; \
-       match[top].nopass = def_authenticate ? UNSPEC : TRUE; \
-       match[top].noexec = def_noexec ? TRUE : UNSPEC; \
-       match[top].setenv = def_setenv ? TRUE : UNSPEC; \
-       match[top].role = NULL; \
-       match[top].type = NULL; \
-       top++; \
-    } while (0)
-
-#define pushcp \
-    do { \
-       if (top >= stacksize) { \
-           while ((stacksize += STACKINCREMENT) < top); \
-           match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
-       } \
-       match[top].user   = match[top-1].user; \
-       match[top].cmnd   = match[top-1].cmnd; \
-       match[top].host   = match[top-1].host; \
-       match[top].runas  = match[top-1].runas; \
-       match[top].nopass = match[top-1].nopass; \
-       match[top].noexec = match[top-1].noexec; \
-       match[top].setenv = match[top-1].setenv; \
-       match[top].role   = estrdup(match[top-1].role); \
-       match[top].type   = estrdup(match[top-1].type); \
-       top++; \
-    } while (0)
-
-#define pop \
-    do { \
-       if (top == 0) \
-           yyerror("matching stack underflow"); \
-       else { \
-           efree(match[top-1].role); \
-           efree(match[top-1].type); \
-           top--; \
-       } \
-    } while (0)
-
-
-/*
- * For testing if foo_matches variable was set to TRUE or FALSE
- */
-#define        MATCHED(_v)     ((_v) >= 0)
-
-/*
- * Shortcuts for append()
- */
-#define append_cmnd(s, p) append(s, &cm_list[cm_list_len].cmnd, \
-       &cm_list[cm_list_len].cmnd_len, &cm_list[cm_list_len].cmnd_size, p)
-
-#define append_runas(s, p) append(s, &cm_list[cm_list_len].runas, \
-       &cm_list[cm_list_len].runas_len, &cm_list[cm_list_len].runas_size, p)
-
-#define append_role(s, p) append(s, &cm_list[cm_list_len].role, \
-       &cm_list[cm_list_len].role_len, &cm_list[cm_list_len].role_size, p)
-
-#define append_type(s, p) append(s, &cm_list[cm_list_len].type, \
-       &cm_list[cm_list_len].type_len, &cm_list[cm_list_len].type_size, p)
-
-#define append_entries(s, p) append(s, &ga_list[ga_list_len-1].entries, \
-       &ga_list[ga_list_len-1].entries_len, \
-       &ga_list[ga_list_len-1].entries_size, p)
-
-/*
- * The stack for printmatches.  A list of allowed commands for the user.
- */
-static struct command_match *cm_list = NULL;
-static size_t cm_list_len = 0, cm_list_size = 0;
-
-/*
- * List of Cmnd_Aliases and expansions for `sudo -l'
- */
-static int in_alias = FALSE;
-static size_t ga_list_len = 0, ga_list_size = 0;
-static struct generic_alias *ga_list = NULL;
-
-/*
- * Does this Defaults list pertain to this user?
- */
-static int defaults_matches = FALSE;
-
-/*
- * Local protoypes
- */
-static int  add_alias          __P((char *, int, int));
-static void append             __P((char *, char **, size_t *, size_t *, char *));
-static void expand_ga_list     __P((void));
-static void expand_match_list  __P((void));
-static aliasinfo *find_alias   __P((char *, int));
-static void more_aliases       __P((void));
-       void init_parser                __P((void));
-       void yyerror            __P((char *));
-
-void
-yyerror(s)
-    char *s;
-{
-    /* Save the line the first error occurred on. */
-    if (errorlineno == -1)
-       errorlineno = sudolineno ? sudolineno - 1 : 0;
-    if (s && !quiet) {
-#ifndef TRACELEXER
-       (void) fprintf(stderr, ">>> sudoers file: %s, line %d <<<\n", s,
-           sudolineno ? sudolineno - 1 : 0);
-#else
-       (void) fprintf(stderr, "<*> ");
-#endif
-    }
-    parse_error = TRUE;
-}
-%}
-
-%union {
-    char *string;
-    int BOOLEAN;
-    struct sudo_command command;
-    int tok;
-    struct selinux_info seinfo;
-}
-
-%start file                            /* special start symbol */
-%token <command> COMMAND               /* absolute pathname w/ optional args */
-%token <string>  ALIAS                 /* an UPPERCASE alias name */
-%token <string>         DEFVAR                 /* a Defaults variable name */
-%token <string>  NTWKADDR              /* w.x.y.z or ipv6 address */
-%token <string>  NETGROUP              /* a netgroup (+NAME) */
-%token <string>  USERGROUP             /* a usergroup (%NAME) */
-%token <string>  WORD                  /* a word */
-%token <tok>    DEFAULTS               /* Defaults entry */
-%token <tok>    DEFAULTS_HOST          /* Host-specific defaults entry */
-%token <tok>    DEFAULTS_USER          /* User-specific defaults entry */
-%token <tok>    DEFAULTS_RUNAS         /* Runas-specific defaults entry */
-%token <tok>    RUNAS                  /* ( runas_list ) */
-%token <tok>    NOPASSWD               /* no passwd req for command */
-%token <tok>    PASSWD                 /* passwd req for command (default) */
-%token <tok>    NOEXEC                 /* preload dummy execve() for cmnd */
-%token <tok>    EXEC                   /* don't preload dummy execve() */
-%token <tok>    SETENV                 /* user may set environment for cmnd */
-%token <tok>    NOSETENV               /* user may not set environment */
-%token <tok>    ALL                    /* ALL keyword */
-%token <tok>    COMMENT                /* comment and/or carriage return */
-%token <tok>    HOSTALIAS              /* Host_Alias keyword */
-%token <tok>    CMNDALIAS              /* Cmnd_Alias keyword */
-%token <tok>    USERALIAS              /* User_Alias keyword */
-%token <tok>    RUNASALIAS             /* Runas_Alias keyword */
-%token <tok>    ':' '=' ',' '!' '+' '-' /* union member tokens */
-%token <tok>    ERROR
-%token <tok>    TYPE                   /* SELinux type */
-%token <tok>    ROLE                   /* SELinux role */
-
-/*
- * NOTE: these are not true booleans as there are actually 4 possible values:
- *        1) TRUE (positive match)
- *        0) FALSE (negative match due to a '!' somewhere)
- *       -1) NOMATCH (don't change the value of *_matches)
- *       -2) UNSPEC (uninitialized value)
- */
-%type <BOOLEAN>         cmnd
-%type <BOOLEAN>         host
-%type <BOOLEAN>         runasuser
-%type <BOOLEAN>         oprunasuser
-%type <BOOLEAN>         runaslist
-%type <BOOLEAN>         user
-%type <seinfo>  selinux
-%type <string>  rolespec
-%type <string>  typespec
-
-%%
-
-file           :       entry
-               |       file entry
-               ;
-
-entry          :       COMMENT
-                           { ; }
-                |       error COMMENT
-                           { yyerrok; }
-               |       { push; } userlist privileges {
-                           while (top && user_matches != TRUE)
-                               pop;
-                       }
-               |       USERALIAS useraliases
-                           { ; }
-               |       HOSTALIAS hostaliases
-                           { ; }
-               |       CMNDALIAS cmndaliases
-                           { ; }
-               |       RUNASALIAS runasaliases
-                           { ; }
-               |       defaults_line
-                           { ; }
-               ;
-
-defaults_line  :       defaults_type defaults_list
-               ;
-
-defaults_type  :       DEFAULTS {
-                           defaults_matches = TRUE;
-                       }
-               |       DEFAULTS_USER { push; } userlist {
-                           defaults_matches = user_matches;
-                           pop;
-                       }
-               |       DEFAULTS_RUNAS { push; } runaslist {
-                           defaults_matches = $3 == TRUE;
-                           pop;
-                       }
-               |       DEFAULTS_HOST { push; } hostlist {
-                           defaults_matches = host_matches;
-                           pop;
-                       }
-               ;
-
-defaults_list  :       defaults_entry
-               |       defaults_entry ',' defaults_list
-               ;
-
-defaults_entry :       DEFVAR {
-                           if (defaults_matches == TRUE &&
-                               !set_default($1, NULL, TRUE)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           efree($1);
-                       }
-               |       '!' DEFVAR {
-                           if (defaults_matches == TRUE &&
-                               !set_default($2, NULL, FALSE)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           efree($2);
-                       }
-               |       DEFVAR '=' WORD {
-                           if (defaults_matches == TRUE &&
-                               !set_default($1, $3, TRUE)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           efree($1);
-                           efree($3);
-                       }
-               |       DEFVAR '+' WORD {
-                           if (defaults_matches == TRUE &&
-                               !set_default($1, $3, '+')) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           efree($1);
-                           efree($3);
-                       }
-               |       DEFVAR '-' WORD {
-                           if (defaults_matches == TRUE &&
-                               !set_default($1, $3, '-')) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           efree($1);
-                           efree($3);
-                       }
-               ;
-
-privileges     :       privilege
-               |       privileges ':' privilege
-               ;
-
-privilege      :       hostlist '=' cmndspeclist {
-                           /*
-                            * We already did a push if necessary in
-                            * cmndspec so just reset some values so
-                            * the next 'privilege' gets a clean slate.
-                            */
-                           host_matches = UNSPEC;
-                           runas_matches = UNSPEC;
-                           no_passwd = def_authenticate ? UNSPEC : TRUE;
-                           no_execve = def_noexec ? TRUE : UNSPEC;
-                           setenv_ok = def_setenv ? TRUE : UNSPEC;
-#ifdef HAVE_SELINUX
-                           efree(match[top-1].role);
-                           match[top-1].role = NULL;
-                           efree(match[top-1].type);
-                           match[top-1].type = NULL;
-#endif
-                       }
-               ;
-
-ophost         :       host {
-                           SETMATCH(host_matches, $1);
-                       }
-               |       '!' host {
-                           SETNMATCH(host_matches, $2);
-                       }
-               ;
-
-host           :       ALL {
-                           $$ = TRUE;
-                       }
-               |       NTWKADDR {
-                           if (addr_matches($1))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           efree($1);
-                       }
-               |       NETGROUP {
-                           if (netgr_matches($1, user_host, user_shost, NULL))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           efree($1);
-                       }
-               |       WORD {
-                           if (hostname_matches(user_shost, user_host, $1) == 0)
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           efree($1);
-                       }
-               |       ALIAS {
-                           aliasinfo *aip = find_alias($1, HOST_ALIAS);
-
-                           /* could be an all-caps hostname */
-                           if (aip)
-                               $$ = aip->val;
-                           else if (strcasecmp(user_shost, $1) == 0)
-                               $$ = TRUE;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared Host_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               $$ = NOMATCH;
-                           }
-                           efree($1);
-                       }
-               ;
-
-cmndspeclist   :       cmndspec
-               |       cmndspeclist ',' cmndspec
-               ;
-
-cmndspec       :       { SETENV_RESET; } runasspec selinux cmndtag opcmnd {
-#ifdef HAVE_SELINUX
-                           /* Replace inherited role/type as needed. */
-                           if ($3.role != NULL) {
-                               efree(match[top-1].role);
-                               match[top-1].role = $3.role;
-                           }
-                           if ($3.type != NULL) {
-                               efree(match[top-1].type);
-                               match[top-1].type = $3.type;
-                           }
-#endif
-                           /*
-                            * Push the entry onto the stack if it is worth
-                            * saving and reset cmnd_matches for next cmnd.
-                            *
-                            * We need to save at least one entry on
-                            * the stack so sudoers_lookup() can tell that
-                            * the user was listed in sudoers.  Also, we
-                            * need to be able to tell whether or not a
-                            * user was listed for this specific host.
-                            *
-                            * If keepall is set and the user matches then
-                            * we need to keep entries around too...
-                            */
-                           if (MATCHED(user_matches) &&
-                               MATCHED(host_matches) &&
-                               MATCHED(cmnd_matches) &&
-                               MATCHED(runas_matches))
-                               pushcp;
-                           else if (MATCHED(user_matches) && (top == 1 ||
-                               (top == 2 && MATCHED(host_matches) &&
-                               !MATCHED(match[0].host))))
-                               pushcp;
-                           else if (user_matches == TRUE && keepall)
-                               pushcp;
-
-                           cmnd_matches = UNSPEC;
-                       }
-               ;
-
-opcmnd         :       cmnd {
-                           SETMATCH(cmnd_matches, $1);
-                       }
-               |       '!' {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("!", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_cmnd("!", NULL);
-                           }
-                       } cmnd {
-                           SETNMATCH(cmnd_matches, $3);
-                       }
-               ;
-
-rolespec       :       ROLE '=' WORD {
-#ifdef HAVE_SELINUX
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE && runas_matches == TRUE)
-                               append_role($3, NULL);
-                           $$ = $3;
-#else
-                           free($3);
-                           $$ = NULL;
-#endif /* HAVE_SELINUX */
-                       }
-               ;
-
-typespec       :       TYPE '=' WORD {
-#ifdef HAVE_SELINUX
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE && runas_matches == TRUE)
-                               append_type($3, NULL);
-                           $$ = $3;
-#else
-                           free($3);
-                           $$ = NULL;
-#endif /* HAVE_SELINUX */
-                       }
-               ;
-
-selinux                :       /* empty */ {
-#ifdef HAVE_SELINUX
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE && runas_matches == TRUE) {
-                               /* Inherit role. */
-                               cm_list[cm_list_len].role =
-                                   estrdup(cm_list[cm_list_len-1].role);
-                               cm_list[cm_list_len].role_len =
-                                   cm_list[cm_list_len-1].role_len;
-                               cm_list[cm_list_len].role_size =
-                                   cm_list[cm_list_len-1].role_len + 1;
-                               /* Inherit type. */
-                               cm_list[cm_list_len].type =
-                                   estrdup(cm_list[cm_list_len-1].type);
-                               cm_list[cm_list_len].type_len =
-                                   cm_list[cm_list_len-1].type_len;
-                               cm_list[cm_list_len].type_size =
-                                   cm_list[cm_list_len-1].type_len + 1;
-                           }
-#endif /* HAVE_SELINUX */
-                           $$.role = NULL;
-                           $$.type = NULL;
-                       }
-               |       rolespec {
-#ifdef HAVE_SELINUX
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE && runas_matches == TRUE) {
-                               /* Inherit type. */
-                               cm_list[cm_list_len].type =
-                                   estrdup(cm_list[cm_list_len-1].type);
-                               cm_list[cm_list_len].type_len =
-                                   cm_list[cm_list_len-1].type_len;
-                               cm_list[cm_list_len].type_size =
-                                   cm_list[cm_list_len-1].type_len + 1;
-                           }
-#endif /* HAVE_SELINUX */
-                           $$.role = $1;
-                           $$.type = NULL;
-                       }
-               |       typespec {
-#ifdef HAVE_SELINUX
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE && runas_matches == TRUE) {
-                               /* Inherit role. */
-                               cm_list[cm_list_len].role =
-                                   estrdup(cm_list[cm_list_len-1].role);
-                               cm_list[cm_list_len].role_len =
-                                   cm_list[cm_list_len-1].role_len;
-                               cm_list[cm_list_len].role_size =
-                                   cm_list[cm_list_len-1].role_len + 1;
-                           }
-#endif /* HAVE_SELINUX */
-                           $$.type = $1;
-                           $$.role = NULL;
-                       }
-               |       rolespec typespec {
-                           $$.role = $1;
-                           $$.type = $2;
-                       }
-               |       typespec rolespec {
-                           $$.type = $1;
-                           $$.role = $2;
-                       }
-               ;
-
-runasspec      :       /* empty */ {
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE) {
-                               if (runas_matches == UNSPEC) {
-                                   cm_list[cm_list_len].runas_len = 0;
-                               } else {
-                                   /* Inherit runas data. */
-                                   cm_list[cm_list_len].runas =
-                                       estrdup(cm_list[cm_list_len-1].runas);
-                                   cm_list[cm_list_len].runas_len =
-                                       cm_list[cm_list_len-1].runas_len;
-                                   cm_list[cm_list_len].runas_size =
-                                       cm_list[cm_list_len-1].runas_len + 1;
-                               }
-                           }
-                           /*
-                            * If this is the first entry in a command list
-                            * then check against default runas user.
-                            */
-                           if (runas_matches == UNSPEC) {
-                               runas_matches = userpw_matches(def_runas_default,
-                                   *user_runas, runas_pw) ? TRUE : NOMATCH;
-                           }
-                       }
-               |       RUNAS runaslist {
-                           runas_matches = $2;
-                       }
-               ;
-
-runaslist      :       oprunasuser { ; }
-               |       runaslist ',' oprunasuser {
-                           /* Later entries override earlier ones. */
-                           if ($3 != NOMATCH)
-                               $$ = $3;
-                           else
-                               $$ = $1;
-                       }
-               ;
-
-oprunasuser    :       runasuser { ; }
-               |       '!' {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("!", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas("!", ", ");
-                           }
-                       } runasuser {
-                           /* Set $$ to the negation of runasuser */
-                           $$ = ($3 == NOMATCH ? NOMATCH : ! $3);
-                       }
-               ;
-
-runasuser      :       WORD {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries($1, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas($1, ", ");
-                           }
-                           if (userpw_matches($1, *user_runas, runas_pw))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           efree($1);
-                           used_runas = TRUE;
-                       }
-               |       USERGROUP {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries($1, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas($1, ", ");
-                           }
-                           if (usergr_matches($1, *user_runas, runas_pw))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           efree($1);
-                           used_runas = TRUE;
-                       }
-               |       NETGROUP {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries($1, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas($1, ", ");
-                           }
-                           if (netgr_matches($1, NULL, NULL, *user_runas))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           efree($1);
-                           used_runas = TRUE;
-                       }
-               |       ALIAS {
-                           aliasinfo *aip = find_alias($1, RUNAS_ALIAS);
-
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries($1, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas($1, ", ");
-                           }
-                           /* could be an all-caps username */
-                           if (aip)
-                               $$ = aip->val;
-                           else if (strcmp($1, *user_runas) == 0)
-                               $$ = TRUE;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared Runas_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               $$ = NOMATCH;
-                           }
-                           efree($1);
-                           used_runas = TRUE;
-                       }
-               |       ALL {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("ALL", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas("ALL", ", ");
-                           }
-                           $$ = TRUE;
-                       }
-               ;
-
-cmndtag                :       /* empty */ {
-                           /* Inherit {NO,}{PASSWD,EXEC,SETENV} status. */
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE) {
-                               if (no_passwd == TRUE)
-                                   cm_list[cm_list_len].nopasswd = TRUE;
-                               else
-                                   cm_list[cm_list_len].nopasswd = FALSE;
-                               if (no_execve == TRUE)
-                                   cm_list[cm_list_len].noexecve = TRUE;
-                               else
-                                   cm_list[cm_list_len].noexecve = FALSE;
-                               if (setenv_ok == TRUE)
-                                   cm_list[cm_list_len].setenv = TRUE;
-                               else
-                                   cm_list[cm_list_len].setenv = FALSE;
-                           }
-                       }
-               |       cmndtag NOPASSWD {
-                           no_passwd = TRUE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].nopasswd = TRUE;
-                       }
-               |       cmndtag PASSWD {
-                           no_passwd = FALSE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].nopasswd = FALSE;
-                       }
-               |       cmndtag NOEXEC {
-                           no_execve = TRUE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].noexecve = TRUE;
-                       }
-               |       cmndtag EXEC {
-                           no_execve = FALSE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].noexecve = FALSE;
-                       }
-               |       cmndtag SETENV {
-                           setenv_ok = TRUE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].setenv = TRUE;
-                       }
-               |       cmndtag NOSETENV {
-                           setenv_ok = FALSE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].setenv = FALSE;
-                       }
-               ;
-
-cmnd           :       ALL {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("ALL", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE) {
-                                   append_cmnd("ALL", NULL);
-                                   expand_match_list();
-                               }
-                           }
-                           /* sudo "ALL" implies the SETENV tag */
-                           if (setenv_ok == UNSPEC)
-                               setenv_ok = IMPLIED;
-
-                           efree(safe_cmnd);
-                           safe_cmnd = NULL;
-                           $$ = TRUE;
-                       }
-               |       ALIAS {
-                           aliasinfo *aip;
-
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries($1, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE) {
-                                   append_cmnd($1, NULL);
-                                   expand_match_list();
-                               }
-                           }
-
-                           if ((aip = find_alias($1, CMND_ALIAS)))
-                               $$ = aip->val;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared Cmnd_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               $$ = NOMATCH;
-                           }
-                           efree($1);
-                       }
-               |        COMMAND {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE) {
-                                   append_entries($1.cmnd, ", ");
-                                   if ($1.args)
-                                       append_entries($1.args, " ");
-                               }
-                               if (host_matches == TRUE &&
-                                   user_matches == TRUE)  {
-                                   append_cmnd($1.cmnd, NULL);
-                                   if ($1.args)
-                                       append_cmnd($1.args, " ");
-                                   expand_match_list();
-                               }
-                           }
-
-                           if (command_matches($1.cmnd, $1.args))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-
-                           efree($1.cmnd);
-                           efree($1.args);
-                       }
-               ;
-
-hostaliases    :       hostalias
-               |       hostaliases ':' hostalias
-               ;
-
-hostalias      :       ALIAS { push; } '=' hostlist {
-                           if ((MATCHED(host_matches) || pedantic) &&
-                               !add_alias($1, HOST_ALIAS, host_matches)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           pop;
-                       }
-               ;
-
-hostlist       :       ophost
-               |       hostlist ',' ophost
-               ;
-
-cmndaliases    :       cmndalias
-               |       cmndaliases ':' cmndalias
-               ;
-
-cmndalias      :       ALIAS {
-                           push;
-                           if (printmatches == TRUE) {
-                               in_alias = TRUE;
-                               /* Allocate space for ga_list if necessary. */
-                               expand_ga_list();
-                               ga_list[ga_list_len-1].type = CMND_ALIAS;
-                               ga_list[ga_list_len-1].alias = estrdup($1);
-                            }
-                       } '=' cmndlist {
-                           if ((MATCHED(cmnd_matches) || pedantic) &&
-                               !add_alias($1, CMND_ALIAS, cmnd_matches)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           pop;
-                           efree($1);
-
-                           if (printmatches == TRUE)
-                               in_alias = FALSE;
-                       }
-               ;
-
-cmndlist       :       opcmnd { ; }
-               |       cmndlist ',' opcmnd
-               ;
-
-runasaliases   :       runasalias
-               |       runasaliases ':' runasalias
-               ;
-
-runasalias     :       ALIAS {
-                           if (printmatches == TRUE) {
-                               in_alias = TRUE;
-                               /* Allocate space for ga_list if necessary. */
-                               expand_ga_list();
-                               ga_list[ga_list_len-1].type = RUNAS_ALIAS;
-                               ga_list[ga_list_len-1].alias = estrdup($1);
-                           }
-                       } '=' runaslist {
-                           if (($4 != NOMATCH || pedantic) &&
-                               !add_alias($1, RUNAS_ALIAS, $4)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           efree($1);
-
-                           if (printmatches == TRUE)
-                               in_alias = FALSE;
-                       }
-               ;
-
-useraliases    :       useralias
-               |       useraliases ':' useralias
-               ;
-
-useralias      :       ALIAS { push; } '=' userlist {
-                           if ((MATCHED(user_matches) || pedantic) &&
-                               !add_alias($1, USER_ALIAS, user_matches)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           pop;
-                           efree($1);
-                       }
-               ;
-
-userlist       :       opuser
-               |       userlist ',' opuser
-               ;
-
-opuser         :       user {
-                           SETMATCH(user_matches, $1);
-                       }
-               |       '!' user {
-                           SETNMATCH(user_matches, $2);
-                       }
-               ;
-
-user           :       WORD {
-                           if (userpw_matches($1, user_name, sudo_user.pw))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           efree($1);
-                       }
-               |       USERGROUP {
-                           if (usergr_matches($1, user_name, sudo_user.pw))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           efree($1);
-                       }
-               |       NETGROUP {
-                           if (netgr_matches($1, NULL, NULL, user_name))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           efree($1);
-                       }
-               |       ALIAS {
-                           aliasinfo *aip = find_alias($1, USER_ALIAS);
-
-                           /* could be an all-caps username */
-                           if (aip)
-                               $$ = aip->val;
-                           else if (strcmp($1, user_name) == 0)
-                               $$ = TRUE;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared User_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               $$ = NOMATCH;
-                           }
-                           efree($1);
-                       }
-               |       ALL {
-                           $$ = TRUE;
-                       }
-               ;
-
-%%
-
-#define MOREALIASES (32)
-aliasinfo *aliases = NULL;
-size_t naliases = 0;
-size_t nslots = 0;
-
-
-/*
- * Compare two aliasinfo structures, strcmp() style.
- * Note that we do *not* compare their values.
- */
-static int
-aliascmp(a1, a2)
-    const VOID *a1, *a2;
-{
-    int r;
-    aliasinfo *ai1, *ai2;
-
-    ai1 = (aliasinfo *) a1;
-    ai2 = (aliasinfo *) a2;
-    if ((r = strcmp(ai1->name, ai2->name)) == 0)
-       r = ai1->type - ai2->type;
-
-    return(r);
-}
-
-/*
- * Compare two generic_alias structures, strcmp() style.
- */
-static int
-genaliascmp(entry, key)
-    const VOID *entry, *key;
-{
-    int r;
-    struct generic_alias *ga1, *ga2;
-
-    ga1 = (struct generic_alias *) key;
-    ga2 = (struct generic_alias *) entry;
-    if ((r = strcmp(ga1->alias, ga2->alias)) == 0)
-       r = ga1->type - ga2->type;
-
-    return(r);
-}
-
-
-/*
- * Adds the named alias of the specified type to the aliases list.
- */
-static int
-add_alias(alias, type, val)
-    char *alias;
-    int type;
-    int val;
-{
-    aliasinfo ai, *aip;
-    size_t onaliases;
-    char s[512];
-
-    if (naliases >= nslots)
-       more_aliases();
-
-    ai.type = type;
-    ai.val = val;
-    ai.name = estrdup(alias);
-    onaliases = naliases;
-
-    aip = (aliasinfo *) lsearch((VOID *)&ai, (VOID *)aliases, &naliases,
-                               sizeof(ai), aliascmp);
-    if (aip == NULL) {
-       (void) snprintf(s, sizeof(s), "Aliases corrupted defining alias `%s'",
-                       alias);
-       yyerror(s);
-       return(FALSE);
-    }
-    if (onaliases == naliases) {
-       (void) snprintf(s, sizeof(s), "Alias `%s' already defined", alias);
-       yyerror(s);
-       return(FALSE);
-    }
-
-    return(TRUE);
-}
-
-/*
- * Searches for the named alias of the specified type.
- */
-static aliasinfo *
-find_alias(alias, type)
-    char *alias;
-    int type;
-{
-    aliasinfo ai;
-
-    ai.name = alias;
-    ai.type = type;
-
-    return((aliasinfo *) lfind((VOID *)&ai, (VOID *)aliases, &naliases,
-                sizeof(ai), aliascmp));
-}
-
-/*
- * Allocates more space for the aliases list.
- */
-static void
-more_aliases()
-{
-
-    nslots += MOREALIASES;
-    aliases = (aliasinfo *) erealloc3(aliases, nslots, sizeof(aliasinfo));
-}
-
-/*
- * Lists the contents of the aliases list.
- */
-void
-dumpaliases()
-{
-    size_t n;
-
-    for (n = 0; n < naliases; n++) {
-       if (aliases[n].val == -1)
-           continue;
-
-       switch (aliases[n].type) {
-       case HOST_ALIAS:
-           (void) puts("HOST_ALIAS");
-           break;
-
-       case CMND_ALIAS:
-           (void) puts("CMND_ALIAS");
-           break;
-
-       case USER_ALIAS:
-           (void) puts("USER_ALIAS");
-           break;
-
-       case RUNAS_ALIAS:
-           (void) puts("RUNAS_ALIAS");
-           break;
-       }
-       (void) printf("\t%s: %d\n", aliases[n].name, aliases[n].val);
-    }
-}
-
-/*
- * Lists the contents of cm_list and ga_list for `sudo -l'.
- */
-void
-list_matches()
-{
-    size_t count;
-    char *p;
-    struct generic_alias *ga, key;
-
-    (void) printf("User %s may run the following commands on this host:\n",
-       user_name);
-    for (count = 0; count < cm_list_len; count++) {
-
-       /* Print the runas list. */
-       (void) fputs("    ", stdout);
-       if (cm_list[count].runas) {
-           (void) putchar('(');
-           p = strtok(cm_list[count].runas, ", ");
-           do {
-               if (p != cm_list[count].runas)
-                   (void) fputs(", ", stdout);
-
-               key.alias = p;
-               key.type = RUNAS_ALIAS;
-               if ((ga = (struct generic_alias *) lfind((VOID *) &key,
-                   (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
-                   (void) fputs(ga->entries, stdout);
-               else
-                   (void) fputs(p, stdout);
-           } while ((p = strtok(NULL, ", ")));
-           (void) fputs(") ", stdout);
-       } else {
-           (void) printf("(%s) ", def_runas_default);
-       }
-
-#ifdef HAVE_SELINUX
-       /* SELinux role and type */
-       if (cm_list[count].role != NULL)
-           (void) printf("ROLE=%s ", cm_list[count].role);
-       if (cm_list[count].type != NULL)
-           (void) printf("TYPE=%s ", cm_list[count].type);
-#endif
-
-       /* Is execve(2) disabled? */
-       if (cm_list[count].noexecve == TRUE && !def_noexec)
-           (void) fputs("NOEXEC: ", stdout);
-       else if (cm_list[count].noexecve == FALSE && def_noexec)
-           (void) fputs("EXEC: ", stdout);
-
-       /* Is a password required? */
-       if (cm_list[count].nopasswd == TRUE && def_authenticate)
-           (void) fputs("NOPASSWD: ", stdout);
-       else if (cm_list[count].nopasswd == FALSE && !def_authenticate)
-           (void) fputs("PASSWD: ", stdout);
-
-       /* Is setenv enabled? */
-       if (cm_list[count].setenv == TRUE && !def_setenv)
-           (void) fputs("SETENV: ", stdout);
-       else if (cm_list[count].setenv == FALSE && def_setenv)
-           (void) fputs("NOSETENV: ", stdout);
-
-       /* Print the actual command or expanded Cmnd_Alias. */
-       key.alias = cm_list[count].cmnd;
-       key.type = CMND_ALIAS;
-       if ((ga = (struct generic_alias *) lfind((VOID *) &key,
-           (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
-           (void) puts(ga->entries);
-       else
-           (void) puts(cm_list[count].cmnd);
-    }
-
-    /* Be nice and free up space now that we are done. */
-    for (count = 0; count < ga_list_len; count++) {
-       efree(ga_list[count].alias);
-       efree(ga_list[count].entries);
-    }
-    efree(ga_list);
-    ga_list = NULL;
-
-    for (count = 0; count < cm_list_len; count++) {
-       efree(cm_list[count].runas);
-       efree(cm_list[count].cmnd);
-       efree(cm_list[count].role);
-       efree(cm_list[count].type);
-    }
-    efree(cm_list);
-    cm_list = NULL;
-    cm_list_len = 0;
-    cm_list_size = 0;
-}
-
-/*
- * Appends a source string to the destination, optionally prefixing a separator.
- */
-static void
-append(src, dstp, dst_len, dst_size, separator)
-    char *src, **dstp;
-    size_t *dst_len, *dst_size;
-    char *separator;
-{
-    size_t src_len = strlen(src);
-    char *dst = *dstp;
-
-    /*
-     * Only add the separator if there is something to separate from.
-     * If the last char is a '!', don't apply the separator (XXX).
-     */
-    if (separator && dst && dst[*dst_len - 1] != '!')
-       src_len += strlen(separator);
-    else
-       separator = NULL;
-
-    /* Assumes dst will be NULL if not set. */
-    if (dst == NULL) {
-       dst = (char *) emalloc(BUFSIZ);
-       *dst = '\0';
-       *dst_size = BUFSIZ;
-       *dst_len = 0;
-       *dstp = dst;
-    }
-
-    /* Allocate more space if necessary. */
-    if (*dst_size <= *dst_len + src_len) {
-       while (*dst_size <= *dst_len + src_len)
-           *dst_size += BUFSIZ;
-
-       dst = (char *) erealloc(dst, *dst_size);
-       *dstp = dst;
-    }
-
-    /* Copy src -> dst adding a separator if appropriate and adjust len. */
-    if (separator)
-       (void) strlcat(dst, separator, *dst_size);
-    (void) strlcat(dst, src, *dst_size);
-    *dst_len += src_len;
-}
-
-/*
- * Frees up space used by the aliases list and resets the associated counters.
- */
-void
-reset_aliases()
-{
-    size_t n;
-
-    if (aliases) {
-       for (n = 0; n < naliases; n++)
-           efree(aliases[n].name);
-       efree(aliases);
-       aliases = NULL;
-    }
-    naliases = nslots = 0;
-}
-
-/*
- * Increments ga_list_len, allocating more space as necessary.
- */
-static void
-expand_ga_list()
-{
-
-    if (++ga_list_len >= ga_list_size) {
-       while ((ga_list_size += STACKINCREMENT) < ga_list_len)
-           ;
-       ga_list = (struct generic_alias *)
-           erealloc3(ga_list, ga_list_size, sizeof(struct generic_alias));
-    }
-
-    ga_list[ga_list_len - 1].entries = NULL;
-}
-
-/*
- * Increments cm_list_len, allocating more space as necessary.
- */
-static void
-expand_match_list()
-{
-
-    if (++cm_list_len >= cm_list_size) {
-       while ((cm_list_size += STACKINCREMENT) < cm_list_len)
-           ;
-       if (cm_list == NULL)
-           cm_list_len = 0;            /* start at 0 since it is a subscript */
-       cm_list = (struct command_match *)
-           erealloc3(cm_list, cm_list_size, sizeof(struct command_match));
-    }
-
-    cm_list[cm_list_len].runas = cm_list[cm_list_len].cmnd = NULL;
-    cm_list[cm_list_len].type = cm_list[cm_list_len].role = NULL;
-    cm_list[cm_list_len].nopasswd = FALSE;
-    cm_list[cm_list_len].noexecve = FALSE;
-    cm_list[cm_list_len].setenv = FALSE;
-}
-
-/*
- * Frees up spaced used by a previous parser run and allocates new space
- * for various data structures.
- */
-void
-init_parser()
-{
-
-    /* Free up old data structures if we run the parser more than once. */
-    if (match) {
-       efree(match);
-       match = NULL;
-       top = 0;
-       parse_error = FALSE;
-       used_runas = FALSE;
-       errorlineno = -1;
-       sudolineno = 1;
-    }
-
-    /* Allocate space for the matching stack. */
-    stacksize = STACKINCREMENT;
-    match = (struct matchstack *) emalloc2(stacksize, sizeof(struct matchstack));
-
-    /* Allocate space for the match list (for `sudo -l'). */
-    if (printmatches == TRUE)
-       expand_match_list();
-}
index 3fc32495cf1d17ba7b96617d62b312777b1159a4..430f96a99ab7629b7b934e76885378d02844c882 100644 (file)
@@ -18,7 +18,7 @@
  * Agency (DARPA) and Air Force Research Laboratory, Air Force
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  *
- * $Sudo: pathnames.h.in,v 1.51.2.4 2008/02/09 14:44:48 millert Exp $
+ * $Sudo: pathnames.h.in,v 1.63 2008/11/10 13:07:38 millert Exp $
  */
 
 /*
 #define _PATH_DEFPATH          "/usr/bin:/bin"
 #endif /* _PATH_DEFPATH */
 
+#ifndef _PATH_ENVIRONMENT
+#define _PATH_ENVIRONMENT      "/etc/environment"
+#endif /* _PATH_ENVIRONMENT */
+
 /*
- * NOTE: _PATH_SUDOERS is usually overriden by the Makefile.
+ * NOTE: _PATH_SUDOERS is usually overridden by the Makefile.
  */
 #ifndef _PATH_SUDOERS
 #define _PATH_SUDOERS          "/etc/sudoers"
 #endif /* _PATH_SUDOERS */
 
-/*
- * NOTE:  _PATH_SUDOERS_TMP is usually overriden by the Makefile.
- *        _PATH_SUDOERS_TMP *MUST* be on the same partition
- *        as _PATH_SUDOERS!
- */
-#ifndef _PATH_SUDOERS_TMP
-#define _PATH_SUDOERS_TMP      "/etc/sudoers.tmp"
-#endif /* _PATH_SUDOERS_TMP */
-
 /*
  * The following paths are controlled via the configure script.
  */
 #undef _PATH_SUDO_NOEXEC
 #endif /* _PATH_SUDO_NOEXEC */
 
+#ifndef _PATH_SUDO_ASKPASS
+#undef _PATH_SUDO_ASKPASS
+#endif /* _PATH_SUDO_ASKPASS */
+
 #ifndef _PATH_VI
 #undef _PATH_VI
 #endif /* _PATH_VI */
 #undef _PATH_BSHELL
 #endif /* _PATH_BSHELL */
 
-#ifndef _PATH_SUDO_SESH
-#undef _PATH_SUDO_SESH
-#endif /* _PATH_SUDO_SESH */
-
 #ifndef _PATH_TMP
 #define        _PATH_TMP       "/tmp/"
 #endif /* _PATH_TMP */
 #define        _PATH_USRTMP    "/usr/tmp/"
 #endif /* _PATH_USRTMP */
 
+#ifndef _PATH_SUDO_SESH
+#undef _PATH_SUDO_SESH
+#endif /* _PATH_SUDO_SESH */
+
 #ifndef _PATH_LDAP_CONF
-#define        _PATH_LDAP_CONF "/etc/ldap.conf"
+#undef _PATH_LDAP_CONF
 #endif /* _PATH_LDAP_CONF */
 
 #ifndef _PATH_LDAP_SECRET
-#define _PATH_LDAP_SECRET      "/etc/ldap.secret"
+#undef _PATH_LDAP_SECRET
 #endif /* _PATH_LDAP_SECRET */
+
+#ifndef _PATH_NSSWITCH_CONF
+#undef _PATH_NSSWITCH_CONF
+#endif /* _PATH_NSSWITCH_CONF */
diff --git a/pwutil.c b/pwutil.c
new file mode 100644 (file)
index 0000000..2fd0988
--- /dev/null
+++ b/pwutil.c
@@ -0,0 +1,579 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
+#  include <memory.h>
+# endif
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#include <grp.h>
+
+#include "sudo.h"
+#include "redblack.h"
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: pwutil.c,v 1.21 2008/11/09 14:13:12 millert Exp $";
+#endif /* lint */
+
+#ifdef MYPW
+extern void (*my_setgrent) __P((void));
+extern void (*my_endgrent) __P((void));
+extern struct group *(*my_getgrnam) __P((const char *));
+extern struct group *(*my_getgrgid) __P((gid_t));
+#define setgrent()     my_setgrent()
+#define endgrent()     my_endgrent()
+#define getgrnam(n)    my_getgrnam(n)
+#define getgrgid(g)    my_getgrgid(g)
+
+extern void (*my_setpwent) __P((void));
+extern void (*my_endpwent) __P((void));
+extern struct passwd *(*my_getpwnam) __P((const char *));
+extern struct passwd *(*my_getpwuid) __P((uid_t));
+#define setpwent()     my_setpwent()
+#define endpwent()     my_endpwent()
+#define getpwnam(n)    my_getpwnam(n)
+#define getpwuid(u)    my_getpwuid(u)
+#endif
+
+/*
+ * The passwd and group caches.
+ */
+static struct rbtree *pwcache_byuid, *pwcache_byname;
+static struct rbtree *grcache_bygid, *grcache_byname;
+
+static int  cmp_pwuid  __P((const void *, const void *));
+static int  cmp_pwnam  __P((const void *, const void *));
+static int  cmp_grgid  __P((const void *, const void *));
+static int  cmp_grnam  __P((const void *, const void *));
+
+/*
+ * Compare by uid.
+ */
+static int
+cmp_pwuid(v1, v2)
+    const void *v1;
+    const void *v2;
+{
+    const struct passwd *pw1 = (const struct passwd *) v1;
+    const struct passwd *pw2 = (const struct passwd *) v2;
+    return(pw1->pw_uid - pw2->pw_uid);
+}
+
+/*
+ * Compare by user name.
+ */
+static int
+cmp_pwnam(v1, v2)
+    const void *v1;
+    const void *v2;
+{
+    const struct passwd *pw1 = (const struct passwd *) v1;
+    const struct passwd *pw2 = (const struct passwd *) v2;
+    return(strcmp(pw1->pw_name, pw2->pw_name));
+}
+
+#define FIELD_SIZE(src, name, size)                    \
+do {                                                   \
+       if (src->name) {                                \
+               size = strlen(src->name) + 1;           \
+               total += size;                          \
+       }                                               \
+} while (0)
+
+#define FIELD_COPY(src, dst, name, size)               \
+do {                                                   \
+       if (src->name) {                                \
+               memcpy(cp, src->name, size);            \
+               dst->name = cp;                         \
+               cp += size;                             \
+       }                                               \
+} while (0)
+
+/*
+ * Dynamically allocate space for a struct password and the constituent parts
+ * that we care about.  Fills in pw_passwd from shadow file.
+ */
+static struct passwd *
+sudo_pwdup(pw)
+    const struct passwd *pw;
+{
+    char *cp;
+    const char *pw_shell;
+    size_t nsize, psize, csize, gsize, dsize, ssize, total;
+    struct passwd *newpw;
+
+    /* If shell field is empty, expand to _PATH_BSHELL. */
+    pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
+       ? _PATH_BSHELL : pw->pw_shell;
+
+    /* Allocate in one big chunk for easy freeing. */
+    nsize = psize = csize = gsize = dsize = ssize = 0;
+    total = sizeof(struct passwd);
+    FIELD_SIZE(pw, pw_name, nsize);
+    FIELD_SIZE(pw, pw_passwd, psize);
+#ifdef HAVE_LOGIN_CAP_H
+    FIELD_SIZE(pw, pw_class, csize);
+#endif
+    FIELD_SIZE(pw, pw_gecos, gsize);
+    FIELD_SIZE(pw, pw_dir, dsize);
+    FIELD_SIZE(pw, pw_shell, ssize);
+
+    if ((cp = malloc(total)) == NULL)
+           return(NULL);
+    newpw = (struct passwd *) cp;
+
+    /*
+     * Copy in passwd contents and make strings relative to space
+     * at the end of the buffer.
+     */
+    memcpy(newpw, pw, sizeof(struct passwd));
+    cp += sizeof(struct passwd);
+    FIELD_COPY(pw, newpw, pw_name, nsize);
+    FIELD_COPY(pw, newpw, pw_passwd, psize);
+#ifdef HAVE_LOGIN_CAP_H
+    FIELD_COPY(pw, newpw, pw_class, csize);
+#endif
+    FIELD_COPY(pw, newpw, pw_gecos, gsize);
+    FIELD_COPY(pw, newpw, pw_dir, dsize);
+    FIELD_COPY(pw, newpw, pw_shell, ssize);
+
+    return(newpw);
+}
+
+/*
+ * Get a password entry by uid and allocate space for it.
+ * Fills in pw_passwd from shadow file if necessary.
+ */
+struct passwd *
+sudo_getpwuid(uid)
+    uid_t uid;
+{
+    struct passwd key, *pw;
+    struct rbnode *node;
+    char *cp;
+
+    key.pw_uid = uid;
+    if ((node = rbfind(pwcache_byuid, &key)) != NULL) {
+       pw = (struct passwd *) node->data;
+       return(pw->pw_name != NULL ? pw : NULL);
+    }
+    /*
+     * Cache passwd db entry if it exists or a negative response if not.
+     */
+    if ((pw = getpwuid(uid)) != NULL) {
+       pw = sudo_pwdup(pw);
+       cp = sudo_getepw(pw);           /* get shadow password */
+       if (pw->pw_passwd != NULL)
+           zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd));
+       pw->pw_passwd = cp;
+
+       if (rbinsert(pwcache_byname, (void *) pw) != NULL)
+           errorx(1, "unable to cache user name, already exists");
+       if (rbinsert(pwcache_byuid, (void *) pw) != NULL)
+           errorx(1, "unable to cache uid, already exists");
+       return(pw);
+    } else {
+       pw = emalloc(sizeof(*pw));
+       zero_bytes(pw, sizeof(*pw));
+       pw->pw_uid = uid;
+       if (rbinsert(pwcache_byuid, (void *) pw) != NULL)
+           errorx(1, "unable to cache uid, already exists");
+       return(NULL);
+    }
+}
+
+/*
+ * Get a password entry by name and allocate space for it.
+ * Fills in pw_passwd from shadow file if necessary.
+ */
+struct passwd *
+sudo_getpwnam(name)
+    const char *name;
+{
+    struct passwd key, *pw;
+    struct rbnode *node;
+    size_t len;
+    char *cp;
+
+    key.pw_name = (char *) name;
+    if ((node = rbfind(pwcache_byname, &key)) != NULL) {
+       pw = (struct passwd *) node->data;
+       return(pw->pw_uid != (uid_t) -1 ? pw : NULL);
+    }
+    /*
+     * Cache passwd db entry if it exists or a negative response if not.
+     */
+    if ((pw = getpwnam(name)) != NULL) {
+       pw = sudo_pwdup(pw);
+       cp = sudo_getepw(pw);           /* get shadow password */
+       if (pw->pw_passwd != NULL)
+           zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd));
+       pw->pw_passwd = cp;
+
+       if (rbinsert(pwcache_byname, (void *) pw) != NULL)
+           errorx(1, "unable to cache user name, already exists");
+       if (rbinsert(pwcache_byuid, (void *) pw) != NULL)
+           errorx(1, "unable to cache uid, already exists");
+       return(pw);
+    } else {
+       len = strlen(name) + 1;
+       cp = emalloc(sizeof(*pw) + len);
+       zero_bytes(cp, sizeof(*pw));
+       pw = (struct passwd *) cp;
+       cp += sizeof(*pw);
+       memcpy(cp, name, len);
+       pw->pw_name = cp;
+       pw->pw_uid = (uid_t) -1;
+       if (rbinsert(pwcache_byname, (void *) pw) != NULL)
+           errorx(1, "unable to cache user name, already exists");
+       return(NULL);
+    }
+}
+
+/*
+ * Take a uid in string form "#123" and return a faked up passwd struct.
+ */
+struct passwd *
+sudo_fakepwnam(user, gid)
+    const char *user;
+    gid_t gid;
+{
+    struct passwd *pw;
+    struct rbnode *node;
+    size_t len;
+
+    len = strlen(user);
+    pw = emalloc(sizeof(struct passwd) + len + 1 /* pw_name */ +
+       sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +
+       sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL));
+    zero_bytes(pw, sizeof(struct passwd));
+    pw->pw_uid = (uid_t) atoi(user + 1);
+    pw->pw_gid = gid;
+    pw->pw_name = (char *)pw + sizeof(struct passwd);
+    memcpy(pw->pw_name, user, len + 1);
+    pw->pw_passwd = pw->pw_name + len + 1;
+    memcpy(pw->pw_passwd, "*", 2);
+    pw->pw_gecos = pw->pw_passwd + 2;
+    pw->pw_gecos[0] = '\0';
+    pw->pw_dir = pw->pw_gecos + 1;
+    memcpy(pw->pw_dir, "/", 2);
+    pw->pw_shell = pw->pw_dir + 2;
+    memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL));
+
+    /* Store by uid and by name, overwriting cached version. */
+    if ((node = rbinsert(pwcache_byuid, pw)) != NULL) {
+       efree(node->data);
+       node->data = (void *) pw;
+    }
+    if ((node = rbinsert(pwcache_byname, pw)) != NULL) {
+       efree(node->data);
+       node->data = (void *) pw;
+    }
+    return(pw);
+}
+
+/*
+ * Take a gid in string form "#123" and return a faked up group struct.
+ */
+struct group *
+sudo_fakegrnam(group)
+    const char *group;
+{
+    struct group *gr;
+    struct rbnode *node;
+    size_t len;
+
+    len = strlen(group);
+    gr = emalloc(sizeof(struct group) + len + 1);
+    zero_bytes(gr, sizeof(struct group));
+    gr->gr_gid = (gid_t) atoi(group + 1);
+    gr->gr_name = (char *)gr + sizeof(struct group);
+    strlcpy(gr->gr_name, group, len + 1);
+
+    /* Store by gid and by name, overwriting cached version. */
+    if ((node = rbinsert(grcache_bygid, gr)) != NULL) {
+       efree(node->data);
+       node->data = (void *) gr;
+    }
+    if ((node = rbinsert(grcache_byname, gr)) != NULL) {
+       efree(node->data);
+       node->data = (void *) gr;
+    }
+    return(gr);
+}
+
+void
+sudo_setpwent()
+{
+    setpwent();
+    sudo_setspent();
+    if (pwcache_byuid == NULL)
+       pwcache_byuid = rbcreate(cmp_pwuid);
+    if (pwcache_byname == NULL)
+       pwcache_byname = rbcreate(cmp_pwnam);
+}
+
+#ifdef PURIFY
+static void pw_free    __P((void *));
+
+void
+sudo_freepwcache()
+{
+    if (pwcache_byuid != NULL) {
+       rbdestroy(pwcache_byuid, pw_free);
+       pwcache_byuid = NULL;
+    }
+    if (pwcache_byname != NULL) {
+       rbdestroy(pwcache_byname, NULL);
+       pwcache_byname = NULL;
+    }
+}
+
+static void
+pw_free(v)
+    void *v;
+{
+    struct passwd *pw = (struct passwd *) v;
+
+    if (pw->pw_passwd != NULL) {
+       zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd));
+       efree(pw->pw_passwd);
+    }
+    efree(pw);
+}
+#endif /* PURIFY */
+
+void
+sudo_endpwent()
+{
+    endpwent();
+    sudo_endspent();
+#ifdef PURIFY
+    sudo_freepwcache();
+#endif
+}
+
+/*
+ * Compare by gid.
+ */
+static int
+cmp_grgid(v1, v2)
+    const void *v1;
+    const void *v2;
+{
+    const struct group *grp1 = (const struct group *) v1;
+    const struct group *grp2 = (const struct group *) v2;
+    return(grp1->gr_gid - grp2->gr_gid);
+}
+
+/*
+ * Compare by group name.
+ */
+static int
+cmp_grnam(v1, v2)
+    const void *v1;
+    const void *v2;
+{
+    const struct group *grp1 = (const struct group *) v1;
+    const struct group *grp2 = (const struct group *) v2;
+    return(strcmp(grp1->gr_name, grp2->gr_name));
+}
+
+struct group *
+sudo_grdup(gr)
+    const struct group *gr;
+{
+    char *cp;
+    size_t nsize, psize, nmem, total, len;
+    struct group *newgr;
+
+    /* Allocate in one big chunk for easy freeing. */
+    nsize = psize = nmem = 0;
+    total = sizeof(struct group);
+    FIELD_SIZE(gr, gr_name, nsize);
+    FIELD_SIZE(gr, gr_passwd, psize);
+    if (gr->gr_mem) {
+       for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++)
+           total += strlen(gr->gr_mem[nmem]) + 1;
+       nmem++;
+       total += sizeof(char *) * nmem;
+    }
+    if ((cp = malloc(total)) == NULL)
+           return(NULL);
+    newgr = (struct group *)cp;
+
+    /*
+     * Copy in group contents and make strings relative to space
+     * at the end of the buffer.  Note that gr_mem must come
+     * immediately after struct group to guarantee proper alignment.
+     */
+    (void)memcpy(newgr, gr, sizeof(struct group));
+    cp += sizeof(struct group);
+    if (gr->gr_mem) {
+       newgr->gr_mem = (char **)cp;
+       cp += sizeof(char *) * nmem;
+       for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++) {
+           len = strlen(gr->gr_mem[nmem]) + 1;
+           memcpy(cp, gr->gr_mem[nmem], len);
+           newgr->gr_mem[nmem] = cp;
+           cp += len;
+       }
+       newgr->gr_mem[nmem] = NULL;
+    }
+    FIELD_COPY(gr, newgr, gr_passwd, psize);
+    FIELD_COPY(gr, newgr, gr_name, nsize);
+
+    return(newgr);
+}
+
+/*
+ * Get a group entry by gid and allocate space for it.
+ */
+struct group *
+sudo_getgrgid(gid)
+    gid_t gid;
+{
+    struct group key, *gr;
+    struct rbnode *node;
+
+    key.gr_gid = gid;
+    if ((node = rbfind(grcache_bygid, &key)) != NULL) {
+       gr = (struct group *) node->data;
+       return(gr->gr_name != NULL ? gr : NULL);
+    }
+    /*
+     * Cache group db entry if it exists or a negative response if not.
+     */
+    if ((gr = getgrgid(gid)) != NULL) {
+       gr = sudo_grdup(gr);
+       if (rbinsert(grcache_byname, (void *) gr) != NULL)
+           errorx(1, "unable to cache group name, already exists");
+       if (rbinsert(grcache_bygid, (void *) gr) != NULL)
+           errorx(1, "unable to cache gid, already exists");
+       return(gr);
+    } else {
+       gr = emalloc(sizeof(*gr));
+       zero_bytes(gr, sizeof(*gr));
+       gr->gr_gid = gid;
+       if (rbinsert(grcache_bygid, (void *) gr) != NULL)
+           errorx(1, "unable to cache gid, already exists");
+       return(NULL);
+    }
+}
+
+/*
+ * Get a group entry by name and allocate space for it.
+ */
+struct group *
+sudo_getgrnam(name)
+    const char *name;
+{
+    struct group key, *gr;
+    struct rbnode *node;
+    size_t len;
+    char *cp;
+
+    key.gr_name = (char *) name;
+    if ((node = rbfind(grcache_byname, &key)) != NULL) {
+       gr = (struct group *) node->data;
+       return(gr->gr_gid != (gid_t) -1 ? gr : NULL);
+    }
+    /*
+     * Cache group db entry if it exists or a negative response if not.
+     */
+    if ((gr = getgrnam(name)) != NULL) {
+       gr = sudo_grdup(gr);
+       if (rbinsert(grcache_byname, (void *) gr) != NULL)
+           errorx(1, "unable to cache group name, already exists");
+       if (rbinsert(grcache_bygid, (void *) gr) != NULL)
+           errorx(1, "unable to cache gid, already exists");
+       return(gr);
+    } else {
+       len = strlen(name) + 1;
+       cp = emalloc(sizeof(*gr) + len);
+       zero_bytes(cp, sizeof(*gr));
+       gr = (struct group *) cp;
+       cp += sizeof(*gr);
+       memcpy(cp, name, len);
+       gr->gr_name = cp;
+       gr->gr_gid = (gid_t) -1;
+       if (rbinsert(grcache_byname, (void *) gr) != NULL)
+           errorx(1, "unable to cache group name, already exists");
+       return(NULL);
+    }
+}
+
+void
+sudo_setgrent()
+{
+    setgrent();
+    if (grcache_bygid == NULL)
+       grcache_bygid = rbcreate(cmp_grgid);
+    if (grcache_byname == NULL)
+       grcache_byname = rbcreate(cmp_grnam);
+}
+
+#ifdef PURIFY
+void
+sudo_freegrcache()
+{
+    if (grcache_bygid != NULL) {
+       rbdestroy(grcache_bygid, free);
+       grcache_bygid = NULL;
+    }
+    if (grcache_byname != NULL) {
+       rbdestroy(grcache_byname, NULL);
+       grcache_byname = NULL;
+    }
+}
+#endif /* PURIFY */
+
+void
+sudo_endgrent()
+{
+    endgrent();
+#ifdef PURIFY
+    sudo_freegrcache();
+#endif
+}
diff --git a/redblack.c b/redblack.c
new file mode 100644 (file)
index 0000000..555e938
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2004-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Adapted from the following code written by Emin Martinian:
+ * http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
+ *
+ * Copyright (c) 2001 Emin Martinian
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that neither the name of Emin
+ * Martinian nor the names of any contributors are be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT
+ * OWNER OR CONTRIBUTORS 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 <sys/types.h>
+#include <sys/param.h>
+
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+
+#include "sudo.h"
+#include "redblack.h"
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: redblack.c,v 1.10 2008/11/22 15:01:25 millert Exp $";
+#endif /* lint */
+
+static void rbrepair           __P((struct rbtree *, struct rbnode *));
+static void rotate_left                __P((struct rbtree *, struct rbnode *));
+static void rotate_right       __P((struct rbtree *, struct rbnode *));
+static void _rbdestroy         __P((struct rbtree *, struct rbnode *,
+                                   void (*)(void *)));
+
+/*
+ * Red-Black tree, see http://en.wikipedia.org/wiki/Red-black_tree
+ *
+ * A red-black tree is a binary search tree where each node has a color
+ * attribute, the value of which is either red or black.  Essentially, it
+ * is just a convenient way to express a 2-3-4 binary search tree where
+ * the color indicates whether the node is part of a 3-node or a 4-node.
+ * In addition to the ordinary requirements imposed on binary search
+ * trees, we make the following additional requirements of any valid
+ * red-black tree:
+ *  1) The root is black.
+ *  2) All leaves are black.
+ *  3) Both children of each red node are black.
+ *  4) The paths from each leaf up to the root each contain the same
+ *     number of black nodes.
+ */
+
+/*
+ * Create a red black tree struct using the specified compare routine.
+ * Allocates and returns the initialized (empty) tree.
+ */
+struct rbtree *
+rbcreate(compar)
+    int (*compar)__P((const void *, const void*));
+{
+    struct rbtree *tree;
+
+    tree = (struct rbtree *) emalloc(sizeof(*tree));
+    tree->compar = compar;
+
+    /*
+     * We use a self-referencing sentinel node called nil to simplify the
+     * code by avoiding the need to check for NULL pointers.
+     */
+    tree->nil.left = tree->nil.right = tree->nil.parent = &tree->nil;
+    tree->nil.color = black;
+    tree->nil.data = NULL;
+
+    /*
+     * Similarly, the fake root node keeps us from having to worry
+     * about splitting the root.
+     */
+    tree->root.left = tree->root.right = tree->root.parent = &tree->nil;
+    tree->root.color = black;
+    tree->root.data = NULL;
+
+    return(tree);
+}
+
+/*
+ * Perform a left rotation starting at node.
+ */
+static void
+rotate_left(tree, node)
+    struct rbtree *tree;
+    struct rbnode *node;
+{
+    struct rbnode *child;
+
+    child = node->right;
+    node->right = child->left;
+
+    if (child->left != rbnil(tree))
+        child->left->parent = node;
+    child->parent = node->parent;
+
+    if (node == node->parent->left)
+       node->parent->left = child;
+    else
+       node->parent->right = child;
+    child->left = node;
+    node->parent = child;
+}
+
+/*
+ * Perform a right rotation starting at node.
+ */
+static void
+rotate_right(tree, node)
+    struct rbtree *tree;
+    struct rbnode *node;
+{
+    struct rbnode *child;
+
+    child = node->left;
+    node->left = child->right;
+
+    if (child->right != rbnil(tree))
+        child->right->parent = node;
+    child->parent = node->parent;
+
+    if (node == node->parent->left)
+       node->parent->left = child;
+    else
+       node->parent->right = child;
+    child->right = node;
+    node->parent = child;
+}
+
+/*
+ * Insert data pointer into a redblack tree.
+ * Returns a NULL pointer on success.  If a node matching "data"
+ * already exists, a pointer to the existant node is returned.
+ */
+struct rbnode *
+rbinsert(tree, data)
+    struct rbtree *tree;
+    void *data;
+{
+    struct rbnode *node = rbfirst(tree);
+    struct rbnode *parent = rbroot(tree);
+    int res;
+
+    /* Find correct insertion point. */
+    while (node != rbnil(tree)) {
+       parent = node;
+       if ((res = tree->compar(data, node->data)) == 0)
+           return(node);
+       node = res < 0 ? node->left : node->right;
+    }
+
+    node = (struct rbnode *) emalloc(sizeof(*node));
+    node->data = data;
+    node->left = node->right = rbnil(tree);
+    node->parent = parent;
+    if (parent == rbroot(tree) || tree->compar(data, parent->data) < 0)
+       parent->left = node;
+    else
+       parent->right = node;
+    node->color = red;
+
+    /*
+     * If the parent node is black we are all set, if it is red we have
+     * the following possible cases to deal with.  We iterate through
+     * the rest of the tree to make sure none of the required properties
+     * is violated.
+     *
+     * 1) The uncle is red.  We repaint both the parent and uncle black
+     *     and repaint the grandparent node red.
+     *
+     *  2) The uncle is black and the new node is the right child of its
+     *     parent, and the parent in turn is the left child of its parent.
+     *     We do a left rotation to switch the roles of the parent and
+     *     child, relying on further iterations to fixup the old parent.
+     *
+     *  3) The uncle is black and the new node is the left child of its
+     *     parent, and the parent in turn is the left child of its parent.
+     *     We switch the colors of the parent and grandparent and perform
+     *     a right rotation around the grandparent.  This makes the former
+     *     parent the parent of the new node and the former grandparent.
+     *
+     * Note that because we use a sentinel for the root node we never
+     * need to worry about replacing the root.
+     */
+    while (node->parent->color == red) {
+       struct rbnode *uncle;
+       if (node->parent == node->parent->parent->left) {
+           uncle = node->parent->parent->right;
+           if (uncle->color == red) {
+               node->parent->color = black;
+               uncle->color = black;
+               node->parent->parent->color = red;
+               node = node->parent->parent;
+           } else /* if (uncle->color == black) */ {
+               if (node == node->parent->right) {
+                   node = node->parent;
+                   rotate_left(tree, node);
+               }
+               node->parent->color = black;
+               node->parent->parent->color = red;
+               rotate_right(tree, node->parent->parent);
+           }
+       } else { /* if (node->parent == node->parent->parent->right) */
+           uncle = node->parent->parent->left;
+           if (uncle->color == red) {
+               node->parent->color = black;
+               uncle->color = black;
+               node->parent->parent->color = red;
+               node = node->parent->parent;
+           } else /* if (uncle->color == black) */ {
+               if (node == node->parent->left) {
+                   node = node->parent;
+                   rotate_right(tree, node);
+               }
+               node->parent->color = black;
+               node->parent->parent->color = red;
+               rotate_left(tree, node->parent->parent);
+           }
+       }
+    }
+    rbfirst(tree)->color = black;      /* first node is always black */
+    return(NULL);
+}
+
+/*
+ * Look for a node matching key in tree.
+ * Returns a pointer to the node if found, else NULL.
+ */
+struct rbnode *
+rbfind(tree, key)
+    struct rbtree *tree;
+    void *key;
+{
+    struct rbnode *node = rbfirst(tree);
+    int res;
+
+    while (node != rbnil(tree)) {
+       if ((res = tree->compar(key, node->data)) == 0)
+           return(node);
+       node = res < 0 ? node->left : node->right;
+    }
+    return(NULL);
+}
+
+/*
+ * Call func() for each node, passing it the node data and a cookie;
+ * If func() returns non-zero for a node, the traversal stops and the
+ * error value is returned.  Returns 0 on successful traversal.
+ */
+int
+rbapply_node(tree, node, func, cookie, order)
+    struct rbtree *tree;
+    struct rbnode *node;
+    int (*func)__P((void *, void *));
+    void *cookie;
+    enum rbtraversal order;
+{
+    int error;
+
+    if (node != rbnil(tree)) {
+       if (order == preorder)
+           if ((error = func(node->data, cookie)) != 0)
+               return(error);
+       if ((error = rbapply_node(tree, node->left, func, cookie, order)) != 0)
+           return(error);
+       if (order == inorder)
+           if ((error = func(node->data, cookie)) != 0)
+               return(error);
+       if ((error = rbapply_node(tree, node->right, func, cookie, order)) != 0)
+           return(error);
+       if (order == postorder)
+           if ((error = func(node->data, cookie)) != 0)
+               return(error);
+    }
+    return (0);
+}
+
+/*
+ * Returns the successor of node, or nil if there is none.
+ */
+static struct rbnode *
+rbsuccessor(tree, node)
+    struct rbtree *tree;
+    struct rbnode *node;
+{
+    struct rbnode *succ;
+
+    if ((succ = node->right) != rbnil(tree)) {
+       while (succ->left != rbnil(tree))
+           succ = succ->left;
+    } else {
+       /* No right child, move up until we find it or hit the root */
+       for (succ = node->parent; node == succ->right; succ = succ->parent)
+           node = succ;
+       if (succ == rbroot(tree))
+           succ = rbnil(tree);
+    }
+    return(succ);
+}
+
+/*
+ * Recursive portion of rbdestroy().
+ */
+static void
+_rbdestroy(tree, node, destroy)
+    struct rbtree *tree;
+    struct rbnode *node;
+    void (*destroy)__P((void *));
+{
+    if (node != rbnil(tree)) {
+       _rbdestroy(tree, node->left, destroy);
+       _rbdestroy(tree, node->right, destroy);
+       if (destroy != NULL)
+           destroy(node->data);
+       efree(node);
+    }
+}
+
+/*
+ * Destroy the specified tree, calling the destructor destroy
+ * for each node and then freeing the tree itself.
+ */
+void
+rbdestroy(tree, destroy)
+    struct rbtree *tree;
+    void (*destroy)__P((void *));
+{
+    _rbdestroy(tree, rbfirst(tree), destroy);
+    efree(tree);
+}
+
+/*
+ * Delete node 'z' from the tree and return its data pointer.
+ */
+void *rbdelete(tree, z)
+    struct rbtree* tree;
+    struct rbnode* z;
+{
+    struct rbnode *x, *y;
+    void *data = z->data;
+
+    if (z->left == rbnil(tree) || z->right == rbnil(tree))
+       y = z;
+    else
+       y = rbsuccessor(tree, z);
+    x = (y->left == rbnil(tree)) ? y->right : y->left;
+
+    if ((x->parent = y->parent) == rbroot(tree)) {
+       rbfirst(tree) = x;
+    } else {
+       if (y == y->parent->left)
+           y->parent->left = x;
+       else
+           y->parent->right = x;
+    }
+    if (y->color == black)
+       rbrepair(tree, x);
+    if (y != z) {
+       y->left = z->left;
+       y->right = z->right;
+       y->parent = z->parent;
+       y->color = z->color;
+       z->left->parent = z->right->parent = y;
+       if (z == z->parent->left)
+           z->parent->left = y; 
+       else
+           z->parent->right = y;
+    }
+    free(z); 
+    
+    return (data);
+}
+
+/*
+ * Repair the tree after a node has been deleted by rotating and repainting
+ * colors to restore the 4 properties inherent in red-black trees.
+ */
+static void
+rbrepair(tree, node)
+    struct rbtree *tree;
+    struct rbnode *node;
+{
+    struct rbnode *sibling;
+
+    while (node->color == black) {
+       if (node == node->parent->left) {
+           sibling = node->parent->right;
+           if (sibling->color == red) {
+               sibling->color = black;
+               node->parent->color = red;
+               rotate_left(tree, node->parent);
+               sibling = node->parent->right;
+           }
+           if (sibling->right->color == black && sibling->left->color == black) {
+               sibling->color = red;
+               node = node->parent;
+           } else {
+               if (sibling->right->color == black) {
+                     sibling->left->color = black;
+                     sibling->color = red;
+                     rotate_right(tree, sibling);
+                     sibling = node->parent->right;
+               }
+               sibling->color = node->parent->color;
+               node->parent->color = black;
+               sibling->right->color = black;
+               rotate_left(tree, node->parent);
+               break;
+           }
+       } else { /* if (node == node->parent->right) */
+           sibling = node->parent->left;
+           if (sibling->color == red) {
+               sibling->color = black;
+               node->parent->color = red;
+               rotate_right(tree, node->parent);
+               sibling = node->parent->left;
+           }
+           if (sibling->right->color == black && sibling->left->color == black) {
+               sibling->color = red;
+               node = node->parent;
+           } else {
+               if (sibling->left->color == black) {
+                   sibling->right->color = black;
+                   sibling->color = red;
+                   rotate_left(tree, sibling);
+                   sibling = node->parent->left;
+               }
+               sibling->color = node->parent->color;
+               node->parent->color = black;
+               sibling->left->color = black;
+               rotate_right(tree, node->parent);
+               break;
+           }
+       }
+    }
+}
diff --git a/redblack.h b/redblack.h
new file mode 100644 (file)
index 0000000..8c7ead7
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2004, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Sudo: redblack.h,v 1.4 2008/11/09 14:13:12 millert Exp $
+ */
+
+#ifndef _SUDO_REDBLACK_H
+#define _SUDO_REDBLACK_H
+
+enum rbcolor {
+    red,
+    black
+};
+
+enum rbtraversal {
+    preorder,
+    inorder,
+    postorder
+};
+
+struct rbnode {
+    struct rbnode *left, *right, *parent;
+    void *data;
+    enum rbcolor color;
+};
+
+struct rbtree {
+    int (*compar) __P((const void *, const void *));
+    struct rbnode root;
+    struct rbnode nil;
+};
+
+#define rbapply(t, f, c, o)    rbapply_node((t), (t)->root.left, (f), (c), (o))
+#define rbisempty(t)           ((t)->root.left == &(t)->nil && (t)->root.right == &(t)->nil)
+#define rbfirst(t)             ((t)->root.left)
+#define rbroot(t)              (&(t)->root)
+#define rbnil(t)               (&(t)->nil)
+
+void *rbdelete                 __P((struct rbtree *, struct rbnode *));
+int rbapply_node               __P((struct rbtree *, struct rbnode *,
+                                   int (*)(void *, void *), void *,
+                                   enum rbtraversal));
+struct rbnode *rbfind          __P((struct rbtree *, void *));
+struct rbnode *rbinsert                __P((struct rbtree *, void *));
+struct rbtree *rbcreate                __P((int (*)(const void *, const void *)));
+void rbdestroy                 __P((struct rbtree *, void (*)(void *)));
+
+#endif /* _SUDO_REDBLACK_H */
index 603fdede6be946d9155a125f3ce95ea923bb879f..b603a84ee1c34bce9cd2bfadbd87672a4e4aadab 100644 (file)
@@ -5,7 +5,9 @@
 #
 #   There are two basic ways to configure PAM, either via pam_stack
 #   or by explicitly specifying the various methods to use.
-#   
+#
+# $Sudo: sample.pam,v 1.3 2004/10/01 14:58:15 millert Exp $
+#
 # Here we use pam_stack
 auth       required    pam_stack.so service=system-auth
 account    required    pam_stack.so service=system-auth
index 06823019b23585cb609ea3e506d5845245e39446..220df7fa8da9f78b35b53c182703904df5cfe615 100644 (file)
@@ -5,6 +5,17 @@
 #
 # See the sudoers man page for the details on how to write a sudoers file.
 #
+# $Sudo: sample.sudoers,v 1.29 2008/10/03 19:55:57 millert Exp $
+
+##
+# Override built-in defaults
+##
+Defaults               syslog=auth
+Defaults>root          !set_logname
+Defaults:FULLTIMERS    !lecture
+Defaults:millert       !authenticate
+Defaults@SERVERS       log_year, logfile=/var/log/sudo.log
+Defaults!PAGERS                noexec
 
 ##
 # User alias specification
@@ -47,15 +58,7 @@ Cmnd_Alias   SHELLS = /sbin/sh, /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \
 Cmnd_Alias     SU = /usr/bin/su
 Cmnd_Alias     VIPW = /usr/sbin/vipw, /usr/bin/passwd, /usr/bin/chsh, \
                       /usr/bin/chfn
-
-##
-# Override built-in defaults
-##
-Defaults               syslog=auth
-Defaults>root          !set_logname
-Defaults:FULLTIMERS    !lecture
-Defaults:millert       !authenticate
-Defaults@SERVERS       log_year, logfile=/var/log/sudo.log
+Cmnd_Alias     PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less
 
 ##
 # User specification
@@ -85,7 +88,7 @@ operator      ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\
 joe            ALL = /usr/bin/su operator
 
 # pete may change passwords for anyone but root on the hp snakes
-pete           HPPA = /usr/bin/passwd [A-z]*, !/usr/bin/passwd root
+pete           HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root
 
 # bob may run anything on the sparc and sgi machines as any user
 # listed in the Runas_Alias "OP" (ie: root and operator)
index 2effbab72aad76e385191006a4eb2ed87da5e4e8..90e2c61ef0be93967513176949ec9970dc10211f 100644 (file)
@@ -16,6 +16,8 @@
 #      Syslogd will not create new log files for you, you must first
 #      create the file before syslogd will log to it.  Eg.
 #      'touch /var/log/sudo'
+#
+# $Sudo: sample.syslog.conf,v 1.3 2004/10/01 14:58:15 millert Exp $
 
 # This logs successful and failed sudo attempts to the file /var/log/sudo
 local2.debug                                   /var/log/sudo
diff --git a/schema.ActiveDirectory b/schema.ActiveDirectory
new file mode 100644 (file)
index 0000000..60f70bc
--- /dev/null
@@ -0,0 +1,172 @@
+#
+# Active Directory Schema for sudo configuration (sudoers)
+#
+# To extend your Active Directory schema, run the following command
+# on your Windows DC:
+#
+#  ldifde -i -f schema.ActiveDirectory -c dc=X dc=YOURDOMAIN,DC=COM
+#
+
+dn: CN=sudoUser,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoUser
+distinguishedName: CN=sudoUser,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.1
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoUser
+adminDescription: User(s) who may run sudo
+oMSyntax: 22
+searchFlags: 1
+lDAPDisplayName: sudoUser
+name: sudoUser
+schemaIDGUID:: JrGcaKpnoU+0s+HgeFjAbg==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoHost,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoHost
+distinguishedName: CN=sudoHost,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.2
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoHost
+adminDescription: Host(s) who may run sudo
+oMSyntax: 22
+lDAPDisplayName: sudoHost
+name: sudoHost
+schemaIDGUID:: d0TTjg+Y6U28g/Y+ns2k4w==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoCommand,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoCommand
+distinguishedName: CN=sudoCommand,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.3
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoCommand
+adminDescription: Command(s) to be executed by sudo
+oMSyntax: 22
+lDAPDisplayName: sudoCommand
+name: sudoCommand
+schemaIDGUID:: D6QR4P5UyUen3RGYJCHCPg==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoRunAs,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoRunAs
+distinguishedName: CN=sudoRunAs,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.4
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoRunAs
+adminDescription: User(s) impersonated by sudo (deprecated)
+oMSyntax: 22
+lDAPDisplayName: sudoRunAs
+name: sudoRunAs
+schemaIDGUID:: CP98mCQTyUKKxGrQeM80hQ==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoOption,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoOption
+distinguishedName: CN=sudoOption,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.5
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoOption
+adminDescription: Option(s) followed by sudo
+oMSyntax: 22
+lDAPDisplayName: sudoOption
+name: sudoOption
+schemaIDGUID:: ojaPzBBlAEmsvrHxQctLnA==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoRunAsUser,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoRunAsUser
+distinguishedName: CN=sudoRunAsUser,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.6
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoRunAsUser
+adminDescription: User(s) impersonated by sudo
+oMSyntax: 22
+lDAPDisplayName: sudoRunAsUser
+name: sudoRunAsUser
+schemaIDGUID:: 9C52yPYd3RG3jMR2VtiVkw==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoRunAsGroup
+distinguishedName: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.7
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoRunAsGroup
+adminDescription: Groups(s) impersonated by sudo
+oMSyntax: 22
+lDAPDisplayName: sudoRunAsGroup
+name: sudoRunAsGroup
+schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoRole,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: classSchema
+cn: sudoRole
+distinguishedName: CN=sudoRole,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+possSuperiors: container
+possSuperiors: top
+subClassOf: top
+governsID: 1.3.6.1.4.1.15953.9.2.1
+mayContain: sudoCommand
+mayContain: sudoHost
+mayContain: sudoOption
+mayContain: sudoRunAs
+mayContain: sudoRunAsUser
+mayContain: sudoRunAsGroup
+mayContain: sudoUser
+rDNAttID: cn
+showInAdvancedViewOnly: FALSE
+adminDisplayName: sudoRole
+adminDescription: Sudoer Entries
+objectClassCategory: 1
+lDAPDisplayName: sudoRole
+name: sudoRole
+schemaIDGUID:: SQn432lnZ0+ukbdh3+gN3w==
+systemOnly: FALSE
+objectCategory: CN=Class-Schema,CN=Schema,CN=Configuration,DC=X
+defaultObjectCategory: CN=sudoRole,CN=Schema,CN=Configuration,DC=X
index 3e2e6550f874863f2b8230ed92cf4b47a4fdeec7..df3fc0fab6546574cdf5c871fdaa8a19e222edb1 100644 (file)
@@ -25,7 +25,7 @@ attributetype ( 1.3.6.1.4.1.15953.9.1.3
 
 attributetype ( 1.3.6.1.4.1.15953.9.1.4
     NAME 'sudoRunAs'
-    DESC 'User(s) impersonated by sudo'
+    DESC 'User(s) impersonated by sudo (deprecated)'
     EQUALITY caseExactIA5Match
     SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
 
@@ -35,9 +35,21 @@ attributetype ( 1.3.6.1.4.1.15953.9.1.5
     EQUALITY caseExactIA5Match
     SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
 
+attributetype ( 1.3.6.1.4.1.15953.9.1.6
+    NAME 'sudoRunAsUser'
+    DESC 'User(s) impersonated by sudo'
+    EQUALITY caseExactIA5Match
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.7
+    NAME 'sudoRunAsGroup'
+    DESC 'Group(s) impersonated by sudo'
+    EQUALITY caseExactIA5Match
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
 objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL
     DESC 'Sudoer Entries'
     MUST ( cn )
-    MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoOption $
+    MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $
            description )
     )
index 879c2e967045beb3b01b290f811382d186cf6dd9..3718fd7fa7882d789f753186dbc6ba92393d4450 100644 (file)
@@ -2,6 +2,8 @@ dn: cn=schema
 attributeTypes: ( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s) who may  run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' )
 attributeTypes: ( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' )
 attributeTypes: ( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Command(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' )
-attributeTypes: ( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s) impersonated by sudo (deprecated)' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' )
 attributeTypes: ( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Options(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' )
-objectClasses: ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL DESC 'Sudoer Entries' MUST ( cn ) MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoOption $ description ) X-ORIGIN 'SUDO' )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'User(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Group(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' )
+objectClasses: ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL DESC 'Sudoer Entries' MUST ( cn ) MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ description ) X-ORIGIN 'SUDO' )
index 7d498549558f77c31a625a196527ad3672986ff2..05ac1a06667eae96ecc6084a4834c4df5589b220 100644 (file)
--- a/selinux.c
+++ b/selinux.c
@@ -32,7 +32,6 @@
 #include <stddef.h>
 #include <string.h>
 #include <unistd.h>
-#include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
@@ -50,7 +49,7 @@
 #include "pathnames.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: selinux.c,v 1.2.2.4 2008/02/22 20:33:10 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: selinux.c,v 1.5 2008/02/22 20:33:00 millert Exp $";
 #endif /* lint */
 
 /*
@@ -77,17 +76,17 @@ restore_tty_label(int fd, const char *ttyn, security_context_t tty_context,
 
     /* Verify that the tty still has the context set by sudo. */
     if ((rc = fgetfilecon(fd, &chk_tty_context)) < 0) {
-           warn("unable to fgetfilecon %s", ttyn);
+           warning("unable to fgetfilecon %s", ttyn);
            goto skip_relabel;
     }
 
     if ((rc = strcmp(chk_tty_context, new_tty_context))) {
-           warnx("%s changed labels.", ttyn);
+           warningx("%s changed labels.", ttyn);
            goto skip_relabel;
     }
 
     if ((rc = fsetfilecon(fd, tty_context)) < 0)
-       warn("unable to restore context for %s", ttyn);
+       warning("unable to restore context for %s", ttyn);
 
 skip_relabel:
     freecon(chk_tty_context);
@@ -117,13 +116,13 @@ relabel_tty(const char *ttyn, security_context_t new_context,
     /* Re-open TTY descriptor */
     fd = open(ttyn, O_RDWR | O_NONBLOCK);
     if (fd == -1) {
-       warn("unable to open %s", ttyn);
+       warning("unable to open %s", ttyn);
        return(-1);
     }
     (void)fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
 
     if (fgetfilecon(fd, &tty_con) < 0) {
-       warn("unable to get current context for %s, not relabeling tty",
+       warning("unable to get current context for %s, not relabeling tty",
            ttyn);
        if (enforcing)
            goto error;
@@ -131,14 +130,14 @@ relabel_tty(const char *ttyn, security_context_t new_context,
 
     if (tty_con && (security_compute_relabel(new_context, tty_con,
        SECCLASS_CHR_FILE, &new_tty_con) < 0)) {
-       warn("unable to get new context for %s, not relabeling tty", ttyn);
+       warning("unable to get new context for %s, not relabeling tty", ttyn);
        if (enforcing)
            goto error;
     }
 
     if (new_tty_con != NULL) {
        if (fsetfilecon(fd, new_tty_con) < 0) {
-           warn("unable to set new context for %s", ttyn);
+           warning("unable to set new context for %s", ttyn);
            if (enforcing)
                goto error;
        }
@@ -167,12 +166,12 @@ get_exec_context(security_context_t old_context, char *role, char *type)
     
     /* We must have a role, the type is optional (we can use the default). */
     if (!role) {
-       warnx("you must specify a role.");
+       warningx("you must specify a role.");
        return(NULL);
     }
     if (!type) {
        if (get_default_type(role, &typebuf)) {
-           warnx("unable to get default type");
+           warningx("unable to get default type");
            return(NULL);
        }
        type = typebuf;
@@ -189,11 +188,11 @@ get_exec_context(security_context_t old_context, char *role, char *type)
      * type we will be running the command as.
      */
     if (context_role_set(context, role)) {
-       warnx("failed to set new role %s", role);
+       warningx("failed to set new role %s", role);
        goto error;
     }
     if (context_type_set(context, type)) {
-       warnx("failed to set new type %s", type);
+       warningx("failed to set new type %s", type);
        goto error;
     }
       
@@ -202,12 +201,12 @@ get_exec_context(security_context_t old_context, char *role, char *type)
      */
     new_context = estrdup(context_str(context));
     if (security_check_context(new_context) < 0) {
-       warnx("%s is not a valid context", new_context);
+       warningx("%s is not a valid context", new_context);
        goto error;
     }
 
 #ifdef DEBUG
-    warnx("Your new context is %s", new_context);
+    warningx("Your new context is %s", new_context);
 #endif
 
     context_free(context);
@@ -227,7 +226,7 @@ error:
  * will simply execute the command pass to it on the command line.
  */
 void
-selinux_exec(char *role, char *type, char **argv, char **envp, int login_shell)
+selinux_exec(char *role, char *type, char **argv, int login_shell)
 {
     security_context_t old_context = NULL;
     security_context_t new_context = NULL;
@@ -238,19 +237,19 @@ selinux_exec(char *role, char *type, char **argv, char **envp, int login_shell)
 
     /* Must have a tty. */
     if (user_ttypath == NULL || *user_ttypath == '\0')
-       err(EXIT_FAILURE, "unable to determine tty");
+       error(EXIT_FAILURE, "unable to determine tty");
 
     /* Store the caller's SID in old_context. */
     if (getprevcon(&old_context))
-       err(EXIT_FAILURE, "failed to get old_context");
+       error(EXIT_FAILURE, "failed to get old_context");
 
     enforcing = security_getenforce();
     if (enforcing < 0)
-       err(EXIT_FAILURE, "unable to determine enforcing mode.");
+       error(EXIT_FAILURE, "unable to determine enforcing mode.");
 
     
 #ifdef DEBUG
-    warnx("your old context was %s", old_context);
+    warningx("your old context was %s", old_context);
 #endif
     new_context = get_exec_context(old_context, role, type);
     if (!new_context)
@@ -259,19 +258,19 @@ selinux_exec(char *role, char *type, char **argv, char **envp, int login_shell)
     ttyfd = relabel_tty(user_ttypath, new_context, &tty_context,
        &new_tty_context, enforcing);
     if (ttyfd < 0)
-       err(EXIT_FAILURE, "unable to setup tty context for %s", new_context);
+       error(EXIT_FAILURE, "unable to setup tty context for %s", new_context);
 
 #ifdef DEBUG
-    warnx("your old tty context is %s", tty_context);
-    warnx("your new tty context is %s", new_tty_context);
+    warningx("your old tty context is %s", tty_context);
+    warningx("your new tty context is %s", new_tty_context);
 #endif
 
     childPid = fork();
     if (childPid < 0) {
        /* fork failed, no child to worry about */
-       warn("unable to fork");
+       warning("unable to fork");
        if (restore_tty_label(ttyfd, user_ttypath, tty_context, new_tty_context))
-           warnx("unable to restore tty label");
+           warningx("unable to restore tty label");
        exit(EXIT_FAILURE);
     } else if (childPid) {
        pid_t pid;
@@ -283,10 +282,10 @@ selinux_exec(char *role, char *type, char **argv, char **envp, int login_shell)
        } while (pid == -1 && errno == EINTR);
 
        if (pid == -1)
-           err(EXIT_FAILURE, "waitpid");
+           error(EXIT_FAILURE, "waitpid");
        
        if (restore_tty_label(ttyfd, user_ttypath, tty_context, new_tty_context))
-           errx(EXIT_FAILURE, "unable to restore tty label");
+           errorx(EXIT_FAILURE, "unable to restore tty label");
 
        /* Preserve child exit status. */
        if (WIFEXITED(status))
@@ -297,7 +296,7 @@ selinux_exec(char *role, char *type, char **argv, char **envp, int login_shell)
     /* Close the tty and reopen descriptors 0 through 2 */
     if (close(ttyfd) || close(STDIN_FILENO) || close(STDOUT_FILENO) ||
        close(STDERR_FILENO)) {
-       warn("could not close descriptors");
+       warning("could not close descriptors");
        goto error;
     }
     ttyfd = open(user_ttypath, O_RDONLY | O_NONBLOCK);
@@ -313,13 +312,13 @@ selinux_exec(char *role, char *type, char **argv, char **envp, int login_shell)
        goto error;
 
     if (setexeccon(new_context)) {
-       warn("unable to set exec context to %s", new_context);
+       warning("unable to set exec context to %s", new_context);
        if (enforcing)
            goto error;
     }
 
     if (setkeycreatecon(new_context)) {
-       warn("unable to set key creation context to %s", new_context);
+       warning("unable to set key creation context to %s", new_context);
        if (enforcing)
            goto error;
     }
@@ -334,8 +333,8 @@ selinux_exec(char *role, char *type, char **argv, char **envp, int login_shell)
     argv[0] = login_shell ? "-sesh" : "sesh";
     argv[1] = safe_cmnd;
 
-    execve(_PATH_SUDO_SESH, argv, envp);
-    warn("%s", safe_cmnd);
+    execv(_PATH_SUDO_SESH, argv);
+    warning("%s", safe_cmnd);
 
 error:
     _exit(EXIT_FAILURE);
diff --git a/sesh.c b/sesh.c
index 06728d4995a6061bd2b058b2ce8c9fe027ca2042..715980e933eceb211379a89edf4ae677c02aab8e 100644 (file)
--- a/sesh.c
+++ b/sesh.c
@@ -30,7 +30,7 @@
 #include "compat.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: sesh.c,v 1.1.2.1 2008/02/09 14:44:49 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: sesh.c,v 1.1 2008/02/09 14:30:06 millert Exp $";
 #endif /* lint */
 
 int
index 77c68e986af22a499c258e19d5d695ae27905568..bc88a844de35233e3bc434687bd9c4ce8f047c8b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994-1996,1998-2006 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1994-1996,1998-2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <pwd.h>
 #include <errno.h>
 #include <grp.h>
@@ -57,7 +52,7 @@
 #include "sudo.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: set_perms.c,v 1.30.2.7 2007/11/27 23:41:23 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: set_perms.c,v 1.44 2008/03/06 17:19:56 millert Exp $";
 #endif /* lint */
 
 #ifdef __TANDEM
@@ -86,13 +81,17 @@ void
 set_perms(perm)
     int perm;
 {
+    const char *errstr;
+
     if (perm == current_perm)
        return;
 
     switch (perm) {
        case PERM_ROOT:
-                               if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID))
-                                   errx(1, "setresuid(ROOT_UID, ROOT_UID, ROOT_UID) failed, your operating system may have a broken setresuid() function\nTry running configure with --disable-setresuid");
+                               if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID)) {
+                                   errstr = "setresuid(ROOT_UID, ROOT_UID, ROOT_UID)";
+                                   goto bad;
+                               }
                                (void) setresgid(-1, user_gid, -1);
                                if (current_perm == PERM_RUNAS)
                                    restore_groups();
@@ -100,22 +99,30 @@ set_perms(perm)
 
        case PERM_USER:
                                (void) setresgid(-1, user_gid, -1);
-                               if (setresuid(user_uid, user_uid, ROOT_UID))
-                                   err(1, "setresuid(user_uid, user_uid, ROOT_UID)");
+                               if (setresuid(user_uid, user_uid, ROOT_UID)) {
+                                   errstr = "setresuid(user_uid, user_uid, ROOT_UID)";
+                                   goto bad;
+                               }
                                break;
                                
        case PERM_FULL_USER:
                                /* headed for exec() */
                                (void) setgid(user_gid);
-                               if (setresuid(user_uid, user_uid, user_uid))
-                                   err(1, "setresuid(user_uid, user_uid, user_uid)");
+                               if (setresuid(user_uid, user_uid, user_uid)) {
+                                   errstr = "setresuid(user_uid, user_uid, user_uid)";
+                                   goto bad;
+                               }
                                break;
                                
        case PERM_RUNAS:
                                runas_setgroups();
-                               (void) setresgid(-1, runas_pw->pw_gid, -1);
-                               if (setresuid(-1, runas_pw->pw_uid, -1))
-                                   err(1, "unable to change to runas uid");
+                               (void) setresgid(-1, runas_gr ?
+                                   runas_gr->gr_gid : runas_pw->pw_gid, -1);
+                               if (setresuid(-1, runas_pw ? runas_pw->pw_uid :
+                                   user_uid, -1)) {
+                                   errstr = "unable to change to runas uid";
+                                   goto bad;
+                               }
                                break;
 
        case PERM_FULL_RUNAS:
@@ -123,14 +130,16 @@ set_perms(perm)
                                runas_setup();
                                if (setresuid(def_stay_setuid ?
                                    user_uid : runas_pw->pw_uid,
-                                   runas_pw->pw_uid, runas_pw->pw_uid))
-                                   err(1, "unable to change to runas uid");
+                                   runas_pw->pw_uid, runas_pw->pw_uid)) {
+                                   errstr = "unable to change to runas uid";
+                                   goto bad;
+                               }
                                break;
 
        case PERM_SUDOERS:
                                /* assume euid == ROOT_UID, ruid == user */
                                if (setresgid(-1, SUDOERS_GID, -1))
-                                   err(1, "unable to change to sudoers gid");
+                                   error(1, "unable to change to sudoers gid");
 
                                /*
                                 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
@@ -140,20 +149,30 @@ set_perms(perm)
                                 * work on all OS's.
                                 */
                                if (SUDOERS_UID == ROOT_UID) {
-                                   if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID))
-                                       err(1, "setresuid(ROOT_UID, 1, ROOT_UID)");
+                                   if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID)) {
+                                       errstr = "setresuid(ROOT_UID, 1, ROOT_UID)";
+                                       goto bad;
+                                   }
                                } else {
-                                   if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID))
-                                       err(1, "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)");
+                                   if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)) {
+                                       errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)";
+                                       goto bad;
+                                   }
                                }
                                break;
        case PERM_TIMESTAMP:
-                               if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID))
-                                   err(1, "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)");
+                               if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID)) {
+                                   errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)";
+                                   goto bad;
+                               }
                                break;
     }
 
     current_perm = perm;
+    return;
+bad:
+    errorx(1, "%s: %s", errstr,
+       errno == EAGAIN ? "too many processes" : strerror(errno));
 }
 
 #else
@@ -169,15 +188,21 @@ void
 set_perms(perm)
     int perm;
 {
+    const char *errstr;
+
     if (perm == current_perm)
        return;
 
     switch (perm) {
        case PERM_ROOT:
-                               if (setreuid(-1, ROOT_UID))
-                                   errx(1, "setreuid(-1, ROOT_UID) failed, your operating system may have a broken setreuid() function\nTry running configure with --disable-setreuid");
-                               if (setuid(ROOT_UID))
-                                   err(1, "setuid(ROOT_UID)");
+                               if (setreuid(-1, ROOT_UID)) {
+                                   errstr = "setreuid(-1, ROOT_UID)";
+                                   goto bad;
+                               }
+                               if (setuid(ROOT_UID)) {
+                                   errstr = "setuid(ROOT_UID)";
+                                   goto bad;
+                               }
                                (void) setregid(-1, user_gid);
                                if (current_perm == PERM_RUNAS)
                                    restore_groups();
@@ -185,36 +210,46 @@ set_perms(perm)
 
        case PERM_USER:
                                (void) setregid(-1, user_gid);
-                               if (setreuid(ROOT_UID, user_uid))
-                                   err(1, "setreuid(ROOT_UID, user_uid)");
+                               if (setreuid(ROOT_UID, user_uid)) {
+                                   errstr = "setreuid(ROOT_UID, user_uid)";
+                                   goto bad;
+                               }
                                break;
                                
        case PERM_FULL_USER:
                                /* headed for exec() */
                                (void) setgid(user_gid);
-                               if (setreuid(user_uid, user_uid))
-                                   err(1, "setreuid(user_uid, user_uid)");
+                               if (setreuid(user_uid, user_uid)) {
+                                   errstr = "setreuid(user_uid, user_uid)";
+                                   goto bad;
+                               }
                                break;
                                
        case PERM_RUNAS:
                                runas_setgroups();
-                               (void) setregid(-1, runas_pw->pw_gid);
-                               if (setreuid(-1, runas_pw->pw_uid))
-                                   err(1, "unable to change to runas uid");
+                               (void) setregid(-1, runas_gr ?
+                                   runas_gr->gr_gid : runas_pw->pw_gid);
+                               if (setreuid(-1,
+                                   runas_pw ? runas_pw->pw_uid : user_uid)) {
+                                   errstr = "unable to change to runas uid";
+                                   goto bad;
+                               }
                                break;
 
        case PERM_FULL_RUNAS:
                                /* headed for exec(), assume euid == ROOT_UID */
                                runas_setup();
                                if (setreuid(def_stay_setuid ? user_uid :
-                                   runas_pw->pw_uid, runas_pw->pw_uid))
-                                   err(1, "unable to change to runas uid");
+                                   runas_pw->pw_uid, runas_pw->pw_uid)) {
+                                   errstr = "unable to change to runas uid";
+                                   goto bad;
+                               }
                                break;
 
        case PERM_SUDOERS:
                                /* assume euid == ROOT_UID, ruid == user */
                                if (setregid(-1, SUDOERS_GID))
-                                   err(1, "unable to change to sudoers gid");
+                                   error(1, "unable to change to sudoers gid");
 
                                /*
                                 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
@@ -224,20 +259,30 @@ set_perms(perm)
                                 * work on all OS's.
                                 */
                                if (SUDOERS_UID == ROOT_UID) {
-                                   if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1))
-                                       err(1, "setreuid(ROOT_UID, 1)");
+                                   if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1)) {
+                                       errstr = "setreuid(ROOT_UID, 1)";
+                                       goto bad;
+                                   }
                                } else {
-                                   if (setreuid(ROOT_UID, SUDOERS_UID))
-                                       err(1, "setreuid(ROOT_UID, SUDOERS_UID)");
+                                   if (setreuid(ROOT_UID, SUDOERS_UID)) {
+                                       errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
+                                       goto bad;
+                                   }
                                }
                                break;
        case PERM_TIMESTAMP:
-                               if (setreuid(ROOT_UID, timestamp_uid))
-                                   err(1, "setreuid(ROOT_UID, timestamp_uid)");
+                               if (setreuid(ROOT_UID, timestamp_uid)) {
+                                   errstr = "setreuid(ROOT_UID, timestamp_uid)";
+                                   goto bad;
+                               }
                                break;
     }
 
     current_perm = perm;
+    return;
+bad:
+    errorx(1, "%s: %s", errstr,
+       errno == EAGAIN ? "too many processes" : strerror(errno));
 }
 
 # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
@@ -251,6 +296,8 @@ void
 set_perms(perm)
     int perm;
 {
+    const char *errstr;
+
     if (perm == current_perm)
        return;
 
@@ -259,10 +306,14 @@ set_perms(perm)
      * for these calls differ on various systems, we set
      * real and effective uids to ROOT_UID initially to be safe.
      */
-    if (seteuid(ROOT_UID))
-       err(1, "seteuid(ROOT_UID)");
-    if (setuid(ROOT_UID))
-       err(1, "setuid(ROOT_UID)");
+    if (seteuid(ROOT_UID)) {
+       errstr = "seteuid(ROOT_UID)";
+       goto bad;
+    }
+    if (setuid(ROOT_UID)) {
+       errstr = "setuid(ROOT_UID)";
+       goto bad;
+    }
 
     switch (perm) {
        case PERM_ROOT:
@@ -274,34 +325,43 @@ set_perms(perm)
 
        case PERM_USER:
                                (void) setegid(user_gid);
-                               if (seteuid(user_uid))
-                                   err(1, "seteuid(user_uid)");
+                               if (seteuid(user_uid)) {
+                                   errstr = "seteuid(user_uid)";
+                                   goto bad;
+                               }
                                break;
                                
        case PERM_FULL_USER:
                                /* headed for exec() */
                                (void) setgid(user_gid);
-                               if (setuid(user_uid))
-                                   err(1, "setuid(user_uid)");
+                               if (setuid(user_uid)) {
+                                   errstr = "setuid(user_uid)";
+                                   goto bad;
+                               }
                                break;
                                
        case PERM_RUNAS:
                                runas_setgroups();
-                               (void) setegid(runas_pw->pw_gid);
-                               if (seteuid(runas_pw->pw_uid))
-                                   err(1, "unable to change to runas uid");
+                               (void) setegid(runas_gr ?
+                                   runas_gr->gr_gid : runas_pw->pw_gid);
+                               if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid)) {
+                                   errstr = "unable to change to runas uid";
+                                   goto bad;
+                               }
                                break;
 
        case PERM_FULL_RUNAS:
                                /* headed for exec() */
                                runas_setup();
-                               if (setuid(runas_pw->pw_uid))
-                                   err(1, "unable to change to runas uid");
+                               if (setuid(runas_pw->pw_uid)) {
+                                   errstr = "unable to change to runas uid";
+                                   goto bad;
+                               }
                                break;
 
        case PERM_SUDOERS:
                                if (setegid(SUDOERS_GID))
-                                   err(1, "unable to change to sudoers gid");
+                                   error(1, "unable to change to sudoers gid");
 
                                /*
                                 * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
@@ -311,20 +371,30 @@ set_perms(perm)
                                 * work on all OS's.
                                 */
                                if (SUDOERS_UID == ROOT_UID) {
-                                   if ((SUDOERS_MODE & 040) && seteuid(1))
-                                       err(1, "seteuid(1)");
+                                   if ((SUDOERS_MODE & 040) && seteuid(1)) {
+                                       errstr = "seteuid(1)";
+                                       goto bad;
+                                   }
                                } else {
-                                   if (seteuid(SUDOERS_UID))
-                                       err(1, "seteuid(SUDOERS_UID)");
+                                   if (seteuid(SUDOERS_UID)) {
+                                       errstr = "seteuid(SUDOERS_UID)";
+                                       goto bad;
+                                   }
                                }
                                break;
        case PERM_TIMESTAMP:
-                               if (seteuid(timestamp_uid))
-                                   err(1, "seteuid(timestamp_uid)");
+                               if (seteuid(timestamp_uid)) {
+                                   errstr = "seteuid(timestamp_uid)";
+                                   goto bad;
+                               }
                                break;
     }
 
     current_perm = perm;
+    return;
+bad:
+    errorx(1, "%s: %s", errstr,
+       errno == EAGAIN ? "too many processes" : strerror(errno));
 }
 
 # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
@@ -338,27 +408,35 @@ void
 set_perms(perm)
     int perm;
 {
+    const char *errstr;
+
     if (perm == current_perm)
        return;
 
     switch (perm) {
        case PERM_ROOT:
-                               if (setuid(ROOT_UID))
-                                       err(1, "setuid(ROOT_UID)");
+                               if (setuid(ROOT_UID)) {
+                                   errstr = "setuid(ROOT_UID)";
+                                   goto bad;
+                               }
                                if (current_perm == PERM_RUNAS)
                                    restore_groups();
                                break;
 
        case PERM_FULL_USER:
                                (void) setgid(user_gid);
-                               if (setuid(user_uid))
-                                   err(1, "setuid(user_uid)");
+                               if (setuid(user_uid)) {
+                                   errstr = "setuid(user_uid)";
+                                   goto bad;
+                               }
                                break;
                                
        case PERM_FULL_RUNAS:
                                runas_setup();
-                               if (setuid(runas_pw->pw_uid))
-                                   err(1, "unable to change to runas uid");
+                               if (setuid(runas_pw->pw_uid)) {
+                                   errstr = "unable to change to runas uid";
+                                   goto bad;
+                               }
                                break;
 
        case PERM_USER:
@@ -370,6 +448,10 @@ set_perms(perm)
     }
 
     current_perm = perm;
+    return;
+bad:
+    errorx(1, "%s: %s", errstr,
+       errno == EAGAIN ? "too many processes" : strerror(errno));
 }
 #  endif /* HAVE_SETEUID */
 # endif /* HAVE_SETREUID */
@@ -430,12 +512,17 @@ restore_groups()
 static void
 runas_setup()
 {
+    gid_t gid;
 #ifdef HAVE_LOGIN_CAP_H
     int flags;
     extern login_cap_t *lc;
 #endif
 
     if (runas_pw->pw_name != NULL) {
+       gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
+#ifdef HAVE_GETUSERATTR
+       aix_setlimits(runas_pw->pw_name);
+#endif
 #ifdef HAVE_PAM
        pam_prep_user(runas_pw);
 #endif /* HAVE_PAM */
@@ -448,20 +535,20 @@ runas_setup()
            flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
            if (!def_preserve_groups)
                SET(flags, LOGIN_SETGROUP);
-           else if (setgid(runas_pw->pw_gid))
-               warn("cannot set gid to runas gid");
+           else if (setgid(gid))
+               warning("cannot set gid to runas gid");
            if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
                if (runas_pw->pw_uid != ROOT_UID)
-                   err(1, "unable to set user context");
+                   error(1, "unable to set user context");
                else
-                   warn("unable to set user context");
+                   warning("unable to set user context");
            }
        }
 #endif /* HAVE_LOGIN_CAP_H */
-       if (setgid(runas_pw->pw_gid))
-           warn("cannot set gid to runas gid");
+       if (setgid(gid))
+           warning("cannot set gid to runas gid");
        /*
-        * Initialize group vector unless asked not to.
+        * Initialize group vector
         */
        runas_setgroups();
     }
index d334ebf186b3fcb80ca9fcbb4d7046beb6fc489e..3af91c5e67583b300895aa5d2881c4ced67ca8e6 100644 (file)
@@ -24,7 +24,7 @@
 #include <compat.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: sigaction.c,v 1.5.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: sigaction.c,v 1.7 2005/02/12 22:56:06 millert Exp $";
 #endif /* lint */
 
 int
index 4b7b2b52f3ae5c8d2af122b8c95462b17d92a98d..e9410c0d50ecf21f40785345de2e47afef9b70a1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005, 2008 Todd C. Miller <Todd.Miller@courtesan.com>
  * Copyright (c) 1990, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
@@ -52,6 +52,9 @@
 #  include <stdlib.h>
 # endif
 #endif /* STDC_HEADERS */
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
 #ifdef HAVE_STRING_H
 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
 #  include <memory.h>
@@ -76,7 +79,7 @@
 #include <compat.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: snprintf.c,v 1.14.4.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: snprintf.c,v 1.22 2008/11/09 14:13:12 millert Exp $";
 #endif /* lint */
 
 static int xxxprintf    __P((char **, size_t, int, const char *, va_list));
@@ -91,18 +94,18 @@ static int xxxprintf         __P((char **, size_t, int, const char *, va_list));
 # define LONG_MAX      (ULONG_MAX / 2)
 #endif
 #ifdef HAVE_LONG_LONG
-# ifndef UQUAD_MAX
-#  ifdef ULONG_LONG_MAX
-#   define UQUAD_MAX   ULONG_LONG_MAX
+# ifndef ULLONG_MAX
+#  ifdef UQUAD_MAX
+#   define ULLONG_MAX  UQUAD_MAX
 #  else
-#   define UQUAD_MAX   ((unsigned long long)-1)
+#   define ULLONG_MAX  ((unsigned long long)-1)
 #  endif
 # endif
-# ifndef QUAD_MAX
-#  ifdef LONG_LONG_MAX
-#   define QUAD_MAX    LONG_LONG_MAX
+# ifndef LLONG_MAX
+#  ifdef QUAD_MAX
+#   define LLONG_MAX   QUAD_MAX
 #  else
-#   define QUAD_MAX    (UQUAD_MAX / 2)
+#   define LLONG_MAX   (ULLONG_MAX / 2)
 #  endif
 # endif
 #endif /* HAVE_LONG_LONG */
@@ -129,9 +132,9 @@ static int xxxprintf         __P((char **, size_t, int, const char *, va_list));
 #define BUF            68
 
 #ifndef HAVE_MEMCHR
-VOID *
+void *
 memchr(s, c, n)
-       const VOID *s;
+       const void *s;
        unsigned char c;
        size_t n;
 {
@@ -140,7 +143,7 @@ memchr(s, c, n)
 
                do {
                        if (*p++ == c)
-                               return ((VOID *)(p - 1));
+                               return ((void *)(p - 1));
                } while (--n != 0);
        }
        return (NULL);
@@ -237,7 +240,7 @@ __uqtoa(val, endp, base, octzero, xdigs)
                        *--cp = to_char(val % 10);
                        return (cp);
                }
-               if (val > QUAD_MAX) {
+               if (val > LLONG_MAX) {
                        *--cp = to_char(val % 10);
                        sval = val / 10;
                } else
@@ -537,7 +540,7 @@ reswitch:   switch (ch) {
                         * defined manner.''
                         *      -- ANSI X3J11
                         */
-                       ulval = (unsigned long)va_arg(ap, VOID *);
+                       ulval = (unsigned long)va_arg(ap, void *);
                        base = 16;
                        xdigs = "0123456789abcdef";
                        flags = (flags & ~QUADINT) | HEXPREFIX;
index a21e80584f508cf8a57d72c08850c91308babce9..fa47bd3d025e71e6336db27966d8e284a552d33d 100644 (file)
@@ -19,7 +19,7 @@
 #include <compat.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: strcasecmp.c,v 1.3.4.2 2007/06/12 16:19:15 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: strcasecmp.c,v 1.7 2005/02/12 22:56:06 millert Exp $";
 #endif /* lint */
 
 /*
index 7a50245e5f14f0b219bf0e3ebb4b1cb8f1fcbc39..1e0267cd313044bb0b571bccbaa81a303d33f101 100644 (file)
@@ -25,7 +25,7 @@
 #include <compat.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: strerror.c,v 1.8.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: strerror.c,v 1.11 2005/02/12 22:56:06 millert Exp $";
 #endif /* lint */
 
 /*
index fefe57b7b378e70247f289d6a2fcbbf035aff702..2084bdd59d2f9b18c2715cbf18e20c8e651697e6 100644 (file)
--- a/strlcat.c
+++ b/strlcat.c
@@ -23,7 +23,7 @@
 #include <compat.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: strlcat.c,v 1.4.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: strlcat.c,v 1.7 2005/02/12 22:56:06 millert Exp $";
 #endif /* lint */
 
 
index d7883c0802f8e1ad329642885088431947f0cb4a..b03316dc377e13f1fefc2d8f166057e9948a7004 100644 (file)
--- a/strlcpy.c
+++ b/strlcpy.c
@@ -22,7 +22,7 @@
 #include <compat.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: strlcpy.c,v 1.4.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: strlcpy.c,v 1.7 2005/02/12 22:56:06 millert Exp $";
 #endif /* lint */
 
 /*
diff --git a/sudo.c b/sudo.c
index 7348fcf43e61200a1f88dd33d4bc45b7325eb55a..7191ee14a68ecfb5f57d02bf3d72557cd4a06856 100644 (file)
--- a/sudo.c
+++ b/sudo.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1993-1996,1998-2007 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1993-1996, 1998-2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <pwd.h>
 #include <errno.h>
 #include <fcntl.h>
 #endif
 
 #include "sudo.h"
+#include "sudo_usage.h"
+#include "lbuf.h"
 #include "interfaces.h"
 #include "version.h"
 
 #ifndef lint
-__unused __unused static const char rcsid[] = "$Sudo: sudo.c,v 1.369.2.41 2008/06/21 19:04:07 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: sudo.c,v 1.500 2008/11/18 15:57:09 millert Exp $";
 #endif /* lint */
 
 /*
  * Prototypes
  */
-static int init_vars                   __P((int, char **));
+static void init_vars                  __P((int, char **));
+static int set_cmnd                    __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 set_project                        __P((struct passwd *));
+static void set_runasgr                        __P((char *));
+static void set_runaspw                        __P((char *));
+static void show_version               __P((void));
 static void usage                      __P((int))
                                            __attribute__((__noreturn__));
 static void usage_excl                 __P((int))
                                            __attribute__((__noreturn__));
-static void usage_excl                 __P((int));
 static struct passwd *get_authpw       __P((void));
 extern int sudo_edit                   __P((int, char **, char **));
-extern void list_matches               __P((void));
-extern char **rebuild_env              __P((char **, int, int));
-extern void validate_env_vars          __P((struct list_member *));
-extern char **insert_env_vars          __P((char **, struct list_member *));
-extern struct passwd *sudo_getpwnam    __P((const char *));
-extern struct passwd *sudo_getpwuid    __P((uid_t));
-extern struct passwd *sudo_pwdup       __P((const struct passwd *));
+extern void rebuild_env                        __P((int, int));
+void validate_env_vars                 __P((struct list_member *));
+void insert_env_vars                   __P((struct list_member *));
 
 /*
  * Globals
@@ -138,14 +133,17 @@ extern struct passwd *sudo_pwdup  __P((const struct passwd *));
 int Argc, NewArgc;
 char **Argv, **NewArgv;
 char *prev_user;
+static int user_closefrom = -1;
 struct sudo_user sudo_user;
-struct passwd *auth_pw;
-FILE *sudoers_fp;
+struct passwd *auth_pw, *list_pw;
 struct interface *interfaces;
 int num_interfaces;
 int tgetpass_flags;
+int long_list;
 uid_t timestamp_uid;
 extern int errorlineno;
+extern int parse_error;
+extern char *errorfile;
 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
 static struct rlimit corelimit;
 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
@@ -156,7 +154,13 @@ login_cap_t *lc;
 char *login_style;
 #endif /* HAVE_BSD_AUTH_H */
 sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
+static char *runas_user;
+static char *runas_group;
+static struct sudo_nss_list *snl;
 
+/* For getopt(3) */
+extern char *optarg;
+extern int optind;
 
 int
 main(argc, argv, envp)
@@ -164,14 +168,14 @@ main(argc, argv, envp)
     char **argv;
     char **envp;
 {
-    int validated;
-    int fd;
-    int cmnd_status;
-    int sudo_mode;
-    int pwflag;
+    int sources = 0, validated;
+    int fd, cmnd_status, sudo_mode, pwflag, rc = 0;
     sigaction_t sa;
-    extern int printmatches;
-    extern char **environ;
+    struct sudo_nss *nss;
+#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
+    extern char *malloc_options;
+    malloc_options = "AFGJPR";
+#endif
 
 #ifdef HAVE_SETLOCALE
     setlocale(LC_ALL, "");
@@ -190,7 +194,7 @@ main(argc, argv, envp)
 #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
 
     if (geteuid() != 0)
-       errx(1, "must be setuid root");
+       errorx(1, "must be setuid root");
 
     /*
      * Signal setup:
@@ -198,6 +202,7 @@ main(argc, argv, envp)
      *  us at some point and avoid the logging.
      *  Install handler to wait for children when they exit.
      */
+    zero_bytes(&sa, sizeof(sa));
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = SA_RESTART;
     sa.sa_handler = SIG_IGN;
@@ -206,10 +211,11 @@ main(argc, argv, envp)
     (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
 
     /*
-     * Turn off core dumps and close open files.
+     * Turn off core dumps and make sure fds 0-2 are open.
      */
     initial_setup();
-    setpwent();
+    sudo_setpwent();
+    sudo_setgrent();
 
     /* Parse our arguments. */
     sudo_mode = parse_args(Argc, Argv);
@@ -228,15 +234,7 @@ main(argc, argv, envp)
     else
        switch (sudo_mode) {
            case MODE_VERSION:
-               (void) printf("Sudo version %s\n", version);
-               if (getuid() == 0) {
-                   putchar('\n');
-                   (void) printf("Sudoers path: %s\n", _PATH_SUDOERS);
-                   dump_auth_methods();
-                   dump_defaults();
-                   dump_interfaces();
-               }
-               exit(0);
+               show_version();
                break;
            case MODE_HELP:
                usage(0);
@@ -257,7 +255,9 @@ main(argc, argv, envp)
            case MODE_LIST:
                user_cmnd = "list";
                pwflag = I_LISTPW;
-               printmatches = 1;
+               break;
+           case MODE_CHECK:
+               pwflag = I_LISTPW;
                break;
        }
 
@@ -265,31 +265,97 @@ main(argc, argv, envp)
     if (user_cmnd == NULL && NewArgc == 0)
        usage(1);
 
-    cmnd_status = init_vars(sudo_mode, environ);
+    init_vars(sudo_mode, envp);                /* XXX - move this later? */
 
-#ifdef HAVE_LDAP
-    validated = sudo_ldap_check(pwflag);
+    /* Parse nsswitch.conf for sudoers order. */
+    snl = sudo_read_nss();
+
+    /* Open and parse sudoers, set global defaults */
+    tq_foreach_fwd(snl, nss) {
+       if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
+           sources++;
+           nss->setdefs(nss);
+       }
+    }
+    if (sources == 0)
+       log_error(0, "no valid sudoers sources found, quitting");
+
+    /* XXX - collect post-sudoers parse settings into a function */
+
+    /*
+     * Set runas passwd/group entries based on command line or sudoers.
+     * Note that if runas_group was specified without runas_user we
+     * defer setting runas_pw so the match routines know to ignore it.
+     */
+    if (runas_group != NULL) {
+       set_runasgr(runas_group);
+       if (runas_user != NULL)
+           set_runaspw(runas_user);
+    } else
+       set_runaspw(runas_user ? runas_user : def_runas_default);
+
+    if (!update_defaults(SETDEF_RUNAS))
+       log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
 
-    /* Skip reading /etc/sudoers if LDAP told us to */
-    if (!def_ignore_local_sudoers) {
-       int v;
+    /* Set login class if applicable. */
+    set_loginclass(sudo_user.pw);
 
-       check_sudoers();        /* check mode/owner on _PATH_SUDOERS */
+    /* Update initial shell now that runas is set. */
+    if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
+       NewArgv[0] = runas_pw->pw_shell;
 
-       /* Local sudoers file overrides LDAP if we have a match. */
-       v = sudoers_lookup(pwflag);
-       if (validated == VALIDATE_ERROR || ISSET(v, VALIDATE_OK))
-           validated = v;
+    /* This goes after sudoers is parsed since it may have timestamp options. */
+    if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) {
+       remove_timestamp((sudo_mode == MODE_KILL));
+       cleanup(0);
+       exit(0);
     }
-#else
-    check_sudoers();   /* check mode/owner on _PATH_SUDOERS */
 
-    /* Validate the user but don't search for pseudo-commands. */
-    validated = sudoers_lookup(pwflag);
+    /* Is root even allowed to run sudo? */
+    if (user_uid == 0 && !def_root_sudo) {
+       (void) fprintf(stderr,
+           "Sorry, %s has been configured to not allow root to run it.\n",
+           getprogname());
+       exit(1);
+    }
+
+    /* Check for -C overriding def_closefrom. */
+    if (user_closefrom >= 0 && user_closefrom != def_closefrom) {
+       if (!def_closefrom_override)
+           errorx(1, "you are not permitted to use the -C option");
+       else
+           def_closefrom = user_closefrom;
+    }
+
+    cmnd_status = set_cmnd(sudo_mode);
+
+#ifdef HAVE_SETLOCALE
+    if (!setlocale(LC_ALL, def_sudoers_locale)) {
+       warningx("unable to set locale to \"%s\", using \"C\"",
+           def_sudoers_locale);
+       setlocale(LC_ALL, "C");
+    }
 #endif
+
+    validated = FLAG_NO_USER | FLAG_NO_HOST;
+    tq_foreach_fwd(snl, nss) {
+       validated = nss->lookup(nss, validated, pwflag);
+
+       /* Handle [NOTFOUND=return] */
+       if (!ISSET(validated, VALIDATE_OK) && nss->ret_notfound)
+           break;
+    }
     if (safe_cmnd == NULL)
        safe_cmnd = estrdup(user_cmnd);
 
+#ifdef HAVE_SETLOCALE
+    setlocale(LC_ALL, "");
+#endif
+
+    /* If only a group was specified, set runas_pw based on invoking user. */
+    if (runas_pw == NULL)
+       set_runaspw(user_name);
+
     /*
      * Look up the timestamp dir owner if one is specified.
      */
@@ -297,33 +363,15 @@ main(argc, argv, envp)
        struct passwd *pw;
 
        if (*def_timestampowner == '#')
-           pw = getpwuid(atoi(def_timestampowner + 1));
+           pw = sudo_getpwuid(atoi(def_timestampowner + 1));
        else
-           pw = getpwnam(def_timestampowner);
+           pw = sudo_getpwnam(def_timestampowner);
        if (!pw)
            log_error(0, "timestamp owner (%s): No such user",
                def_timestampowner);
        timestamp_uid = pw->pw_uid;
     }
 
-    /* This goes after the sudoers parse since we honor sudoers options. */
-    if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) {
-       remove_timestamp((sudo_mode == MODE_KILL));
-       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,
-           "Sorry, %s has been configured to not allow root to run it.\n",
-           getprogname());
-       exit(1);
-    }
-
     /* If given the -P option, set the "preserve_groups" flag. */
     if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
        def_preserve_groups = TRUE;
@@ -340,42 +388,44 @@ main(argc, argv, envp)
            (void) close(fd);
     }
 
-    /* User may have overriden environment resetting via the -E flag. */
-    if (ISSET(sudo_mode, MODE_PRESERVE_ENV) && ISSET(validated, FLAG_SETENV))
+    /* Use askpass value from sudoers unless user specified their own. */
+    if (def_askpass && !user_askpass)
+       user_askpass = def_askpass;
+
+    /* User may have overridden environment resetting via the -E flag. */
+    if (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv)
        def_env_reset = FALSE;
 
     /* Build a new environment that avoids any nasty bits. */
-    environ = rebuild_env(environ, sudo_mode, ISSET(validated, FLAG_NOEXEC));
+    rebuild_env(sudo_mode, def_noexec);
 
     /* Fill in passwd struct based on user we are authenticating as.  */
     auth_pw = get_authpw();
 
     /* Require a password if sudoers says so.  */
-    if (!ISSET(validated, FLAG_NOPASS))
-       check_user(validated);
+    if (def_authenticate)
+       check_user(validated, !ISSET(sudo_mode, MODE_NONINTERACTIVE));
 
     /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
-    if (user_uid == 0 && prev_user != NULL && strcmp(prev_user, "root") != 0) {
+    /* XXX - causes confusion when root is not listed in sudoers */
+    if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) {
+       if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
            struct passwd *pw;
 
-           if ((pw = sudo_getpwnam(prev_user)) != NULL) {
-                   efree(sudo_user.pw);
+           if ((pw = sudo_getpwnam(prev_user)) != NULL)
                    sudo_user.pw = pw;
-           }
+       }
     }
 
     if (ISSET(validated, VALIDATE_OK)) {
        /* Finally tell the user if the command did not exist. */
-       if (cmnd_status == NOT_FOUND_DOT) {
-           warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
-           exit(1);
-       } else if (cmnd_status == NOT_FOUND) {
-           warnx("%s: command not found", user_cmnd);
-           exit(1);
-       }
+       if (cmnd_status == NOT_FOUND_DOT)
+           errorx(1, "ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
+       else if (cmnd_status == NOT_FOUND)
+           errorx(1, "%s: command not found", user_cmnd);
 
        /* If user specified env vars make sure sudoers allows it. */
-       if (ISSET(sudo_mode, MODE_RUN) && !ISSET(validated, FLAG_SETENV)) {
+       if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) {
            if (ISSET(sudo_mode, MODE_PRESERVE_ENV))
                log_error(NO_MAIL,
                    "sorry, you are not allowed to preserve the environment");
@@ -383,20 +433,31 @@ main(argc, argv, envp)
                validate_env_vars(sudo_user.env_vars);
        }
 
-       log_auth(validated, 1);
-       if (sudo_mode == MODE_VALIDATE)
-           exit(0);
-       else if (sudo_mode == MODE_LIST) {
-           list_matches();
-#ifdef HAVE_LDAP
-           sudo_ldap_list_matches();
-#endif
-           exit(0);
-       }
+       log_allowed(validated);
+       if (sudo_mode == MODE_CHECK)
+           rc = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw);
+       else if (sudo_mode == MODE_LIST)
+           display_privs(snl, list_pw ? list_pw : sudo_user.pw);
+
+       /* Cleanup sudoers sources */
+       tq_foreach_fwd(snl, nss)
+           nss->close(nss);
+
+       /* Deferred exit due to sudo_ldap_close() */
+       if (sudo_mode == MODE_VALIDATE || sudo_mode == MODE_CHECK ||
+           sudo_mode == MODE_LIST)
+           exit(rc);
 
-       /* Override user's umask if configured to do so. */
-       if (def_umask != 0777)
-           (void) umask(def_umask);
+       /*
+        * Override user's umask if configured to do so.
+        * If user's umask is more restrictive, OR in those bits too.
+        */
+       if (def_umask != 0777) {
+           mode_t mask = umask(def_umask);
+           mask |= def_umask;
+           if (mask != def_umask)
+               umask(mask);
+       }
 
        /* Restore coredumpsize resource limit. */
 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
@@ -407,10 +468,6 @@ main(argc, argv, envp)
        if (ISSET(sudo_mode, MODE_RUN))
            set_perms(PERM_FULL_RUNAS);
 
-       /* Close the password and group files */
-       endpwent();
-       endgrent();
-
        if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
            char *p;
 
@@ -422,49 +479,63 @@ main(argc, argv, envp)
 
            /* Change to target user's homedir. */
            if (chdir(runas_pw->pw_dir) == -1)
-               warn("unable to change directory to %s", runas_pw->pw_dir);
+               warning("unable to change directory to %s", runas_pw->pw_dir);
+
+#if defined(__linux__) || defined(_AIX)
+           /* Insert system-wide environment variables. */
+           read_env_file(_PATH_ENVIRONMENT, TRUE);
+#endif
        }
 
        if (ISSET(sudo_mode, MODE_EDIT))
            exit(sudo_edit(NewArgc, NewArgv, envp));
 
+       /* Insert system-wide environment variables. */
+       if (def_env_file)
+           read_env_file(def_env_file, FALSE);
+
        /* Insert user-specified environment variables. */
-       environ = insert_env_vars(environ, sudo_user.env_vars);
+       insert_env_vars(sudo_user.env_vars);
 
        /* Restore signal handlers before we exec. */
        (void) sigaction(SIGINT, &saved_sa_int, NULL);
        (void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
        (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
 
+       /* Close the password and group files and free up memory. */
+       sudo_endpwent();
+       sudo_endgrent();
+
+       closefrom(def_closefrom + 1);
+
 #ifndef PROFILING
        if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0)
            exit(0);
        else {
 #ifdef HAVE_SELINUX
            if (is_selinux_enabled() > 0 && user_role != NULL)
-               selinux_exec(user_role, user_type, NewArgv, environ,
+               selinux_exec(user_role, user_type, NewArgv,
                    ISSET(sudo_mode, MODE_LOGIN_SHELL));
 #endif
-           execve(safe_cmnd, NewArgv, environ);
+           execv(safe_cmnd, NewArgv);
        }
 #else
        exit(0);
 #endif /* PROFILING */
        /*
-        * If we got here then the exec() failed...
+        * If we got here then execve() failed...
         */
        if (errno == ENOEXEC) {
            NewArgv--;                  /* at least one extra slot... */
            NewArgv[0] = "sh";
            NewArgv[1] = safe_cmnd;
-           execve(_PATH_BSHELL, NewArgv, environ);
-       }
-       warn("unable to execute %s", safe_cmnd);
+           execv(_PATH_BSHELL, NewArgv);
+       } warning("unable to execute %s", safe_cmnd);
        exit(127);
-    } else if (ISSET(validated, FLAG_NO_USER) || (validated & FLAG_NO_HOST)) {
-       log_auth(validated, 1);
+    } else if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) {
+       log_denial(validated, 1);
        exit(1);
-    } else if (ISSET(validated, VALIDATE_NOT_OK)) {
+    } else {
        if (def_path_info) {
            /*
             * We'd like to not leak path info at all here, but that can
@@ -473,21 +544,17 @@ main(argc, argv, envp)
             * is just "no foo in path" since the user can trivially set
             * their path to just contain a single dir.
             */
-           log_auth(validated,
+           log_denial(validated,
                !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND));
            if (cmnd_status == NOT_FOUND)
-               warnx("%s: command not found", user_cmnd);
+               warningx("%s: command not found", user_cmnd);
            else if (cmnd_status == NOT_FOUND_DOT)
-               warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
+               warningx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
        } else {
            /* Just tell the user they are not allowed to run foo. */
-           log_auth(validated, 1);
+           log_denial(validated, 1);
        }
        exit(1);
-    } else {
-       /* should never get here */
-       log_auth(validated, 1);
-       exit(1);
     }
     exit(0);   /* not reached */
 }
@@ -496,17 +563,17 @@ main(argc, argv, envp)
  * Initialize timezone, set umask, fill in ``sudo_user'' struct and
  * load the ``interfaces'' array.
  */
-static int
+static void
 init_vars(sudo_mode, envp)
     int sudo_mode;
     char **envp;
 {
-    char *p, **ep, thost[MAXHOSTNAMELEN];
-    int nohostname, rval;
+    char *p, **ep, thost[MAXHOSTNAMELEN + 1];
+    int nohostname;
 
     /* Sanity check command from user. */
     if (user_cmnd == NULL && strlen(NewArgv[0]) >= PATH_MAX)
-       errx(1, "%s: File name too long", NewArgv[0]);
+       errorx(1, "%s: File name too long", NewArgv[0]);
 
 #ifdef HAVE_TZSET
     (void) tzset();            /* set the timezone if applicable */
@@ -527,6 +594,7 @@ init_vars(sudo_mode, envp)
     if (nohostname)
        user_host = user_shost = "localhost";
     else {
+       thost[sizeof(thost) - 1] = '\0';
        user_host = estrdup(thost);
        if (def_fqdn) {
            /* Defer call to set_fqdn() until log_error() is safe. */
@@ -550,7 +618,16 @@ init_vars(sudo_mode, envp)
        user_tty = "unknown";
 
     for (ep = envp; *ep; ep++) {
+       /* XXX - don't fill in if empty string */
        switch (**ep) {
+           case 'D':
+               if (strncmp("DISPLAY=", *ep, 8) == 0)
+                   user_display = *ep + 8;
+               break;
+           case 'K':
+               if (strncmp("KRB5CCNAME=", *ep, 11) == 0)
+                   user_ccname = *ep + 11;
+               break;
            case 'P':
                if (strncmp("PATH=", *ep, 5) == 0)
                    user_path = *ep + 5;
@@ -562,8 +639,9 @@ init_vars(sudo_mode, envp)
                    user_prompt = *ep + 12;
                else if (strncmp("SUDO_USER=", *ep, 10) == 0)
                    prev_user = *ep + 10;
+               else if (strncmp("SUDO_ASKPASS=", *ep, 13) == 0)
+                   user_askpass = *ep + 13;
                break;
-
            }
     }
 
@@ -589,11 +667,11 @@ init_vars(sudo_mode, envp)
         * be run during reboot after the YP/NIS/NIS+/LDAP/etc daemon has died.
         */
        if (sudo_mode & (MODE_INVALIDATE|MODE_KILL))
-           errx(1, "uid %s does not exist in the passwd file!", pw_name);
-       log_error(0, "uid %s does not exist in the passwd file!", pw_name);
+           errorx(1, "unknown uid: %s", pw_name);
+       log_error(0, "unknown uid: %s", pw_name);
     }
     if (user_shell == NULL || *user_shell == '\0')
-       user_shell = sudo_user.pw->pw_shell;
+       user_shell = estrdup(sudo_user.pw->pw_shell);
 
     /* It is now safe to use log_error() and set_perms() */
 
@@ -612,10 +690,6 @@ init_vars(sudo_mode, envp)
     if (nohostname)
        log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
 
-    set_runaspw(*user_runas);          /* may call log_error() */
-    if (*user_runas[0] == '#' && runas_pw->pw_name && runas_pw->pw_name[0])
-       *user_runas = estrdup(runas_pw->pw_name);
-
     /*
      * Get current working directory.  Try as user, fall back to root.
      */
@@ -623,7 +697,7 @@ init_vars(sudo_mode, envp)
     if (!getcwd(user_cwd, sizeof(user_cwd))) {
        set_perms(PERM_ROOT);
        if (!getcwd(user_cwd, sizeof(user_cwd))) {
-           warnx("cannot get working directory");
+           warningx("cannot get working directory");
            (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
        }
     } else
@@ -633,28 +707,47 @@ init_vars(sudo_mode, envp)
      * If we were given the '-e', '-i' or '-s' options we need to redo
      * NewArgv and NewArgc.
      */
-    if ((sudo_mode & (MODE_SHELL | MODE_EDIT))) {
-       char **dst, **src = NewArgv;
+    if (ISSET(sudo_mode, MODE_EDIT)) {
+       NewArgv--;
+       NewArgc++;
+       NewArgv[0] = "sudoedit";
+    } else if (ISSET(sudo_mode, MODE_SHELL)) {
+       char **av;
 
        /* Allocate an extra slot for execve() failure (ENOEXEC). */
-       NewArgv = (char **) emalloc2((++NewArgc + 2), sizeof(char *));
-       NewArgv++;
-       if (ISSET(sudo_mode, MODE_EDIT))
-           NewArgv[0] = "sudoedit";
-       else if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
-           NewArgv[0] = runas_pw->pw_shell;
-       else if (user_shell && *user_shell)
-           NewArgv[0] = user_shell;
-       else
-           errx(1, "unable to determine shell");
-
-       /* copy the args from NewArgv */
-       for (dst = NewArgv + 1; (*dst = *src) != NULL; ++src, ++dst)
-           continue;
+       av = (char **) emalloc2(5, sizeof(char *));
+       av++;
+
+       av[0] = user_shell;     /* may be updated later */
+       if (NewArgc > 0) {
+           size_t size;
+           char *cmnd, *src, *dst, *end;
+           size = (size_t) (NewArgv[NewArgc - 1] - NewArgv[0]) +
+                   strlen(NewArgv[NewArgc - 1]) + 1;
+           cmnd = emalloc(size);
+           src = NewArgv[0];
+           dst = cmnd;
+           for (end = src + size - 1; src < end; src++, dst++)
+               *dst = *src == 0 ? ' ' : *src;
+           *dst = '\0';
+           av[1] = "-c";
+           av[2] = cmnd;
+           NewArgc = 2;
+       }
+       av[++NewArgc] = NULL;
+       NewArgv = av;
     }
+}
 
-    /* Set login class if applicable. */
-    set_loginclass(sudo_user.pw);
+/*
+ * Fill in user_cmnd, user_args, user_base and user_stat variables
+ * and apply any command-specific defaults entries.
+ */
+static int
+set_cmnd(sudo_mode)
+    int sudo_mode;
+{
+    int rval;
 
     /* Set project if applicable. */
     set_project(runas_pw);
@@ -662,9 +755,8 @@ init_vars(sudo_mode, envp)
     /* Resolve the path and return. */
     rval = FOUND;
     user_stat = emalloc(sizeof(struct stat));
-    if (sudo_mode & (MODE_RUN | MODE_EDIT)) {
-       if (ISSET(sudo_mode, MODE_RUN)) {
-           /* XXX - default_runas may be modified during parsing of sudoers */
+    if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
+       if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
            set_perms(PERM_RUNAS);
            rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
            set_perms(PERM_ROOT);
@@ -682,7 +774,7 @@ init_vars(sudo_mode, envp)
            size_t size, n;
 
            /* If we didn't realloc NewArgv it is contiguous so just count. */
-           if (!(sudo_mode & (MODE_SHELL | MODE_EDIT))) {
+           if (!ISSET(sudo_mode, MODE_SHELL)) {
                size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
                        strlen(NewArgv[NewArgc-1]) + 1;
            } else {
@@ -695,7 +787,7 @@ init_vars(sudo_mode, envp)
            for (to = user_args, from = NewArgv + 1; *from; from++) {
                n = strlcpy(to, *from, size - (to - user_args));
                if (n >= size - (to - user_args))
-                   errx(1, "internal error, init_vars() overflow");
+                   errorx(1, "internal error, init_vars() overflow");
                to += n;
                *to++ = ' ';
            }
@@ -707,265 +799,259 @@ init_vars(sudo_mode, envp)
     else
        user_base = user_cmnd;
 
+    if (!update_defaults(SETDEF_CMND))
+       log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
+
     return(rval);
 }
 
 /*
- * Command line argument parsing, can't use getopt(3).
+ * Command line argument parsing.
+ * Sets NewArgc and NewArgv which corresponds to the argc/argv we'll use
+ * for the command to be run (if we are running one).
  */
 static int
 parse_args(argc, argv)
     int argc;
     char **argv;
 {
-    int rval = MODE_RUN;               /* what mode is sudo to be run in? */
-    int excl = 0;                      /* exclusive arg, no others allowed */
-
-    NewArgv = argv + 1;
-    NewArgc = argc - 1;
+    int mode = 0;              /* what mode is sudo to be run in? */
+    int flags = 0;             /* mode flags */
+    int ch;
 
     /* First, check to see if we were invoked as "sudoedit". */
-    if (strcmp(getprogname(), "sudoedit") == 0) {
-       rval = MODE_EDIT;
-       excl = 'e';
-    } else
-       rval = MODE_RUN;
-
-    while (NewArgc > 0) {
-       if (NewArgv[0][0] == '-') {
-           if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0') {
-               warnx("please use single character options");
-               usage(1);
-           }
-
-           switch (NewArgv[0][1]) {
-               case 'p':
-                   /* Must have an associated prompt. */
-                   if (NewArgv[1] == NULL)
-                       usage(1);
+    if (strcmp(getprogname(), "sudoedit") == 0)
+       mode = MODE_EDIT;
 
-                   user_prompt = NewArgv[1];
-                   def_passprompt_override = TRUE;
+    /* Returns true if the last option string was "--" */
+#define got_end_of_args        (optind > 1 && argv[optind - 1][0] == '-' && \
+           argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0')
 
-                   NewArgc--;
-                   NewArgv++;
-                   break;
-               case 'u':
-                   /* Must have an associated runas user. */
-                   if (NewArgv[1] == NULL)
-                       usage(1);
+    /* Returns true if next option is an environment variable */
+#define is_envar (optind < argc && argv[optind][0] != '/' && \
+           strchr(argv[optind], '=') != NULL)
 
-                   user_runas = &NewArgv[1];
-
-                   NewArgc--;
-                   NewArgv++;
+    for (;;) {
+       /*
+        * We disable arg permutation for GNU getopt().
+        * Some trickiness is required to allow environment variables
+        * to be interspersed with command line options.
+        */
+       if ((ch = getopt(argc, argv, "+Aa:bC:c:Eeg:HhiKkLlnPp:r:Sst:U:u:Vv")) != -1) {
+           switch (ch) {
+               case 'A':
+                   SET(tgetpass_flags, TGP_ASKPASS);
                    break;
 #ifdef HAVE_BSD_AUTH_H
                case 'a':
-                   /* Must have an associated authentication style. */
-                   if (NewArgv[1] == NULL)
-                       usage(1);
-
-                   login_style = NewArgv[1];
-
-                   NewArgc--;
-                   NewArgv++;
+                   login_style = optarg;
                    break;
 #endif
+               case 'b':
+                   SET(flags, MODE_BACKGROUND);
+                   break;
+               case 'C':
+                   if ((user_closefrom = atoi(optarg)) < 3) {
+                       warningx("the argument to -C must be at least 3");
+                       usage(1);
+                   }
+                   break;
 #ifdef HAVE_LOGIN_CAP_H
                case 'c':
-                   /* Must have an associated login class. */
-                   if (NewArgv[1] == NULL)
-                       usage(1);
-
-                   login_class = NewArgv[1];
+                   login_class = optarg;
                    def_use_loginclass = TRUE;
-
-                   NewArgc--;
-                   NewArgv++;
                    break;
 #endif
-               case 'b':
-                   SET(rval, MODE_BACKGROUND);
+               case 'E':
+                   SET(flags, MODE_PRESERVE_ENV);
                    break;
                case 'e':
-                   rval = MODE_EDIT;
-                   if (excl && excl != 'e')
+                   if (mode && mode != MODE_EDIT)
                        usage_excl(1);
-                   excl = 'e';
+                   mode = MODE_EDIT;
                    break;
-               case 'v':
-                   rval = MODE_VALIDATE;
-                   if (excl && excl != 'v')
+               case 'g':
+                   runas_group = optarg;
+                   break;
+               case 'H':
+                   SET(flags, MODE_RESET_HOME);
+                   break;
+               case 'h':
+                   if (mode && mode != MODE_HELP)
                        usage_excl(1);
-                   excl = 'v';
+                   mode = MODE_HELP;
                    break;
                case 'i':
-                   SET(rval, (MODE_LOGIN_SHELL | MODE_SHELL));
+                   SET(flags, MODE_LOGIN_SHELL);
                    def_env_reset = TRUE;
-                   if (excl && excl != 'i')
-                       usage_excl(1);
-                   excl = 'i';
                    break;
                case 'k':
-                   rval = MODE_INVALIDATE;
-                   if (excl && excl != 'k')
+                   if (mode && mode != MODE_INVALIDATE)
                        usage_excl(1);
-                   excl = 'k';
+                   mode = MODE_INVALIDATE;
                    break;
                case 'K':
-                   rval = MODE_KILL;
-                   if (excl && excl != 'K')
+                   if (mode && mode != MODE_KILL)
                        usage_excl(1);
-                   excl = 'K';
+                   mode = MODE_KILL;
                    break;
                case 'L':
-                   rval = MODE_LISTDEFS;
-                   if (excl && excl != 'L')
+                   if (mode && mode != MODE_LISTDEFS)
                        usage_excl(1);
-                   excl = 'L';
+                   mode = MODE_LISTDEFS;
                    break;
                case 'l':
-                   rval = MODE_LIST;
-                   if (excl && excl != 'l')
-                       usage_excl(1);
-                   excl = 'l';
+                   if (mode) {
+                       if (mode == MODE_LIST)
+                           long_list = 1;
+                       else
+                           usage_excl(1);
+                   }
+                   mode = MODE_LIST;
                    break;
-               case 'V':
-                   rval = MODE_VERSION;
-                   if (excl && excl != 'V')
-                       usage_excl(1);
-                   excl = 'V';
+               case 'n':
+                   SET(flags, MODE_NONINTERACTIVE);
                    break;
-               case 'h':
-                   rval = MODE_HELP;
-                   if (excl && excl != 'h')
-                       usage_excl(1);
-                   excl = 'h';
+               case 'P':
+                   SET(flags, MODE_PRESERVE_GROUPS);
                    break;
-               case 's':
-                   SET(rval, MODE_SHELL);
-                   if (excl && excl != 's')
-                       usage_excl(1);
-                   excl = 's';
+               case 'p':
+                   user_prompt = optarg;
+                   def_passprompt_override = TRUE;
                    break;
-               case 'H':
-                   SET(rval, MODE_RESET_HOME);
+#ifdef HAVE_SELINUX
+               case 'r':
+                   user_role = optarg;
                    break;
-               case 'P':
-                   SET(rval, MODE_PRESERVE_GROUPS);
+               case 't':
+                   user_type = optarg;
                    break;
+#endif
                case 'S':
                    SET(tgetpass_flags, TGP_STDIN);
                    break;
-               case 'E':
-                   SET(rval, MODE_PRESERVE_ENV);
+               case 's':
+                   SET(flags, MODE_SHELL);
                    break;
-#ifdef HAVE_SELINUX
-               case 'r':
-                   /* Must have an associated SELinux role. */
-                   if (NewArgv[1] == NULL)
-                       usage(1);
-
-                   user_role = NewArgv[1];
-
-                   NewArgc--;
-                   NewArgv++;
+               case 'U':
+                   if ((list_pw = sudo_getpwnam(optarg)) == NULL)
+                       errorx(1, "unknown user: %s", optarg);
                    break;
-               case 't':
-                   /* Must have an associated SELinux type. */
-                   if (NewArgv[1] == NULL)
-                       usage(1);
-
-                   user_type = NewArgv[1];
-
-                   NewArgc--;
-                   NewArgv++;
+               case 'u':
+                   runas_user = optarg;
+                   break;
+               case 'v':
+                   if (mode && mode != MODE_VALIDATE)
+                       usage_excl(1);
+                   mode = MODE_VALIDATE;
+                   break;
+               case 'V':
+                   if (mode && mode != MODE_VERSION)
+                       usage_excl(1);
+                   mode = MODE_VERSION;
                    break;
-#endif
-               case '-':
-                   NewArgc--;
-                   NewArgv++;
-                   goto args_done;
-               case '\0':
-                   warnx("'-' requires an argument");
-                   usage(1);
                default:
-                   warnx("illegal option `%s'", NewArgv[0]);
                    usage(1);
            }
-       } else if (NewArgv[0][0] != '/' && strchr(NewArgv[0], '=') != NULL) {
-           /* Could be an environment variable. */
+       } else if (!got_end_of_args && is_envar) {
            struct list_member *ev;
+
+           /* Store environment variable. */
            ev = emalloc(sizeof(*ev));
-           ev->value = NewArgv[0];
+           ev->value = argv[optind];
            ev->next = sudo_user.env_vars;
            sudo_user.env_vars = ev;
+
+           /* Crank optind and resume getopt. */
+           optind++;
        } else {
-           /* Not an arg */
+           /* Not an option or an environment variable -- we're done. */
            break;
        }
-       NewArgc--;
-       NewArgv++;
     }
-args_done:
 
-    if (ISSET(rval, MODE_EDIT) &&
-       (ISSET(rval, MODE_PRESERVE_ENV) || sudo_user.env_vars != NULL)) {
-       if (ISSET(rval, MODE_PRESERVE_ENV))
-           warnx("the `-E' option is not valid in edit mode");
+    NewArgc = argc - optind;
+    NewArgv = argv + optind;
+
+    if (!mode)
+       mode = MODE_RUN;
+
+    if (NewArgc > 0 && mode == MODE_LIST)
+       mode = MODE_CHECK;
+
+    if (ISSET(flags, MODE_LOGIN_SHELL)) {
+       if (ISSET(flags, MODE_SHELL)) {
+           warningx("you may not specify both the `-i' and `-s' options");
+           usage(1);
+       }
+       if (ISSET(flags, MODE_PRESERVE_ENV)) {
+           warningx("you may not specify both the `-i' and `-E' options");
+           usage(1);
+       }
+       SET(flags, MODE_SHELL);
+    }
+    if (mode == MODE_EDIT &&
+       (ISSET(flags, MODE_PRESERVE_ENV) || sudo_user.env_vars != NULL)) {
+       if (ISSET(mode, MODE_PRESERVE_ENV))
+           warningx("the `-E' option is not valid in edit mode");
        if (sudo_user.env_vars != NULL)
-           warnx("you may not specify environment variables in edit mode");
+           warningx("you may not specify environment variables in edit mode");
+       usage(1);
+    }
+    if ((runas_user != NULL || runas_group != NULL) &&
+       !ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK)) {
        usage(1);
     }
-    if (ISSET(rval, MODE_PRESERVE_ENV) && ISSET(rval, MODE_LOGIN_SHELL)) {
-       warnx("you may not specify both the `-i' and `-E' options");
+    if (list_pw != NULL && mode != MODE_LIST && mode != MODE_CHECK) {
+       warningx("the `-U' option may only be used with the `-l' option");
        usage(1);
     }
-    if (user_runas != NULL && !ISSET(rval, (MODE_EDIT|MODE_RUN))) {
-       if (excl != '\0')
-           warnx("the `-u' and '-%c' options may not be used together", excl);
+    if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) {
+       warningx("the `-A' and `-S' options may not be used together");
        usage(1);
     }
-    if ((NewArgc == 0 && (rval & MODE_EDIT)) ||
-       (NewArgc > 0 && !(rval & (MODE_RUN | MODE_EDIT))))
+    if ((NewArgc == 0 && mode == MODE_EDIT) ||
+       (NewArgc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
        usage(1);
-    if (NewArgc == 0 && rval == MODE_RUN)
-       SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL));
+    if (NewArgc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL))
+       SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
 
-    return(rval);
+    return(mode | flags);
 }
 
 /*
- * Sanity check sudoers mode/owner/type.
- * Leaves a file pointer to the sudoers file open in ``fp''.
+ * Open sudoers and sanity check mode/owner/type.
+ * Returns a handle to the sudoers file or NULL on error.
  */
-static void
-check_sudoers()
+FILE *
+open_sudoers(sudoers, keepopen)
+    const char *sudoers;
+    int *keepopen;
 {
     struct stat statbuf;
-    int rootstat, i;
+    FILE *fp = NULL;
+    int rootstat;
 
     /*
      * 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 &&
+    if ((rootstat = stat_sudoers(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);
+       if (chmod(sudoers, SUDOERS_MODE) == 0) {
+           warningx("fixed mode on %s", 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);
+               if (chown(sudoers, (uid_t) -1, SUDOERS_GID) == 0) {
+                   warningx("set group on %s", sudoers);
                    statbuf.st_gid = SUDOERS_GID;
                } else
-                   warn("unable to set group on %s", _PATH_SUDOERS);
+                   warning("unable to set group on %s", sudoers);
            }
        } else
-           warn("unable to fix mode on %s", _PATH_SUDOERS);
+           warning("unable to fix mode on %s", sudoers);
     }
 
     /*
@@ -975,46 +1061,40 @@ check_sudoers()
      */
     set_perms(PERM_SUDOERS);
 
-    if (rootstat != 0 && stat_sudoers(_PATH_SUDOERS, &statbuf) != 0)
-       log_error(USE_ERRNO, "can't stat %s", _PATH_SUDOERS);
+    if (rootstat != 0 && stat_sudoers(sudoers, &statbuf) != 0)
+       log_error(USE_ERRNO|NO_EXIT, "can't stat %s", 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);
+       log_error(NO_EXIT, "%s is not a regular file", sudoers);
     else if ((statbuf.st_mode & 07777) != SUDOERS_MODE)
-       log_error(0, "%s is mode 0%o, should be 0%o", _PATH_SUDOERS,
+       log_error(NO_EXIT, "%s is mode 0%o, should be 0%o", sudoers,
            (unsigned int) (statbuf.st_mode & 07777),
            (unsigned int) SUDOERS_MODE);
     else if (statbuf.st_uid != SUDOERS_UID)
-       log_error(0, "%s is owned by uid %lu, should be %lu", _PATH_SUDOERS,
+       log_error(NO_EXIT, "%s is owned by uid %lu, should be %lu", 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,
+       log_error(NO_EXIT, "%s is owned by gid %lu, should be %lu", 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 ||
-               fgetc(sudoers_fp) == EOF) {
-               if (sudoers_fp != NULL)
-                   fclose(sudoers_fp);
-               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);
+    else if ((fp = fopen(sudoers, "r")) == NULL)
+       log_error(USE_ERRNO, "can't open %s", sudoers);
+    else if (statbuf.st_size != 0) {
+       /*
+        * Make sure we can actually read sudoers so we can present the
+        * user with a reasonable error message.
+        */
+       if (fgetc(fp) == EOF)
+           log_error(USE_ERRNO, "can't read %s", sudoers);
+       rewind(fp);
     }
+    (void) fcntl(fileno(fp), F_SETFD, 1);
 
     set_perms(PERM_ROOT);              /* change back to root */
+    return(fp);
 }
 
 /*
  * Close all open files (except std*) and turn off core dumps.
+ * Also sets the set_perms() pointer to the correct function.
  */
 static void
 initial_setup()
@@ -1063,9 +1143,10 @@ initial_setup()
                (void) dup2(devnull, STDOUT_FILENO);
            if (miss[STDERR_FILENO])
                (void) dup2(devnull, STDERR_FILENO);
+           if (devnull > STDERR_FILENO)
+               close(devnull);
        }
     }
-    closefrom(STDERR_FILENO + 1);
 }
 
 #ifdef HAVE_LOGIN_CAP_H
@@ -1086,8 +1167,9 @@ set_loginclass(pw)
        errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
 
     if (login_class && strcmp(login_class, "-") != 0) {
-       if (strcmp(*user_runas, "root") != 0 && user_uid != 0)
-           errx(1, "only root can use -c %s", login_class);
+       if (user_uid != 0 &&
+           strcmp(runas_user ? runas_user : def_runas_default, "root") != 0)
+           errorx(1, "only root can use -c %s", login_class);
     } else {
        login_class = pw->pw_class;
        if (!login_class || !*login_class)
@@ -1190,7 +1272,7 @@ set_fqdn()
     char *p;
 
 #ifdef HAVE_GETADDRINFO
-    memset(&hint, 0, sizeof(hint));
+    zero_bytes(&hint, sizeof(hint));
     hint.ai_family = PF_UNSPEC;
     hint.ai_flags = AI_CANONNAME;
     if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
@@ -1223,28 +1305,34 @@ set_fqdn()
  * Get passwd entry for the user we are going to run commands as.
  * By default, this is "root".  Updates runas_pw as a side effect.
  */
-int
+static void
 set_runaspw(user)
     char *user;
 {
-    if (runas_pw != NULL) {
-       if (user_runas != &def_runas_default)
-           return(TRUE);               /* don't override -u option */
-       efree(runas_pw);
-    }
     if (*user == '#') {
-       runas_pw = sudo_getpwuid(atoi(user + 1));
-       if (runas_pw == NULL) {
-           runas_pw = emalloc(sizeof(struct passwd));
-           (void) memset((VOID *)runas_pw, 0, sizeof(struct passwd));
-           runas_pw->pw_uid = atoi(user + 1);
-       }
+       if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
+           runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
     } else {
-       runas_pw = sudo_getpwnam(user);
-       if (runas_pw == NULL)
-           log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %s!", user);
+       if ((runas_pw = sudo_getpwnam(user)) == NULL)
+           log_error(NO_MAIL|MSG_ONLY, "unknown user: %s", user);
+    }
+}
+
+/*
+ * Get group entry for the group we are going to run commands as.
+ * Updates runas_pw as a side effect.
+ */
+static void
+set_runasgr(group)
+    char *group;
+{
+    if (*group == '#') {
+       if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)
+           runas_gr = sudo_fakegrnam(group);
+    } else {
+       if ((runas_gr = sudo_getgrnam(group)) == NULL)
+           log_error(NO_MAIL|MSG_ONLY, "unknown group: %s", group);
     }
-    return(TRUE);
 }
 
 /*
@@ -1258,19 +1346,14 @@ get_authpw()
     struct passwd *pw;
 
     if (def_rootpw) {
-       if (runas_pw->pw_uid == 0)
-           pw = runas_pw;
-       else if ((pw = sudo_getpwuid(0)) == NULL)
-           log_error(0, "uid 0 does not exist in the passwd file!");
+       if ((pw = sudo_getpwuid(0)) == NULL)
+           log_error(0, "unknown uid: 0");
     } else if (def_runaspw) {
-       if (strcmp(def_runas_default, *user_runas) == 0)
-           pw = runas_pw;
-       else if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
-           log_error(0, "user %s does not exist in the passwd file!",
-               def_runas_default);
+       if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
+           log_error(0, "unknown user: %s", def_runas_default);
     } else if (def_targetpw) {
        if (runas_pw->pw_name == NULL)
-           log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %lu!",
+           log_error(NO_MAIL|MSG_ONLY, "unknown uid: %lu",
                (unsigned long) runas_pw->pw_uid);
        pw = runas_pw;
     } else
@@ -1279,6 +1362,46 @@ get_authpw()
     return(pw);
 }
 
+/*
+ * Cleanup hook for error()/errorx()
+ */
+void
+cleanup(gotsignal)
+    int gotsignal;
+{
+    struct sudo_nss *nss;
+
+    if (!gotsignal) {
+       if (snl != NULL) {
+           tq_foreach_fwd(snl, nss)
+               nss->close(nss);
+       }
+       sudo_endpwent();
+       sudo_endgrent();
+    }
+}
+
+static void
+show_version()
+{
+    (void) printf("Sudo version %s\n", version);
+    if (getuid() == 0) {
+       putchar('\n');
+       (void) printf("Sudoers path: %s\n", _PATH_SUDOERS);
+#ifdef HAVE_LDAP
+# ifdef _PATH_NSSWITCH_CONF
+       (void) printf("nsswitch path: %s\n", _PATH_NSSWITCH_CONF);
+# endif
+       (void) printf("ldap.conf path: %s\n", _PATH_LDAP_CONF);
+       (void) printf("ldap.secret path: %s\n", _PATH_LDAP_SECRET);
+#endif
+       dump_auth_methods();
+       dump_defaults();
+       dump_interfaces();
+    }
+    exit(0);
+}
+
 /*
  * Tell which options are mutually exclusive and exit.
  */
@@ -1286,98 +1409,46 @@ static void
 usage_excl(exit_val)
     int exit_val;
 {
-    warnx("Only one of the -e, -h, i, -k, -K, -l, -s, -v or -V options may be used");
+    warningx("Only one of the -e, -h, -i, -k, -K, -l, -s, -v or -V options may be specified");
     usage(exit_val);
 }
 
 /*
  * Give usage message and exit.
+ * The actual usage strings are in sudo_usage.h for configure substitution.
  */
 static void
 usage(exit_val)
     int exit_val;
 {
-    char **p, **uvec[4];
-    int i, linelen, linemax, ulen, plen;
-    static char *uvec1[] = {
-       " -h |",
-       " -K |",
-       " -k |",
-       " -L |",
-       " -l |",
-       " -V |",
-       " -v",
-       NULL
-    };
-    static char *uvec2[] = {
-       " [-bEHPS]",
-#ifdef HAVE_BSD_AUTH_H
-       " [-a auth_type]",
-#endif
-#ifdef HAVE_LOGIN_CAP_H
-       " [-c class|-]",
-#endif
-#ifdef HAVE_SELINUX
-       " [-r role]",
-#endif
-       " [-p prompt]",
-#ifdef HAVE_SELINUX
-       " [-t type]",
-#endif
-       " [-u username|#uid]",
-       " [VAR=value]",
-       " {-i | -s | <command>}",
-       NULL
-    };
-    static char *uvec3[] = {
-       " -e",
-       " [-S]",
-#ifdef HAVE_BSD_AUTH_H
-       " [-a auth_type]",
-#endif
-#ifdef HAVE_LOGIN_CAP_H
-       " [-c class|-]",
-#endif
-       " [-p prompt]",
-       " [-u username|#uid]",
-       " file ...",
-       NULL
-    };
+    struct lbuf lbuf;
+    char *uvec[5];
+    int i, ulen;
 
     /*
      * Use usage vectors appropriate to the progname.
      */
     if (strcmp(getprogname(), "sudoedit") == 0) {
-       uvec[0] = uvec3 + 1;
+       uvec[0] = SUDO_USAGE4 + 3;
        uvec[1] = NULL;
     } else {
-       uvec[0] = uvec1;
-       uvec[1] = uvec2;
-       uvec[2] = uvec3;
-       uvec[3] = NULL;
+       uvec[0] = SUDO_USAGE1;
+       uvec[1] = SUDO_USAGE2;
+       uvec[2] = SUDO_USAGE3;
+       uvec[3] = SUDO_USAGE4;
+       uvec[4] = NULL;
     }
 
     /*
-     * Print usage and wrap lines as needed.
-     * Assumes an 80-character wide terminal, which is kind of bogus...
+     * Print usage and wrap lines as needed, depending on the
+     * tty width.
      */
-    ulen = (int)strlen(getprogname()) + 7;
-    linemax = 80;
+    ulen = (int)strlen(getprogname()) + 8;
+    lbuf_init(&lbuf, NULL, ulen, 0);
     for (i = 0; uvec[i] != NULL; i++) {
-       printf("usage: %s", getprogname());
-       linelen = linemax - ulen;
-       for (p = uvec[i]; *p != NULL; p++) {
-           plen = (int)strlen(*p);
-           if (linelen >= plen || linelen == linemax - ulen) {
-               fputs(*p, stdout);
-               linelen -= plen;
-           } else {
-               p--;
-               linelen = linemax - ulen;
-               printf("\n%*s", ulen, "");
-           }
-       }
-       putchar('\n');
+       lbuf_append(&lbuf, "usage: ", getprogname(), uvec[i], NULL);
+       lbuf_print(&lbuf);
     }
+    lbuf_destroy(&lbuf);
     exit(exit_val);
 }
index febd93bf2133338775d52452f181e7bf83b2ae62..07290ee23723a038959340bb490b34f648b93a58 100644 (file)
--- a/sudo.cat
+++ b/sudo.cat
@@ -8,60 +8,60 @@ N\bNA\bAM\bME\bE
        sudo, sudoedit - execute a command as another user
 
 S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS
-       s\bsu\bud\bdo\b-\b-h\bh | -\b-K\bK | -\b-k\bk | -\b-L\bL | -\b-l\bl | -\b-V\bV | -\b-v\bv
+       s\bsu\bud\bdo\b[-\b-n\bn] -\b-h\bh | -\b-K\bK | -\b-k\bk | -\b-L\bL | -\b-V\bV | -\b-v\bv
 
-       s\bsu\bud\bdo\b[-\b-b\bbE\bEH\bHP\bPS\bS] [-\b-a\ba _\ba_\bu_\bt_\bh_\b__\bt_\by_\bp_\be] [-\b-c\bc _\bc_\bl_\ba_\bs_\bs|_\b-] [-\b-p\bp _\bp_\br_\bo_\bm_\bp_\bt]
-       [-\b-u\bu _\bu_\bs_\be_\br_\bn_\ba_\bm_\be|_\b#_\bu_\bi_\bd] [V\bVA\bAR\bR=_\bv_\ba_\bl_\bu_\be] {-\b-i\bi | -\b-s\bs | _\bc_\bo_\bm_\bm_\ba_\bn_\bd}
+       s\bsu\bud\bdo\b-\b-l\bl[\b[l\bl]\b] [-\b-A\bAn\bnS\bS] [-\b-g\bg _\bg_\br_\bo_\bu_\bp_\bn_\ba_\bm_\be|_\b#_\bg_\bi_\bd] [-\b-U\bU _\bu_\bs_\be_\br_\bn_\ba_\bm_\be] [-\b-u\bu _\bu_\bs_\be_\br_\bn_\ba_\bm_\be|_\b#_\bu_\bi_\bd]
+       [_\bc_\bo_\bm_\bm_\ba_\bn_\bd]
 
-       s\bsu\bud\bdo\boe\bed\bdi\bit\bt [-\b-S\bS] [-\b-a\ba _\ba_\bu_\bt_\bh_\b__\bt_\by_\bp_\be] [-\b-c\bc _\bc_\bl_\ba_\bs_\bs|_\b-] [-\b-p\bp _\bp_\br_\bo_\bm_\bp_\bt]
-       [-\b-u\bu _\bu_\bs_\be_\br_\bn_\ba_\bm_\be|_\b#_\bu_\bi_\bd] file ...
+       s\bsu\bud\bdo\bo [-\b-A\bAb\bbE\bEH\bHn\bnP\bPS\bS] [-\b-a\ba _\ba_\bu_\bt_\bh_\b__\bt_\by_\bp_\be] [-\b-C\bC _\bf_\bd] [-\b-c\bc _\bc_\bl_\ba_\bs_\bs|_\b-] [-\b-g\bg _\bg_\br_\bo_\bu_\bp_\bn_\ba_\bm_\be|_\b#_\bg_\bi_\bd]
+       [-\b-p\bp _\bp_\br_\bo_\bm_\bp_\bt] [-\b-u\bu _\bu_\bs_\be_\br_\bn_\ba_\bm_\be|_\b#_\bu_\bi_\bd] [V\bVA\bAR\bR=_\bv_\ba_\bl_\bu_\be] [-\b-i\bi | -\b-s\bs] [_\bc_\bo_\bm_\bm_\ba_\bn_\bd]
+
+       s\bsu\bud\bdo\boe\bed\bdi\bit\bt [-\b-A\bAn\bnS\bS] [-\b-a\ba _\ba_\bu_\bt_\bh_\b__\bt_\by_\bp_\be] [-\b-C\bC _\bf_\bd] [-\b-c\bc _\bc_\bl_\ba_\bs_\bs|_\b-] [-\b-g\bg _\bg_\br_\bo_\bu_\bp_\bn_\ba_\bm_\be|_\b#_\bg_\bi_\bd]
+       [-\b-p\bp _\bp_\br_\bo_\bm_\bp_\bt] [-\b-u\bu _\bu_\bs_\be_\br_\bn_\ba_\bm_\be|_\b#_\bu_\bi_\bd] file ...
 
 D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
-       s\bsu\bud\bdo\bo allows a permitted user to execute a _\bc_\bo_\bm_\bm_\ba_\bn_\bd as the
-       superuser or another user, as specified in the _\bs_\bu_\bd_\bo_\be_\br_\bs
-       file.  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\bP option was specified).  If the invok­
-       ing user is root or if the target user is the same as the
-       invoking user, no password is required.  Otherwise, s\bsu\bud\bdo\bo
-       requires that users authenticate themselves with a pass­
-       word by default (NOTE: in the default configuration this
-       is the user's password, not the root password).  Once a
-       user has been authenticated, a timestamp is updated and
-       the user may then use sudo without a password for a short
-       period of time (5 minutes unless overridden in _\bs_\bu_\bd_\bo_\be_\br_\bs).
+       s\bsu\bud\bdo\bo allows a permitted user to execute a _\bc_\bo_\bm_\bm_\ba_\bn_\bd as the superuser or
+       another user, as specified in the _\bs_\bu_\bd_\bo_\be_\br_\bs file.  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\bP option was specified).  If the invoking user is
+       root or if the target user is the same as the invoking user, no
+       password is required.  Otherwise, s\bsu\bud\bdo\bo requires that users authenticate
+       themselves with a password by default (NOTE: in the default
+       configuration this is the user's password, not the root password).
+       Once a user has been authenticated, a timestamp is updated and the user
+       may then use sudo without a password for a short period of time (5
+       minutes unless overridden in _\bs_\bu_\bd_\bo_\be_\br_\bs).
+
+       When invoked as s\bsu\bud\bdo\boe\bed\bdi\bit\bt, the -\b-e\be option (described below), is implied.
 
-       When invoked as s\bsu\bud\bdo\boe\bed\bdi\bit\bt, the -\b-e\be option (described below),
-       is implied.
+       s\bsu\bud\bdo\bo determines who is an authorized user by consulting the file
+       _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs.  By running s\bsu\bud\bdo\bo with the -\b-v\bv option, a user can update
+       the time stamp without running a _\bc_\bo_\bm_\bm_\ba_\bn_\bd. The password prompt itself
+       will also time out if the user's password is not entered within 5
+       minutes (unless overridden via _\bs_\bu_\bd_\bo_\be_\br_\bs).
 
-       s\bsu\bud\bdo\bo determines who is an authorized user by consulting
-       the file _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs.  By giving s\bsu\bud\bdo\bo the -\b-v\bv flag, a user
-       can update the time stamp without running a _\bc_\bo_\bm_\bm_\ba_\bn_\bd. The
-       password prompt itself will also time out if the user's
-       password is not entered within 5 minutes (unless overrid­
-       den via _\bs_\bu_\bd_\bo_\be_\br_\bs).
+       If a user who is not listed in the _\bs_\bu_\bd_\bo_\be_\br_\bs file tries to run a command
+       via s\bsu\bud\bdo\bo, mail is sent to the proper authorities, as defined at
+       configure time or in the _\bs_\bu_\bd_\bo_\be_\br_\bs file (defaults to root).  Note that
+       the mail will not be sent if an unauthorized user tries to run sudo
+       with the -\b-l\bl or -\b-v\bv option.  This allows users to determine for
+       themselves whether or not they are allowed to use s\bsu\bud\bdo\bo.
 
-       If a user who is not listed in the _\bs_\bu_\bd_\bo_\be_\br_\bs file tries to
-       run a command via s\bsu\bud\bdo\bo, mail is sent to the proper author­
-       ities, as defined at configure time or in the _\bs_\bu_\bd_\bo_\be_\br_\bs file
-       (defaults to root).  Note that the mail will not be sent
-       if an unauthorized user tries to run sudo with the -\b-l\bl or
-       -\b-v\bv flags.  This allows users to determine for themselves
-       whether or not they are allowed to use s\bsu\bud\bdo\bo.
+       If s\bsu\bud\bdo\bo is run by root and the SUDO_USER environment variable is set,
+       s\bsu\bud\bdo\bo will use this value to determine who the actual user is.  This can
+       be used by a user to log commands through sudo even when a root shell
+       has been invoked.  It also allows the -\b-e\be option to remain useful even
+       when being run via a sudo-run script or program.  Note however, that
+       the sudoers lookup is still done for root, not the user specified by
+       SUDO_USER.
 
-       If s\bsu\bud\bdo\bo is run by root and the SUDO_USER environment vari­
-       able is set, s\bsu\bud\bdo\bo will use this value to determine who the
-       actual user is.  This can be used by a user to log com­
-       mands through sudo even when a root shell has been
-       invoked.  It also allows the -\b-e\be flag to remain useful even
-       when being run via a sudo-run script or program.  Note
-       however, that the sudoers lookup is still done for root,
-       not the user specified by SUDO_USER.
+       s\bsu\bud\bdo\bo can log both successful and unsuccessful attempts (as well as
+       errors) to _\bs_\by_\bs_\bl_\bo_\bg(3), a log file, or both.  By default s\bsu\bud\bdo\bo will log
 
 
 
-1.6.9p17                   Jun 21, 2008                         1
+1.7.0                   November 15, 2008                       1
 
 
 
@@ -70,64 +70,64 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 
 
-       s\bsu\bud\bdo\bo can log both successful and unsuccessful attempts (as
-       well as errors) to _\bs_\by_\bs_\bl_\bo_\bg(3), a log file, or both.  By
-       default s\bsu\bud\bdo\bo will log via _\bs_\by_\bs_\bl_\bo_\bg(3) but this is changeable
-       at configure time or via the _\bs_\bu_\bd_\bo_\be_\br_\bs file.
+       via _\bs_\by_\bs_\bl_\bo_\bg(3) but this is changeable at configure time or via the
+       _\bs_\bu_\bd_\bo_\be_\br_\bs file.
 
 O\bOP\bPT\bTI\bIO\bON\bNS\bS
        s\bsu\bud\bdo\bo accepts the following command line options:
 
-       -a  The -\b-a\ba (_\ba_\bu_\bt_\bh_\be_\bn_\bt_\bi_\bc_\ba_\bt_\bi_\bo_\bn _\bt_\by_\bp_\be) option causes s\bsu\bud\bdo\bo to use
-           the specified authentication type when validating the
-           user, as allowed by _\b/_\be_\bt_\bc_\b/_\bl_\bo_\bg_\bi_\bn_\b._\bc_\bo_\bn_\bf.  The system
-           administrator may specify a list of sudo-specific
-           authentication methods by adding an "auth-sudo" entry
-           in _\b/_\be_\bt_\bc_\b/_\bl_\bo_\bg_\bi_\bn_\b._\bc_\bo_\bn_\bf.  This option is only available on
-           systems that support BSD authentication.
-
-       -b  The -\b-b\bb (_\bb_\ba_\bc_\bk_\bg_\br_\bo_\bu_\bn_\bd) option tells s\bsu\bud\bdo\bo to run the given
-           command in the background.  Note that if you use the
-           -\b-b\bb option you cannot use shell job control to manipu­
-           late the process.
+       -A          Normally, if s\bsu\bud\bdo\bo requires a password, it will read it from
+                   the current terminal.  If the -\b-A\bA (_\ba_\bs_\bk_\bp_\ba_\bs_\bs) option is
+                   specified, a helper program is executed to read the user's
+                   password and output the password to the standard output.
+                   If the SUDO_ASKPASS environment variable is set, it
+                   specifies the path to the helper program.  Otherwise, the
+                   value specified by the _\ba_\bs_\bk_\bp_\ba_\bs_\bs option in _\bs_\bu_\bd_\bo_\be_\br_\bs(4) is
+                   used.
 
-       -c  The -\b-c\bc (_\bc_\bl_\ba_\bs_\bs) option causes s\bsu\bud\bdo\bo to run the specified
-           command with resources limited by the specified login
-           class.  The _\bc_\bl_\ba_\bs_\bs argument can be either a class name
-           as defined in /etc/login.conf, or a single '-' charac­
-           ter.  Specifying a _\bc_\bl_\ba_\bs_\bs of - indicates that the com­
-           mand should be run restricted by the default login
-           capabilities for the user the command is run as.  If
-           the _\bc_\bl_\ba_\bs_\bs argument specifies an existing user class,
-           the command must be run as root, or the s\bsu\bud\bdo\bo command
-           must be run from a shell that is already root.  This
-           option is only available on systems with BSD login
-           classes.
+       -a _\bt_\by_\bp_\be     The -\b-a\ba (_\ba_\bu_\bt_\bh_\be_\bn_\bt_\bi_\bc_\ba_\bt_\bi_\bo_\bn _\bt_\by_\bp_\be) option causes s\bsu\bud\bdo\bo to use the
+                   specified authentication type when validating the user, as
+                   allowed by _\b/_\be_\bt_\bc_\b/_\bl_\bo_\bg_\bi_\bn_\b._\bc_\bo_\bn_\bf.  The system administrator may
+                   specify a list of sudo-specific authentication methods by
+                   adding an "auth-sudo" entry in _\b/_\be_\bt_\bc_\b/_\bl_\bo_\bg_\bi_\bn_\b._\bc_\bo_\bn_\bf.  This
+                   option is only available on systems that support BSD
+                   authentication.
 
-       -E  The -\b-E\bE (_\bp_\br_\be_\bs_\be_\br_\bv_\be _\be_\bn_\bv_\bi_\br_\bo_\bn_\bm_\be_\bn_\bt) option will override the
-           _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option in _\bs_\bu_\bd_\bo_\be_\br_\bs(4)).  It is only available
-           when either the matching command has the SETENV tag or
-           the _\bs_\be_\bt_\be_\bn_\bv option is set in _\bs_\bu_\bd_\bo_\be_\br_\bs(4).
+       -b          The -\b-b\bb (_\bb_\ba_\bc_\bk_\bg_\br_\bo_\bu_\bn_\bd) option tells s\bsu\bud\bdo\bo to run the given
+                   command in the background.  Note that if you use the -\b-b\bb
+                   option you cannot use shell job control to manipulate the
+                   process.
 
-       -e  The -\b-e\be (_\be_\bd_\bi_\bt) option indicates that, instead of run­
-           ning a command, the user wishes to edit one or more
-           files.  In lieu of a command, the string "sudoedit" is
-           used when consulting the _\bs_\bu_\bd_\bo_\be_\br_\bs file.  If the user is
-           authorized by _\bs_\bu_\bd_\bo_\be_\br_\bs the following steps are taken:
+       -C _\bf_\bd       Normally, s\bsu\bud\bdo\bo will close all open file descriptors other
+                   than standard input, standard output and standard error.
+                   The -\b-C\bC (_\bc_\bl_\bo_\bs_\be _\bf_\br_\bo_\bm) option allows the user to specify a
+                   starting point above the standard error (file descriptor
+                   three).  Values less than three are not permitted.  This
+                   option is only available if the administrator has enabled
+                   the _\bc_\bl_\bo_\bs_\be_\bf_\br_\bo_\bm_\b__\bo_\bv_\be_\br_\br_\bi_\bd_\be option in _\bs_\bu_\bd_\bo_\be_\br_\bs(4).
 
-           1.  Temporary copies are made of the files to be
-               edited with the owner set to the invoking user.
+       -c _\bc_\bl_\ba_\bs_\bs    The -\b-c\bc (_\bc_\bl_\ba_\bs_\bs) option causes s\bsu\bud\bdo\bo to run the specified
+                   command with resources limited by the specified login
+                   class.  The _\bc_\bl_\ba_\bs_\bs argument can be either a class name as
+                   defined in _\b/_\be_\bt_\bc_\b/_\bl_\bo_\bg_\bi_\bn_\b._\bc_\bo_\bn_\bf, or a single '-' character.
+                   Specifying a _\bc_\bl_\ba_\bs_\bs of - indicates that the command should
+                   be run restricted by the default login capabilities for the
+                   user the command is run as.  If the _\bc_\bl_\ba_\bs_\bs argument
+                   specifies an existing user class, the command must be run
+                   as root, or the s\bsu\bud\bdo\bo command must be run from a shell that
+                   is already root.  This option is only available on systems
+                   with BSD login classes.
 
-           2.  The editor specified by the VISUAL or EDITOR envi­
-               ronment variables is run to edit the temporary
-               files.  If neither VISUAL nor EDITOR are set, the
-               program listed in the _\be_\bd_\bi_\bt_\bo_\br _\bs_\bu_\bd_\bo_\be_\br_\bs variable is
-               used.
+       -E          The -\b-E\bE (_\bp_\br_\be_\bs_\be_\br_\bv_\be _\be_\bn_\bv_\bi_\br_\bo_\bn_\bm_\be_\bn_\bt) option will override the
+                   _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option in _\bs_\bu_\bd_\bo_\be_\br_\bs(4)).  It is only available when
+                   either the matching command has the SETENV tag or the
+                   _\bs_\be_\bt_\be_\bn_\bv option is set in _\bs_\bu_\bd_\bo_\be_\br_\bs(4).
 
+       -e          The -\b-e\be (_\be_\bd_\bi_\bt) option indicates that, instead of running a
 
 
 
-1.6.9p17                   Jun 21, 2008                         2
+1.7.0                   November 15, 2008                       2
 
 
 
@@ -136,64 +136,64 @@ O\bOP\bPT\bTI\bIO\bON\bNS\bS
 SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 
 
-           3.  If they have been modified, the temporary files
-               are copied back to their original location and the
-               temporary versions are removed.
+                   command, the user wishes to edit one or more files.  In
+                   lieu of a command, the string "sudoedit" is used when
+                   consulting the _\bs_\bu_\bd_\bo_\be_\br_\bs file.  If the user is authorized by
+                   _\bs_\bu_\bd_\bo_\be_\br_\bs the following steps are taken:
 
-           If the specified file does not exist, it will be cre­
-           ated.  Note that unlike most commands run by s\bsu\bud\bdo\bo, the
-           editor is run with the invoking user's environment
-           unmodified.  If, for some reason, s\bsu\bud\bdo\bo is unable to
-           update a file with its edited version, the user will
-           receive a warning and the edited copy will remain in a
-           temporary file.
+                   1.  Temporary copies are made of the files to be edited
+                       with the owner set to the invoking user.
 
-       -H  The -\b-H\bH (_\bH_\bO_\bM_\bE) option sets the HOME environment vari­
-           able to the homedir of the target user (root by
-           default) as specified in _\bp_\ba_\bs_\bs_\bw_\bd(4).  By default, s\bsu\bud\bdo\bo
-           does not modify HOME (see _\bs_\be_\bt_\b__\bh_\bo_\bm_\be and _\ba_\bl_\bw_\ba_\by_\bs_\b__\bs_\be_\bt_\b__\bh_\bo_\bm_\be
-           in _\bs_\bu_\bd_\bo_\be_\br_\bs(4)).
+                   2.  The editor specified by the SUDO_EDITOR, VISUAL or
+                       EDITOR environment variables is run to edit the
+                       temporary files.  If none of SUDO_EDITOR, VISUAL or
+                       EDITOR are set, the first program listed in the _\be_\bd_\bi_\bt_\bo_\br
+                       _\bs_\bu_\bd_\bo_\be_\br_\bs variable is used.
 
-       -h  The -\b-h\bh (_\bh_\be_\bl_\bp) option causes s\bsu\bud\bdo\bo to print a usage mes­
-           sage and exit.
+                   3.  If they have been modified, the temporary files are
+                       copied back to their original location and the
+                       temporary versions are removed.
 
-       -i  The -\b-i\bi (_\bs_\bi_\bm_\bu_\bl_\ba_\bt_\be _\bi_\bn_\bi_\bt_\bi_\ba_\bl _\bl_\bo_\bg_\bi_\bn) option runs the shell
-           specified in the _\bp_\ba_\bs_\bs_\bw_\bd(4) entry of the user that the
-           command is being run as.  The command name argument
-           given to the shell begins with a `-' to tell the shell
-           to run as a login shell.  s\bsu\bud\bdo\bo attempts to change to
-           that user's home directory before running the shell.
-           It also initializes the environment, leaving _\bT_\bE_\bR_\bM
-           unchanged, setting _\bH_\bO_\bM_\bE, _\bS_\bH_\bE_\bL_\bL, _\bU_\bS_\bE_\bR, _\bL_\bO_\bG_\bN_\bA_\bM_\bE, and
-           _\bP_\bA_\bT_\bH, and unsetting all other environment variables.
-           Note that because the shell to use is determined
-           before the _\bs_\bu_\bd_\bo_\be_\br_\bs file is parsed, a _\br_\bu_\bn_\ba_\bs_\b__\bd_\be_\bf_\ba_\bu_\bl_\bt
-           setting in _\bs_\bu_\bd_\bo_\be_\br_\bs will specify the user to run the
-           shell as but will not affect which shell is actually
-           run.
+                   If the specified file does not exist, it will be created.
+                   Note that unlike most commands run by s\bsu\bud\bdo\bo, the editor is
+                   run with the invoking user's environment unmodified.  If,
+                   for some reason, s\bsu\bud\bdo\bo is unable to update a file with its
+                   edited version, the user will receive a warning and the
+                   edited copy will remain in a temporary file.
 
-       -K  The -\b-K\bK (sure _\bk_\bi_\bl_\bl) option is like -\b-k\bk except that it
-           removes the user's timestamp entirely.  Like -\b-k\bk, this
-           option does not require a password.
+       -g _\bg_\br_\bo_\bu_\bp    Normally, s\bsu\bud\bdo\bo sets the primary group to the one specified
+                   by the passwd database for the user the command is being
+                   run as (by default, root).  The -\b-g\bg (_\bg_\br_\bo_\bu_\bp) option causes
+                   s\bsu\bud\bdo\bo to run the specified command with the primary group
+                   set to _\bg_\br_\bo_\bu_\bp.  To specify a _\bg_\bi_\bd instead of a _\bg_\br_\bo_\bu_\bp _\bn_\ba_\bm_\be,
+                   use _\b#_\bg_\bi_\bd.  When running commands as a _\bg_\bi_\bd, many shells
+                   require that the '#' be escaped with a backslash ('\').  If
+                   no -\b-u\bu option is specified, the command will be run as the
+                   invoking user (not root).  In either case, the primary
+                   group will be set to _\bg_\br_\bo_\bu_\bp.
 
-       -k  The -\b-k\bk (_\bk_\bi_\bl_\bl) option to s\bsu\bud\bdo\bo invalidates the user's
-           timestamp by setting the time on it to the Epoch.  The
-           next time s\bsu\bud\bdo\bo is run a password will be required.
-           This option does not require a password and was added
-           to allow a user to revoke s\bsu\bud\bdo\bo permissions from a
-           .logout file.
+       -H          The -\b-H\bH (_\bH_\bO_\bM_\bE) option sets the HOME environment variable to
+                   the homedir of the target user (root by default) as
+                   specified in _\bp_\ba_\bs_\bs_\bw_\bd(4).  By default, s\bsu\bud\bdo\bo does not modify
+                   HOME (see _\bs_\be_\bt_\b__\bh_\bo_\bm_\be and _\ba_\bl_\bw_\ba_\by_\bs_\b__\bs_\be_\bt_\b__\bh_\bo_\bm_\be in _\bs_\bu_\bd_\bo_\be_\br_\bs(4)).
 
-       -L  The -\b-L\bL (_\bl_\bi_\bs_\bt defaults) option will list out the param­
-           eters that may be set in a _\bD_\be_\bf_\ba_\bu_\bl_\bt_\bs line along with a
-           short description for each.  This option is useful in
-           conjunction with _\bg_\br_\be_\bp(1).
+       -h          The -\b-h\bh (_\bh_\be_\bl_\bp) option causes s\bsu\bud\bdo\bo to print a usage message
+                   and exit.
 
-       -l  The -\b-l\bl (_\bl_\bi_\bs_\bt) option will list out the allowed (and
-           forbidden) commands for the invoking user on the
+       -i [command]
+                   The -\b-i\bi (_\bs_\bi_\bm_\bu_\bl_\ba_\bt_\be _\bi_\bn_\bi_\bt_\bi_\ba_\bl _\bl_\bo_\bg_\bi_\bn) option runs the shell
+                   specified in the _\bp_\ba_\bs_\bs_\bw_\bd(4) entry of the target user as a
+                   login shell.  This means that login-specific resource files
+                   such as .profile or .login will be read by the shell.  If a
+                   command is specified, it is passed to the shell for
+                   execution.  Otherwise, an interactive shell is executed.
+                   s\bsu\bud\bdo\bo attempts to change to that user's home directory
+                   before running the shell.  It also initializes the
+                   environment, leaving _\bD_\bI_\bS_\bP_\bL_\bA_\bY and _\bT_\bE_\bR_\bM unchanged, setting
 
 
 
-1.6.9p17                   Jun 21, 2008                         3
+1.7.0                   November 15, 2008                       3
 
 
 
@@ -202,130 +202,130 @@ SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 
 
-           current host.
+                   _\bH_\bO_\bM_\bE, _\bS_\bH_\bE_\bL_\bL, _\bU_\bS_\bE_\bR, _\bL_\bO_\bG_\bN_\bA_\bM_\bE, and _\bP_\bA_\bT_\bH, as well as the
+                   contents of _\b/_\be_\bt_\bc_\b/_\be_\bn_\bv_\bi_\br_\bo_\bn_\bm_\be_\bn_\bt on Linux and AIX systems.  All
+                   other environment variables are removed.
 
-       -P  The -\b-P\bP (_\bp_\br_\be_\bs_\be_\br_\bv_\be _\bg_\br_\bo_\bu_\bp _\bv_\be_\bc_\bt_\bo_\br) option causes s\bsu\bud\bdo\bo to
-           preserve the invoking user's group vector unaltered.
-           By default, s\bsu\bud\bdo\bo will initialize the group vector to
-           the list of groups the target user is in.  The real
-           and effective group IDs, however, are still set to
-           match the target user.
+       -K          The -\b-K\bK (sure _\bk_\bi_\bl_\bl) option is like -\b-k\bk except that it removes
+                   the user's timestamp entirely.  Like -\b-k\bk, this option does
+                   not require a password.
 
-       -p  The -\b-p\bp (_\bp_\br_\bo_\bm_\bp_\bt) option allows you to override the
-           default password prompt and use a custom one.  The
-           following percent (`%') escapes are supported:
+       -k          The -\b-k\bk (_\bk_\bi_\bl_\bl) option to s\bsu\bud\bdo\bo invalidates the user's
+                   timestamp by setting the time on it to the Epoch.  The next
+                   time s\bsu\bud\bdo\bo is run a password will be required.  This option
+                   does not require a password and was added to allow a user
+                   to revoke s\bsu\bud\bdo\bo permissions from a .logout file.
 
-           %H  expanded to the local hostname including the
-               domain name (on if the machine's hostname is fully
-               qualified or the _\bf_\bq_\bd_\bn _\bs_\bu_\bd_\bo_\be_\br_\bs option is set)
+       -L          The -\b-L\bL (_\bl_\bi_\bs_\bt defaults) option will list out the parameters
+                   that may be set in a _\bD_\be_\bf_\ba_\bu_\bl_\bt_\bs line along with a short
+                   description for each.  This option is useful in conjunction
+                   with _\bg_\br_\be_\bp(1).
 
-           %h  expanded to the local hostname without the domain
-               name
+       -l[l] [_\bc_\bo_\bm_\bm_\ba_\bn_\bd]
+                   If no _\bc_\bo_\bm_\bm_\ba_\bn_\bd is specified, the -\b-l\bl (_\bl_\bi_\bs_\bt) option will list
+                   the allowed (and forbidden) commands for the invoking user
+                   (or the user specified by the -\b-U\bU option) on the current
+                   host.  If a _\bc_\bo_\bm_\bm_\ba_\bn_\bd is specified and is permitted by
+                   _\bs_\bu_\bd_\bo_\be_\br_\bs, the fully-qualified path to the command is
+                   displayed along with any command line arguments.  If
+                   _\bc_\bo_\bm_\bm_\ba_\bn_\bd is specified but not allowed, s\bsu\bud\bdo\bo will exit with a
+                   status value of 1.  If the -\b-l\bl option is specified with an l\bl
+                   argument (i.e. -\b-l\bll\bl), or if -\b-l\bl is specified multiple times,
+                   a longer list format is used.
 
-           %p  expanded to the user whose password is being asked
-               for (respects the _\br_\bo_\bo_\bt_\bp_\bw, _\bt_\ba_\br_\bg_\be_\bt_\bp_\bw and _\br_\bu_\bn_\ba_\bs_\bp_\bw
-               flags in _\bs_\bu_\bd_\bo_\be_\br_\bs)
+       -n          The -\b-n\bn (_\bn_\bo_\bn_\b-_\bi_\bn_\bt_\be_\br_\ba_\bc_\bt_\bi_\bv_\be) option prevents s\bsu\bud\bdo\bo from
+                   prompting the user for a password.  If a password is
+                   required for the command to run, s\bsu\bud\bdo\bo will display an error
+                   messages and exit.
 
-           %U  expanded to the login name of the user the command
-               will be run as (defaults to root)
+       -P          The -\b-P\bP (_\bp_\br_\be_\bs_\be_\br_\bv_\be _\bg_\br_\bo_\bu_\bp _\bv_\be_\bc_\bt_\bo_\br) option causes s\bsu\bud\bdo\bo to
+                   preserve the invoking user's group vector unaltered.  By
+                   default, s\bsu\bud\bdo\bo will initialize the group vector to the list
+                   of groups the target user is in.  The real and effective
+                   group IDs, however, are still set to match the target user.
 
-           %u  expanded to the invoking user's login name
+       -p _\bp_\br_\bo_\bm_\bp_\bt   The -\b-p\bp (_\bp_\br_\bo_\bm_\bp_\bt) option allows you to override the default
+                   password prompt and use a custom one.  The following
+                   percent (`%') escapes are supported:
 
-           %%  two consecutive % characters are collapsed into a
-               single % character
+                   %H  expanded to the local hostname including the domain
+                       name (on if the machine's hostname is fully qualified
+                       or the _\bf_\bq_\bd_\bn _\bs_\bu_\bd_\bo_\be_\br_\bs option is set)
 
-       -S  The -\b-S\bS (_\bs_\bt_\bd_\bi_\bn) option causes s\bsu\bud\bdo\bo to read the password
-           from the standard input instead of the terminal
-           device.
+                   %h  expanded to the local hostname without the domain name
 
-       -s  The -\b-s\bs (_\bs_\bh_\be_\bl_\bl) option runs the shell specified by the
-           _\bS_\bH_\bE_\bL_\bL environment variable if it is set or the shell
-           as specified in _\bp_\ba_\bs_\bs_\bw_\bd(4).
+                   %p  expanded to the user whose password is being asked for
+                       (respects the _\br_\bo_\bo_\bt_\bp_\bw, _\bt_\ba_\br_\bg_\be_\bt_\bp_\bw and _\br_\bu_\bn_\ba_\bs_\bp_\bw flags in
 
-       -u  The -\b-u\bu (_\bu_\bs_\be_\br) option causes s\bsu\bud\bdo\bo to run the specified
-           command as a user other than _\br_\bo_\bo_\bt.  To specify a _\bu_\bi_\bd
-           instead of a _\bu_\bs_\be_\br_\bn_\ba_\bm_\be, use _\b#_\bu_\bi_\bd.  When running com­
-           mands as a _\bu_\bi_\bd, many shells require that the '#' be
-           escaped with a backslash ('\').  Note that if the _\bt_\ba_\br_\b­
-           _\bg_\be_\bt_\bp_\bw Defaults option is set (see _\bs_\bu_\bd_\bo_\be_\br_\bs(4)) it is
-           not possible to run commands with a uid not listed in
-           the password database.
 
-       -V  The -\b-V\bV (_\bv_\be_\br_\bs_\bi_\bo_\bn) option causes s\bsu\bud\bdo\bo to print the ver­
-           sion number and exit.  If the invoking user is already
-           root the -\b-V\bV option will print out a list of the
-           defaults s\bsu\bud\bdo\bo was compiled with as well as the
-           machine's local network addresses.
 
+1.7.0                   November 15, 2008                       4
 
 
-1.6.9p17                   Jun 21, 2008                         4
 
 
 
+SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 
 
-SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
+                       _\bs_\bu_\bd_\bo_\be_\br_\bs)
 
+                   %U  expanded to the login name of the user the command will
+                       be run as (defaults to root)
 
-       -v  If given the -\b-v\bv (_\bv_\ba_\bl_\bi_\bd_\ba_\bt_\be) option, s\bsu\bud\bdo\bo will update
-           the user's timestamp, prompting for the user's pass­
-           word if necessary.  This extends the s\bsu\bud\bdo\bo timeout for
-           another 5 minutes (or whatever the timeout is set to
-           in _\bs_\bu_\bd_\bo_\be_\br_\bs) but does not run a command.
+                   %u  expanded to the invoking user's login name
 
-       --  The -\b--\b- flag indicates that s\bsu\bud\bdo\bo should stop processing
-           command line arguments.  It is most useful in conjunc­
-           tion with the -\b-s\bs flag.
+                   %%  two consecutive % characters are collapsed into a
+                       single % character
 
-       Environment variables to be set for the command may also
-       be passed on the command line in the form of V\bVA\bAR\bR=_\bv_\ba_\bl_\bu_\be,
-       e.g.  L\bLD\bD_\b_L\bLI\bIB\bBR\bRA\bAR\bRY\bY_\b_P\bPA\bAT\bTH\bH=_\b/_\bu_\bs_\br_\b/_\bl_\bo_\bc_\ba_\bl_\b/_\bp_\bk_\bg_\b/_\bl_\bi_\bb.  Variables
-       passed on the command line are subject to the same
-       restrictions as normal environment variables with one
-       important exception.  If the _\bs_\be_\bt_\be_\bn_\bv option is set in _\bs_\bu_\bd_\bo_\b­
-       _\be_\br_\bs, the command to be run has the SETENV tag set or the
-       command matched is ALL, the user may set variables that
-       would overwise be forbidden.  See _\bs_\bu_\bd_\bo_\be_\br_\bs(4) for more
-       information.
+                   The prompt specified by the -\b-p\bp option will override the
+                   system password prompt on systems that support PAM unless
+                   the _\bp_\ba_\bs_\bs_\bp_\br_\bo_\bm_\bp_\bt_\b__\bo_\bv_\be_\br_\br_\bi_\bd_\be flag is disabled in _\bs_\bu_\bd_\bo_\be_\br_\bs.
 
-R\bRE\bET\bTU\bUR\bRN\bN V\bVA\bAL\bLU\bUE\bES\bS
-       Upon successful execution of a program, the return value
-       from s\bsu\bud\bdo\bo will simply be the return value of the program
-       that was executed.
-
-       Otherwise, s\bsu\bud\bdo\bo quits with an exit value of 1 if there is
-       a configuration/permission problem or if s\bsu\bud\bdo\bo cannot exe­
-       cute the given command.  In the latter case the error
-       string is printed to stderr.  If s\bsu\bud\bdo\bo cannot _\bs_\bt_\ba_\bt(2) one
-       or more entries in the user's PATH an error is printed on
-       stderr.  (If the directory does not exist or if it is not
-       really a directory, the entry is ignored and no error is
-       printed.)  This should not happen under normal circum­
-       stances.  The most common reason for _\bs_\bt_\ba_\bt(2) to return
-       "permission denied" is if you are running an automounter
-       and one of the directories in your PATH is on a machine
-       that is currently unreachable.
+       -S          The -\b-S\bS (_\bs_\bt_\bd_\bi_\bn) option causes s\bsu\bud\bdo\bo to read the password from
+                   the standard input instead of the terminal device.
 
-S\bSE\bEC\bCU\bUR\bRI\bIT\bTY\bY N\bNO\bOT\bTE\bES\bS
-       s\bsu\bud\bdo\bo tries to be safe when executing external commands.
+       -s [command]
+                   The -\b-s\bs (_\bs_\bh_\be_\bl_\bl) option runs the shell specified by the _\bS_\bH_\bE_\bL_\bL
+                   environment variable if it is set or the shell as specified
+                   in _\bp_\ba_\bs_\bs_\bw_\bd(4).  If a command is specified, it is passed to
+                   the shell for execution.  Otherwise, an interactive shell
+                   is executed.
+
+       -U _\bu_\bs_\be_\br     The -\b-U\bU (_\bo_\bt_\bh_\be_\br _\bu_\bs_\be_\br) option is used in conjunction with the
+                   -\b-l\bl option to specify the user whose privileges should be
+                   listed.  Only root or a user with s\bsu\bud\bdo\bo ALL on the current
+                   host may use this option.
 
-       There are two distinct ways to deal with environment vari­
-       ables.  By default, the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt _\bs_\bu_\bd_\bo_\be_\br_\bs option is
-       enabled.  This causes commands to be executed with a mini­
-       mal environment containing TERM, PATH, HOME, SHELL, LOG­
-       NAME, USER and USERNAME in addition to variables from the
-       invoking process permitted by the _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk and _\be_\bn_\bv_\b__\bk_\be_\be_\bp
-       _\bs_\bu_\bd_\bo_\be_\br_\bs options.  There is effectively a whitelist for
-       environment variables.
+       -u _\bu_\bs_\be_\br     The -\b-u\bu (_\bu_\bs_\be_\br) option causes s\bsu\bud\bdo\bo to run the specified
+                   command as a user other than _\br_\bo_\bo_\bt.  To specify a _\bu_\bi_\bd
+                   instead of a _\bu_\bs_\be_\br _\bn_\ba_\bm_\be, use _\b#_\bu_\bi_\bd.  When running commands as
+                   a _\bu_\bi_\bd, many shells require that the '#' be escaped with a
+                   backslash ('\').  Note that if the _\bt_\ba_\br_\bg_\be_\bt_\bp_\bw Defaults option
+                   is set (see _\bs_\bu_\bd_\bo_\be_\br_\bs(4)) it is not possible to run commands
+                   with a uid not listed in the password database.
 
-       If, however, the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is disabled in _\bs_\bu_\bd_\bo_\be_\br_\bs,
-       any variables not explicitly denied by the _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk and
-       _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be options are inherited from the invoking
+       -V          The -\b-V\bV (_\bv_\be_\br_\bs_\bi_\bo_\bn) option causes s\bsu\bud\bdo\bo to print the version
+                   number and exit.  If the invoking user is already root the
+                   -\b-V\bV option will print out a list of the defaults s\bsu\bud\bdo\bo was
+                   compiled with as well as the machine's local network
+                   addresses.
 
+       -v          If given the -\b-v\bv (_\bv_\ba_\bl_\bi_\bd_\ba_\bt_\be) option, s\bsu\bud\bdo\bo will update the
+                   user's timestamp, prompting for the user's password if
+                   necessary.  This extends the s\bsu\bud\bdo\bo timeout for another 5
+                   minutes (or whatever the timeout is set to in _\bs_\bu_\bd_\bo_\be_\br_\bs) but
+                   does not run a command.
 
+       --          The -\b--\b- option indicates that s\bsu\bud\bdo\bo should stop processing
+                   command line arguments.  It is most useful in conjunction
+                   with the -\b-s\bs option.
 
-1.6.9p17                   Jun 21, 2008                         5
+       Environment variables to be set for the command may also be passed on
+
+
+
+1.7.0                   November 15, 2008                       5
 
 
 
@@ -334,64 +334,64 @@ S\bSE\bEC\bCU\bUR\bRI\bIT\bTY\bY N\bNO\bOT\bTE\bES\bS
 SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 
 
-       process.  In this case, _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk and _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be behave
-       like a blacklist.  Since it is not possible to blacklist
-       all potentially dangerous environment variables, use of
-       the default _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt behavior is encouraged.
-
-       In all cases, environment variables with a value beginning
-       with () are removed as they could be interpreted as b\bba\bas\bsh\bh
-       functions.  The list of environment variables that s\bsu\bud\bdo\bo
-       allows or denies is contained in the output of sudo -V
-       when run as root.
-
-       Note that the dynamic linker on most operating systems
-       will remove variables that can control dynamic linking
-       from the environment of setuid executables, including
-       s\bsu\bud\bdo\bo.  Depending on the operating system this may include
-       _RLD*, DYLD_*, LD_*, LDR_*, LIBPATH, SHLIB_PATH, and oth­
-       ers.  These type of variables are removed from the envi­
-       ronment before s\bsu\bud\bdo\bo even begins execution and, as such, it
-       is not possible for s\bsu\bud\bdo\bo to preserve them.
-
-       To prevent command spoofing, s\bsu\bud\bdo\bo checks "." and "" (both
-       denoting current directory) last when searching for a com­
-       mand in the user's PATH (if one or both are in the PATH).
-       Note, however, that the actual PATH environment variable
-       is _\bn_\bo_\bt modified and is passed unchanged to the program
-       that s\bsu\bud\bdo\bo executes.
-
-       s\bsu\bud\bdo\bo will check the ownership of its timestamp directory
-       (_\b/_\bv_\ba_\br_\b/_\br_\bu_\bn_\b/_\bs_\bu_\bd_\bo by default) and ignore the directory's con­
-       tents if it is not owned by root or if it is writable by a
-       user other than root.  On systems that allow non-root
-       users to give away files via _\bc_\bh_\bo_\bw_\bn(2), if the timestamp
-       directory is located in a directory writable by anyone
-       (e.g., _\b/_\bt_\bm_\bp), it is possible for a user to create the
-       timestamp directory before s\bsu\bud\bdo\bo is run.  However, because
-       s\bsu\bud\bdo\bo checks the ownership and mode of the directory and
-       its contents, the only damage that can be done is to
-       "hide" files by putting them in the timestamp dir.  This
-       is unlikely to happen since once the timestamp dir is
-       owned by root and inaccessible by any other user, the user
-       placing files there would be unable to get them back out.
-       To get around this issue you can use a directory that is
-       not world-writable for the timestamps (_\b/_\bv_\ba_\br_\b/_\ba_\bd_\bm_\b/_\bs_\bu_\bd_\bo for
-       instance) or create _\b/_\bv_\ba_\br_\b/_\br_\bu_\bn_\b/_\bs_\bu_\bd_\bo with the appropriate
-       owner (root) and permissions (0700) in the system startup
-       files.
-
-       s\bsu\bud\bdo\bo will not honor timestamps set far in the future.
-       Timestamps with a date greater than current_time + 2 *
-       TIMEOUT will be ignored and sudo will log and complain.
-       This is done to keep a user from creating his/her own
-       timestamp with a bogus date on systems that allow users to
-       give away files.
+       the command line in the form of V\bVA\bAR\bR=_\bv_\ba_\bl_\bu_\be, e.g.
+       L\bLD\bD_\b_L\bLI\bIB\bBR\bRA\bAR\bRY\bY_\b_P\bPA\bAT\bTH\bH=_\b/_\bu_\bs_\br_\b/_\bl_\bo_\bc_\ba_\bl_\b/_\bp_\bk_\bg_\b/_\bl_\bi_\bb.  Variables passed on the command
+       line are subject to the same restrictions as normal environment
+       variables with one important exception.  If the _\bs_\be_\bt_\be_\bn_\bv option is set in
+       _\bs_\bu_\bd_\bo_\be_\br_\bs, the command to be run has the SETENV tag set or the command
+       matched is ALL, the user may set variables that would overwise be
+       forbidden.  See _\bs_\bu_\bd_\bo_\be_\br_\bs(4) for more information.
+
+R\bRE\bET\bTU\bUR\bRN\bN V\bVA\bAL\bLU\bUE\bES\bS
+       Upon successful execution of a program, the exit status from s\bsu\bud\bdo\bo will
+       simply be the exit status of the program that was executed.
+
+       Otherwise, s\bsu\bud\bdo\bo quits with an exit value of 1 if there is a
+       configuration/permission problem or if s\bsu\bud\bdo\bo cannot execute the given
+       command.  In the latter case the error string is printed to stderr.  If
+       s\bsu\bud\bdo\bo cannot _\bs_\bt_\ba_\bt(2) one or more entries in the user's PATH an error is
+       printed on stderr.  (If the directory does not exist or if it is not
+       really a directory, the entry is ignored and no error is printed.)
+       This should not happen under normal circumstances.  The most common
+       reason for _\bs_\bt_\ba_\bt(2) to return "permission denied" is if you are running
+       an automounter and one of the directories in your PATH is on a machine
+       that is currently unreachable.
+
+S\bSE\bEC\bCU\bUR\bRI\bIT\bTY\bY N\bNO\bOT\bTE\bES\bS
+       s\bsu\bud\bdo\bo tries to be safe when executing external commands.
 
+       There are two distinct ways to deal with environment variables.  By
+       default, the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt _\bs_\bu_\bd_\bo_\be_\br_\bs option is enabled.  This causes commands
+       to be executed with a minimal environment containing TERM, PATH, HOME,
+       SHELL, LOGNAME, USER and USERNAME in addition to variables from the
+       invoking process permitted by the _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk and _\be_\bn_\bv_\b__\bk_\be_\be_\bp _\bs_\bu_\bd_\bo_\be_\br_\bs
+       options.  There is effectively a whitelist for environment variables.
 
+       If, however, the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is disabled in _\bs_\bu_\bd_\bo_\be_\br_\bs, any variables
+       not explicitly denied by the _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk and _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be options are
+       inherited from the invoking process.  In this case, _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk and
+       _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be behave like a blacklist.  Since it is not possible to
+       blacklist all potentially dangerous environment variables, use of the
+       default _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt behavior is encouraged.
 
+       In all cases, environment variables with a value beginning with () are
+       removed as they could be interpreted as b\bba\bas\bsh\bh functions.  The list of
+       environment variables that s\bsu\bud\bdo\bo allows or denies is contained in the
+       output of sudo -V when run as root.
 
-1.6.9p17                   Jun 21, 2008                         6
+       Note that the dynamic linker on most operating systems will remove
+       variables that can control dynamic linking from the environment of
+       setuid executables, including s\bsu\bud\bdo\bo.  Depending on the operating system
+       this may include _RLD*, DYLD_*, LD_*, LDR_*, LIBPATH, SHLIB_PATH, and
+       others.  These type of variables are removed from the environment
+       before s\bsu\bud\bdo\bo even begins execution and, as such, it is not possible for
+       s\bsu\bud\bdo\bo to preserve them.
+
+       To prevent command spoofing, s\bsu\bud\bdo\bo checks "." and "" (both denoting
+
+
+
+1.7.0                   November 15, 2008                       6
 
 
 
@@ -400,83 +400,112 @@ SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 
 
-       Please note that s\bsu\bud\bdo\bo will normally only log the command
-       it explicitly runs.  If a user runs a command such as sudo
-       su or sudo sh, subsequent commands run from that shell
-       will _\bn_\bo_\bt be logged, nor will s\bsu\bud\bdo\bo's access control affect
-       them.  The same is true for commands that offer shell
-       escapes (including most editors).  Because of this, care
-       must be taken when giving users access to commands via
-       s\bsu\bud\bdo\bo to verify that the command does not inadvertently
-       give the user an effective root shell.  For more informa­
-       tion, please see the PREVENTING SHELL ESCAPES section in
-       _\bs_\bu_\bd_\bo_\be_\br_\bs(4).
+       current directory) last when searching for a command in the user's PATH
+       (if one or both are in the PATH).  Note, however, that the actual PATH
+       environment variable is _\bn_\bo_\bt modified and is passed unchanged to the
+       program that s\bsu\bud\bdo\bo executes.
+
+       s\bsu\bud\bdo\bo will check the ownership of its timestamp directory (_\b/_\bv_\ba_\br_\b/_\br_\bu_\bn_\b/_\bs_\bu_\bd_\bo
+       by default) and ignore the directory's contents if it is not owned by
+       root or if it is writable by a user other than root.  On systems that
+       allow non-root users to give away files via _\bc_\bh_\bo_\bw_\bn(2), if the timestamp
+       directory is located in a directory writable by anyone (e.g., _\b/_\bt_\bm_\bp), it
+       is possible for a user to create the timestamp directory before s\bsu\bud\bdo\bo is
+       run.  However, because s\bsu\bud\bdo\bo checks the ownership and mode of the
+       directory and its contents, the only damage that can be done is to
+       "hide" files by putting them in the timestamp dir.  This is unlikely to
+       happen since once the timestamp dir is owned by root and inaccessible
+       by any other user, the user placing files there would be unable to get
+       them back out.  To get around this issue you can use a directory that
+       is not world-writable for the timestamps (_\b/_\bv_\ba_\br_\b/_\ba_\bd_\bm_\b/_\bs_\bu_\bd_\bo for instance)
+       or create _\b/_\bv_\ba_\br_\b/_\br_\bu_\bn_\b/_\bs_\bu_\bd_\bo with the appropriate owner (root) and
+       permissions (0700) in the system startup files.
+
+       s\bsu\bud\bdo\bo will not honor timestamps set far in the future.  Timestamps with
+       a date greater than current_time + 2 * TIMEOUT will be ignored and sudo
+       will log and complain.  This is done to keep a user from creating
+       his/her own timestamp with a bogus date on systems that allow users to
+       give away files.
+
+       Please note that s\bsu\bud\bdo\bo will normally only log the command it explicitly
+       runs.  If a user runs a command such as sudo su or sudo sh, subsequent
+       commands run from that shell will _\bn_\bo_\bt be logged, nor will s\bsu\bud\bdo\bo's access
+       control affect them.  The same is true for commands that offer shell
+       escapes (including most editors).  Because of this, care must be taken
+       when giving users access to commands via s\bsu\bud\bdo\bo to verify that the
+       command does not inadvertently give the user an effective root shell.
+       For more information, please see the PREVENTING SHELL ESCAPES section
+       in _\bs_\bu_\bd_\bo_\be_\br_\bs(4).
 
 E\bEN\bNV\bVI\bIR\bRO\bON\bNM\bME\bEN\bNT\bT
        s\bsu\bud\bdo\bo utilizes the following environment variables:
 
-       EDITOR          Default editor to use in -\b-e\be (sudoedit)
-                       mode if VISUAL is not set
+       EDITOR          Default editor to use in -\b-e\be (sudoedit) mode if neither
+                       SUDO_EDITOR nor VISUAL is set
 
-       HOME            In -\b-s\bs or -\b-H\bH mode (or if sudo was config­
-                       ured with the --enable-shell-sets-home
-                       option), set to homedir of the target user
+       HOME            In -\b-s\bs or -\b-H\bH mode (or if sudo was configured with the
+                       --enable-shell-sets-home option), set to homedir of the
+                       target user
 
-       PATH            Set to a sane value if the _\bs_\be_\bc_\bu_\br_\be_\b__\bp_\ba_\bt_\bh
-                       sudoers option is set.
+       PATH            Set to a sane value if the _\bs_\be_\bc_\bu_\br_\be_\b__\bp_\ba_\bt_\bh sudoers option
+                       is set.
 
-       SHELL           Used to determine shell to run with -s
-                       option
+       SHELL           Used to determine shell to run with -s option
 
-       SUDO_PROMPT     Used as the default password prompt
+       SUDO_ASKPASS    Specifies the path to a helper program used to read the
+                       password if no terminal is available or if the -A
 
-       SUDO_COMMAND    Set to the command run by sudo
 
-       SUDO_USER       Set to the login of the user who invoked
-                       sudo
 
-       SUDO_UID        Set to the uid of the user who invoked
-                       sudo
+1.7.0                   November 15, 2008                       7
 
-       SUDO_GID        Set to the gid of the user who invoked
-                       sudo
 
-       SUDO_PS1        If set, PS1 will be set to its value
 
-       USER            Set to the target user (root unless the -\b-u\bu
-                       option is specified)
 
-       VISUAL          Default editor to use in -\b-e\be (sudoedit)
-                       mode
 
-F\bFI\bIL\bLE\bES\bS
-       _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs            List of who can run what
+SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 
-       _\b/_\bv_\ba_\br_\b/_\br_\bu_\bn_\b/_\bs_\bu_\bd_\bo           Directory containing timestamps
 
+                       option is specified.
 
+       SUDO_COMMAND    Set to the command run by sudo
 
+       SUDO_EDITOR     Default editor to use in -\b-e\be (sudoedit) mode
 
-1.6.9p17                   Jun 21, 2008                         7
+       SUDO_GID        Set to the group ID of the user who invoked sudo
 
+       SUDO_PROMPT     Used as the default password prompt
 
+       SUDO_PS1        If set, PS1 will be set to its value for the program
+                       being run
 
+       SUDO_UID        Set to the user ID of the user who invoked sudo
 
+       SUDO_USER       Set to the login of the user who invoked sudo
 
-SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
+       USER            Set to the target user (root unless the -\b-u\bu option is
+                       specified)
 
+       VISUAL          Default editor to use in -\b-e\be (sudoedit) mode if
+                       SUDO_EDITOR is not set
+
+F\bFI\bIL\bLE\bES\bS
+       _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs            List of who can run what
+
+       _\b/_\bv_\ba_\br_\b/_\br_\bu_\bn_\b/_\bs_\bu_\bd_\bo           Directory containing timestamps
+
+       _\b/_\be_\bt_\bc_\b/_\be_\bn_\bv_\bi_\br_\bo_\bn_\bm_\be_\bn_\bt        Initial environment for -\b-i\bi mode on Linux and
+                               AIX
 
 E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
-       Note: the following examples assume suitable _\bs_\bu_\bd_\bo_\be_\br_\bs(4)
-       entries.
+       Note: the following examples assume suitable _\bs_\bu_\bd_\bo_\be_\br_\bs(4) entries.
 
        To get a file listing of an unreadable directory:
 
         $ sudo ls /usr/local/protected
 
-       To list the home directory of user yazza on a machine
-       where the file system holding ~yazza is not exported as
-       root:
+       To list the home directory of user yazza on a machine where the file
+       system holding ~yazza is not exported as root:
 
         $ sudo -u yazza ls ~yazza
 
@@ -488,107 +517,78 @@ E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
 
         $ sudo shutdown -r +15 "quick reboot"
 
-       To make a usage listing of the directories in the /home
-       partition.  Note that this runs the commands in a sub-
-       shell to make the cd and file redirection work.
+       To make a usage listing of the directories in the /home partition.
+       Note that this runs the commands in a sub-shell to make the cd and file
+       redirection work.
 
-        $ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE"
 
-S\bSE\bEE\bE A\bAL\bLS\bSO\bO
-       _\bg_\br_\be_\bp(1), _\bs_\bu(1), _\bs_\bt_\ba_\bt(2), _\bl_\bo_\bg_\bi_\bn_\b__\bc_\ba_\bp(3), _\bp_\ba_\bs_\bs_\bw_\bd(4),
-       _\bs_\bu_\bd_\bo_\be_\br_\bs(5), _\bv_\bi_\bs_\bu_\bd_\bo(1m)
 
-A\bAU\bUT\bTH\bHO\bOR\bRS\bS
-       Many people have worked on s\bsu\bud\bdo\bo over the years; this ver­
-       sion consists of code written primarily by:
+1.7.0                   November 15, 2008                       8
 
-               Todd C. Miller
-               Chris Jepeway
 
-       See the HISTORY file in the s\bsu\bud\bdo\bo distribution or visit
-       http://www.sudo.ws/sudo/history.html for a short history
-       of s\bsu\bud\bdo\bo.
 
-C\bCA\bAV\bVE\bEA\bAT\bTS\bS
-       There is no easy way to prevent a user from gaining a root
-       shell if that user is allowed to run arbitrary commands
-       via s\bsu\bud\bdo\bo.  Also, many programs (such as editors) allow the
-       user to run commands via shell escapes, thus avoiding
-       s\bsu\bud\bdo\bo's checks.  However, on most systems it is possible to
-       prevent shell escapes with s\bsu\bud\bdo\bo's _\bn_\bo_\be_\bx_\be_\bc functionality.
-       See the _\bs_\bu_\bd_\bo_\be_\br_\bs(4) manual for details.
 
-       It is not meaningful to run the cd command directly via
-       sudo, e.g.,
 
+SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 
 
-1.6.9p17                   Jun 21, 2008                         8
+        $ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE"
 
+S\bSE\bEE\bE A\bAL\bLS\bSO\bO
+       _\bg_\br_\be_\bp(1), _\bs_\bu(1), _\bs_\bt_\ba_\bt(2), _\bl_\bo_\bg_\bi_\bn_\b__\bc_\ba_\bp(3), _\bp_\ba_\bs_\bs_\bw_\bd(4), _\bs_\bu_\bd_\bo_\be_\br_\bs(5),
+       _\bv_\bi_\bs_\bu_\bd_\bo(1m)
 
+A\bAU\bUT\bTH\bHO\bOR\bRS\bS
+       Many people have worked on s\bsu\bud\bdo\bo over the years; this version consists
+       of code written primarily by:
 
+               Todd C. Miller
 
+       See the HISTORY file in the s\bsu\bud\bdo\bo distribution or visit
+       http://www.sudo.ws/sudo/history.html for a short history of s\bsu\bud\bdo\bo.
 
-SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
+C\bCA\bAV\bVE\bEA\bAT\bTS\bS
+       There is no easy way to prevent a user from gaining a root shell if
+       that user is allowed to run arbitrary commands via s\bsu\bud\bdo\bo.  Also, many
+       programs (such as editors) allow the user to run commands via shell
+       escapes, thus avoiding s\bsu\bud\bdo\bo's checks.  However, on most systems it is
+       possible to prevent shell escapes with s\bsu\bud\bdo\bo's _\bn_\bo_\be_\bx_\be_\bc functionality.
+       See the _\bs_\bu_\bd_\bo_\be_\br_\bs(4) manual for details.
 
+       It is not meaningful to run the cd command directly via sudo, e.g.,
 
         $ sudo cd /usr/local/protected
 
-       since when the command exits the parent process (your
-       shell) will still be the same.  Please see the EXAMPLES
-       section for more information.
+       since when the command exits the parent process (your shell) will still
+       be the same.  Please see the EXAMPLES section for more information.
 
-       If users have sudo ALL there is nothing to prevent them
-       from creating their own program that gives them a root
-       shell regardless of any '!' elements in the user specifi­
-       cation.
+       If users have sudo ALL there is nothing to prevent them from creating
+       their own program that gives them a root shell regardless of any '!'
+       elements in the user specification.
 
-       Running shell scripts via s\bsu\bud\bdo\bo can expose the same kernel
-       bugs that make setuid shell scripts unsafe on some operat­
-       ing systems (if your OS has a /dev/fd/ directory, setuid
-       shell scripts are generally safe).
+       Running shell scripts via s\bsu\bud\bdo\bo can expose the same kernel bugs that
+       make setuid shell scripts unsafe on some operating systems (if your OS
+       has a /dev/fd/ directory, setuid shell scripts are generally safe).
 
 B\bBU\bUG\bGS\bS
-       If you feel you have found a bug in s\bsu\bud\bdo\bo, please submit a
-       bug report at http://www.sudo.ws/sudo/bugs/
+       If you feel you have found a bug in s\bsu\bud\bdo\bo, please submit a bug report at
+       http://www.sudo.ws/sudo/bugs/
 
 S\bSU\bUP\bPP\bPO\bOR\bRT\bT
-       Limited free support is available via the sudo-users mail­
-       ing list, see http://www.sudo.ws/mail­
-       man/listinfo/sudo-users to subscribe or search the
-       archives.
+       Limited free support is available via the sudo-users mailing list, see
+       http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search
+       the archives.
 
 D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
-       s\bsu\bud\bdo\bo is provided ``AS IS'' and any express or implied war­
-       ranties, including, but not limited to, the implied war­
-       ranties of merchantability and fitness for a particular
-       purpose are disclaimed.  See the LICENSE file distributed
-       with s\bsu\bud\bdo\bo or http://www.sudo.ws/sudo/license.html for com­
-       plete details.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+       s\bsu\bud\bdo\bo 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.
+       See the LICENSE file distributed with s\bsu\bud\bdo\bo or
+       http://www.sudo.ws/sudo/license.html for complete details.
 
 
 
 
-1.6.9p17                   Jun 21, 2008                         9
+1.7.0                   November 15, 2008                       9
 
 
diff --git a/sudo.h b/sudo.h
index 889cd4abc8361f93be86eaaad5fbac31d800f4af..ac5fdbde6d0a56ceb3c427c741c88f376eb210ba 100644 (file)
--- a/sudo.h
+++ b/sudo.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1993-1996,1998-2007 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1993-1996, 1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,7 +18,7 @@
  * Agency (DARPA) and Air Force Research Laboratory, Air Force
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  *
- * $Sudo: sudo.h,v 1.209.2.14 2008/02/09 14:44:48 millert Exp $
+ * $Sudo: sudo.h,v 1.269 2008/11/25 17:01:34 millert Exp $
  */
 
 #ifndef _SUDO_SUDO_H
 #include <limits.h>
 #include "compat.h"
 #include "defaults.h"
+#include "error.h"
+#include "list.h"
 #include "logging.h"
+#include "sudo_nss.h"
 
 /*
  * Info pertaining to the invoking user.
 struct sudo_user {
     struct passwd *pw;
     struct passwd *_runas_pw;
+    struct group *_runas_gr;
     struct stat *cmnd_stat;
     char *path;
     char *shell;
     char *tty;
     char *ttypath;
-    char  cwd[PATH_MAX];
     char *host;
     char *shost;
-    char **runas;
     char *prompt;
     char *cmnd;
     char *cmnd_args;
     char *cmnd_base;
     char *cmnd_safe;
     char *class_name;
-    int ngroups;
+    char *krb5_ccname;
+    char *display;
+    char *askpass;
+    int   ngroups;
     GETGROUPS_T *groups;
     struct list_member *env_vars;
 #ifdef HAVE_SELINUX
     char *role;
     char *type;
 #endif
+    char  cwd[PATH_MAX];
 };
 
 /*
@@ -68,12 +75,9 @@ struct sudo_user {
 #define VALIDATE_OK            0x002
 #define VALIDATE_NOT_OK                0x004
 #define FLAG_CHECK_USER                0x010
-#define FLAG_NOPASS            0x020
-#define FLAG_NO_USER           0x040
-#define FLAG_NO_HOST           0x080
-#define FLAG_NO_CHECK          0x100
-#define FLAG_NOEXEC            0x200
-#define FLAG_SETENV            0x400
+#define FLAG_NO_USER           0x020
+#define FLAG_NO_HOST           0x040
+#define FLAG_NO_CHECK          0x080
 
 /*
  * Pseudo-boolean values
@@ -82,12 +86,6 @@ struct sudo_user {
 #define TRUE                     1
 #undef FALSE
 #define FALSE                    0
-#undef IMPLIED
-#define IMPLIED                  2
-#undef NOMATCH
-#define NOMATCH                 -1
-#undef UNSPEC
-#define UNSPEC                  -2
 
 /*
  * find_path()/load_cmnd() return values
@@ -99,22 +97,27 @@ struct sudo_user {
 /*
  * Various modes sudo can be in (based on arguments) in hex
  */
-#define MODE_RUN               0x0001
-#define MODE_EDIT              0x0002
-#define MODE_VALIDATE          0x0004
-#define MODE_INVALIDATE                0x0008
-#define MODE_KILL              0x0010
-#define MODE_VERSION           0x0020
-#define MODE_HELP              0x0040
-#define MODE_LIST              0x0080
-#define MODE_LISTDEFS          0x0100
-#define MODE_BACKGROUND                0x0200
-#define MODE_SHELL             0x0400
-#define MODE_LOGIN_SHELL       0x0800
-#define MODE_IMPLIED_SHELL     0x1000
-#define MODE_RESET_HOME                0x2000
-#define MODE_PRESERVE_GROUPS   0x4000
-#define MODE_PRESERVE_ENV      0x8000
+#define MODE_RUN               0x00000001
+#define MODE_EDIT              0x00000002
+#define MODE_VALIDATE          0x00000004
+#define MODE_INVALIDATE                0x00000008
+#define MODE_KILL              0x00000010
+#define MODE_VERSION           0x00000020
+#define MODE_HELP              0x00000040
+#define MODE_LIST              0x00000080
+#define MODE_CHECK             0x00000100
+#define MODE_LISTDEFS          0x00000200
+#define MODE_MASK              0x0000ffff
+
+/* Mode flags */
+#define MODE_BACKGROUND                0x00010000
+#define MODE_SHELL             0x00020000
+#define MODE_LOGIN_SHELL       0x00040000
+#define MODE_IMPLIED_SHELL     0x00080000
+#define MODE_RESET_HOME                0x00100000
+#define MODE_PRESERVE_GROUPS   0x00200000
+#define MODE_PRESERVE_ENV      0x00400000
+#define MODE_NONINTERACTIVE    0x00800000
 
 /*
  * Used with set_perms()
@@ -141,7 +144,6 @@ struct sudo_user {
 #define user_tty               (sudo_user.tty)
 #define user_ttypath           (sudo_user.ttypath)
 #define user_cwd               (sudo_user.cwd)
-#define user_runas             (sudo_user.runas)
 #define user_cmnd              (sudo_user.cmnd)
 #define user_args              (sudo_user.cmnd_args)
 #define user_base              (sudo_user.cmnd_base)
@@ -150,9 +152,13 @@ struct sudo_user {
 #define user_prompt            (sudo_user.prompt)
 #define user_host              (sudo_user.host)
 #define user_shost             (sudo_user.shost)
+#define user_ccname            (sudo_user.krb5_ccname)
+#define user_display           (sudo_user.display)
+#define user_askpass           (sudo_user.askpass)
 #define safe_cmnd              (sudo_user.cmnd_safe)
 #define login_class            (sudo_user.class_name)
 #define runas_pw               (sudo_user._runas_pw)
+#define runas_gr               (sudo_user._runas_gr)
 #define user_role              (sudo_user.role)
 #define user_type              (sudo_user.type)
 
@@ -176,7 +182,9 @@ struct sudo_user {
  */
 #define TGP_ECHO       0x01            /* leave echo on when reading passwd */
 #define TGP_STDIN      0x02            /* read from stdin, not /dev/tty */
+#define TGP_ASKPASS    0x04            /* read from askpass helper program */
 
+struct lbuf;
 struct passwd;
 struct timespec;
 struct timeval;
@@ -224,7 +232,7 @@ size_t strlcat              __P((char *, const char *, size_t));
 size_t strlcpy         __P((char *, const char *, size_t));
 #endif
 #ifndef HAVE_MEMRCHR
-VOID *memrchr          __P((const VOID *, int, size_t));
+void *memrchr          __P((const void *, int, size_t));
 #endif
 #ifndef HAVE_MKSTEMP
 int mkstemp            __P((char *));
@@ -232,13 +240,29 @@ int mkstemp               __P((char *));
 char *sudo_goodpath    __P((const char *, struct stat *));
 char *tgetpass         __P((const char *, int, int));
 int find_path          __P((char *, char **, struct stat *, char *));
-void check_user                __P((int));
+int tty_present                __P((void));
+void check_user                __P((int, int));
 void verify_user       __P((struct passwd *, char *));
-int sudoers_lookup     __P((int));
 #ifdef HAVE_LDAP
-int sudo_ldap_check    __P((int));
-void sudo_ldap_list_matches __P((void));
+int sudo_ldap_open     __P((struct sudo_nss *));
+int sudo_ldap_close    __P((struct sudo_nss *));
+int sudo_ldap_setdefs  __P((struct sudo_nss *));
+int sudo_ldap_lookup   __P((struct sudo_nss *, int, int));
+int sudo_ldap_parse    __P((struct sudo_nss *));
+int sudo_ldap_display_cmnd __P((struct sudo_nss *, struct passwd *));
+int sudo_ldap_display_defaults __P((struct sudo_nss *, struct passwd *, struct lbuf *));
+int sudo_ldap_display_bound_defaults __P((struct sudo_nss *, struct passwd *, struct lbuf *));
+int sudo_ldap_display_privs __P((struct sudo_nss *, struct passwd *, struct lbuf *));
 #endif
+int sudo_file_open     __P((struct sudo_nss *));
+int sudo_file_close    __P((struct sudo_nss *));
+int sudo_file_setdefs  __P((struct sudo_nss *));
+int sudo_file_lookup   __P((struct sudo_nss *, int, int));
+int sudo_file_parse    __P((struct sudo_nss *));
+int sudo_file_display_cmnd __P((struct sudo_nss *, struct passwd *));
+int sudo_file_display_defaults __P((struct sudo_nss *, struct passwd *, struct lbuf *));
+int sudo_file_display_bound_defaults __P((struct sudo_nss *, struct passwd *, struct lbuf *));
+int sudo_file_display_privs __P((struct sudo_nss *, struct passwd *, struct lbuf *));
 void set_perms         __P((int));
 void remove_timestamp  __P((int));
 int check_secureware   __P((char *));
@@ -246,40 +270,63 @@ void sia_attempt_auth     __P((void));
 void pam_attempt_auth  __P((void));
 int yyparse            __P((void));
 void pass_warn         __P((FILE *));
-VOID *emalloc          __P((size_t));
-VOID *emalloc2         __P((size_t, size_t));
-VOID *erealloc         __P((VOID *, size_t));
-VOID *erealloc3                __P((VOID *, size_t, size_t));
+void *emalloc          __P((size_t));
+void *emalloc2         __P((size_t, size_t));
+void *erealloc         __P((void *, size_t));
+void *erealloc3                __P((void *, size_t, size_t));
 char *estrdup          __P((const char *));
 int easprintf          __P((char **, const char *, ...))
                            __printflike(2, 3);
 int evasprintf         __P((char **, const char *, va_list))
                            __printflike(2, 0);
-void efree             __P((VOID *));
+void efree             __P((void *));
 void dump_defaults     __P((void));
 void dump_auth_methods __P((void));
 void init_envtables    __P((void));
+void read_env_file     __P((const char *, int));
 int lock_file          __P((int, int));
 int touch              __P((int, char *, struct timespec *));
 int user_is_exempt     __P((void));
 void set_fqdn          __P((void));
-int set_runaspw                __P((char *));
 char *sudo_getepw      __P((const struct passwd *));
 int pam_prep_user      __P((struct passwd *));
-void zero_bytes                __P((volatile VOID *, size_t));
+void zero_bytes                __P((volatile void *, size_t));
 int gettime            __P((struct timespec *));
+FILE *open_sudoers     __P((const char *, int *));
+void display_privs     __P((struct sudo_nss_list *, struct passwd *));
+int display_cmnd       __P((struct sudo_nss_list *, struct passwd *));
+int get_ttycols                __P((void));
+char *sudo_parseln     __P((FILE *));
+void sudo_setenv       __P((const char *, const char *, int));
+void sudo_unsetenv     __P((const char *));
+void sudo_setgrent     __P((void));
+void sudo_endgrent     __P((void));
+void sudo_setpwent     __P((void));
+void sudo_endpwent     __P((void));
+void sudo_setspent     __P((void));
+void sudo_endspent     __P((void));
+void cleanup           __P((int));
+struct passwd *sudo_getpwnam __P((const char *));
+struct passwd *sudo_fakepwnam __P((const char *, gid_t));
+struct passwd *sudo_getpwuid __P((uid_t));
+struct group *sudo_getgrnam __P((const char *));
+struct group *sudo_fakegrnam __P((const char *));
+struct group *sudo_getgrgid __P((gid_t));
 #ifdef HAVE_SELINUX
-void selinux_exec      __P((char *, char *, char **, char **, int));
+void selinux_exec __P((char *, char *, char **, int));
+#endif
+#ifdef HAVE_GETUSERATTR
+void aix_setlimits __P((char *));
 #endif
 YY_DECL;
 
 /* Only provide extern declarations outside of sudo.c. */
 #ifndef _SUDO_MAIN
 extern struct sudo_user sudo_user;
-extern struct passwd *auth_pw;
+extern struct passwd *auth_pw, *list_pw;
 
-extern FILE *sudoers_fp;
 extern int tgetpass_flags;
+extern int long_list;
 extern uid_t timestamp_uid;
 #endif
 #ifndef errno
index 8d881c90d93bd574398d3bd7ec663b1f1ab947b3..26d8a309538e416889416c0889d03cbf7389c040 100644 (file)
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1994-1996, 1998-2005, 2007
+.\" Copyright (c) 1994-1996, 1998-2005, 2007-2008
 .\"    Todd C. Miller <Todd.Miller@courtesan.com>
 .\" 
 .\" Permission to use, copy, modify, and distribute this software for any
@@ -18,8 +18,8 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\" 
-.\" $Sudo: sudo.man.in,v 1.29.2.27 2008/06/22 20:29:03 millert Exp $
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
+.\" $Sudo: sudo.man.in,v 1.53 2008/11/15 18:34:26 millert Exp $
+.\" Automatically generated by Pod::Man 2.16 (Pod::Simple 3.05)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
 ..
 .\" Set up some character translations and predefined strings.  \*(-- will
 .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote.  | will give a
-.\" real vertical bar.  \*(C+ will give a nicer C++.  Capital omega is used to
-.\" do unbreakable dashes and therefore won't be available.  \*(C` and \*(C'
-.\" expand to `' in nroff, nothing in troff, for use with C<>.
-.tr \(*W-|\(bv\*(Tr
+.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
+.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
 .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
 .ie n \{\
 .    ds -- \(*W-
 .    ds R" ''
 'br\}
 .\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\"
 .\" If the F register is turned on, we'll generate index entries on stderr for
 .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
-.if \nF \{\
+.ie \nF \{\
 .    de IX
 .    tm Index:\\$1\t\\n%\t"\\$2"
 ..
 .    nr % 0
 .    rr F
 .\}
-.\"
-.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
+.el \{\
+.    de IX
+..
+.\}
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
 .\" ========================================================================
 .\"
 .IX Title "SUDO @mansectsu@"
-.TH SUDO @mansectsu@ "Jun 21, 2008" "1.6.9p17" "MAINTENANCE COMMANDS"
+.TH SUDO @mansectsu@ "November 15, 2008" "1.7.0" "MAINTENANCE COMMANDS"
+.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
 .SH "NAME"
 sudo, sudoedit \- execute a command as another user
 .SH "SYNOPSIS"
 .IX Header "SYNOPSIS"
-\&\fBsudo\fR \fB\-h\fR | \fB\-K\fR | \fB\-k\fR | \fB\-L\fR | \fB\-l\fR | \fB\-V\fR | \fB\-v\fR
+\&\fBsudo\fR [\fB\-n\fR] \fB\-h\fR | \fB\-K\fR | \fB\-k\fR | \fB\-L\fR | \fB\-V\fR | \fB\-v\fR
+.PP
+\&\fBsudo\fR \fB\-l[l]\fR [\fB\-AnS\fR] [\fB\-g\fR\ \fIgroupname\fR|\fI#gid\fR] [\fB\-U\fR\ \fIusername\fR]
+[\fB\-u\fR\ \fIusername\fR|\fI#uid\fR] [\fIcommand\fR]
 .PP
-\&\fBsudo\fR [\fB\-bEHPS\fR]
+\&\fBsudo\fR [\fB\-AbEHnPS\fR]
 @BAMAN@[\fB\-a\fR\ \fIauth_type\fR]
+[\fB\-C\fR\ \fIfd\fR]
 @LCMAN@[\fB\-c\fR\ \fIclass\fR|\fI\-\fR]
-[\fB\-p\fR\ \fIprompt\fR]
+[\fB\-g\fR\ \fIgroupname\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR]
 @SEMAN@[\fB\-r\fR\ \fIrole\fR] [\fB\-t\fR\ \fItype\fR]
 [\fB\-u\fR\ \fIusername\fR|\fI#uid\fR]
-[\fB\s-1VAR\s0\fR=\fIvalue\fR] {\fB\-i\fR\ |\ \fB\-s\fR\ |\ \fIcommand\fR}
+[\fB\s-1VAR\s0\fR=\fIvalue\fR] [\fB\-i\fR\ |\ \fB\-s\fR] [\fIcommand\fR]
 .PP
-\&\fBsudoedit\fR [\fB\-S\fR]
+\&\fBsudoedit\fR [\fB\-AnS\fR]
 @BAMAN@[\fB\-a\fR\ \fIauth_type\fR]
+[\fB\-C\fR\ \fIfd\fR]
 @LCMAN@[\fB\-c\fR\ \fIclass\fR|\fI\-\fR]
-[\fB\-p\fR\ \fIprompt\fR] [\fB\-u\fR\ \fIusername\fR|\fI#uid\fR]
-file ...
+[\fB\-g\fR\ \fIgroupname\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR]
+[\fB\-u\fR\ \fIusername\fR|\fI#uid\fR] file ...
 .SH "DESCRIPTION"
 .IX Header "DESCRIPTION"
 \&\fBsudo\fR allows a permitted user to execute a \fIcommand\fR as the
@@ -190,17 +202,17 @@ When invoked as \fBsudoedit\fR, the \fB\-e\fR option (described below),
 is implied.
 .PP
 \&\fBsudo\fR determines who is an authorized user by consulting the file
-\&\fI@sysconfdir@/sudoers\fR.  By giving \fBsudo\fR the \fB\-v\fR flag, a user
-can update the time stamp without running a \fIcommand\fR. The password
-prompt itself will also time out if the user's password is not
-entered within \f(CW\*(C`@password_timeout@\*(C'\fR minutes (unless overridden via
-\&\fIsudoers\fR).
+\&\fI@sysconfdir@/sudoers\fR.  By running \fBsudo\fR with the \fB\-v\fR option,
+a user can update the time stamp without running a \fIcommand\fR. The
+password prompt itself will also time out if the user's password
+is not entered within \f(CW\*(C`@password_timeout@\*(C'\fR minutes (unless overridden
+via \fIsudoers\fR).
 .PP
 If a user who is not listed in the \fIsudoers\fR file tries to run a
 command via \fBsudo\fR, mail is sent to the proper authorities, as
 defined at configure time or in the \fIsudoers\fR file (defaults to
 \&\f(CW\*(C`@mailto@\*(C'\fR).  Note that the mail will not be sent if an unauthorized
-user tries to run sudo with the \fB\-l\fR or \fB\-v\fR flags.  This allows
+user tries to run sudo with the \fB\-l\fR or \fB\-v\fR option.  This allows
 users to determine for themselves whether or not they are allowed
 to use \fBsudo\fR.
 .PP
@@ -208,7 +220,7 @@ If \fBsudo\fR is run by root and the \f(CW\*(C`SUDO_USER\*(C'\fR environment var
 is set, \fBsudo\fR will use this value to determine who the actual
 user is.  This can be used by a user to log commands through sudo
 even when a root shell has been invoked.  It also allows the \fB\-e\fR
-flag to remain useful even when being run via a sudo-run script or
+option to remain useful even when being run via a sudo-run script or
 program.  Note however, that the sudoers lookup is still done for
 root, not the user specified by \f(CW\*(C`SUDO_USER\*(C'\fR.
 .PP
@@ -219,57 +231,75 @@ or via the \fIsudoers\fR file.
 .SH "OPTIONS"
 .IX Header "OPTIONS"
 \&\fBsudo\fR accepts the following command line options:
-@BAMAN@.IP "\-a" 4
-@BAMAN@.IX Item "-a"
+.IP "\-A" 12
+.IX Item "-A"
+Normally, if \fBsudo\fR requires a password, it will read it from the
+current terminal.  If the \fB\-A\fR (\fIaskpass\fR) option is specified,
+a helper program is executed to read the user's password and output
+the password to the standard output.  If the \f(CW\*(C`SUDO_ASKPASS\*(C'\fR
+environment variable is set, it specifies the path to the helper
+program.  Otherwise, the value specified by the \fIaskpass\fR option
+in \fIsudoers\fR\|(@mansectform@) is used.
+@BAMAN@.IP "\-a \fItype\fR" 12
+@BAMAN@.IX Item "-a type"
 @BAMAN@The \fB\-a\fR (\fIauthentication type\fR) option causes \fBsudo\fR to use the
 @BAMAN@specified authentication type when validating the user, as allowed
 @BAMAN@by \fI/etc/login.conf\fR.  The system administrator may specify a list
-@BAMAN@of sudo-specific authentication methods by adding an \*(L"auth\-sudo\*(R"
+@BAMAN@of sudo-specific authentication methods by adding an \*(L"auth-sudo\*(R"
 @BAMAN@entry in \fI/etc/login.conf\fR.  This option is only available on systems
 @BAMAN@that support \s-1BSD\s0 authentication.
-.IP "\-b" 4
+.IP "\-b" 12
 .IX Item "-b"
 The \fB\-b\fR (\fIbackground\fR) option tells \fBsudo\fR to run the given
 command in the background.  Note that if you use the \fB\-b\fR
 option you cannot use shell job control to manipulate the process.
-@LCMAN@.IP "\-c" 4
-@LCMAN@.IX Item "-c"
+.IP "\-C \fIfd\fR" 12
+.IX Item "-C fd"
+Normally, \fBsudo\fR will close all open file descriptors other than
+standard input, standard output and standard error.  The \fB\-C\fR
+(\fIclose from\fR) option allows the user to specify a starting point
+above the standard error (file descriptor three).  Values less than
+three are not permitted.  This option is only available if the
+administrator has enabled the \fIclosefrom_override\fR option in
+\&\fIsudoers\fR\|(@mansectform@).
+@LCMAN@.IP "\-c \fIclass\fR" 12
+@LCMAN@.IX Item "-c class"
 @LCMAN@The \fB\-c\fR (\fIclass\fR) option causes \fBsudo\fR to run the specified command
 @LCMAN@with resources limited by the specified login class.  The \fIclass\fR
-@LCMAN@argument can be either a class name as defined in \f(CW\*(C`/etc/login.conf\*(C'\fR,
+@LCMAN@argument can be either a class name as defined in \fI/etc/login.conf\fR,
 @LCMAN@or a single '\-' character.  Specifying a \fIclass\fR of \f(CW\*(C`\-\*(C'\fR indicates
 @LCMAN@that the command should be run restricted by the default login
 @LCMAN@capabilities for the user the command is run as.  If the \fIclass\fR
 @LCMAN@argument specifies an existing user class, the command must be run
 @LCMAN@as root, or the \fBsudo\fR command must be run from a shell that is already
 @LCMAN@root.  This option is only available on systems with \s-1BSD\s0 login classes.
-.IP "\-E" 4
+.IP "\-E" 12
 .IX Item "-E"
 The \fB\-E\fR (\fIpreserve\fR \fIenvironment\fR) option will override the
 \&\fIenv_reset\fR option in \fIsudoers\fR\|(@mansectform@)).  It is only
 available when either the matching command has the \f(CW\*(C`SETENV\*(C'\fR tag
 or the \fIsetenv\fR option is set in \fIsudoers\fR\|(@mansectform@).
-.IP "\-e" 4
+.IP "\-e" 12
 .IX Item "-e"
 The \fB\-e\fR (\fIedit\fR) option indicates that, instead of running
 a command, the user wishes to edit one or more files.  In lieu
 of a command, the string \*(L"sudoedit\*(R" is used when consulting
 the \fIsudoers\fR file.  If the user is authorized by \fIsudoers\fR
 the following steps are taken:
-.RS 4
+.RS 12
 .IP "1." 4
 Temporary copies are made of the files to be edited with the owner
 set to the invoking user.
 .IP "2." 4
-The editor specified by the \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR environment
-variables is run to edit the temporary files.  If neither \f(CW\*(C`VISUAL\*(C'\fR
-nor \f(CW\*(C`EDITOR\*(C'\fR are set, the program listed in the \fIeditor\fR \fIsudoers\fR
-variable is used.
+The editor specified by the \f(CW\*(C`SUDO_EDITOR\*(C'\fR, \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR
+environment variables is run to edit the temporary files.  If none
+of \f(CW\*(C`SUDO_EDITOR\*(C'\fR, \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR are set, the first program
+listed in the \fIeditor\fR \fIsudoers\fR variable is used.
 .IP "3." 4
 If they have been modified, the temporary files are copied back to
 their original location and the temporary versions are removed.
 .RE
-.RS 4
+.RS 12
 .Sp
 If the specified file does not exist, it will be created.  Note
 that unlike most commands run by \fBsudo\fR, the editor is run with
@@ -278,63 +308,85 @@ the invoking user's environment unmodified.  If, for some reason,
 user will receive a warning and the edited copy will remain in a
 temporary file.
 .RE
-.IP "\-H" 4
+.IP "\-g \fIgroup\fR" 12
+.IX Item "-g group"
+Normally, \fBsudo\fR sets the primary group to the one specified by
+the passwd database for the user the command is being run as (by
+default, root).  The \fB\-g\fR (\fIgroup\fR) option causes \fBsudo\fR to run
+the specified command with the primary group set to \fIgroup\fR.  To
+specify a \fIgid\fR instead of a \fIgroup name\fR, use \fI#gid\fR.  When
+running commands as a \fIgid\fR, many shells require that the '#' be
+escaped with a backslash ('\e').  If no \fB\-u\fR option is specified,
+the command will be run as the invoking user (not root).  In either
+case, the primary group will be set to \fIgroup\fR.
+.IP "\-H" 12
 .IX Item "-H"
 The \fB\-H\fR (\fI\s-1HOME\s0\fR) option sets the \f(CW\*(C`HOME\*(C'\fR environment variable
 to the homedir of the target user (root by default) as specified
 in \fIpasswd\fR\|(@mansectform@).  By default, \fBsudo\fR does not modify \f(CW\*(C`HOME\*(C'\fR
 (see \fIset_home\fR and \fIalways_set_home\fR in \fIsudoers\fR\|(@mansectform@)).
-.IP "\-h" 4
+.IP "\-h" 12
 .IX Item "-h"
 The \fB\-h\fR (\fIhelp\fR) option causes \fBsudo\fR to print a usage message and exit.
-.IP "\-i" 4
-.IX Item "-i"
+.IP "\-i [command]" 12
+.IX Item "-i [command]"
 The \fB\-i\fR (\fIsimulate initial login\fR) option runs the shell specified
-in the \fIpasswd\fR\|(@mansectform@) entry of the user that the command is
-being run as.  The command name argument given to the shell begins
-with a `\f(CW\*(C`\-\*(C'\fR' to tell the shell to run as a login shell.  \fBsudo\fR
-attempts to change to that user's home directory before running the
-shell.  It also initializes the environment, leaving \fI\s-1TERM\s0\fR
-unchanged, setting \fI\s-1HOME\s0\fR, \fI\s-1SHELL\s0\fR, \fI\s-1USER\s0\fR, \fI\s-1LOGNAME\s0\fR, and
-\&\fI\s-1PATH\s0\fR, and unsetting all other environment variables.  Note that
-because the shell to use is determined before the \fIsudoers\fR file
-is parsed, a \fIrunas_default\fR setting in \fIsudoers\fR will specify
-the user to run the shell as but will not affect which shell is
-actually run.
-.IP "\-K" 4
+in the \fIpasswd\fR\|(@mansectform@) entry of the target user as a login shell.  This
+means that login-specific resource files such as \f(CW\*(C`.profile\*(C'\fR or
+\&\f(CW\*(C`.login\*(C'\fR will be read by the shell.  If a command is specified,
+it is passed to the shell for execution.  Otherwise, an interactive
+shell is executed.  \fBsudo\fR attempts to change to that user's home
+directory before running the shell.  It also initializes the
+environment, leaving \fI\s-1DISPLAY\s0\fR and \fI\s-1TERM\s0\fR unchanged, setting
+\&\fI\s-1HOME\s0\fR, \fI\s-1SHELL\s0\fR, \fI\s-1USER\s0\fR, \fI\s-1LOGNAME\s0\fR, and \fI\s-1PATH\s0\fR, as well as
+the contents of \fI/etc/environment\fR on Linux and \s-1AIX\s0 systems.
+All other environment variables are removed.
+.IP "\-K" 12
 .IX Item "-K"
 The \fB\-K\fR (sure \fIkill\fR) option is like \fB\-k\fR except that it removes
 the user's timestamp entirely.  Like \fB\-k\fR, this option does not
 require a password.
-.IP "\-k" 4
+.IP "\-k" 12
 .IX Item "-k"
 The \fB\-k\fR (\fIkill\fR) option to \fBsudo\fR invalidates the user's timestamp
 by setting the time on it to the Epoch.  The next time \fBsudo\fR is
 run a password will be required.  This option does not require a password
 and was added to allow a user to revoke \fBsudo\fR permissions from a .logout
 file.
-.IP "\-L" 4
+.IP "\-L" 12
 .IX Item "-L"
 The \fB\-L\fR (\fIlist\fR defaults) option will list out the parameters
 that may be set in a \fIDefaults\fR line along with a short description
 for each.  This option is useful in conjunction with \fIgrep\fR\|(1).
-.IP "\-l" 4
-.IX Item "-l"
-The \fB\-l\fR (\fIlist\fR) option will list out the allowed (and
-forbidden) commands for the invoking user on the current host.
-.IP "\-P" 4
+.IP "\-l[l] [\fIcommand\fR]" 12
+.IX Item "-l[l] [command]"
+If no \fIcommand\fR is specified, the \fB\-l\fR (\fIlist\fR) option will list
+the allowed (and forbidden) commands for the invoking user (or the
+user specified by the \fB\-U\fR option) on the current host.  If a
+\&\fIcommand\fR is specified and is permitted by \fIsudoers\fR, the
+fully-qualified path to the command is displayed along with any
+command line arguments.  If \fIcommand\fR is specified but not allowed,
+\&\fBsudo\fR will exit with a status value of 1.  If the \fB\-l\fR option is
+specified with an \fBl\fR argument (i.e. \fB\-ll\fR), or if \fB\-l\fR
+is specified multiple times, a longer list format is used.
+.IP "\-n" 12
+.IX Item "-n"
+The \fB\-n\fR (\fInon-interactive\fR) option prevents \fBsudo\fR from prompting
+the user for a password.  If a password is required for the command
+to run, \fBsudo\fR will display an error messages and exit.
+.IP "\-P" 12
 .IX Item "-P"
 The \fB\-P\fR (\fIpreserve\fR \fIgroup vector\fR) option causes \fBsudo\fR to
 preserve the invoking user's group vector unaltered.  By default,
 \&\fBsudo\fR will initialize the group vector to the list of groups the
 target user is in.  The real and effective group IDs, however, are
 still set to match the target user.
-.IP "\-p" 4
-.IX Item "-p"
+.IP "\-p \fIprompt\fR" 12
+.IX Item "-p prompt"
 The \fB\-p\fR (\fIprompt\fR) option allows you to override the default
 password prompt and use a custom one.  The following percent (`\f(CW\*(C`%\*(C'\fR')
 escapes are supported:
-.RS 4
+.RS 12
 .ie n .IP "%H" 4
 .el .IP "\f(CW%H\fR" 4
 .IX Item "%H"
@@ -364,51 +416,62 @@ expanded to the invoking user's login name
 .IX Item "%%"
 two consecutive \f(CW\*(C`%\*(C'\fR characters are collapsed into a single \f(CW\*(C`%\*(C'\fR character
 .RE
-.RS 4
+.RS 12
+.Sp
+The prompt specified by the \fB\-p\fR option will override the system
+password prompt on systems that support \s-1PAM\s0 unless the
+\&\fIpassprompt_override\fR flag is disabled in \fIsudoers\fR.
 .RE
-@SEMAN@.IP "\-r" 4
-@SEMAN@.IX Item "-r"
+@SEMAN@.IP "\-r \fIrole\fR" 12
+@SEMAN@.IX Item "-r role"
 @SEMAN@The \fB\-r\fR (\fIrole\fR) option causes the new (SELinux) security context to 
 @SEMAN@have the role specified by \fIrole\fR.
-.IP "\-S" 4
+.IP "\-S" 12
 .IX Item "-S"
 The \fB\-S\fR (\fIstdin\fR) option causes \fBsudo\fR to read the password from
 the standard input instead of the terminal device.
-.IP "\-s" 4
-.IX Item "-s"
+.IP "\-s [command]" 12
+.IX Item "-s [command]"
 The \fB\-s\fR (\fIshell\fR) option runs the shell specified by the \fI\s-1SHELL\s0\fR
-environment variable if it is set or the shell as specified
-in \fIpasswd\fR\|(@mansectform@).
-@SEMAN@.IP "\-t" 4
-@SEMAN@.IX Item "-t"
+environment variable if it is set or the shell as specified in
+\&\fIpasswd\fR\|(@mansectform@).  If a command is specified, it is passed to the shell
+for execution.  Otherwise, an interactive shell is executed.
+@SEMAN@.IP "\-t \fItype\fR" 12
+@SEMAN@.IX Item "-t type"
 @SEMAN@The \fB\-t\fR (\fItype\fR) option causes the new (SELinux) security context to 
 @SEMAN@have the type specified by \fItype\fR.  If no type is specified, the default
 @SEMAN@type is derived from the specified role.
-.IP "\-u" 4
-.IX Item "-u"
+.IP "\-U \fIuser\fR" 12
+.IX Item "-U user"
+The \fB\-U\fR (\fIother user\fR) option is used in conjunction with the \fB\-l\fR
+option to specify the user whose privileges should be listed.  Only
+root or a user with \fBsudo\fR \f(CW\*(C`ALL\*(C'\fR on the current host may use this
+option.
+.IP "\-u \fIuser\fR" 12
+.IX Item "-u user"
 The \fB\-u\fR (\fIuser\fR) option causes \fBsudo\fR to run the specified
 command as a user other than \fIroot\fR.  To specify a \fIuid\fR instead
-of a \fIusername\fR, use \fI#uid\fR.  When running commands as a \fIuid\fR,
+of a \fIuser name\fR, use \fI#uid\fR.  When running commands as a \fIuid\fR,
 many shells require that the '#' be escaped with a backslash ('\e').
 Note that if the \fItargetpw\fR Defaults option is set (see \fIsudoers\fR\|(@mansectform@))
 it is not possible to run commands with a uid not listed in the
 password database.
-.IP "\-V" 4
+.IP "\-V" 12
 .IX Item "-V"
 The \fB\-V\fR (\fIversion\fR) option causes \fBsudo\fR to print the version
 number and exit.  If the invoking user is already root the \fB\-V\fR
 option will print out a list of the defaults \fBsudo\fR was compiled
 with as well as the machine's local network addresses.
-.IP "\-v" 4
+.IP "\-v" 12
 .IX Item "-v"
 If given the \fB\-v\fR (\fIvalidate\fR) option, \fBsudo\fR will update the
 user's timestamp, prompting for the user's password if necessary.
 This extends the \fBsudo\fR timeout for another \f(CW\*(C`@timeout@\*(C'\fR minutes
 (or whatever the timeout is set to in \fIsudoers\fR) but does not run
 a command.
-.IP "\-\-" 4
-The \fB\-\-\fR flag indicates that \fBsudo\fR should stop processing command
-line arguments.  It is most useful in conjunction with the \fB\-s\fR flag.
+.IP "\-\-" 12
+The \fB\-\-\fR option indicates that \fBsudo\fR should stop processing command
+line arguments.  It is most useful in conjunction with the \fB\-s\fR option.
 .PP
 Environment variables to be set for the command may also be passed
 on the command line in the form of \fB\s-1VAR\s0\fR=\fIvalue\fR, e.g.
@@ -420,8 +483,8 @@ set or the command matched is \f(CW\*(C`ALL\*(C'\fR, the user may set variables
 that would overwise be forbidden.  See \fIsudoers\fR\|(@mansectform@) for more information.
 .SH "RETURN VALUES"
 .IX Header "RETURN VALUES"
-Upon successful execution of a program, the return value from \fBsudo\fR
-will simply be the return value of the program that was executed.
+Upon successful execution of a program, the exit status from \fBsudo\fR
+will simply be the exit status of the program that was executed.
 .PP
 Otherwise, \fBsudo\fR quits with an exit value of 1 if there is a
 configuration/permission problem or if \fBsudo\fR cannot execute the
@@ -511,7 +574,8 @@ information, please see the \f(CW\*(C`PREVENTING SHELL ESCAPES\*(C'\fR section i
 .ie n .IP "\*(C`EDITOR\*(C'" 16
 .el .IP "\f(CW\*(C`EDITOR\*(C'\fR" 16
 .IX Item "EDITOR"
-Default editor to use in \fB\-e\fR (sudoedit) mode if \f(CW\*(C`VISUAL\*(C'\fR is not set
+Default editor to use in \fB\-e\fR (sudoedit) mode if neither \f(CW\*(C`SUDO_EDITOR\*(C'\fR
+nor \f(CW\*(C`VISUAL\*(C'\fR is set
 .ie n .IP "\*(C`HOME\*(C'" 16
 .el .IP "\f(CW\*(C`HOME\*(C'\fR" 16
 .IX Item "HOME"
@@ -525,30 +589,39 @@ Set to a sane value if the \fIsecure_path\fR sudoers option is set.
 .el .IP "\f(CW\*(C`SHELL\*(C'\fR" 16
 .IX Item "SHELL"
 Used to determine shell to run with \f(CW\*(C`\-s\*(C'\fR option
-.ie n .IP "\*(C`SUDO_PROMPT\*(C'" 16
-.el .IP "\f(CW\*(C`SUDO_PROMPT\*(C'\fR" 16
-.IX Item "SUDO_PROMPT"
-Used as the default password prompt
+.ie n .IP "\*(C`SUDO_ASKPASS\*(C'" 16
+.el .IP "\f(CW\*(C`SUDO_ASKPASS\*(C'\fR" 16
+.IX Item "SUDO_ASKPASS"
+Specifies the path to a helper program used to read the password
+if no terminal is available or if the \f(CW\*(C`\-A\*(C'\fR option is specified.
 .ie n .IP "\*(C`SUDO_COMMAND\*(C'" 16
 .el .IP "\f(CW\*(C`SUDO_COMMAND\*(C'\fR" 16
 .IX Item "SUDO_COMMAND"
 Set to the command run by sudo
-.ie n .IP "\*(C`SUDO_USER\*(C'" 16
-.el .IP "\f(CW\*(C`SUDO_USER\*(C'\fR" 16
-.IX Item "SUDO_USER"
-Set to the login of the user who invoked sudo
-.ie n .IP "\*(C`SUDO_UID\*(C'" 16
-.el .IP "\f(CW\*(C`SUDO_UID\*(C'\fR" 16
-.IX Item "SUDO_UID"
-Set to the uid of the user who invoked sudo
+.ie n .IP "\*(C`SUDO_EDITOR\*(C'" 16
+.el .IP "\f(CW\*(C`SUDO_EDITOR\*(C'\fR" 16
+.IX Item "SUDO_EDITOR"
+Default editor to use in \fB\-e\fR (sudoedit) mode
 .ie n .IP "\*(C`SUDO_GID\*(C'" 16
 .el .IP "\f(CW\*(C`SUDO_GID\*(C'\fR" 16
 .IX Item "SUDO_GID"
-Set to the gid of the user who invoked sudo
+Set to the group \s-1ID\s0 of the user who invoked sudo
+.ie n .IP "\*(C`SUDO_PROMPT\*(C'" 16
+.el .IP "\f(CW\*(C`SUDO_PROMPT\*(C'\fR" 16
+.IX Item "SUDO_PROMPT"
+Used as the default password prompt
 .ie n .IP "\*(C`SUDO_PS1\*(C'" 16
 .el .IP "\f(CW\*(C`SUDO_PS1\*(C'\fR" 16
 .IX Item "SUDO_PS1"
-If set, \f(CW\*(C`PS1\*(C'\fR will be set to its value
+If set, \f(CW\*(C`PS1\*(C'\fR will be set to its value for the program being run
+.ie n .IP "\*(C`SUDO_UID\*(C'" 16
+.el .IP "\f(CW\*(C`SUDO_UID\*(C'\fR" 16
+.IX Item "SUDO_UID"
+Set to the user \s-1ID\s0 of the user who invoked sudo
+.ie n .IP "\*(C`SUDO_USER\*(C'" 16
+.el .IP "\f(CW\*(C`SUDO_USER\*(C'\fR" 16
+.IX Item "SUDO_USER"
+Set to the login of the user who invoked sudo
 .ie n .IP "\*(C`USER\*(C'" 16
 .el .IP "\f(CW\*(C`USER\*(C'\fR" 16
 .IX Item "USER"
@@ -556,15 +629,21 @@ Set to the target user (root unless the \fB\-u\fR option is specified)
 .ie n .IP "\*(C`VISUAL\*(C'" 16
 .el .IP "\f(CW\*(C`VISUAL\*(C'\fR" 16
 .IX Item "VISUAL"
-Default editor to use in \fB\-e\fR (sudoedit) mode
+Default editor to use in \fB\-e\fR (sudoedit) mode if \f(CW\*(C`SUDO_EDITOR\*(C'\fR
+is not set
 .SH "FILES"
 .IX Header "FILES"
-.IP "\fI@sysconfdir@/sudoers\fR" 24
+.ie n .IP "\fI@sysconfdir@/sudoers\fR" 24
+.el .IP "\fI@sysconfdir@/sudoers\fR" 24
 .IX Item "@sysconfdir@/sudoers"
 List of who can run what
-.IP "\fI@timedir@\fR" 24
+.ie n .IP "\fI@timedir@\fR" 24
+.el .IP "\fI@timedir@\fR" 24
 .IX Item "@timedir@"
 Directory containing timestamps
+.IP "\fI/etc/environment\fR" 24
+.IX Item "/etc/environment"
+Initial environment for \fB\-i\fR mode on Linux and \s-1AIX\s0
 .SH "EXAMPLES"
 .IX Header "EXAMPLES"
 Note: the following examples assume suitable \fIsudoers\fR\|(@mansectform@) entries.
@@ -579,19 +658,19 @@ To list the home directory of user yazza on a machine where the
 file system holding ~yazza is not exported as root:
 .PP
 .Vb 1
-\& $ sudo -u yazza ls ~yazza
+\& $ sudo \-u yazza ls ~yazza
 .Ve
 .PP
 To edit the \fIindex.html\fR file as user www:
 .PP
 .Vb 1
-\& $ sudo -u www vi ~www/htdocs/index.html
+\& $ sudo \-u www vi ~www/htdocs/index.html
 .Ve
 .PP
 To shutdown a machine:
 .PP
 .Vb 1
-\& $ sudo shutdown -r +15 "quick reboot"
+\& $ sudo shutdown \-r +15 "quick reboot"
 .Ve
 .PP
 To make a usage listing of the directories in the /home
@@ -599,7 +678,7 @@ partition.  Note that this runs the commands in a sub-shell
 to make the \f(CW\*(C`cd\*(C'\fR and file redirection work.
 .PP
 .Vb 1
-\& $ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE"
+\& $ sudo sh \-c "cd /home ; du \-s * | sort \-rn > USAGE"
 .Ve
 .SH "SEE ALSO"
 .IX Header "SEE ALSO"
@@ -611,9 +690,8 @@ to make the \f(CW\*(C`cd\*(C'\fR and file redirection work.
 Many people have worked on \fBsudo\fR over the years; this
 version consists of code written primarily by:
 .PP
-.Vb 2
+.Vb 1
 \&        Todd C. Miller
-\&        Chris Jepeway
 .Ve
 .PP
 See the \s-1HISTORY\s0 file in the \fBsudo\fR distribution or visit
index 33fe5d2314e45f4185d1e2cdbc1e3c8d922695a5..e96f044c0b699bb39273eb03131578afad31be2c 100644 (file)
--- a/sudo.pod
+++ b/sudo.pod
@@ -1,4 +1,4 @@
-Copyright (c) 1994-1996, 1998-2005, 2007
+Copyright (c) 1994-1996, 1998-2005, 2007-2008
        Todd C. Miller <Todd.Miller@courtesan.com>
 
 Permission to use, copy, modify, and distribute this software for any
@@ -18,7 +18,7 @@ Sponsored in part by the Defense Advanced Research Projects
 Agency (DARPA) and Air Force Research Laboratory, Air Force
 Materiel Command, USAF, under agreement number F39502-99-1-0512.
 
-$Sudo: sudo.pod,v 1.70.2.24 2008/02/19 18:22:11 millert Exp $
+$Sudo: sudo.pod,v 1.120 2008/11/15 18:34:01 millert Exp $
 =pod
 
 =head1 NAME
@@ -27,21 +27,26 @@ sudo, sudoedit - execute a command as another user
 
 =head1 SYNOPSIS
 
-B<sudo> B<-h> | B<-K> | B<-k> | B<-L> | B<-l> | B<-V> | B<-v>
+B<sudo> [B<-n>] B<-h> | B<-K> | B<-k> | B<-L> | B<-V> | B<-v>
 
-B<sudo> [B<-bEHPS>]
+B<sudo> B<-l[l]> [B<-AnS>] S<[B<-g> I<groupname>|I<#gid>]> S<[B<-U> I<username>]>
+S<[B<-u> I<username>|I<#uid>]> [I<command>]
+
+B<sudo> [B<-AbEHnPS>]
 S<[B<-a> I<auth_type>]>
+S<[B<-C> I<fd>]>
 S<[B<-c> I<class>|I<->]>
-S<[B<-p> I<prompt>]>
+S<[B<-g> I<groupname>|I<#gid>]> S<[B<-p> I<prompt>]>
 S<[B<-r> I<role>]> S<[B<-t> I<type>]>
 S<[B<-u> I<username>|I<#uid>]>
-S<[B<VAR>=I<value>]> S<{B<-i> | B<-s> | I<command>}>
+S<[B<VAR>=I<value>]> S<[B<-i> | B<-s>]> [I<command>]
 
-B<sudoedit> [B<-S>]
+B<sudoedit> [B<-AnS>]
 S<[B<-a> I<auth_type>]>
+S<[B<-C> I<fd>]>
 S<[B<-c> I<class>|I<->]>
-S<[B<-p> I<prompt>]> S<[B<-u> I<username>|I<#uid>]>
-file ...
+S<[B<-g> I<groupname>|I<#gid>]> S<[B<-p> I<prompt>]>
+S<[B<-u> I<username>|I<#uid>]> file ...
 
 =head1 DESCRIPTION
 
@@ -63,17 +68,17 @@ 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
-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>).
+F<@sysconfdir@/sudoers>.  By running B<sudo> with the B<-v> option,
+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
 command via B<sudo>, mail is sent to the proper authorities, as
 defined at configure time or in the I<sudoers> file (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
+user tries to run sudo with the B<-l> or B<-v> option.  This allows
 users to determine for themselves whether or not they are allowed
 to use B<sudo>.
 
@@ -81,7 +86,7 @@ If B<sudo> is run by root and the C<SUDO_USER> environment variable
 is set, B<sudo> will use this value to determine who the actual
 user is.  This can be used by a user to log commands through sudo
 even when a root shell has been invoked.  It also allows the B<-e>
-flag to remain useful even when being run via a sudo-run script or
+option to remain useful even when being run via a sudo-run script or
 program.  Note however, that the sudoers lookup is still done for
 root, not the user specified by C<SUDO_USER>.
 
@@ -94,9 +99,19 @@ or via the I<sudoers> file.
 
 B<sudo> accepts the following command line options:
 
-=over 4
+=over 12
+
+=item -A
 
-=item -a
+Normally, if B<sudo> requires a password, it will read it from the
+current terminal.  If the B<-A> (I<askpass>) option is specified,
+a helper program is executed to read the user's password and output
+the password to the standard output.  If the C<SUDO_ASKPASS>
+environment variable is set, it specifies the path to the helper
+program.  Otherwise, the value specified by the I<askpass> option
+in L<sudoers(5)> is used.
+
+=item -a I<type>
 
 The B<-a> (I<authentication type>) option causes B<sudo> to use the
 specified authentication type when validating the user, as allowed
@@ -111,11 +126,21 @@ The B<-b> (I<background>) option tells B<sudo> to run the given
 command in the background.  Note that if you use the B<-b>
 option you cannot use shell job control to manipulate the process.
 
-=item -c
+=item -C I<fd>
+
+Normally, B<sudo> will close all open file descriptors other than
+standard input, standard output and standard error.  The B<-C>
+(I<close from>) option allows the user to specify a starting point
+above the standard error (file descriptor three).  Values less than
+three are not permitted.  This option is only available if the
+administrator has enabled the I<closefrom_override> option in
+L<sudoers(5)>.
+
+=item -c I<class>
 
 The B<-c> (I<class>) option causes B<sudo> to run the specified command
 with resources limited by the specified login class.  The I<class>
-argument can be either a class name as defined in C</etc/login.conf>,
+argument can be either a class name as defined in F</etc/login.conf>,
 or a single '-' character.  Specifying a I<class> of C<-> indicates
 that the command should be run restricted by the default login
 capabilities for the user the command is run as.  If the I<class>
@@ -147,10 +172,10 @@ set to the invoking user.
 
 =item 2.
 
-The editor specified by the C<VISUAL> or C<EDITOR> environment
-variables is run to edit the temporary files.  If neither C<VISUAL>
-nor C<EDITOR> are set, the program listed in the I<editor> I<sudoers>
-variable is used.
+The editor specified by the C<SUDO_EDITOR>, C<VISUAL> or C<EDITOR>
+environment variables is run to edit the temporary files.  If none
+of C<SUDO_EDITOR>, C<VISUAL> or C<EDITOR> are set, the first program
+listed in the I<editor> I<sudoers> variable is used.
 
 =item 3.
 
@@ -166,6 +191,18 @@ B<sudo> is unable to update a file with its edited version, the
 user will receive a warning and the edited copy will remain in a
 temporary file.
 
+=item -g I<group>
+
+Normally, B<sudo> sets the primary group to the one specified by
+the passwd database for the user the command is being run as (by
+default, root).  The B<-g> (I<group>) option causes B<sudo> to run
+the specified command with the primary group set to I<group>.  To
+specify a I<gid> instead of a I<group name>, use I<#gid>.  When
+running commands as a I<gid>, many shells require that the '#' be
+escaped with a backslash ('\').  If no B<-u> option is specified,
+the command will be run as the invoking user (not root).  In either
+case, the primary group will be set to I<group>.
+
 =item -H
 
 The B<-H> (I<HOME>) option sets the C<HOME> environment variable
@@ -177,20 +214,19 @@ in passwd(5).  By default, B<sudo> does not modify C<HOME>
 
 The B<-h> (I<help>) option causes B<sudo> to print a usage message and exit.
 
-=item -i
+=item -i [command]
 
 The B<-i> (I<simulate initial login>) option runs the shell specified
-in the L<passwd(5)> entry of the user that the command is
-being run as.  The command name argument given to the shell begins
-with a `C<->' to tell the shell to run as a login shell.  B<sudo>
-attempts to change to that user's home directory before running the
-shell.  It also initializes the environment, leaving I<TERM>
-unchanged, setting I<HOME>, I<SHELL>, I<USER>, I<LOGNAME>, and
-I<PATH>, and unsetting all other environment variables.  Note that
-because the shell to use is determined before the I<sudoers> file
-is parsed, a I<runas_default> setting in I<sudoers> will specify
-the user to run the shell as but will not affect which shell is
-actually run.
+in the L<passwd(5)> entry of the target user as a login shell.  This
+means that login-specific resource files such as C<.profile> or
+C<.login> will be read by the shell.  If a command is specified,
+it is passed to the shell for execution.  Otherwise, an interactive
+shell is executed.  B<sudo> attempts to change to that user's home
+directory before running the shell.  It also initializes the
+environment, leaving I<DISPLAY> and I<TERM> unchanged, setting
+I<HOME>, I<SHELL>, I<USER>, I<LOGNAME>, and I<PATH>, as well as
+the contents of F</etc/environment> on Linux and AIX systems.
+All other environment variables are removed.
 
 =item -K
 
@@ -212,10 +248,23 @@ The B<-L> (I<list> defaults) option will list out the parameters
 that may be set in a I<Defaults> line along with a short description
 for each.  This option is useful in conjunction with L<grep(1)>.
 
-=item -l
+=item -l[l] [I<command>]
 
-The B<-l> (I<list>) option will list out the allowed (and
-forbidden) commands for the invoking user on the current host.
+If no I<command> is specified, the B<-l> (I<list>) option will list
+the allowed (and forbidden) commands for the invoking user (or the
+user specified by the B<-U> option) on the current host.  If a
+I<command> is specified and is permitted by I<sudoers>, the
+fully-qualified path to the command is displayed along with any
+command line arguments.  If I<command> is specified but not allowed,
+B<sudo> will exit with a status value of 1.  If the B<-l> option is
+specified with an B<l> argument (i.e. B<-ll>), or if B<-l>
+is specified multiple times, a longer list format is used.
+
+=item -n
+
+The B<-n> (I<non-interactive>) option prevents B<sudo> from prompting
+the user for a password.  If a password is required for the command
+to run, B<sudo> will display an error messages and exit.
 
 =item -P
 
@@ -225,7 +274,7 @@ B<sudo> will initialize the group vector to the list of groups the
 target user is in.  The real and effective group IDs, however, are
 still set to match the target user.
 
-=item -p
+=item -p I<prompt>
 
 The B<-p> (I<prompt>) option allows you to override the default
 password prompt and use a custom one.  The following percent (`C<%>')
@@ -263,7 +312,11 @@ two consecutive C<%> characters are collapsed into a single C<%> character
 
 =back
 
-=item -r
+The prompt specified by the B<-p> option will override the system
+password prompt on systems that support PAM unless the
+I<passprompt_override> flag is disabled in I<sudoers>.
+
+=item -r I<role>
 
 The B<-r> (I<role>) option causes the new (SELinux) security context to 
 have the role specified by I<role>.
@@ -273,23 +326,31 @@ have the role specified by I<role>.
 The B<-S> (I<stdin>) option causes B<sudo> to read the password from
 the standard input instead of the terminal device.
 
-=item -s
+=item -s [command]
 
 The B<-s> (I<shell>) option runs the shell specified by the I<SHELL>
-environment variable if it is set or the shell as specified
-in L<passwd(5)>.
+environment variable if it is set or the shell as specified in
+L<passwd(5)>.  If a command is specified, it is passed to the shell
+for execution.  Otherwise, an interactive shell is executed.
 
-=item -t
+=item -t I<type>
 
 The B<-t> (I<type>) option causes the new (SELinux) security context to 
 have the type specified by I<type>.  If no type is specified, the default
 type is derived from the specified role.
 
-=item -u
+=item -U I<user>
+
+The B<-U> (I<other user>) option is used in conjunction with the B<-l>
+option to specify the user whose privileges should be listed.  Only
+root or a user with B<sudo> C<ALL> on the current host may use this
+option.
+
+=item -u I<user>
 
 The B<-u> (I<user>) option causes B<sudo> to run the specified
 command as a user other than I<root>.  To specify a I<uid> instead
-of a I<username>, use I<#uid>.  When running commands as a I<uid>,
+of a I<user name>, use I<#uid>.  When running commands as a I<uid>,
 many shells require that the '#' be escaped with a backslash ('\').
 Note that if the I<targetpw> Defaults option is set (see L<sudoers(5)>)
 it is not possible to run commands with a uid not listed in the
@@ -312,8 +373,8 @@ a command.
 
 =item --
 
-The B<--> flag indicates that B<sudo> should stop processing command
-line arguments.  It is most useful in conjunction with the B<-s> flag.
+The B<--> option indicates that B<sudo> should stop processing command
+line arguments.  It is most useful in conjunction with the B<-s> option.
 
 =back
 
@@ -328,8 +389,8 @@ that would overwise be forbidden.  See L<sudoers(5)> for more information.
 
 =head1 RETURN VALUES
 
-Upon successful execution of a program, the return value from B<sudo>
-will simply be the return value of the program that was executed.
+Upon successful execution of a program, the exit status from B<sudo>
+will simply be the exit status of the program that was executed.
 
 Otherwise, B<sudo> quits with an exit value of 1 if there is a
 configuration/permission problem or if B<sudo> cannot execute the
@@ -423,7 +484,8 @@ B<sudo> utilizes the following environment variables:
 
 =item C<EDITOR>
 
-Default editor to use in B<-e> (sudoedit) mode if C<VISUAL> is not set
+Default editor to use in B<-e> (sudoedit) mode if neither C<SUDO_EDITOR>
+nor C<VISUAL> is set
 
 =item C<HOME>
 
@@ -438,29 +500,38 @@ Set to a sane value if the I<secure_path> sudoers option is set.
 
 Used to determine shell to run with C<-s> option
 
-=item C<SUDO_PROMPT>
+=item C<SUDO_ASKPASS>
 
-Used as the default password prompt
+Specifies the path to a helper program used to read the password
+if no terminal is available or if the C<-A> option is specified.
 
 =item C<SUDO_COMMAND>
 
 Set to the command run by sudo
 
-=item C<SUDO_USER>
+=item C<SUDO_EDITOR>
 
-Set to the login of the user who invoked sudo
+Default editor to use in B<-e> (sudoedit) mode
 
-=item C<SUDO_UID>
+=item C<SUDO_GID>
 
-Set to the uid of the user who invoked sudo
+Set to the group ID of the user who invoked sudo
 
-=item C<SUDO_GID>
+=item C<SUDO_PROMPT>
 
-Set to the gid of the user who invoked sudo
+Used as the default password prompt
 
 =item C<SUDO_PS1>
 
-If set, C<PS1> will be set to its value
+If set, C<PS1> will be set to its value for the program being run
+
+=item C<SUDO_UID>
+
+Set to the user ID of the user who invoked sudo
+
+=item C<SUDO_USER>
+
+Set to the login of the user who invoked sudo
 
 =item C<USER>
 
@@ -468,7 +539,8 @@ Set to the target user (root unless the B<-u> option is specified)
 
 =item C<VISUAL>
 
-Default editor to use in B<-e> (sudoedit) mode
+Default editor to use in B<-e> (sudoedit) mode if C<SUDO_EDITOR>
+is not set
 
 =back
 
@@ -484,6 +556,10 @@ List of who can run what
 
 Directory containing timestamps
 
+=item F</etc/environment>
+
+Initial environment for B<-i> mode on Linux and AIX
+
 =back
 
 =head1 EXAMPLES
@@ -525,7 +601,6 @@ Many people have worked on B<sudo> over the years; this
 version consists of code written primarily by:
 
        Todd C. Miller
-       Chris Jepeway
 
 See the HISTORY file in the B<sudo> distribution or visit
 http://www.sudo.ws/sudo/history.html for a short history
diff --git a/sudo.psf b/sudo.psf
new file mode 100644 (file)
index 0000000..59ddef2
--- /dev/null
+++ b/sudo.psf
@@ -0,0 +1,91 @@
+# PSF file for sudo
+#
+# See http://www.software.hp.com/products/SD_AT_HP/docs/cookbook.html
+# for details.
+#
+# To create sudo.depot, run:
+#
+#      swpackage -x target_type=tape -d sudo.depot -s sudo.psf
+#
+# To install, run:
+#
+#      swinstall -s sudo.depot sudo
+#
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+#
+vendor
+        tag GratiSoft
+        title "GratiSoft, Inc."
+        description "GratiSoft, Inc., http://www.gratisoft.us/"
+end
+#
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+#
+product
+        tag sudo
+        title "Sudo"
+        description "execute a command as another user"
+        revision @VERSION@
+        #
+        architecture S700/S800_HPUX_10/11
+        machine_type 9000/[78]*
+        os_name HP-UX
+        os_release ?.10.*|?.11.*
+        os_version *
+        #
+        fileset
+                tag bin
+                title "sudo binaries"
+                revision @VERSION@
+
+                file -m 4111 -o root -g root sudo /usr/local/bin/sudo
+                file -m  111 -o root -g bin visudo /usr/local/sbin/visudo
+
+               postinstall sudo-exec.postinstall
+        end
+        #
+        fileset
+                tag libexec
+                title "sudo noexec library"
+                revision @VERSION@
+
+                file -m 555 -o root -g bin sudo_noexec.sl /usr/local/libexec/sudo_noexec.sl
+        end
+        #
+        fileset
+                tag manpages
+                title "sudo manpages"
+                revision @VERSION@
+
+                file -m 444 -g bin -o root sudo.man /usr/local/man/man1m/sudo.1m
+                file -m 444 -g bin -o root sudoers.man /usr/local/man/man4/sudoers.4
+                file -m 444 -g bin -o root visudo.man /usr/local/man/man1m/visudo.1m
+
+               postinstall sudo-man.postinstall
+        end
+        #
+        fileset
+                tag doc
+                title "sudo doc"
+                revision @VERSION@
+
+                file -m 444 -g bin -o root BUGS /usr/local/doc/sudo/BUGS
+                file -m 444 -g bin -o root CHANGES /usr/local/doc/sudo/CHANGES
+                file -m 444 -g bin -o root HISTORY /usr/local/doc/sudo/HISTORY
+                file -m 444 -g bin -o root LICENSE /usr/local/doc/sudo/LICENSE
+                file -m 444 -g bin -o root README /usr/local/doc/sudo/README
+                file -m 444 -g bin -o root TROUBLESHOOTING /usr/local/doc/sudo/TROUBLESHOOTING
+                file -m 444 -g bin -o root UPGRADE /usr/local/doc/sudo/UPGRADE
+                file -m 444 -g bin -o root sample.syslog.conf /usr/local/doc/sudo/sample.syslog.conf
+                file -m 444 -g bin -o root sample.sudoers /usr/local/doc/sudo/sample.sudoers
+        end
+       #
+        fileset
+                tag config
+                title "sudo config files"
+                revision @VERSION@
+                file -m 444 -g bin -o root sudoers /usr/local/doc/sudo/sudoers
+
+               postinstall sudo-config.postinstall
+       end
+end
diff --git a/sudo.tab.c b/sudo.tab.c
deleted file mode 100644 (file)
index 0e40bef..0000000
+++ /dev/null
@@ -1,2270 +0,0 @@
-#ifndef lint
-/*static char yysccsid[] = "from: @(#)yaccpar  1.9 (Berkeley) 02/21/93";*/
-static char yyrcsid[]
-#if __GNUC__ >= 2
-  __attribute__ ((unused))
-#endif /* __GNUC__ >= 2 */
-  = "$OpenBSD: skeleton.c,v 1.28 2007/09/03 21:14:58 deraadt Exp $";
-#endif
-#include <stdlib.h>
-#define YYBYACC 1
-#define YYMAJOR 1
-#define YYMINOR 9
-#define YYLEX yylex()
-#define YYEMPTY -1
-#define yyclearin (yychar=(YYEMPTY))
-#define yyerrok (yyerrflag=0)
-#define YYRECOVERING() (yyerrflag!=0)
-#define YYPREFIX "yy"
-#line 2 "parse.yacc"
-/*
- * Copyright (c) 1996, 1998-2004, 2007
- *     Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F39502-99-1-0512.
- */
-
-/*
- * XXX - the whole opFOO naming thing is somewhat bogus.
- *
- * XXX - the way things are stored for printmatches is stupid,
- *       they should be stored as elements in an array and then
- *       list_matches() can format things the way it wants.
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <stdio.h>
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif /* STDC_HEADERS */
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# ifdef HAVE_STRINGS_H
-#  include <strings.h>
-# endif
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
-# include <alloca.h>
-#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
-#ifdef HAVE_LSEARCH
-# include <search.h>
-#endif /* HAVE_LSEARCH */
-#include <limits.h>
-
-#include "sudo.h"
-#include "parse.h"
-
-#ifndef HAVE_LSEARCH
-#include "emul/search.h"
-#endif /* HAVE_LSEARCH */
-
-#ifndef lint
-__unused static const char rcsid[] = "$Sudo: sudo.tab.c,v 1.76.2.14 2008/02/27 20:34:42 millert Exp $";
-#endif /* lint */
-
-/*
- * We must define SIZE_MAX for yacc's skeleton.c.
- * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
- * could be signed (as it is on SunOS 4.x).
- */
-#ifndef SIZE_MAX
-# ifdef SIZE_T_MAX
-#  define SIZE_MAX     SIZE_T_MAX
-# else
-#  define SIZE_MAX     INT_MAX
-# endif /* SIZE_T_MAX */
-#endif /* SIZE_MAX */
-
-/*
- * Globals
- */
-extern int sudolineno, parse_error;
-int errorlineno = -1;
-int clearaliases = TRUE;
-int printmatches = FALSE;
-int pedantic = FALSE;
-int keepall = FALSE;
-int quiet = FALSE;
-int used_runas = FALSE;
-
-/*
- * Alias types
- */
-#define HOST_ALIAS              1
-#define CMND_ALIAS              2
-#define USER_ALIAS              3
-#define RUNAS_ALIAS             4
-
-#define SETMATCH(_var, _val)   do { \
-       if ((_var) == UNSPEC || (_val) != NOMATCH) \
-           (_var) = (_val); \
-} while (0)
-
-#define SETNMATCH(_var, _val)  do { \
-       if ((_val) != NOMATCH) \
-           (_var) = ! (_val); \
-       else if ((_var) == UNSPEC) \
-           (_var) = NOMATCH; \
-} while (0)
-
-#define        SETENV_RESET \
-       if (setenv_ok == IMPLIED) setenv_ok = def_setenv ? TRUE : UNSPEC
-
-/*
- * The matching stack, initial space allocated in init_parser().
- */
-struct matchstack *match;
-int top = 0, stacksize = 0;
-
-#define push \
-    do { \
-       if (top >= stacksize) { \
-           while ((stacksize += STACKINCREMENT) < top); \
-           match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
-       } \
-       match[top].user   = UNSPEC; \
-       match[top].cmnd   = UNSPEC; \
-       match[top].host   = UNSPEC; \
-       match[top].runas  = UNSPEC; \
-       match[top].nopass = def_authenticate ? UNSPEC : TRUE; \
-       match[top].noexec = def_noexec ? TRUE : UNSPEC; \
-       match[top].setenv = def_setenv ? TRUE : UNSPEC; \
-       match[top].role = NULL; \
-       match[top].type = NULL; \
-       top++; \
-    } while (0)
-
-#define pushcp \
-    do { \
-       if (top >= stacksize) { \
-           while ((stacksize += STACKINCREMENT) < top); \
-           match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
-       } \
-       match[top].user   = match[top-1].user; \
-       match[top].cmnd   = match[top-1].cmnd; \
-       match[top].host   = match[top-1].host; \
-       match[top].runas  = match[top-1].runas; \
-       match[top].nopass = match[top-1].nopass; \
-       match[top].noexec = match[top-1].noexec; \
-       match[top].setenv = match[top-1].setenv; \
-       match[top].role   = estrdup(match[top-1].role); \
-       match[top].type   = estrdup(match[top-1].type); \
-       top++; \
-    } while (0)
-
-#define pop \
-    do { \
-       if (top == 0) \
-           yyerror("matching stack underflow"); \
-       else { \
-           efree(match[top-1].role); \
-           efree(match[top-1].type); \
-           top--; \
-       } \
-    } while (0)
-
-
-/*
- * For testing if foo_matches variable was set to TRUE or FALSE
- */
-#define        MATCHED(_v)     ((_v) >= 0)
-
-/*
- * Shortcuts for append()
- */
-#define append_cmnd(s, p) append(s, &cm_list[cm_list_len].cmnd, \
-       &cm_list[cm_list_len].cmnd_len, &cm_list[cm_list_len].cmnd_size, p)
-
-#define append_runas(s, p) append(s, &cm_list[cm_list_len].runas, \
-       &cm_list[cm_list_len].runas_len, &cm_list[cm_list_len].runas_size, p)
-
-#define append_role(s, p) append(s, &cm_list[cm_list_len].role, \
-       &cm_list[cm_list_len].role_len, &cm_list[cm_list_len].role_size, p)
-
-#define append_type(s, p) append(s, &cm_list[cm_list_len].type, \
-       &cm_list[cm_list_len].type_len, &cm_list[cm_list_len].type_size, p)
-
-#define append_entries(s, p) append(s, &ga_list[ga_list_len-1].entries, \
-       &ga_list[ga_list_len-1].entries_len, \
-       &ga_list[ga_list_len-1].entries_size, p)
-
-/*
- * The stack for printmatches.  A list of allowed commands for the user.
- */
-static struct command_match *cm_list = NULL;
-static size_t cm_list_len = 0, cm_list_size = 0;
-
-/*
- * List of Cmnd_Aliases and expansions for `sudo -l'
- */
-static int in_alias = FALSE;
-static size_t ga_list_len = 0, ga_list_size = 0;
-static struct generic_alias *ga_list = NULL;
-
-/*
- * Does this Defaults list pertain to this user?
- */
-static int defaults_matches = FALSE;
-
-/*
- * Local protoypes
- */
-static int  add_alias          __P((char *, int, int));
-static void append             __P((char *, char **, size_t *, size_t *, char *));
-static void expand_ga_list     __P((void));
-static void expand_match_list  __P((void));
-static aliasinfo *find_alias   __P((char *, int));
-static void more_aliases       __P((void));
-       void init_parser                __P((void));
-       void yyerror            __P((char *));
-
-void
-yyerror(s)
-    char *s;
-{
-    /* Save the line the first error occurred on. */
-    if (errorlineno == -1)
-       errorlineno = sudolineno ? sudolineno - 1 : 0;
-    if (s && !quiet) {
-#ifndef TRACELEXER
-       (void) fprintf(stderr, ">>> sudoers file: %s, line %d <<<\n", s,
-           sudolineno ? sudolineno - 1 : 0);
-#else
-       (void) fprintf(stderr, "<*> ");
-#endif
-    }
-    parse_error = TRUE;
-}
-#line 251 "parse.yacc"
-#ifndef YYSTYPE_DEFINED
-#define YYSTYPE_DEFINED
-typedef union {
-    char *string;
-    int BOOLEAN;
-    struct sudo_command command;
-    int tok;
-    struct selinux_info seinfo;
-} YYSTYPE;
-#endif /* YYSTYPE_DEFINED */
-#line 279 "sudo.tab.c"
-#define COMMAND 257
-#define ALIAS 258
-#define DEFVAR 259
-#define NTWKADDR 260
-#define NETGROUP 261
-#define USERGROUP 262
-#define WORD 263
-#define DEFAULTS 264
-#define DEFAULTS_HOST 265
-#define DEFAULTS_USER 266
-#define DEFAULTS_RUNAS 267
-#define RUNAS 268
-#define NOPASSWD 269
-#define PASSWD 270
-#define NOEXEC 271
-#define EXEC 272
-#define SETENV 273
-#define NOSETENV 274
-#define ALL 275
-#define COMMENT 276
-#define HOSTALIAS 277
-#define CMNDALIAS 278
-#define USERALIAS 279
-#define RUNASALIAS 280
-#define ERROR 281
-#define TYPE 282
-#define ROLE 283
-#define YYERRCODE 256
-#if defined(__cplusplus) || defined(__STDC__)
-const short yylhs[] =
-#else
-short yylhs[] =
-#endif
-       {                                        -1,
-    0,    0,   10,   10,   12,   10,   10,   10,   10,   10,
-   10,   18,   19,   21,   19,   22,   19,   24,   19,   20,
-   20,   25,   25,   25,   25,   25,   13,   13,   26,   28,
-   28,    2,    2,    2,    2,    2,   27,   27,   31,   29,
-   33,   34,   33,    8,    9,    7,    7,    7,    7,    7,
-   30,   30,    5,    5,    4,   35,    4,    3,    3,    3,
-    3,    3,   32,   32,   32,   32,   32,   32,   32,    1,
-    1,    1,   15,   15,   37,   36,   23,   23,   16,   16,
-   39,   38,   40,   40,   17,   17,   42,   41,   14,   14,
-   44,   43,   11,   11,   45,   45,    6,    6,    6,    6,
-    6,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yylen[] =
-#else
-short yylen[] =
-#endif
-       {                                         2,
-    1,    2,    1,    2,    0,    3,    2,    2,    2,    2,
-    1,    2,    1,    0,    3,    0,    3,    0,    3,    1,
-    3,    1,    2,    3,    3,    3,    1,    3,    3,    1,
-    2,    1,    1,    1,    1,    1,    1,    3,    0,    5,
-    1,    0,    3,    3,    3,    0,    1,    1,    2,    2,
-    0,    2,    1,    3,    1,    0,    3,    1,    1,    1,
-    1,    1,    0,    2,    2,    2,    2,    2,    2,    1,
-    1,    1,    1,    3,    0,    4,    1,    3,    1,    3,
-    0,    4,    1,    3,    1,    3,    0,    4,    1,    3,
-    0,    4,    1,    3,    1,    2,    1,    1,    1,    1,
-    1,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yydefred[] =
-#else
-short yydefred[] =
-#endif
-       {                                      0,
-    0,   13,   18,   14,   16,    3,    0,    0,    0,    0,
-    0,    1,    0,   11,    0,    4,    0,    0,    0,   75,
-    0,   73,   81,    0,   79,   91,    0,   89,   87,    0,
-   85,    2,  100,   99,   98,   97,  101,    0,   95,    0,
-   93,    0,    0,   12,    0,   36,   33,   34,   35,   32,
-    0,   30,    0,   77,    0,   61,   60,   59,   58,   62,
-   56,   55,   53,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,   96,    0,    0,    0,   27,    0,    0,    0,
-   23,    0,   31,    0,    0,    0,    0,   74,    0,   80,
-    0,   90,    0,   86,   94,    0,   39,   24,   25,   26,
-   21,   78,   57,   54,    0,   72,   71,   70,   42,   41,
-   83,    0,    0,    0,   28,    0,   37,    0,    0,    0,
-   39,    0,    0,   43,   84,   38,    0,    0,    0,   63,
-    0,    0,    0,    0,    0,   49,   50,   45,   44,   64,
-   65,   66,   67,   68,   69,   40,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yydgoto[] =
-#else
-short yydgoto[] =
-#endif
-       {                                      11,
-  110,   52,   62,   63,   64,   39,  130,  131,  132,   12,
-   40,   13,   75,   27,   21,   24,   30,   14,   15,   44,
-   18,   19,   76,   17,   45,   77,  116,   54,  117,  123,
-  118,  135,  111,  119,   85,   22,   65,   25,   67,  112,
-   31,   71,   28,   69,   41,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yysindex[] =
-#else
-short yysindex[] =
-#endif
-       {                                   -247,
- -248,    0,    0,    0,    0,    0, -211, -210, -205, -201,
- -247,    0,   62,    0,  -33,    0,   89,   62,  114,    0,
-    2,    0,    0,    3,    0,    0,    4,    0,    0,    6,
-    0,    0,    0,    0,    0,    0,    0, -251,    0,  -28,
-    0,  -18, -194,    0,   14,    0,    0,    0,    0,    0,
- -219,    0,   22,    0,   23,    0,    0,    0,    0,    0,
-    0,    0,    0,   24,    8, -211,    9, -210,   10, -205,
-   11, -201,    0,   62,   16,  -23,    0, -187, -186, -184,
-    0,  -33,    0,   89, -212,  114,   89,    0,  -20,    0,
-   62,    0,  114,    0,    0,   89,    0,    0,    0,    0,
-    0,    0,    0,    0,   22,    0,    0,    0,    0,    0,
-    0,   36,   23,   24,    0,   37,    0, -185, -221,  -20,
-    0,  114, -268,    0,    0,    0,   24,   21,   25,    0,
- -195, -193, -175, -174,  274,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yyrindex[] =
-#else
-short yyrindex[] =
-#endif
-       {                                    141,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-  141,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-  156,    0,    0,  181,    0,    0,  206,    0,    0,  236,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    1,    0,    0,  261,    0,    0,    0,    0,    0,
-    0,    0,  -25,    0,  -11,    0,    0,    0,    0,    0,
-    0,    0,    0,  -10,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,  300,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,   26,    0,    0,    0,    0,    0,
-    0,   52,   78,  104,    0,  130,    0,  -29,    0,    0,
-    0,    0,  340,    0,    0,    0,  313,    0,    0,    0,
-  365,  391,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yygindex[] =
-#else
-short yygindex[] =
-#endif
-       {                                      0,
-  -27,   40,   12,    7,  -87,   56,    0,  -36,  -32,   87,
-  -16,    0,    0,    0,    0,    0,    0,    0,    0,   18,
-    0,    0,  -14,    0,    0,    5,    0,   19,  -19,    0,
-    0,    0,  -80,    0,    0,   39,    0,   38,    0,    0,
-   35,    0,   42,    0,   34,
-};
-#define YYTABLESIZE 666
-#if defined(__cplusplus) || defined(__STDC__)
-const short yytable[] =
-#else
-short yytable[] =
-#endif
-       {                                      43,
-   22,   55,   53,   51,   51,  114,   33,   19,    1,   34,
-   35,   36,  109,  128,  129,   74,    2,    3,    4,    5,
-   84,   15,   17,   37,   79,   76,   80,   16,    6,    7,
-    8,    9,   10,   22,  127,  106,  107,   97,   46,  125,
-   47,   48,   78,   49,   22,   56,   20,   23,   57,   58,
-   59,   82,   26,  108,  146,   50,   29,   82,   76,   66,
-   68,   70,   60,   72,   81,   84,   74,   86,   87,   89,
-   91,   93,  105,   96,  113,   98,   99,   92,  100,  120,
-  121,  133,  122,   76,   82,  134,  128,  138,  139,  129,
-   83,  124,  104,   73,   38,  137,  103,   32,  136,  101,
-  115,  126,  102,   88,   88,   90,   94,   95,    0,   82,
-   92,   92,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,   51,    0,    0,    0,    0,    0,    0,    0,   29,
-    0,    0,    0,    0,    0,   92,   88,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,   61,    0,    0,    0,
-    0,    0,    0,    0,    0,    8,    0,    0,    0,    0,
-    0,   88,   29,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    5,    0,    0,    0,    0,    0,    0,
-    9,    0,    0,    0,    0,    0,    0,   29,    8,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    7,    0,    0,    0,    0,
-    0,    0,    0,    9,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,   42,    0,   51,   51,   46,
-    0,   47,   48,   19,   49,   10,  106,  107,    7,   51,
-   51,   51,   51,   51,   51,   51,   50,   15,   17,    0,
-    0,    0,   51,   51,  108,    0,   22,    0,   22,    0,
-   20,   22,   22,   22,   22,   22,   22,   22,   10,    0,
-    0,    0,    0,    0,    0,   22,   22,   22,   22,   22,
-   22,   76,    0,   76,    0,    0,   76,   76,   76,   76,
-   76,   76,   76,   20,    0,    0,    0,    0,    0,    6,
-   76,   76,   76,   76,   76,   76,  109,   82,    0,   82,
-    0,    0,   82,   82,   82,   82,   82,   82,   82,   33,
-    0,    0,   34,   35,   36,    0,   82,   82,   82,   82,
-   82,   82,    6,   92,    0,   92,   37,    0,   92,   92,
-   92,   92,   92,   92,   92,   52,   46,    0,   47,   48,
-    0,   49,   92,   92,   92,   92,   92,   92,    0,   88,
-    0,   88,    0,   50,   88,   88,   88,   88,   88,   88,
-   88,   56,   46,    0,   57,   58,   59,    0,   88,   88,
-   88,   88,   88,   88,    0,   29,    0,   29,   60,    0,
-   29,   29,   29,   29,   29,   29,   29,   47,    5,    0,
-    0,    5,    5,    5,   29,   29,   29,   29,   29,   29,
-    0,    8,    0,    8,    0,    5,    8,    8,    8,    8,
-    8,    8,    8,   48,    0,    0,    0,    0,    0,    0,
-    8,    8,    8,    8,    8,    8,    9,    0,    9,    0,
-    0,    9,    9,    9,    9,    9,    9,    9,    0,    0,
-    0,    0,    0,    0,    0,    9,    9,    9,    9,    9,
-    9,    7,    0,    7,    0,    0,    7,    7,    7,    7,
-    7,    7,    7,    0,    0,    0,    0,    0,    0,    0,
-    7,    7,    7,    7,    7,    7,    0,    0,    0,    0,
-    0,   10,    0,   10,    0,    0,   10,   10,   10,   10,
-   10,   10,   10,    0,    0,    0,    0,    0,    0,    0,
-   10,   10,   10,   10,   10,   10,   20,    0,   20,    0,
-    0,   20,   20,   20,   20,   20,   20,   20,    0,    0,
-  106,  107,    0,    0,    0,   20,   20,   20,   20,   20,
-   20,    0,  140,  141,  142,  143,  144,  145,  108,    0,
-    0,    0,    0,    0,    0,    6,    0,    6,    0,    0,
-    6,    6,    6,    6,    6,    6,    6,    0,    0,   52,
-   52,    0,    0,    0,    6,    6,    6,    6,    6,    6,
-    0,   52,   52,   52,   52,   52,   52,   52,    0,    0,
-    0,    0,    0,    0,   52,   52,   46,   46,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,   46,   46,
-   46,   46,   46,   46,   46,    0,    0,    0,    0,    0,
-    0,   47,   47,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,   47,   47,   47,   47,   47,   47,   47,
-    0,    0,    0,    0,    0,    0,    0,   48,   48,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,   48,
-   48,   48,   48,   48,   48,   48,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yycheck[] =
-#else
-short yycheck[] =
-#endif
-       {                                      33,
-    0,   18,   17,   33,   33,   93,  258,   33,  256,  261,
-  262,  263,   33,  282,  283,   44,  264,  265,  266,  267,
-   44,   33,   33,  275,   43,    0,   45,  276,  276,  277,
-  278,  279,  280,   33,  122,  257,  258,   61,  258,  120,
-  260,  261,   61,  263,   44,  258,  258,  258,  261,  262,
-  263,    0,  258,  275,  135,  275,  258,   44,   33,   58,
-   58,   58,  275,   58,  259,   44,   44,   44,   61,   61,
-   61,   61,   87,   58,   91,  263,  263,    0,  263,   44,
-   44,   61,  268,   58,   33,   61,  282,  263,  263,  283,
-   51,  119,   86,   38,   33,  132,   85,   11,  131,   82,
-   96,  121,   84,    0,   66,   68,   72,   74,   -1,   58,
-   33,   70,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,    0,
-   -1,   -1,   -1,   -1,   -1,   58,   33,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   33,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,
-   -1,   58,   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   33,   -1,   -1,   -1,   -1,   -1,   -1,
-    0,   -1,   -1,   -1,   -1,   -1,   -1,   58,   33,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   33,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,  259,   -1,  257,  258,  258,
-   -1,  260,  261,  259,  263,    0,  257,  258,   33,  269,
-  270,  271,  272,  273,  274,  275,  275,  259,  259,   -1,
-   -1,   -1,  282,  283,  275,   -1,  256,   -1,  258,   -1,
-    0,  261,  262,  263,  264,  265,  266,  267,   33,   -1,
-   -1,   -1,   -1,   -1,   -1,  275,  276,  277,  278,  279,
-  280,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
-  265,  266,  267,   33,   -1,   -1,   -1,   -1,   -1,    0,
-  275,  276,  277,  278,  279,  280,   33,  256,   -1,  258,
-   -1,   -1,  261,  262,  263,  264,  265,  266,  267,  258,
-   -1,   -1,  261,  262,  263,   -1,  275,  276,  277,  278,
-  279,  280,   33,  256,   -1,  258,  275,   -1,  261,  262,
-  263,  264,  265,  266,  267,   33,  258,   -1,  260,  261,
-   -1,  263,  275,  276,  277,  278,  279,  280,   -1,  256,
-   -1,  258,   -1,  275,  261,  262,  263,  264,  265,  266,
-  267,  258,   33,   -1,  261,  262,  263,   -1,  275,  276,
-  277,  278,  279,  280,   -1,  256,   -1,  258,  275,   -1,
-  261,  262,  263,  264,  265,  266,  267,   33,  258,   -1,
-   -1,  261,  262,  263,  275,  276,  277,  278,  279,  280,
-   -1,  256,   -1,  258,   -1,  275,  261,  262,  263,  264,
-  265,  266,  267,   33,   -1,   -1,   -1,   -1,   -1,   -1,
-  275,  276,  277,  278,  279,  280,  256,   -1,  258,   -1,
-   -1,  261,  262,  263,  264,  265,  266,  267,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,  275,  276,  277,  278,  279,
-  280,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
-  265,  266,  267,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-  275,  276,  277,  278,  279,  280,   -1,   -1,   -1,   -1,
-   -1,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
-  265,  266,  267,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-  275,  276,  277,  278,  279,  280,  256,   -1,  258,   -1,
-   -1,  261,  262,  263,  264,  265,  266,  267,   -1,   -1,
-  257,  258,   -1,   -1,   -1,  275,  276,  277,  278,  279,
-  280,   -1,  269,  270,  271,  272,  273,  274,  275,   -1,
-   -1,   -1,   -1,   -1,   -1,  256,   -1,  258,   -1,   -1,
-  261,  262,  263,  264,  265,  266,  267,   -1,   -1,  257,
-  258,   -1,   -1,   -1,  275,  276,  277,  278,  279,  280,
-   -1,  269,  270,  271,  272,  273,  274,  275,   -1,   -1,
-   -1,   -1,   -1,   -1,  282,  283,  257,  258,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  269,  270,
-  271,  272,  273,  274,  275,   -1,   -1,   -1,   -1,   -1,
-   -1,  257,  258,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,  269,  270,  271,  272,  273,  274,  275,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,  257,  258,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  269,
-  270,  271,  272,  273,  274,  275,
-};
-#define YYFINAL 11
-#ifndef YYDEBUG
-#define YYDEBUG 0
-#endif
-#define YYMAXTOKEN 283
-#if YYDEBUG
-#if defined(__cplusplus) || defined(__STDC__)
-const char * const yyname[] =
-#else
-char *yyname[] =
-#endif
-       {
-"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-"'!'",0,0,0,0,0,0,0,0,0,"'+'","','","'-'",0,0,0,0,0,0,0,0,0,0,0,0,"':'",0,0,
-"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-"COMMAND","ALIAS","DEFVAR","NTWKADDR","NETGROUP","USERGROUP","WORD","DEFAULTS",
-"DEFAULTS_HOST","DEFAULTS_USER","DEFAULTS_RUNAS","RUNAS","NOPASSWD","PASSWD",
-"NOEXEC","EXEC","SETENV","NOSETENV","ALL","COMMENT","HOSTALIAS","CMNDALIAS",
-"USERALIAS","RUNASALIAS","ERROR","TYPE","ROLE",
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const char * const yyrule[] =
-#else
-char *yyrule[] =
-#endif
-       {"$accept : file",
-"file : entry",
-"file : file entry",
-"entry : COMMENT",
-"entry : error COMMENT",
-"$$1 :",
-"entry : $$1 userlist privileges",
-"entry : USERALIAS useraliases",
-"entry : HOSTALIAS hostaliases",
-"entry : CMNDALIAS cmndaliases",
-"entry : RUNASALIAS runasaliases",
-"entry : defaults_line",
-"defaults_line : defaults_type defaults_list",
-"defaults_type : DEFAULTS",
-"$$2 :",
-"defaults_type : DEFAULTS_USER $$2 userlist",
-"$$3 :",
-"defaults_type : DEFAULTS_RUNAS $$3 runaslist",
-"$$4 :",
-"defaults_type : DEFAULTS_HOST $$4 hostlist",
-"defaults_list : defaults_entry",
-"defaults_list : defaults_entry ',' defaults_list",
-"defaults_entry : DEFVAR",
-"defaults_entry : '!' DEFVAR",
-"defaults_entry : DEFVAR '=' WORD",
-"defaults_entry : DEFVAR '+' WORD",
-"defaults_entry : DEFVAR '-' WORD",
-"privileges : privilege",
-"privileges : privileges ':' privilege",
-"privilege : hostlist '=' cmndspeclist",
-"ophost : host",
-"ophost : '!' host",
-"host : ALL",
-"host : NTWKADDR",
-"host : NETGROUP",
-"host : WORD",
-"host : ALIAS",
-"cmndspeclist : cmndspec",
-"cmndspeclist : cmndspeclist ',' cmndspec",
-"$$5 :",
-"cmndspec : $$5 runasspec selinux cmndtag opcmnd",
-"opcmnd : cmnd",
-"$$6 :",
-"opcmnd : '!' $$6 cmnd",
-"rolespec : ROLE '=' WORD",
-"typespec : TYPE '=' WORD",
-"selinux :",
-"selinux : rolespec",
-"selinux : typespec",
-"selinux : rolespec typespec",
-"selinux : typespec rolespec",
-"runasspec :",
-"runasspec : RUNAS runaslist",
-"runaslist : oprunasuser",
-"runaslist : runaslist ',' oprunasuser",
-"oprunasuser : runasuser",
-"$$7 :",
-"oprunasuser : '!' $$7 runasuser",
-"runasuser : WORD",
-"runasuser : USERGROUP",
-"runasuser : NETGROUP",
-"runasuser : ALIAS",
-"runasuser : ALL",
-"cmndtag :",
-"cmndtag : cmndtag NOPASSWD",
-"cmndtag : cmndtag PASSWD",
-"cmndtag : cmndtag NOEXEC",
-"cmndtag : cmndtag EXEC",
-"cmndtag : cmndtag SETENV",
-"cmndtag : cmndtag NOSETENV",
-"cmnd : ALL",
-"cmnd : ALIAS",
-"cmnd : COMMAND",
-"hostaliases : hostalias",
-"hostaliases : hostaliases ':' hostalias",
-"$$8 :",
-"hostalias : ALIAS $$8 '=' hostlist",
-"hostlist : ophost",
-"hostlist : hostlist ',' ophost",
-"cmndaliases : cmndalias",
-"cmndaliases : cmndaliases ':' cmndalias",
-"$$9 :",
-"cmndalias : ALIAS $$9 '=' cmndlist",
-"cmndlist : opcmnd",
-"cmndlist : cmndlist ',' opcmnd",
-"runasaliases : runasalias",
-"runasaliases : runasaliases ':' runasalias",
-"$$10 :",
-"runasalias : ALIAS $$10 '=' runaslist",
-"useraliases : useralias",
-"useraliases : useraliases ':' useralias",
-"$$11 :",
-"useralias : ALIAS $$11 '=' userlist",
-"userlist : opuser",
-"userlist : userlist ',' opuser",
-"opuser : user",
-"opuser : '!' user",
-"user : WORD",
-"user : USERGROUP",
-"user : NETGROUP",
-"user : ALIAS",
-"user : ALL",
-};
-#endif
-#ifdef YYSTACKSIZE
-#undef YYMAXDEPTH
-#define YYMAXDEPTH YYSTACKSIZE
-#else
-#ifdef YYMAXDEPTH
-#define YYSTACKSIZE YYMAXDEPTH
-#else
-#define YYSTACKSIZE 10000
-#define YYMAXDEPTH 10000
-#endif
-#endif
-#define YYINITSTACKSIZE 200
-/* LINTUSED */
-int yydebug;
-int yynerrs;
-int yyerrflag;
-int yychar;
-short *yyssp;
-YYSTYPE *yyvsp;
-YYSTYPE yyval;
-YYSTYPE yylval;
-short *yyss;
-short *yysslim;
-YYSTYPE *yyvs;
-int yystacksize;
-#line 1053 "parse.yacc"
-
-#define MOREALIASES (32)
-aliasinfo *aliases = NULL;
-size_t naliases = 0;
-size_t nslots = 0;
-
-
-/*
- * Compare two aliasinfo structures, strcmp() style.
- * Note that we do *not* compare their values.
- */
-static int
-aliascmp(a1, a2)
-    const VOID *a1, *a2;
-{
-    int r;
-    aliasinfo *ai1, *ai2;
-
-    ai1 = (aliasinfo *) a1;
-    ai2 = (aliasinfo *) a2;
-    if ((r = strcmp(ai1->name, ai2->name)) == 0)
-       r = ai1->type - ai2->type;
-
-    return(r);
-}
-
-/*
- * Compare two generic_alias structures, strcmp() style.
- */
-static int
-genaliascmp(entry, key)
-    const VOID *entry, *key;
-{
-    int r;
-    struct generic_alias *ga1, *ga2;
-
-    ga1 = (struct generic_alias *) key;
-    ga2 = (struct generic_alias *) entry;
-    if ((r = strcmp(ga1->alias, ga2->alias)) == 0)
-       r = ga1->type - ga2->type;
-
-    return(r);
-}
-
-
-/*
- * Adds the named alias of the specified type to the aliases list.
- */
-static int
-add_alias(alias, type, val)
-    char *alias;
-    int type;
-    int val;
-{
-    aliasinfo ai, *aip;
-    size_t onaliases;
-    char s[512];
-
-    if (naliases >= nslots)
-       more_aliases();
-
-    ai.type = type;
-    ai.val = val;
-    ai.name = estrdup(alias);
-    onaliases = naliases;
-
-    aip = (aliasinfo *) lsearch((VOID *)&ai, (VOID *)aliases, &naliases,
-                               sizeof(ai), aliascmp);
-    if (aip == NULL) {
-       (void) snprintf(s, sizeof(s), "Aliases corrupted defining alias `%s'",
-                       alias);
-       yyerror(s);
-       return(FALSE);
-    }
-    if (onaliases == naliases) {
-       (void) snprintf(s, sizeof(s), "Alias `%s' already defined", alias);
-       yyerror(s);
-       return(FALSE);
-    }
-
-    return(TRUE);
-}
-
-/*
- * Searches for the named alias of the specified type.
- */
-static aliasinfo *
-find_alias(alias, type)
-    char *alias;
-    int type;
-{
-    aliasinfo ai;
-
-    ai.name = alias;
-    ai.type = type;
-
-    return((aliasinfo *) lfind((VOID *)&ai, (VOID *)aliases, &naliases,
-                sizeof(ai), aliascmp));
-}
-
-/*
- * Allocates more space for the aliases list.
- */
-static void
-more_aliases()
-{
-
-    nslots += MOREALIASES;
-    aliases = (aliasinfo *) erealloc3(aliases, nslots, sizeof(aliasinfo));
-}
-
-/*
- * Lists the contents of the aliases list.
- */
-void
-dumpaliases()
-{
-    size_t n;
-
-    for (n = 0; n < naliases; n++) {
-       if (aliases[n].val == -1)
-           continue;
-
-       switch (aliases[n].type) {
-       case HOST_ALIAS:
-           (void) puts("HOST_ALIAS");
-           break;
-
-       case CMND_ALIAS:
-           (void) puts("CMND_ALIAS");
-           break;
-
-       case USER_ALIAS:
-           (void) puts("USER_ALIAS");
-           break;
-
-       case RUNAS_ALIAS:
-           (void) puts("RUNAS_ALIAS");
-           break;
-       }
-       (void) printf("\t%s: %d\n", aliases[n].name, aliases[n].val);
-    }
-}
-
-/*
- * Lists the contents of cm_list and ga_list for `sudo -l'.
- */
-void
-list_matches()
-{
-    size_t count;
-    char *p;
-    struct generic_alias *ga, key;
-
-    (void) printf("User %s may run the following commands on this host:\n",
-       user_name);
-    for (count = 0; count < cm_list_len; count++) {
-
-       /* Print the runas list. */
-       (void) fputs("    ", stdout);
-       if (cm_list[count].runas) {
-           (void) putchar('(');
-           p = strtok(cm_list[count].runas, ", ");
-           do {
-               if (p != cm_list[count].runas)
-                   (void) fputs(", ", stdout);
-
-               key.alias = p;
-               key.type = RUNAS_ALIAS;
-               if ((ga = (struct generic_alias *) lfind((VOID *) &key,
-                   (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
-                   (void) fputs(ga->entries, stdout);
-               else
-                   (void) fputs(p, stdout);
-           } while ((p = strtok(NULL, ", ")));
-           (void) fputs(") ", stdout);
-       } else {
-           (void) printf("(%s) ", def_runas_default);
-       }
-
-#ifdef HAVE_SELINUX
-       /* SELinux role and type */
-       if (cm_list[count].role != NULL)
-           (void) printf("ROLE=%s ", cm_list[count].role);
-       if (cm_list[count].type != NULL)
-           (void) printf("TYPE=%s ", cm_list[count].type);
-#endif
-
-       /* Is execve(2) disabled? */
-       if (cm_list[count].noexecve == TRUE && !def_noexec)
-           (void) fputs("NOEXEC: ", stdout);
-       else if (cm_list[count].noexecve == FALSE && def_noexec)
-           (void) fputs("EXEC: ", stdout);
-
-       /* Is a password required? */
-       if (cm_list[count].nopasswd == TRUE && def_authenticate)
-           (void) fputs("NOPASSWD: ", stdout);
-       else if (cm_list[count].nopasswd == FALSE && !def_authenticate)
-           (void) fputs("PASSWD: ", stdout);
-
-       /* Is setenv enabled? */
-       if (cm_list[count].setenv == TRUE && !def_setenv)
-           (void) fputs("SETENV: ", stdout);
-       else if (cm_list[count].setenv == FALSE && def_setenv)
-           (void) fputs("NOSETENV: ", stdout);
-
-       /* Print the actual command or expanded Cmnd_Alias. */
-       key.alias = cm_list[count].cmnd;
-       key.type = CMND_ALIAS;
-       if ((ga = (struct generic_alias *) lfind((VOID *) &key,
-           (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
-           (void) puts(ga->entries);
-       else
-           (void) puts(cm_list[count].cmnd);
-    }
-
-    /* Be nice and free up space now that we are done. */
-    for (count = 0; count < ga_list_len; count++) {
-       efree(ga_list[count].alias);
-       efree(ga_list[count].entries);
-    }
-    efree(ga_list);
-    ga_list = NULL;
-
-    for (count = 0; count < cm_list_len; count++) {
-       efree(cm_list[count].runas);
-       efree(cm_list[count].cmnd);
-       efree(cm_list[count].role);
-       efree(cm_list[count].type);
-    }
-    efree(cm_list);
-    cm_list = NULL;
-    cm_list_len = 0;
-    cm_list_size = 0;
-}
-
-/*
- * Appends a source string to the destination, optionally prefixing a separator.
- */
-static void
-append(src, dstp, dst_len, dst_size, separator)
-    char *src, **dstp;
-    size_t *dst_len, *dst_size;
-    char *separator;
-{
-    size_t src_len = strlen(src);
-    char *dst = *dstp;
-
-    /*
-     * Only add the separator if there is something to separate from.
-     * If the last char is a '!', don't apply the separator (XXX).
-     */
-    if (separator && dst && dst[*dst_len - 1] != '!')
-       src_len += strlen(separator);
-    else
-       separator = NULL;
-
-    /* Assumes dst will be NULL if not set. */
-    if (dst == NULL) {
-       dst = (char *) emalloc(BUFSIZ);
-       *dst = '\0';
-       *dst_size = BUFSIZ;
-       *dst_len = 0;
-       *dstp = dst;
-    }
-
-    /* Allocate more space if necessary. */
-    if (*dst_size <= *dst_len + src_len) {
-       while (*dst_size <= *dst_len + src_len)
-           *dst_size += BUFSIZ;
-
-       dst = (char *) erealloc(dst, *dst_size);
-       *dstp = dst;
-    }
-
-    /* Copy src -> dst adding a separator if appropriate and adjust len. */
-    if (separator)
-       (void) strlcat(dst, separator, *dst_size);
-    (void) strlcat(dst, src, *dst_size);
-    *dst_len += src_len;
-}
-
-/*
- * Frees up space used by the aliases list and resets the associated counters.
- */
-void
-reset_aliases()
-{
-    size_t n;
-
-    if (aliases) {
-       for (n = 0; n < naliases; n++)
-           efree(aliases[n].name);
-       efree(aliases);
-       aliases = NULL;
-    }
-    naliases = nslots = 0;
-}
-
-/*
- * Increments ga_list_len, allocating more space as necessary.
- */
-static void
-expand_ga_list()
-{
-
-    if (++ga_list_len >= ga_list_size) {
-       while ((ga_list_size += STACKINCREMENT) < ga_list_len)
-           ;
-       ga_list = (struct generic_alias *)
-           erealloc3(ga_list, ga_list_size, sizeof(struct generic_alias));
-    }
-
-    ga_list[ga_list_len - 1].entries = NULL;
-}
-
-/*
- * Increments cm_list_len, allocating more space as necessary.
- */
-static void
-expand_match_list()
-{
-
-    if (++cm_list_len >= cm_list_size) {
-       while ((cm_list_size += STACKINCREMENT) < cm_list_len)
-           ;
-       if (cm_list == NULL)
-           cm_list_len = 0;            /* start at 0 since it is a subscript */
-       cm_list = (struct command_match *)
-           erealloc3(cm_list, cm_list_size, sizeof(struct command_match));
-    }
-
-    cm_list[cm_list_len].runas = cm_list[cm_list_len].cmnd = NULL;
-    cm_list[cm_list_len].type = cm_list[cm_list_len].role = NULL;
-    cm_list[cm_list_len].nopasswd = FALSE;
-    cm_list[cm_list_len].noexecve = FALSE;
-    cm_list[cm_list_len].setenv = FALSE;
-}
-
-/*
- * Frees up spaced used by a previous parser run and allocates new space
- * for various data structures.
- */
-void
-init_parser()
-{
-
-    /* Free up old data structures if we run the parser more than once. */
-    if (match) {
-       efree(match);
-       match = NULL;
-       top = 0;
-       parse_error = FALSE;
-       used_runas = FALSE;
-       errorlineno = -1;
-       sudolineno = 1;
-    }
-
-    /* Allocate space for the matching stack. */
-    stacksize = STACKINCREMENT;
-    match = (struct matchstack *) emalloc2(stacksize, sizeof(struct matchstack));
-
-    /* Allocate space for the match list (for `sudo -l'). */
-    if (printmatches == TRUE)
-       expand_match_list();
-}
-#line 1054 "sudo.tab.c"
-/* allocate initial stack or double stack size, up to YYMAXDEPTH */
-#if defined(__cplusplus) || defined(__STDC__)
-static int yygrowstack(void)
-#else
-static int yygrowstack()
-#endif
-{
-    int newsize, i;
-    short *newss;
-    YYSTYPE *newvs;
-
-    if ((newsize = yystacksize) == 0)
-        newsize = YYINITSTACKSIZE;
-    else if (newsize >= YYMAXDEPTH)
-        return -1;
-    else if ((newsize *= 2) > YYMAXDEPTH)
-        newsize = YYMAXDEPTH;
-    i = yyssp - yyss;
-#ifdef SIZE_MAX
-#define YY_SIZE_MAX SIZE_MAX
-#else
-#define YY_SIZE_MAX 0x7fffffff
-#endif
-    if (newsize && YY_SIZE_MAX / newsize < sizeof *newss)
-        goto bail;
-    newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) :
-      (short *)malloc(newsize * sizeof *newss); /* overflow check above */
-    if (newss == NULL)
-        goto bail;
-    yyss = newss;
-    yyssp = newss + i;
-    if (newsize && YY_SIZE_MAX / newsize < sizeof *newvs)
-        goto bail;
-    newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) :
-      (YYSTYPE *)malloc(newsize * sizeof *newvs); /* overflow check above */
-    if (newvs == NULL)
-        goto bail;
-    yyvs = newvs;
-    yyvsp = newvs + i;
-    yystacksize = newsize;
-    yysslim = yyss + newsize - 1;
-    return 0;
-bail:
-    if (yyss)
-            free(yyss);
-    if (yyvs)
-            free(yyvs);
-    yyss = yyssp = NULL;
-    yyvs = yyvsp = NULL;
-    yystacksize = 0;
-    return -1;
-}
-
-#define YYABORT goto yyabort
-#define YYREJECT goto yyabort
-#define YYACCEPT goto yyaccept
-#define YYERROR goto yyerrlab
-int
-#if defined(__cplusplus) || defined(__STDC__)
-yyparse(void)
-#else
-yyparse()
-#endif
-{
-    int yym, yyn, yystate;
-#if YYDEBUG
-#if defined(__cplusplus) || defined(__STDC__)
-    const char *yys;
-#else /* !(defined(__cplusplus) || defined(__STDC__)) */
-    char *yys;
-#endif /* !(defined(__cplusplus) || defined(__STDC__)) */
-
-    if ((yys = getenv("YYDEBUG")))
-    {
-        yyn = *yys;
-        if (yyn >= '0' && yyn <= '9')
-            yydebug = yyn - '0';
-    }
-#endif /* YYDEBUG */
-
-    yynerrs = 0;
-    yyerrflag = 0;
-    yychar = (-1);
-
-    if (yyss == NULL && yygrowstack()) goto yyoverflow;
-    yyssp = yyss;
-    yyvsp = yyvs;
-    *yyssp = yystate = 0;
-
-yyloop:
-    if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
-    if (yychar < 0)
-    {
-        if ((yychar = yylex()) < 0) yychar = 0;
-#if YYDEBUG
-        if (yydebug)
-        {
-            yys = 0;
-            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
-            if (!yys) yys = "illegal-symbol";
-            printf("%sdebug: state %d, reading %d (%s)\n",
-                    YYPREFIX, yystate, yychar, yys);
-        }
-#endif
-    }
-    if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
-            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
-    {
-#if YYDEBUG
-        if (yydebug)
-            printf("%sdebug: state %d, shifting to state %d\n",
-                    YYPREFIX, yystate, yytable[yyn]);
-#endif
-        if (yyssp >= yysslim && yygrowstack())
-        {
-            goto yyoverflow;
-        }
-        *++yyssp = yystate = yytable[yyn];
-        *++yyvsp = yylval;
-        yychar = (-1);
-        if (yyerrflag > 0)  --yyerrflag;
-        goto yyloop;
-    }
-    if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
-            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
-    {
-        yyn = yytable[yyn];
-        goto yyreduce;
-    }
-    if (yyerrflag) goto yyinrecovery;
-#if defined(lint) || defined(__GNUC__)
-    goto yynewerror;
-#endif
-yynewerror:
-    yyerror("syntax error");
-#if defined(lint) || defined(__GNUC__)
-    goto yyerrlab;
-#endif
-yyerrlab:
-    ++yynerrs;
-yyinrecovery:
-    if (yyerrflag < 3)
-    {
-        yyerrflag = 3;
-        for (;;)
-        {
-            if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
-                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
-            {
-#if YYDEBUG
-                if (yydebug)
-                    printf("%sdebug: state %d, error recovery shifting\
- to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
-#endif
-                if (yyssp >= yysslim && yygrowstack())
-                {
-                    goto yyoverflow;
-                }
-                *++yyssp = yystate = yytable[yyn];
-                *++yyvsp = yylval;
-                goto yyloop;
-            }
-            else
-            {
-#if YYDEBUG
-                if (yydebug)
-                    printf("%sdebug: error recovery discarding state %d\n",
-                            YYPREFIX, *yyssp);
-#endif
-                if (yyssp <= yyss) goto yyabort;
-                --yyssp;
-                --yyvsp;
-            }
-        }
-    }
-    else
-    {
-        if (yychar == 0) goto yyabort;
-#if YYDEBUG
-        if (yydebug)
-        {
-            yys = 0;
-            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
-            if (!yys) yys = "illegal-symbol";
-            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
-                    YYPREFIX, yystate, yychar, yys);
-        }
-#endif
-        yychar = (-1);
-        goto yyloop;
-    }
-yyreduce:
-#if YYDEBUG
-    if (yydebug)
-        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
-                YYPREFIX, yystate, yyn, yyrule[yyn]);
-#endif
-    yym = yylen[yyn];
-    yyval = yyvsp[1-yym];
-    switch (yyn)
-    {
-case 3:
-#line 313 "parse.yacc"
-{ ; }
-break;
-case 4:
-#line 315 "parse.yacc"
-{ yyerrok; }
-break;
-case 5:
-#line 316 "parse.yacc"
-{ push; }
-break;
-case 6:
-#line 316 "parse.yacc"
-{
-                           while (top && user_matches != TRUE)
-                               pop;
-                       }
-break;
-case 7:
-#line 321 "parse.yacc"
-{ ; }
-break;
-case 8:
-#line 323 "parse.yacc"
-{ ; }
-break;
-case 9:
-#line 325 "parse.yacc"
-{ ; }
-break;
-case 10:
-#line 327 "parse.yacc"
-{ ; }
-break;
-case 11:
-#line 329 "parse.yacc"
-{ ; }
-break;
-case 13:
-#line 335 "parse.yacc"
-{
-                           defaults_matches = TRUE;
-                       }
-break;
-case 14:
-#line 338 "parse.yacc"
-{ push; }
-break;
-case 15:
-#line 338 "parse.yacc"
-{
-                           defaults_matches = user_matches;
-                           pop;
-                       }
-break;
-case 16:
-#line 342 "parse.yacc"
-{ push; }
-break;
-case 17:
-#line 342 "parse.yacc"
-{
-                           defaults_matches = yyvsp[0].BOOLEAN == TRUE;
-                           pop;
-                       }
-break;
-case 18:
-#line 346 "parse.yacc"
-{ push; }
-break;
-case 19:
-#line 346 "parse.yacc"
-{
-                           defaults_matches = host_matches;
-                           pop;
-                       }
-break;
-case 22:
-#line 356 "parse.yacc"
-{
-                           if (defaults_matches == TRUE &&
-                               !set_default(yyvsp[0].string, NULL, TRUE)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 23:
-#line 364 "parse.yacc"
-{
-                           if (defaults_matches == TRUE &&
-                               !set_default(yyvsp[0].string, NULL, FALSE)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 24:
-#line 372 "parse.yacc"
-{
-                           if (defaults_matches == TRUE &&
-                               !set_default(yyvsp[-2].string, yyvsp[0].string, TRUE)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           efree(yyvsp[-2].string);
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 25:
-#line 381 "parse.yacc"
-{
-                           if (defaults_matches == TRUE &&
-                               !set_default(yyvsp[-2].string, yyvsp[0].string, '+')) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           efree(yyvsp[-2].string);
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 26:
-#line 390 "parse.yacc"
-{
-                           if (defaults_matches == TRUE &&
-                               !set_default(yyvsp[-2].string, yyvsp[0].string, '-')) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           efree(yyvsp[-2].string);
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 29:
-#line 405 "parse.yacc"
-{
-                           /*
-                            * We already did a push if necessary in
-                            * cmndspec so just reset some values so
-                            * the next 'privilege' gets a clean slate.
-                            */
-                           host_matches = UNSPEC;
-                           runas_matches = UNSPEC;
-                           no_passwd = def_authenticate ? UNSPEC : TRUE;
-                           no_execve = def_noexec ? TRUE : UNSPEC;
-                           setenv_ok = def_setenv ? TRUE : UNSPEC;
-#ifdef HAVE_SELINUX
-                           efree(match[top-1].role);
-                           match[top-1].role = NULL;
-                           efree(match[top-1].type);
-                           match[top-1].type = NULL;
-#endif
-                       }
-break;
-case 30:
-#line 425 "parse.yacc"
-{
-                           SETMATCH(host_matches, yyvsp[0].BOOLEAN);
-                       }
-break;
-case 31:
-#line 428 "parse.yacc"
-{
-                           SETNMATCH(host_matches, yyvsp[0].BOOLEAN);
-                       }
-break;
-case 32:
-#line 433 "parse.yacc"
-{
-                           yyval.BOOLEAN = TRUE;
-                       }
-break;
-case 33:
-#line 436 "parse.yacc"
-{
-                           if (addr_matches(yyvsp[0].string))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 34:
-#line 443 "parse.yacc"
-{
-                           if (netgr_matches(yyvsp[0].string, user_host, user_shost, NULL))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 35:
-#line 450 "parse.yacc"
-{
-                           if (hostname_matches(user_shost, user_host, yyvsp[0].string) == 0)
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 36:
-#line 457 "parse.yacc"
-{
-                           aliasinfo *aip = find_alias(yyvsp[0].string, HOST_ALIAS);
-
-                           /* could be an all-caps hostname */
-                           if (aip)
-                               yyval.BOOLEAN = aip->val;
-                           else if (strcasecmp(user_shost, yyvsp[0].string) == 0)
-                               yyval.BOOLEAN = TRUE;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared Host_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", yyvsp[0].string, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               yyval.BOOLEAN = NOMATCH;
-                           }
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 39:
-#line 485 "parse.yacc"
-{ SETENV_RESET; }
-break;
-case 40:
-#line 485 "parse.yacc"
-{
-#ifdef HAVE_SELINUX
-                           /* Replace inherited role/type as needed. */
-                           if (yyvsp[-2].seinfo.role != NULL) {
-                               efree(match[top-1].role);
-                               match[top-1].role = yyvsp[-2].seinfo.role;
-                           }
-                           if (yyvsp[-2].seinfo.type != NULL) {
-                               efree(match[top-1].type);
-                               match[top-1].type = yyvsp[-2].seinfo.type;
-                           }
-#endif
-                           /*
-                            * Push the entry onto the stack if it is worth
-                            * saving and reset cmnd_matches for next cmnd.
-                            *
-                            * We need to save at least one entry on
-                            * the stack so sudoers_lookup() can tell that
-                            * the user was listed in sudoers.  Also, we
-                            * need to be able to tell whether or not a
-                            * user was listed for this specific host.
-                            *
-                            * If keepall is set and the user matches then
-                            * we need to keep entries around too...
-                            */
-                           if (MATCHED(user_matches) &&
-                               MATCHED(host_matches) &&
-                               MATCHED(cmnd_matches) &&
-                               MATCHED(runas_matches))
-                               pushcp;
-                           else if (MATCHED(user_matches) && (top == 1 ||
-                               (top == 2 && MATCHED(host_matches) &&
-                               !MATCHED(match[0].host))))
-                               pushcp;
-                           else if (user_matches == TRUE && keepall)
-                               pushcp;
-
-                           cmnd_matches = UNSPEC;
-                       }
-break;
-case 41:
-#line 526 "parse.yacc"
-{
-                           SETMATCH(cmnd_matches, yyvsp[0].BOOLEAN);
-                       }
-break;
-case 42:
-#line 529 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("!", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_cmnd("!", NULL);
-                           }
-                       }
-break;
-case 43:
-#line 537 "parse.yacc"
-{
-                           SETNMATCH(cmnd_matches, yyvsp[0].BOOLEAN);
-                       }
-break;
-case 44:
-#line 542 "parse.yacc"
-{
-#ifdef HAVE_SELINUX
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE && runas_matches == TRUE)
-                               append_role(yyvsp[0].string, NULL);
-                           yyval.string = yyvsp[0].string;
-#else
-                           free(yyvsp[0].string);
-                           yyval.string = NULL;
-#endif /* HAVE_SELINUX */
-                       }
-break;
-case 45:
-#line 555 "parse.yacc"
-{
-#ifdef HAVE_SELINUX
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE && runas_matches == TRUE)
-                               append_type(yyvsp[0].string, NULL);
-                           yyval.string = yyvsp[0].string;
-#else
-                           free(yyvsp[0].string);
-                           yyval.string = NULL;
-#endif /* HAVE_SELINUX */
-                       }
-break;
-case 46:
-#line 568 "parse.yacc"
-{
-#ifdef HAVE_SELINUX
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE && runas_matches == TRUE) {
-                               /* Inherit role. */
-                               cm_list[cm_list_len].role =
-                                   estrdup(cm_list[cm_list_len-1].role);
-                               cm_list[cm_list_len].role_len =
-                                   cm_list[cm_list_len-1].role_len;
-                               cm_list[cm_list_len].role_size =
-                                   cm_list[cm_list_len-1].role_len + 1;
-                               /* Inherit type. */
-                               cm_list[cm_list_len].type =
-                                   estrdup(cm_list[cm_list_len-1].type);
-                               cm_list[cm_list_len].type_len =
-                                   cm_list[cm_list_len-1].type_len;
-                               cm_list[cm_list_len].type_size =
-                                   cm_list[cm_list_len-1].type_len + 1;
-                           }
-#endif /* HAVE_SELINUX */
-                           yyval.seinfo.role = NULL;
-                           yyval.seinfo.type = NULL;
-                       }
-break;
-case 47:
-#line 591 "parse.yacc"
-{
-#ifdef HAVE_SELINUX
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE && runas_matches == TRUE) {
-                               /* Inherit type. */
-                               cm_list[cm_list_len].type =
-                                   estrdup(cm_list[cm_list_len-1].type);
-                               cm_list[cm_list_len].type_len =
-                                   cm_list[cm_list_len-1].type_len;
-                               cm_list[cm_list_len].type_size =
-                                   cm_list[cm_list_len-1].type_len + 1;
-                           }
-#endif /* HAVE_SELINUX */
-                           yyval.seinfo.role = yyvsp[0].string;
-                           yyval.seinfo.type = NULL;
-                       }
-break;
-case 48:
-#line 607 "parse.yacc"
-{
-#ifdef HAVE_SELINUX
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE && runas_matches == TRUE) {
-                               /* Inherit role. */
-                               cm_list[cm_list_len].role =
-                                   estrdup(cm_list[cm_list_len-1].role);
-                               cm_list[cm_list_len].role_len =
-                                   cm_list[cm_list_len-1].role_len;
-                               cm_list[cm_list_len].role_size =
-                                   cm_list[cm_list_len-1].role_len + 1;
-                           }
-#endif /* HAVE_SELINUX */
-                           yyval.seinfo.type = yyvsp[0].string;
-                           yyval.seinfo.role = NULL;
-                       }
-break;
-case 49:
-#line 623 "parse.yacc"
-{
-                           yyval.seinfo.role = yyvsp[-1].string;
-                           yyval.seinfo.type = yyvsp[0].string;
-                       }
-break;
-case 50:
-#line 627 "parse.yacc"
-{
-                           yyval.seinfo.type = yyvsp[-1].string;
-                           yyval.seinfo.role = yyvsp[0].string;
-                       }
-break;
-case 51:
-#line 633 "parse.yacc"
-{
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE) {
-                               if (runas_matches == UNSPEC) {
-                                   cm_list[cm_list_len].runas_len = 0;
-                               } else {
-                                   /* Inherit runas data. */
-                                   cm_list[cm_list_len].runas =
-                                       estrdup(cm_list[cm_list_len-1].runas);
-                                   cm_list[cm_list_len].runas_len =
-                                       cm_list[cm_list_len-1].runas_len;
-                                   cm_list[cm_list_len].runas_size =
-                                       cm_list[cm_list_len-1].runas_len + 1;
-                               }
-                           }
-                           /*
-                            * If this is the first entry in a command list
-                            * then check against default runas user.
-                            */
-                           if (runas_matches == UNSPEC) {
-                               runas_matches = userpw_matches(def_runas_default,
-                                   *user_runas, runas_pw) ? TRUE : NOMATCH;
-                           }
-                       }
-break;
-case 52:
-#line 657 "parse.yacc"
-{
-                           runas_matches = yyvsp[0].BOOLEAN;
-                       }
-break;
-case 53:
-#line 662 "parse.yacc"
-{ ; }
-break;
-case 54:
-#line 663 "parse.yacc"
-{
-                           /* Later entries override earlier ones. */
-                           if (yyvsp[0].BOOLEAN != NOMATCH)
-                               yyval.BOOLEAN = yyvsp[0].BOOLEAN;
-                           else
-                               yyval.BOOLEAN = yyvsp[-2].BOOLEAN;
-                       }
-break;
-case 55:
-#line 672 "parse.yacc"
-{ ; }
-break;
-case 56:
-#line 673 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("!", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas("!", ", ");
-                           }
-                       }
-break;
-case 57:
-#line 681 "parse.yacc"
-{
-                           /* Set $$ to the negation of runasuser */
-                           yyval.BOOLEAN = (yyvsp[0].BOOLEAN == NOMATCH ? NOMATCH : ! yyvsp[0].BOOLEAN);
-                       }
-break;
-case 58:
-#line 687 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries(yyvsp[0].string, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas(yyvsp[0].string, ", ");
-                           }
-                           if (userpw_matches(yyvsp[0].string, *user_runas, runas_pw))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           efree(yyvsp[0].string);
-                           used_runas = TRUE;
-                       }
-break;
-case 59:
-#line 702 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries(yyvsp[0].string, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas(yyvsp[0].string, ", ");
-                           }
-                           if (usergr_matches(yyvsp[0].string, *user_runas, runas_pw))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           efree(yyvsp[0].string);
-                           used_runas = TRUE;
-                       }
-break;
-case 60:
-#line 717 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries(yyvsp[0].string, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas(yyvsp[0].string, ", ");
-                           }
-                           if (netgr_matches(yyvsp[0].string, NULL, NULL, *user_runas))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           efree(yyvsp[0].string);
-                           used_runas = TRUE;
-                       }
-break;
-case 61:
-#line 732 "parse.yacc"
-{
-                           aliasinfo *aip = find_alias(yyvsp[0].string, RUNAS_ALIAS);
-
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries(yyvsp[0].string, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas(yyvsp[0].string, ", ");
-                           }
-                           /* could be an all-caps username */
-                           if (aip)
-                               yyval.BOOLEAN = aip->val;
-                           else if (strcmp(yyvsp[0].string, *user_runas) == 0)
-                               yyval.BOOLEAN = TRUE;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared Runas_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", yyvsp[0].string, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               yyval.BOOLEAN = NOMATCH;
-                           }
-                           efree(yyvsp[0].string);
-                           used_runas = TRUE;
-                       }
-break;
-case 62:
-#line 762 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("ALL", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas("ALL", ", ");
-                           }
-                           yyval.BOOLEAN = TRUE;
-                       }
-break;
-case 63:
-#line 774 "parse.yacc"
-{
-                           /* Inherit {NO,}{PASSWD,EXEC,SETENV} status. */
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE) {
-                               if (no_passwd == TRUE)
-                                   cm_list[cm_list_len].nopasswd = TRUE;
-                               else
-                                   cm_list[cm_list_len].nopasswd = FALSE;
-                               if (no_execve == TRUE)
-                                   cm_list[cm_list_len].noexecve = TRUE;
-                               else
-                                   cm_list[cm_list_len].noexecve = FALSE;
-                               if (setenv_ok == TRUE)
-                                   cm_list[cm_list_len].setenv = TRUE;
-                               else
-                                   cm_list[cm_list_len].setenv = FALSE;
-                           }
-                       }
-break;
-case 64:
-#line 792 "parse.yacc"
-{
-                           no_passwd = TRUE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].nopasswd = TRUE;
-                       }
-break;
-case 65:
-#line 798 "parse.yacc"
-{
-                           no_passwd = FALSE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].nopasswd = FALSE;
-                       }
-break;
-case 66:
-#line 804 "parse.yacc"
-{
-                           no_execve = TRUE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].noexecve = TRUE;
-                       }
-break;
-case 67:
-#line 810 "parse.yacc"
-{
-                           no_execve = FALSE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].noexecve = FALSE;
-                       }
-break;
-case 68:
-#line 816 "parse.yacc"
-{
-                           setenv_ok = TRUE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].setenv = TRUE;
-                       }
-break;
-case 69:
-#line 822 "parse.yacc"
-{
-                           setenv_ok = FALSE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].setenv = FALSE;
-                       }
-break;
-case 70:
-#line 830 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("ALL", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE) {
-                                   append_cmnd("ALL", NULL);
-                                   expand_match_list();
-                               }
-                           }
-                           /* sudo "ALL" implies the SETENV tag */
-                           if (setenv_ok == UNSPEC)
-                               setenv_ok = IMPLIED;
-
-                           efree(safe_cmnd);
-                           safe_cmnd = NULL;
-                           yyval.BOOLEAN = TRUE;
-                       }
-break;
-case 71:
-#line 848 "parse.yacc"
-{
-                           aliasinfo *aip;
-
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries(yyvsp[0].string, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE) {
-                                   append_cmnd(yyvsp[0].string, NULL);
-                                   expand_match_list();
-                               }
-                           }
-
-                           if ((aip = find_alias(yyvsp[0].string, CMND_ALIAS)))
-                               yyval.BOOLEAN = aip->val;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared Cmnd_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", yyvsp[0].string, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               yyval.BOOLEAN = NOMATCH;
-                           }
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 72:
-#line 877 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE) {
-                                   append_entries(yyvsp[0].command.cmnd, ", ");
-                                   if (yyvsp[0].command.args)
-                                       append_entries(yyvsp[0].command.args, " ");
-                               }
-                               if (host_matches == TRUE &&
-                                   user_matches == TRUE)  {
-                                   append_cmnd(yyvsp[0].command.cmnd, NULL);
-                                   if (yyvsp[0].command.args)
-                                       append_cmnd(yyvsp[0].command.args, " ");
-                                   expand_match_list();
-                               }
-                           }
-
-                           if (command_matches(yyvsp[0].command.cmnd, yyvsp[0].command.args))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-
-                           efree(yyvsp[0].command.cmnd);
-                           efree(yyvsp[0].command.args);
-                       }
-break;
-case 75:
-#line 907 "parse.yacc"
-{ push; }
-break;
-case 76:
-#line 907 "parse.yacc"
-{
-                           if ((MATCHED(host_matches) || pedantic) &&
-                               !add_alias(yyvsp[-3].string, HOST_ALIAS, host_matches)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           pop;
-                       }
-break;
-case 81:
-#line 925 "parse.yacc"
-{
-                           push;
-                           if (printmatches == TRUE) {
-                               in_alias = TRUE;
-                               /* Allocate space for ga_list if necessary. */
-                               expand_ga_list();
-                               ga_list[ga_list_len-1].type = CMND_ALIAS;
-                               ga_list[ga_list_len-1].alias = estrdup(yyvsp[0].string);
-                            }
-                       }
-break;
-case 82:
-#line 934 "parse.yacc"
-{
-                           if ((MATCHED(cmnd_matches) || pedantic) &&
-                               !add_alias(yyvsp[-3].string, CMND_ALIAS, cmnd_matches)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           pop;
-                           efree(yyvsp[-3].string);
-
-                           if (printmatches == TRUE)
-                               in_alias = FALSE;
-                       }
-break;
-case 83:
-#line 948 "parse.yacc"
-{ ; }
-break;
-case 87:
-#line 956 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               in_alias = TRUE;
-                               /* Allocate space for ga_list if necessary. */
-                               expand_ga_list();
-                               ga_list[ga_list_len-1].type = RUNAS_ALIAS;
-                               ga_list[ga_list_len-1].alias = estrdup(yyvsp[0].string);
-                           }
-                       }
-break;
-case 88:
-#line 964 "parse.yacc"
-{
-                           if ((yyvsp[0].BOOLEAN != NOMATCH || pedantic) &&
-                               !add_alias(yyvsp[-3].string, RUNAS_ALIAS, yyvsp[0].BOOLEAN)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           efree(yyvsp[-3].string);
-
-                           if (printmatches == TRUE)
-                               in_alias = FALSE;
-                       }
-break;
-case 91:
-#line 981 "parse.yacc"
-{ push; }
-break;
-case 92:
-#line 981 "parse.yacc"
-{
-                           if ((MATCHED(user_matches) || pedantic) &&
-                               !add_alias(yyvsp[-3].string, USER_ALIAS, user_matches)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           pop;
-                           efree(yyvsp[-3].string);
-                       }
-break;
-case 95:
-#line 996 "parse.yacc"
-{
-                           SETMATCH(user_matches, yyvsp[0].BOOLEAN);
-                       }
-break;
-case 96:
-#line 999 "parse.yacc"
-{
-                           SETNMATCH(user_matches, yyvsp[0].BOOLEAN);
-                       }
-break;
-case 97:
-#line 1004 "parse.yacc"
-{
-                           if (userpw_matches(yyvsp[0].string, user_name, sudo_user.pw))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 98:
-#line 1011 "parse.yacc"
-{
-                           if (usergr_matches(yyvsp[0].string, user_name, sudo_user.pw))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 99:
-#line 1018 "parse.yacc"
-{
-                           if (netgr_matches(yyvsp[0].string, NULL, NULL, user_name))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 100:
-#line 1025 "parse.yacc"
-{
-                           aliasinfo *aip = find_alias(yyvsp[0].string, USER_ALIAS);
-
-                           /* could be an all-caps username */
-                           if (aip)
-                               yyval.BOOLEAN = aip->val;
-                           else if (strcmp(yyvsp[0].string, user_name) == 0)
-                               yyval.BOOLEAN = TRUE;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared User_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", yyvsp[0].string, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               yyval.BOOLEAN = NOMATCH;
-                           }
-                           efree(yyvsp[0].string);
-                       }
-break;
-case 101:
-#line 1047 "parse.yacc"
-{
-                           yyval.BOOLEAN = TRUE;
-                       }
-break;
-#line 2149 "sudo.tab.c"
-    }
-    yyssp -= yym;
-    yystate = *yyssp;
-    yyvsp -= yym;
-    yym = yylhs[yyn];
-    if (yystate == 0 && yym == 0)
-    {
-#if YYDEBUG
-        if (yydebug)
-            printf("%sdebug: after reduction, shifting from state 0 to\
- state %d\n", YYPREFIX, YYFINAL);
-#endif
-        yystate = YYFINAL;
-        *++yyssp = YYFINAL;
-        *++yyvsp = yyval;
-        if (yychar < 0)
-        {
-            if ((yychar = yylex()) < 0) yychar = 0;
-#if YYDEBUG
-            if (yydebug)
-            {
-                yys = 0;
-                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
-                if (!yys) yys = "illegal-symbol";
-                printf("%sdebug: state %d, reading %d (%s)\n",
-                        YYPREFIX, YYFINAL, yychar, yys);
-            }
-#endif
-        }
-        if (yychar == 0) goto yyaccept;
-        goto yyloop;
-    }
-    if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
-            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
-        yystate = yytable[yyn];
-    else
-        yystate = yydgoto[yym];
-#if YYDEBUG
-    if (yydebug)
-        printf("%sdebug: after reduction, shifting from state %d \
-to state %d\n", YYPREFIX, *yyssp, yystate);
-#endif
-    if (yyssp >= yysslim && yygrowstack())
-    {
-        goto yyoverflow;
-    }
-    *++yyssp = yystate;
-    *++yyvsp = yyval;
-    goto yyloop;
-yyoverflow:
-    yyerror("yacc stack overflow");
-yyabort:
-    if (yyss)
-            free(yyss);
-    if (yyvs)
-            free(yyvs);
-    yyss = yyssp = NULL;
-    yyvs = yyvsp = NULL;
-    yystacksize = 0;
-    return (1);
-yyaccept:
-    if (yyss)
-            free(yyss);
-    if (yyvs)
-            free(yyvs);
-    yyss = yyssp = NULL;
-    yyvs = yyvsp = NULL;
-    yystacksize = 0;
-    return (0);
-}
diff --git a/sudo.tab.h b/sudo.tab.h
deleted file mode 100644 (file)
index ba97b3a..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#define COMMAND 257
-#define ALIAS 258
-#define DEFVAR 259
-#define NTWKADDR 260
-#define NETGROUP 261
-#define USERGROUP 262
-#define WORD 263
-#define DEFAULTS 264
-#define DEFAULTS_HOST 265
-#define DEFAULTS_USER 266
-#define DEFAULTS_RUNAS 267
-#define RUNAS 268
-#define NOPASSWD 269
-#define PASSWD 270
-#define NOEXEC 271
-#define EXEC 272
-#define SETENV 273
-#define NOSETENV 274
-#define ALL 275
-#define COMMENT 276
-#define HOSTALIAS 277
-#define CMNDALIAS 278
-#define USERALIAS 279
-#define RUNASALIAS 280
-#define ERROR 281
-#define TYPE 282
-#define ROLE 283
-#ifndef YYSTYPE_DEFINED
-#define YYSTYPE_DEFINED
-typedef union {
-    char *string;
-    int BOOLEAN;
-    struct sudo_command command;
-    int tok;
-    struct selinux_info seinfo;
-} YYSTYPE;
-#endif /* YYSTYPE_DEFINED */
-extern YYSTYPE yylval;
index 5ed8e66ce92a29c8a2463f541582e3851288a0fe..fba5a1b945cf4eb87ea0ca75e38bfa72edf477f8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2004-2008 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <ctype.h>
 #include <pwd.h>
-#include <grp.h>
 #include <signal.h>
 #include <errno.h>
 #include <fcntl.h>
 #include "sudo.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: sudo_edit.c,v 1.6.2.9 2008/06/21 00:47:52 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: sudo_edit.c,v 1.37 2008/11/09 14:13:12 millert Exp $";
 #endif /* lint */
 
 extern sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
 extern char **environ;
 
+static char *find_editor();
+
 /*
  * Wrapper to allow users to edit privileged files with their own uid.
  */
-int sudo_edit(argc, argv, envp)
+int
+sudo_edit(argc, argv, envp)
     int argc;
     char **argv;
     char **envp;
@@ -82,7 +79,6 @@ int sudo_edit(argc, argv, envp)
     char **nargv, **ap, *editor, *cp;
     char buf[BUFSIZ];
     int error, i, ac, ofd, tfd, nargc, rval, tmplen, wasblank;
-    sigaction_t sa;
     struct stat sb;
     struct timespec ts1, ts2;
     struct tempfile {
@@ -107,24 +103,25 @@ int sudo_edit(argc, argv, envp)
     while (tmplen > 0 && tmpdir[tmplen - 1] == '/')
        tmplen--;
 
+    /*
+     * Close password, shadow, and group files before we try to open
+     * user-specified files to prevent the opening of things like /dev/fd/4
+     */
+    sudo_endpwent();
+    sudo_endgrent();
+
     /*
      * For each file specified by the user, make a temporary version
      * and copy the contents of the original to it.
      */
     tf = emalloc2(argc - 1, sizeof(*tf));
-    memset(tf, 0, (argc - 1) * sizeof(*tf));
+    zero_bytes(tf, (argc - 1) * sizeof(*tf));
     for (i = 0, ap = argv + 1; i < argc - 1 && *ap != NULL; i++, ap++) {
        error = -1;
        set_perms(PERM_RUNAS);
-
-       /*
-        * We close the password file before we try to open the user-specified
-        * path to prevent the opening of things like /dev/fd/4.
-        */
-       endpwent();
        if ((ofd = open(*ap, O_RDONLY, 0644)) != -1 || errno == ENOENT) {
            if (ofd == -1) {
-               memset(&sb, 0, sizeof(sb));             /* new file */
+               zero_bytes(&sb, sizeof(sb));            /* new file */
                error = 0;
            } else {
 #ifdef HAVE_FSTAT
@@ -137,9 +134,9 @@ int sudo_edit(argc, argv, envp)
        set_perms(PERM_ROOT);
        if (error || (ofd != -1 && !S_ISREG(sb.st_mode))) {
            if (error)
-               warn("%s", *ap);
+               warning("%s", *ap);
            else
-               warnx("%s: not a regular file", *ap);
+               warningx("%s: not a regular file", *ap);
            if (ofd != -1)
                close(ofd);
            argc--;
@@ -159,16 +156,16 @@ int sudo_edit(argc, argv, envp)
        tfd = mkstemp(tf[i].tfile);
        set_perms(PERM_ROOT);
        if (tfd == -1) {
-           warn("mkstemp");
+           warning("mkstemp");
            goto cleanup;
        }
        if (ofd != -1) {
            while ((nread = read(ofd, buf, sizeof(buf))) != 0) {
                if ((nwritten = write(tfd, buf, nread)) != nread) {
                    if (nwritten == -1)
-                       warn("%s", tf[i].tfile);
+                       warning("%s", tf[i].tfile);
                    else
-                       warnx("%s: short write", tf[i].tfile);
+                       warningx("%s: short write", tf[i].tfile);
                    goto cleanup;
                }
            }
@@ -194,20 +191,8 @@ int sudo_edit(argc, argv, envp)
     if (argc == 1)
        return(1);                      /* no files readable, you lose */
 
-    /*
-     * Determine which editor to use.  We don't bother restricting this
-     * based on def_env_editor or def_editor since the editor runs with
-     * the uid of the invoking user, not the runas (privileged) user.
-     */
     environ = envp;
-    if (((editor = getenv("VISUAL")) != NULL && *editor != '\0') ||
-       ((editor = getenv("EDITOR")) != NULL && *editor != '\0')) {
-       editor = estrdup(editor);
-    } else {
-       editor = estrdup(def_editor);
-       if ((cp = strchr(editor, ':')) != NULL)
-           *cp = '\0';                 /* def_editor could be a path */
-    }
+    editor = find_editor();
 
     /*
      * Allocate space for the new argument vector and fill it in.
@@ -232,9 +217,6 @@ int sudo_edit(argc, argv, envp)
     nargv[ac] = NULL;
 
     /* Allow the editor to be suspended. */
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = SA_RESTART;
-    sa.sa_handler = SIG_DFL;
     (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
 
     /*
@@ -244,18 +226,16 @@ int sudo_edit(argc, argv, envp)
     gettime(&ts1);
     kidpid = fork();
     if (kidpid == -1) {
-       warn("fork");
+       warning("fork");
        goto cleanup;
     } else if (kidpid == 0) {
        /* child */
        (void) sigaction(SIGINT, &saved_sa_int, NULL);
        (void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
        set_perms(PERM_FULL_USER);
-       endpwent();
-       endgrent();
-       closefrom(STDERR_FILENO + 1);
+       closefrom(def_closefrom + 1);
        execvp(nargv[0], nargv);
-       warn("unable to execute %s", nargv[0]);
+       warning("unable to execute %s", nargv[0]);
        _exit(127);
     }
 
@@ -299,10 +279,10 @@ int sudo_edit(argc, argv, envp)
        set_perms(PERM_ROOT);
        if (error || !S_ISREG(sb.st_mode)) {
            if (error)
-               warn("%s", tf[i].tfile);
+               warning("%s", tf[i].tfile);
            else
-               warnx("%s: not a regular file", tf[i].tfile);
-           warnx("%s left unmodified", tf[i].ofile);
+               warningx("%s: not a regular file", tf[i].tfile);
+           warningx("%s left unmodified", tf[i].ofile);
            if (tfd != -1)
                close(tfd);
            continue;
@@ -319,7 +299,7 @@ int sudo_edit(argc, argv, envp)
            timespecsub(&ts1, &ts2, &ts2);
 #endif
            if (timespecisset(&ts2)) {
-               warnx("%s unchanged", tf[i].ofile);
+               warningx("%s unchanged", tf[i].ofile);
                unlink(tf[i].tfile);
                close(tfd);
                continue;
@@ -329,17 +309,17 @@ int sudo_edit(argc, argv, envp)
        ofd = open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT, 0644);
        set_perms(PERM_ROOT);
        if (ofd == -1) {
-           warn("unable to write to %s", tf[i].ofile);
-           warnx("contents of edit session left in %s", tf[i].tfile);
+           warning("unable to write to %s", tf[i].ofile);
+           warningx("contents of edit session left in %s", tf[i].tfile);
            close(tfd);
            continue;
        }
        while ((nread = read(tfd, buf, sizeof(buf))) > 0) {
            if ((nwritten = write(ofd, buf, nread)) != nread) {
                if (nwritten == -1)
-                   warn("%s", tf[i].ofile);
+                   warning("%s", tf[i].ofile);
                else
-                   warnx("%s: short write", tf[i].ofile);
+                   warningx("%s: short write", tf[i].ofile);
                break;
            }
        }
@@ -347,11 +327,11 @@ int sudo_edit(argc, argv, envp)
            /* success, got EOF */
            unlink(tf[i].tfile);
        } else if (nread < 0) {
-           warn("unable to read temporary file");
-           warnx("contents of edit session left in %s", tf[i].tfile);
+           warning("unable to read temporary file");
+           warningx("contents of edit session left in %s", tf[i].tfile);
        } else {
-           warn("unable to write to %s", tf[i].ofile);
-           warnx("contents of edit session left in %s", tf[i].tfile);
+           warning("unable to write to %s", tf[i].ofile);
+           warningx("contents of edit session left in %s", tf[i].tfile);
        }
        close(ofd);
     }
@@ -365,3 +345,40 @@ cleanup:
     }
     return(1);
 }
+
+/*
+ * Determine which editor to use.  We don't bother restricting this
+ * based on def_env_editor or def_editor since the editor runs with
+ * the uid of the invoking user, not the runas (privileged) user.
+ */
+static char *
+find_editor()
+{
+    char *cp, *editor = NULL, **ev, *ev0[4];
+
+    ev0[0] = "SUDO_EDITOR";
+    ev0[1] = "VISUAL";
+    ev0[2] = "EDITOR";
+    ev0[3] = NULL;
+    for (ev = ev0; *ev != NULL; ev++) {
+       if ((editor = getenv(*ev)) != NULL && *editor != '\0') {
+           if ((cp = strrchr(editor, '/')) != NULL)
+               cp++;
+           else
+               cp = editor;
+           /* Ignore "sudoedit" and "sudo" to avoid an endless loop. */
+           if (strncmp(cp, "sudo", 4) != 0 ||
+               (cp[4] != ' ' && cp[4] != '\0' && strcmp(cp + 4, "edit") != 0)) {
+               editor = estrdup(editor);
+               break;
+           }
+       }
+       editor = NULL;
+    }
+    if (editor == NULL) {
+       editor = estrdup(def_editor);
+       if ((cp = strchr(editor, ':')) != NULL)
+           *cp = '\0';                 /* def_editor could be a path */
+    }
+    return(editor);
+}
index f0723d0e2a3ee16c7823de1062bbbd0227328610..084000abd53c7a7a7d39b1ecf5e5501710ee849c 100644 (file)
@@ -29,7 +29,7 @@
 #include <compat.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: sudo_noexec.c,v 1.5.2.2 2007/06/12 00:56:43 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: sudo_noexec.c,v 1.12 2005/03/12 23:43:40 millert Exp $";
 #endif /* lint */
 
 /*
diff --git a/sudo_nss.c b/sudo_nss.c
new file mode 100644 (file)
index 0000000..7d70617
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#include <grp.h>
+
+#include "sudo.h"
+#include "lbuf.h"
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: sudo_nss.c,v 1.6 2008/02/08 13:18:12 millert Exp $";
+#endif /* lint */
+
+extern struct sudo_nss sudo_nss_file;
+#ifdef HAVE_LDAP
+extern struct sudo_nss sudo_nss_ldap;
+#endif
+
+#if defined(HAVE_LDAP) && defined(_PATH_NSSWITCH_CONF)
+/*
+ * Read in /etc/nsswitch.conf
+ * Returns a tail queue of matches.
+ */
+struct sudo_nss_list *
+sudo_read_nss()
+{
+    FILE *fp;
+    char *cp;
+    int saw_files = FALSE;
+    int saw_ldap = FALSE;
+    int got_match = FALSE;
+    static struct sudo_nss_list snl;
+
+    if ((fp = fopen(_PATH_NSSWITCH_CONF, "r")) == NULL)
+       goto nomatch;
+
+    while ((cp = sudo_parseln(fp)) != NULL) {
+       /* Skip blank or comment lines */
+       if (*cp == '\0')
+           continue;
+
+       /* Look for a line starting with "sudoers:" */
+       if (strncasecmp(cp, "sudoers:", 8) != 0)
+           continue;
+
+       /* Parse line */
+       for ((cp = strtok(cp + 8, " \t")); cp != NULL; (cp = strtok(NULL, " \t"))) {
+           if (strcasecmp(cp, "files") == 0 && !saw_files) {
+               tq_append(&snl, &sudo_nss_file);
+               got_match = TRUE;
+           } else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) {
+               tq_append(&snl, &sudo_nss_ldap);
+               got_match = TRUE;
+           } else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) {
+               /* NOTFOUND affects the most recent entry */
+               tq_last(&snl)->ret_notfound = TRUE;
+               got_match = FALSE;
+           } else
+               got_match = FALSE;
+       }
+       /* Only parse the first "sudoers:" line */
+       break;
+    }
+    fclose(fp);
+
+nomatch:
+    /* Default to files only if no matches */
+    if (tq_empty(&snl))
+       tq_append(&snl, &sudo_nss_file);
+
+    return(&snl);
+}
+
+#else /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
+
+/*
+ * Non-nsswitch.conf version with hard-coded order.
+ */
+struct sudo_nss_list *
+sudo_read_nss()
+{
+    static struct sudo_nss_list snl;
+
+# ifdef HAVE_LDAP
+    tq_append(&snl, &sudo_nss_ldap);
+# endif
+    tq_append(&snl, &sudo_nss_file);
+
+    return(&snl);
+}
+
+#endif /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
+
+/* Reset user_groups based on passwd entry. */
+static void
+reset_groups(pw)
+    struct passwd *pw;
+{
+#if defined(HAVE_INITGROUPS) && defined(HAVE_GETGROUPS)
+    if (pw != sudo_user.pw) {
+       (void) initgroups(pw->pw_name, pw->pw_gid);
+       if ((user_ngroups = getgroups(0, NULL)) > 0) {
+           user_groups = erealloc3(user_groups, user_ngroups,
+               sizeof(GETGROUPS_T));
+           if (getgroups(user_ngroups, user_groups) < 0)
+               log_error(USE_ERRNO|MSG_ONLY, "can't get group vector");
+       } else {
+           user_ngroups = 0;
+           efree(user_groups);
+       }
+    }
+#endif
+}
+
+/*
+ * Print out privileges for the specified user.
+ * We only get here if the user is allowed to run something on this host.
+ */
+void
+display_privs(snl, pw)
+    struct sudo_nss_list *snl;
+    struct passwd *pw;
+{
+    struct sudo_nss *nss;
+    struct lbuf lbuf;
+    int count;
+
+    /* Reset group vector so group matching works correctly. */
+    reset_groups(pw);
+
+    lbuf_init(&lbuf, NULL, 4, 0);
+
+    /* Display defaults from all sources. */
+    count = 0;
+    tq_foreach_fwd(snl, nss)
+       count += nss->display_defaults(nss, pw, &lbuf);
+    if (count) {
+       printf("Matching Defaults entries for %s on this host:\n", pw->pw_name);
+       lbuf_print(&lbuf);
+       putchar('\n');
+    }
+
+    /* Display Runas and Cmnd-specific defaults from all sources. */
+    count = 0;
+    tq_foreach_fwd(snl, nss)
+       count += nss->display_bound_defaults(nss, pw, &lbuf);
+    if (count) {
+       printf("Runas and Command-specific defaults for %s:\n", pw->pw_name);
+       lbuf_print(&lbuf);
+       putchar('\n');
+    }
+
+    /* Display privileges from all sources. */
+    printf("User %s may run the following commands on this host:\n",
+       pw->pw_name);
+    tq_foreach_fwd(snl, nss)
+       (void) nss->display_privs(nss, pw, &lbuf);
+    if (lbuf.len != 0)
+       lbuf_print(&lbuf);              /* print remainder, if any */
+    lbuf_destroy(&lbuf);
+}
+
+/*
+ * Check user_cmnd against sudoers and print the matching entry if the
+ * command is allowed.
+ */
+int
+display_cmnd(snl, pw)
+    struct sudo_nss_list *snl;
+    struct passwd *pw;
+{
+    struct sudo_nss *nss;
+
+    /* Reset group vector so group matching works correctly. */
+    reset_groups(pw);
+
+    tq_foreach_fwd(snl, nss) {
+       if (nss->display_cmnd(nss, pw) == 0)
+           return(0);
+    }
+    return(1);
+}
diff --git a/sudo_nss.h b/sudo_nss.h
new file mode 100644 (file)
index 0000000..361510f
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Sudo: sudo_nss.h,v 1.5 2008/11/09 14:13:12 millert Exp $
+ */
+
+struct lbuf;
+struct passwd;
+
+struct sudo_nss {
+    struct sudo_nss *prev;
+    struct sudo_nss *next;
+    int (*open) __P((struct sudo_nss *nss));
+    int (*close) __P((struct sudo_nss *nss));
+    int (*parse) __P((struct sudo_nss *nss));
+    int (*setdefs) __P((struct sudo_nss *nss));
+    int (*lookup) __P((struct sudo_nss *nss, int, int));
+    int (*display_cmnd) __P((struct sudo_nss *nss, struct passwd *));
+    int (*display_defaults) __P((struct sudo_nss *nss, struct passwd *, struct lbuf *));
+    int (*display_bound_defaults) __P((struct sudo_nss *nss, struct passwd *, struct lbuf *));
+    int (*display_privs) __P((struct sudo_nss *nss, struct passwd *, struct lbuf *));
+    void *handle;
+    int ret_notfound;
+};
+
+TQ_DECLARE(sudo_nss)
+
+struct sudo_nss_list *sudo_read_nss    __P((void));
diff --git a/sudo_usage.h.in b/sudo_usage.h.in
new file mode 100644 (file)
index 0000000..5a1bfc6
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _SUDO_USAGE_H
+#define _SUDO_USAGE_H
+
+/*
+ * Usage strings for sudo.  These are here because we
+ * need to be able to substitute values from configure.
+ */
+#define SUDO_USAGE1 " [-n] -h | -K | -k | -L | -V | -v"
+#define SUDO_USAGE2 " -l[l] [-AnS] [-g groupname|#gid] [-U username] [-u username|#uid] [-g groupname|#gid] [command]"
+#define SUDO_USAGE3 " [-AbEHnPS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] [<command>]"
+#define SUDO_USAGE4 " -e [-AnS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u username|#uid] file ..."
+
+#endif /* _SUDO_USAGE_H */
index 379c6994f43e5bca9337939b41001f1e36d82c10..8c7876d3fd0d6fe3a9cdac791e2ec28bc4f634c2 100644 (file)
@@ -8,60 +8,60 @@ N\bNA\bAM\bME\bE
        sudoers - list of which users may execute what
 
 D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
-       The _\bs_\bu_\bd_\bo_\be_\br_\bs file is composed of two types of entries:
-       aliases (basically variables) and user specifications
-       (which specify who may run what).
+       The _\bs_\bu_\bd_\bo_\be_\br_\bs file is composed of two types of entries: aliases
+       (basically variables) and user specifications (which specify who may
+       run what).
 
-       When multiple entries match for a user, they are applied
-       in order.  Where there are multiple matches, the last
-       match is used (which is not necessarily the most specific
-       match).
+       When multiple entries match for a user, they are applied in order.
+       Where there are multiple matches, the last match is used (which is not
+       necessarily the most specific match).
 
-       The _\bs_\bu_\bd_\bo_\be_\br_\bs grammar will be described below in Extended
-       Backus-Naur Form (EBNF).  Don't despair if you don't know
-       what EBNF is; it is fairly simple, and the definitions
-       below are annotated.
+       The _\bs_\bu_\bd_\bo_\be_\br_\bs grammar will be described below in Extended Backus-Naur
+       Form (EBNF).  Don't despair if you don't know what EBNF is; it is
+       fairly simple, and the definitions below are annotated.
 
        Q\bQu\bui\bic\bck\bk g\bgu\bui\bid\bde\be t\bto\bo E\bEB\bBN\bNF\bF
 
-       EBNF is a concise and exact way of describing the grammar
-       of a language.  Each EBNF definition is made up of _\bp_\br_\bo_\bd_\bu_\bc_\b­
-       _\bt_\bi_\bo_\bn _\br_\bu_\bl_\be_\bs.  E.g.,
+       EBNF is a concise and exact way of describing the grammar of a
+       language.  Each EBNF definition is made up of _\bp_\br_\bo_\bd_\bu_\bc_\bt_\bi_\bo_\bn _\br_\bu_\bl_\be_\bs.  E.g.,
 
         symbol ::= definition | alternate1 | alternate2 ...
 
-       Each _\bp_\br_\bo_\bd_\bu_\bc_\bt_\bi_\bo_\bn _\br_\bu_\bl_\be references others and thus makes up a
-       grammar for the language.  EBNF also contains the follow­
-       ing operators, which many readers will recognize from reg­
-       ular expressions.  Do not, however, confuse them with
-       "wildcard" characters, which have different meanings.
+       Each _\bp_\br_\bo_\bd_\bu_\bc_\bt_\bi_\bo_\bn _\br_\bu_\bl_\be references others and thus makes up a grammar for
+       the language.  EBNF also contains the following operators, which many
+       readers will recognize from regular expressions.  Do not, however,
+       confuse them with "wildcard" characters, which have different meanings.
 
-       ?   Means that the preceding symbol (or group of symbols)
-           is optional.  That is, it may appear once or not at
-           all.
+       ?   Means that the preceding symbol (or group of symbols) is optional.
+           That is, it may appear once or not at all.
 
-       *   Means that the preceding symbol (or group of symbols)
-           may appear zero or more times.
+       *   Means that the preceding symbol (or group of symbols) may appear
+           zero or more times.
 
-       +   Means that the preceding symbol (or group of symbols)
-           may appear one or more times.
+       +   Means that the preceding symbol (or group of symbols) may appear
+           one or more times.
 
-       Parentheses may be used to group symbols together.  For
-       clarity, we will use single quotes ('') to designate what
-       is a verbatim character string (as opposed to a symbol
-       name).
+       Parentheses may be used to group symbols together.  For clarity, we
+       will use single quotes ('') to designate what is a verbatim character
+       string (as opposed to a symbol name).
 
        A\bAl\bli\bia\bas\bse\bes\bs
 
-       There are four kinds of aliases: User_Alias, Runas_Alias,
-       Host_Alias and Cmnd_Alias.
+       There are four kinds of aliases: User_Alias, Runas_Alias, Host_Alias
+       and Cmnd_Alias.
 
+        Alias ::= 'User_Alias'  User_Alias (':' User_Alias)* |
+                  'Runas_Alias' Runas_Alias (':' Runas_Alias)* |
+                  'Host_Alias'  Host_Alias (':' Host_Alias)* |
+                  'Cmnd_Alias'  Cmnd_Alias (':' Cmnd_Alias)*
 
+        User_Alias ::= NAME '=' User_List
 
+        Runas_Alias ::= NAME '=' Runas_List
 
 
 
-1.6.9p17                   Jun 21, 2008                         1
+1.7.0                   December  3, 2008                       1
 
 
 
@@ -70,14 +70,6 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-        Alias ::= 'User_Alias'  User_Alias (':' User_Alias)* |
-                  'Runas_Alias' Runas_Alias (':' Runas_Alias)* |
-                  'Host_Alias'  Host_Alias (':' Host_Alias)* |
-                  'Cmnd_Alias'  Cmnd_Alias (':' Cmnd_Alias)*
-
-        User_Alias ::= NAME '=' User_List
-
-        Runas_Alias ::= NAME '=' Runas_List
 
         Host_Alias ::= NAME '=' Host_List
 
@@ -89,64 +81,61 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
         Alias_Type NAME = item1, item2, ...
 
-       where _\bA_\bl_\bi_\ba_\bs_\b__\bT_\by_\bp_\be is one of User_Alias, Runas_Alias,
-       Host_Alias, or Cmnd_Alias.  A NAME is a string of upper­
-       case letters, numbers, and underscore characters ('_').  A
-       NAME m\bmu\bus\bst\bt start with an uppercase letter.  It is possible
-       to put several alias definitions of the same type on a
-       single line, joined by a colon (':').  E.g.,
+       where _\bA_\bl_\bi_\ba_\bs_\b__\bT_\by_\bp_\be is one of User_Alias, Runas_Alias, Host_Alias, or
+       Cmnd_Alias.  A NAME is a string of uppercase letters, numbers, and
+       underscore characters ('_').  A NAME m\bmu\bus\bst\bt start with an uppercase
+       letter.  It is possible to put several alias definitions of the same
+       type on a single line, joined by a colon (':').  E.g.,
 
         Alias_Type NAME = item1, item2, item3 : NAME = item4, item5
 
-       The definitions of what constitutes a valid _\ba_\bl_\bi_\ba_\bs member
-       follow.
+       The definitions of what constitutes a valid _\ba_\bl_\bi_\ba_\bs member follow.
 
         User_List ::= User |
                       User ',' User_List
 
         User ::= '!'* username |
+                 '!'* '#'uid |
                  '!'* '%'group |
                  '!'* '+'netgroup |
                  '!'* User_Alias
 
-       A User_List is made up of one or more usernames, system
-       groups (prefixed with '%'), netgroups (prefixed with '+')
-       and other aliases.  Each list item may be prefixed with
-       one or more '!' operators.  An odd number of '!' operators
-       negate the value of the item; an even number just cancel
-       each other out.
+       A User_List is made up of one or more usernames, uids (prefixed with
+       '#'), system groups (prefixed with '%'), netgroups (prefixed with '+')
+       and User_Aliases.  Each list item may be prefixed with zero or more '!'
+       operators.  An odd number of '!' operators negate the value of the
+       item; an even number just cancel each other out.
 
-        Runas_List ::= Runas_User |
-                       Runas_User ',' Runas_List
+        Runas_List ::= Runas_Member |
+                       Runas_Member ',' Runas_List
 
-        Runas_User ::= '!'* username |
-                       '!'* '#'uid |
-                       '!'* '%'group |
-                       '!'* +netgroup |
-                       '!'* Runas_Alias
+        Runas_Member ::= '!'* username |
+                         '!'* '#'uid |
+                         '!'* '%'group |
+                         '!'* +netgroup |
+                         '!'* Runas_Alias
 
+       A Runas_List is similar to a User_List except that instead of
+       User_Aliases it can contain Runas_Aliases.  Note that usernames and
+       groups are matched as strings.  In other words, two users (groups) with
+       the same uid (gid) are considered to be distinct.  If you wish to match
+       all usernames with the same uid (e.g. root and toor), you can use a uid
+       instead (#0 in the example given).
 
+        Host_List ::= Host |
+                      Host ',' Host_List
 
-1.6.9p17                   Jun 21, 2008                         2
 
 
+1.7.0                   December  3, 2008                       2
 
 
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-       A Runas_List is similar to a User_List except that it can
-       also contain uids (prefixed with '#') and instead of
-       User_Aliases it can contain Runas_Aliases.  Note that
-       usernames and groups are matched as strings.  In other
-       words, two users (groups) with the same uid (gid) are con­
-       sidered to be distinct.  If you wish to match all user­
-       names with the same uid (e.g. root and toor), you can use
-       a uid instead (#0 in the example given).
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
+
 
-        Host_List ::= Host |
-                      Host ',' Host_List
 
         Host ::= '!'* hostname |
                  '!'* ip_addr |
@@ -154,21 +143,18 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                  '!'* '+'netgroup |
                  '!'* Host_Alias
 
-       A Host_List is made up of one or more hostnames, IP
-       addresses, network numbers, netgroups (prefixed with '+')
-       and other aliases.  Again, the value of an item may be
-       negated with the '!' operator.  If you do not specify a
-       netmask along with the network number, s\bsu\bud\bdo\bo will query
-       each of the local host's network interfaces and, if the
-       network number corresponds to one of the hosts's network
-       interfaces, the corresponding netmask will be used.  The
-       netmask may be specified either in standard IP address
-       notation (e.g. 255.255.255.0 or ffff:ffff:ffff:ffff::), or
-       CIDR notation (number of bits, e.g. 24 or 64).  A hostname
-       may include shell-style wildcards (see the Wildcards sec­
-       tion below), but unless the hostname command on your
-       machine returns the fully qualified hostname, you'll need
-       to use the _\bf_\bq_\bd_\bn option for wildcards to be useful.
+       A Host_List is made up of one or more hostnames, IP addresses, network
+       numbers, netgroups (prefixed with '+') and other aliases.  Again, the
+       value of an item may be negated with the '!' operator.  If you do not
+       specify a netmask along with the network number, s\bsu\bud\bdo\bo will query each
+       of the local host's network interfaces and, if the network number
+       corresponds to one of the hosts's network interfaces, the corresponding
+       netmask will be used.  The netmask may be specified either in standard
+       IP address notation (e.g. 255.255.255.0 or ffff:ffff:ffff:ffff::), or
+       CIDR notation (number of bits, e.g. 24 or 64).  A hostname may include
+       shell-style wildcards (see the Wildcards section below), but unless the
+       hostname command on your machine returns the fully qualified hostname,
+       you'll need to use the _\bf_\bq_\bd_\bn option for wildcards to be useful.
 
         Cmnd_List ::= Cmnd |
                       Cmnd ',' Cmnd_List
@@ -182,53 +168,54 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                  '!'* "sudoedit" |
                  '!'* Cmnd_Alias
 
-       A Cmnd_List is a list of one or more commandnames, direc­
-       tories, and other aliases.  A commandname is a fully qual­
-       ified filename which may include shell-style wildcards
-       (see the Wildcards section below).  A simple filename
-       allows the user to run the command with any arguments
-       he/she wishes.  However, you may also specify command line
-       arguments (including wildcards).  Alternately, you can
-       specify "" to indicate that the command may only be run
+       A Cmnd_List is a list of one or more commandnames, directories, and
+       other aliases.  A commandname is a fully qualified filename which may
+       include shell-style wildcards (see the Wildcards section below).  A
+       simple filename allows the user to run the command with any arguments
+       he/she wishes.  However, you may also specify command line arguments
+       (including wildcards).  Alternately, you can specify "" to indicate
+       that the command may only be run w\bwi\bit\bth\bho\bou\but\bt command line arguments.  A
+       directory is a fully qualified pathname ending in a '/'.  When you
+       specify a directory in a Cmnd_List, the user will be able to run any
+       file within that directory (but not in any subdirectories therein).
 
+       If a Cmnd has associated command line arguments, then the arguments in
+       the Cmnd must match exactly those given by the user on the command line
+       (or match the wildcards if there are any).  Note that the following
+       characters must be escaped with a '\' if they are used in command
+       arguments: ',', ':', '=', '\'.  The special command "sudoedit" is used
+       to permit a user to run s\bsu\bud\bdo\bo with the -\b-e\be option (or as s\bsu\bud\bdo\boe\bed\bdi\bit\bt).  It
+       may take command line arguments just as a normal command does.
 
 
-1.6.9p17                   Jun 21, 2008                         3
 
 
 
 
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
+1.7.0                   December  3, 2008                       3
+
 
 
-       w\bwi\bit\bth\bho\bou\but\bt command line arguments.  A directory is a fully
-       qualified pathname ending in a '/'.  When you specify a
-       directory in a Cmnd_List, the user will be able to run any
-       file within that directory (but not in any subdirectories
-       therein).
 
-       If a Cmnd has associated command line arguments, then the
-       arguments in the Cmnd must match exactly those given by
-       the user on the command line (or match the wildcards if
-       there are any).  Note that the following characters must
-       be escaped with a '\' if they are used in command argu­
-       ments: ',', ':', '=', '\'.  The special command "sudoedit"
-       is used to permit a user to run s\bsu\bud\bdo\bo with the -\b-e\be flag (or
-       as s\bsu\bud\bdo\boe\bed\bdi\bit\bt).  It may take command line arguments just as
-       a normal command does.
+
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
+
 
        D\bDe\bef\bfa\bau\bul\blt\bts\bs
 
-       Certain configuration options may be changed from their
-       default values at runtime via one or more Default_Entry
-       lines.  These may affect all users on any host, all users
-       on a specific host, a specific user, or commands being run
-       as a specific user.
+       Certain configuration options may be changed from their default values
+       at runtime via one or more Default_Entry lines.  These may affect all
+       users on any host, all users on a specific host, a specific user, a
+       specific command, or commands being run as a specific user.  Note that
+       per-command entries may not include command line arguments.  If you
+       need to specify arguments, define a Cmnd_Alias and reference that
+       instead.
 
         Default_Type ::= 'Defaults' |
                          'Defaults' '@' Host_List |
                          'Defaults' ':' User_List |
+                         'Defaults' '!' Cmnd_List |
                          'Defaults' '>' Runas_List
 
         Default_Entry ::= Default_Type Parameter_List
@@ -241,91 +228,104 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                       Parameter '-=' Value |
                       '!'* Parameter
 
-       Parameters may be f\bfl\bla\bag\bgs\bs, i\bin\bnt\bte\beg\bge\ber\br values, s\bst\btr\bri\bin\bng\bgs\bs, or
-       l\bli\bis\bst\bts\bs.  Flags are implicitly boolean and can be turned off
-       via the '!'  operator.  Some integer, string and list
-       parameters may also be used in a boolean context to dis­
-       able them.  Values may be enclosed in double quotes (")
-       when they contain multiple words.  Special characters may
-       be escaped with a backslash (\).
+       Parameters may be f\bfl\bla\bag\bgs\bs, i\bin\bnt\bte\beg\bge\ber\br values, s\bst\btr\bri\bin\bng\bgs\bs, or l\bli\bis\bst\bts\bs.  Flags are
+       implicitly boolean and can be turned off via the '!'  operator.  Some
+       integer, string and list parameters may also be used in a boolean
+       context to disable them.  Values may be enclosed in double quotes (")
+       when they contain multiple words.  Special characters may be escaped
+       with a backslash (\).
 
-       Lists have two additional assignment operators, += and -=.
-       These operators are used to add to and delete from a list
-       respectively.  It is not an error to use the -= operator
-       to remove an element that does not exist in a list.
+       Lists have two additional assignment operators, += and -=.  These
+       operators are used to add to and delete from a list respectively.  It
+       is not an error to use the -= operator to remove an element that does
+       not exist in a list.
 
-       See "SUDOERS OPTIONS" for a list of supported Defaults
-       parameters.
+       Defaults entries are parsed in the following order: generic, host and
+       user Defaults first, then runas Defaults and finally command defaults.
 
+       See "SUDOERS OPTIONS" for a list of supported Defaults parameters.
 
+       U\bUs\bse\ber\br S\bSp\bpe\bec\bci\bif\bfi\bic\bca\bat\bti\bio\bon\bn
 
-1.6.9p17                   Jun 21, 2008                         4
+        User_Spec ::= User_List Host_List '=' Cmnd_Spec_List \
+                      (':' Host_List '=' Cmnd_Spec_List)*
 
+        Cmnd_Spec_List ::= Cmnd_Spec |
+                           Cmnd_Spec ',' Cmnd_Spec_List
 
+        Cmnd_Spec ::= Runas_Spec? Tag_Spec* Cmnd
 
+        Runas_Spec ::= '(' Runas_List? (: Runas_List)? ')'
 
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
+1.7.0                   December  3, 2008                       4
 
-       U\bUs\bse\ber\br S\bSp\bpe\bec\bci\bif\bfi\bic\bca\bat\bti\bio\bon\bn
 
-        User_Spec ::= User_List Host_List '=' Cmnd_Spec_List \
-                      (':' Host_List '=' Cmnd_Spec_List)*
 
-        Cmnd_Spec_List ::= Cmnd_Spec |
-                           Cmnd_Spec ',' Cmnd_Spec_List
 
-        Cmnd_Spec ::= Runas_Spec? Tag_Spec* Cmnd
 
-        Runas_Spec ::= '(' Runas_List ')'
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
+
+
 
         Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' |
-                      'SETENV:' | 'NOSETENV:')
+                      'SETENV:' | 'NOSETENV:' )
 
-       A u\bus\bse\ber\br s\bsp\bpe\bec\bci\bif\bfi\bic\bca\bat\bti\bio\bon\bn determines which commands a user may
-       run (and as what user) on specified hosts.  By default,
-       commands are run as r\bro\boo\bot\bt, but this can be changed on a
-       per-command basis.
+       A u\bus\bse\ber\br s\bsp\bpe\bec\bci\bif\bfi\bic\bca\bat\bti\bio\bon\bn determines which commands a user may run (and as
+       what user) on specified hosts.  By default, commands are run as r\bro\boo\bot\bt,
+       but this can be changed on a per-command basis.
 
        Let's break that down into its constituent parts:
 
        R\bRu\bun\bna\bas\bs_\b_S\bSp\bpe\bec\bc
 
-       A Runas_Spec is simply a Runas_List (as defined above)
-       enclosed in a set of parentheses.  If you do not specify a
-       Runas_Spec in the user specification, a default Runas_Spec
-       of r\bro\boo\bot\bt will be used.  A Runas_Spec sets the default for
-       commands that follow it.  What this means is that for the
-       entry:
+       A Runas_Spec determines the user and/or the group that a command may be
+       run as.  A fully-specified Runas_Spec consists of two Runas_Lists (as
+       defined above) separated by a colon (':') and enclosed in a set of
+       parentheses.  The first Runas_List indicates which users the command
+       may be run as via s\bsu\bud\bdo\bo's -\b-u\bu option.  The second defines a list of
+       groups that can be specified via s\bsu\bud\bdo\bo's -\b-g\bg option.  If both Runas_Lists
+       are specified, the command may be run with any combination of users and
+       groups listed in their respective Runas_Lists.  If only the first is
+       specified, the command may be run as any user in the list but no -\b-g\bg
+       option may be specified.  If the first Runas_List is empty but the
+       second is specified, the command may be run as the invoking user with
+       the group set to any listed in the Runas_List.  If no Runas_Spec is
+       specified the command may be run as r\bro\boo\bot\bt and no group may be specified.
+
+       A Runas_Spec sets the default for the commands that follow it.  What
+       this means is that for the entry:
 
         dgb    boulder = (operator) /bin/ls, /bin/kill, /usr/bin/lprm
 
-       The user d\bdg\bgb\bb may run _\b/_\bb_\bi_\bn_\b/_\bl_\bs, _\b/_\bb_\bi_\bn_\b/_\bk_\bi_\bl_\bl, and _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bl_\bp_\br_\bm
-       -- but only as o\bop\bpe\ber\bra\bat\bto\bor\br.  E.g.,
+       The user d\bdg\bgb\bb may run _\b/_\bb_\bi_\bn_\b/_\bl_\bs, _\b/_\bb_\bi_\bn_\b/_\bk_\bi_\bl_\bl, and _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bl_\bp_\br_\bm -- but only
+       as o\bop\bpe\ber\bra\bat\bto\bor\br.  E.g.,
 
         $ sudo -u operator /bin/ls.
 
-       It is also possible to override a Runas_Spec later on in
-       an entry.  If we modify the entry like so:
+       It is also possible to override a Runas_Spec later on in an entry.  If
+       we modify the entry like so:
 
         dgb    boulder = (operator) /bin/ls, (root) /bin/kill, /usr/bin/lprm
 
-       Then user d\bdg\bgb\bb is now allowed to run _\b/_\bb_\bi_\bn_\b/_\bl_\bs as o\bop\bpe\ber\bra\bat\bto\bor\br,
-       but  _\b/_\bb_\bi_\bn_\b/_\bk_\bi_\bl_\band _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bl_\bp_\br_\bm as r\bro\boo\bot\bt.
+       Then user d\bdg\bgb\bb is now allowed to run _\b/_\bb_\bi_\bn_\b/_\bl_\bs as o\bop\bpe\ber\bra\bat\bto\bor\br, but  _\b/_\bb_\bi_\bn_\b/_\bk_\bi_\bl_\bl
+       and _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bl_\bp_\br_\bm as r\bro\boo\bot\bt.
 
-       T\bTa\bag\bg_\b_S\bSp\bpe\bec\bc
+       We can extend this to allow d\bdg\bgb\bb to run /bin/ls with either the user or
+       group set to o\bop\bpe\ber\bra\bat\bto\bor\br:
+
+        dgb    boulder = (operator : operator) /bin/ls, (root) /bin/kill, \
+               /usr/bin/lprm
+
+       In the following example, user t\btc\bcm\bm may run commands that access a modem
+       device file with the dialer group.  Note that in this example only the
+       group will be set, the command still runs as user t\btc\bcm\bm.
 
-       A command may have zero or more tags associated with it.
-       There are six possible tag values, NOPASSWD, PASSWD,
-       NOEXEC, EXEC, SETENV and NOSETENV.  Once a tag is set on a
-       Cmnd, subsequent Cmnds in the Cmnd_Spec_List, inherit the
-       tag unless it is overridden by the opposite tag (i.e.:
-       PASSWD overrides NOPASSWD and NOEXEC overrides EXEC).
 
 
 
-1.6.9p17                   Jun 21, 2008                         5
+1.7.0                   December  3, 2008                       5
 
 
 
@@ -334,64 +334,64 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
+        tcm    boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \
+               /usr/local/bin/minicom
+
+       T\bTa\bag\bg_\b_S\bSp\bpe\bec\bc
+
+       A command may have zero or more tags associated with it.  There are
+       eight possible tag values, NOPASSWD, PASSWD, NOEXEC, EXEC, SETENV and
+       NOSETENV.  Once a tag is set on a Cmnd, subsequent Cmnds in the
+       Cmnd_Spec_List, inherit the tag unless it is overridden by the opposite
+       tag (i.e.: PASSWD overrides NOPASSWD and NOEXEC overrides EXEC).
+
        _\bN_\bO_\bP_\bA_\bS_\bS_\bW_\bD _\ba_\bn_\bd _\bP_\bA_\bS_\bS_\bW_\bD
 
-       By default, s\bsu\bud\bdo\bo requires that a user authenticate him or
-       herself before running a command.  This behavior can be
-       modified via the NOPASSWD tag.  Like a Runas_Spec, the
-       NOPASSWD tag sets a default for the commands that follow
-       it in the Cmnd_Spec_List.  Conversely, the PASSWD tag can
-       be used to reverse things.  For example:
+       By default, s\bsu\bud\bdo\bo requires that a user authenticate him or herself
+       before running a command.  This behavior can be modified via the
+       NOPASSWD tag.  Like a Runas_Spec, the NOPASSWD tag sets a default for
+       the commands that follow it in the Cmnd_Spec_List.  Conversely, the
+       PASSWD tag can be used to reverse things.  For example:
 
         ray    rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm
 
-       would allow the user r\bra\bay\by to run _\b/_\bb_\bi_\bn_\b/_\bk_\bi_\bl_\bl, _\b/_\bb_\bi_\bn_\b/_\bl_\bs, and
-       _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bl_\bp_\br_\bm as root on the machine rushmore as r\bro\boo\bot\bt
-       without authenticating himself.  If we only want r\bra\bay\by to be
-       able to run _\b/_\bb_\bi_\bn_\b/_\bk_\bi_\bl_\bl without a password the entry would
-       be:
+       would allow the user r\bra\bay\by to run _\b/_\bb_\bi_\bn_\b/_\bk_\bi_\bl_\bl, _\b/_\bb_\bi_\bn_\b/_\bl_\bs, and _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bl_\bp_\br_\bm
+       as r\bro\boo\bot\bt on the machine rushmore without authenticating himself.  If we
+       only want r\bra\bay\by to be able to run _\b/_\bb_\bi_\bn_\b/_\bk_\bi_\bl_\bl without a password the entry
+       would be:
 
         ray    rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm
 
-       Note, however, that the PASSWD tag has no effect on users
-       who are in the group specified by the _\be_\bx_\be_\bm_\bp_\bt_\b__\bg_\br_\bo_\bu_\bp option.
+       Note, however, that the PASSWD tag has no effect on users who are in
+       the group specified by the _\be_\bx_\be_\bm_\bp_\bt_\b__\bg_\br_\bo_\bu_\bp option.
 
-       By default, if the NOPASSWD tag is applied to any of the
-       entries for a user on the current host, he or she will be
-       able to run sudo -l without a password.  Additionally, a
-       user may only run sudo -v without a password if the
-       NOPASSWD tag is present for all a user's entries that per­
-       tain to the current host.  This behavior may be overridden
-       via the verifypw and listpw options.
+       By default, if the NOPASSWD tag is applied to any of the entries for a
+       user on the current host, he or she will be able to run sudo -l without
+       a password.  Additionally, a user may only run sudo -v without a
+       password if the NOPASSWD tag is present for all a user's entries that
+       pertain to the current host.  This behavior may be overridden via the
+       verifypw and listpw options.
 
        _\bN_\bO_\bE_\bX_\bE_\bC _\ba_\bn_\bd _\bE_\bX_\bE_\bC
 
-       If s\bsu\bud\bdo\bo has been compiled with _\bn_\bo_\be_\bx_\be_\bc support and the
-       underlying operating system supports it, the NOEXEC tag
-       can be used to prevent a dynamically-linked executable
-       from running further commands itself.
+       If s\bsu\bud\bdo\bo has been compiled with _\bn_\bo_\be_\bx_\be_\bc support and the underlying
+       operating system supports it, the NOEXEC tag can be used to prevent a
+       dynamically-linked executable from running further commands itself.
 
-       In the following example, user a\baa\bar\bro\bon\bn may run _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bm_\bo_\br_\be
-       and _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bv_\bi but shell escapes will be disabled.
+       In the following example, user a\baa\bar\bro\bon\bn may run _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bm_\bo_\br_\be and
+       _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bv_\bi but shell escapes will be disabled.
 
         aaron  shanty = NOEXEC: /usr/bin/more, /usr/bin/vi
 
-       See the "PREVENTING SHELL ESCAPES" section below for more
-       details on how NOEXEC works and whether or not it will
-       work on your system.
+       See the "PREVENTING SHELL ESCAPES" section below for more details on
+       how NOEXEC works and whether or not it will work on your system.
 
        _\bS_\bE_\bT_\bE_\bN_\bV _\ba_\bn_\bd _\bN_\bO_\bS_\bE_\bT_\bE_\bN_\bV
 
-       These tags override the value of the _\bs_\be_\bt_\be_\bn_\bv option on a
-       per-command basis.  Note that if SETENV has been set for a
-       command, any environment variables set on the command line
-       way are not subject to the restrictions imposed by
-       _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk, _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be, or _\be_\bn_\bv_\b__\bk_\be_\be_\bp.  As such, only trusted
-       users should be allowed to set variables in this manner.
 
 
 
-1.6.9p17                   Jun 21, 2008                         6
+1.7.0                   December  3, 2008                       6
 
 
 
@@ -400,17 +400,20 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-       If the command matched is A\bAL\bLL\bL, the SETENV tag is implied
-       for that command; this default may be overridden by use of
-       the UNSETENV tag.
+       These tags override the value of the _\bs_\be_\bt_\be_\bn_\bv option on a per-command
+       basis.  Note that if SETENV has been set for a command, any environment
+       variables set on the command line way are not subject to the
+       restrictions imposed by _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk, _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be, or _\be_\bn_\bv_\b__\bk_\be_\be_\bp.  As such,
+       only trusted users should be allowed to set variables in this manner.
+       If the command matched is A\bAL\bLL\bL, the SETENV tag is implied for that
+       command; this default may be overridden by use of the UNSETENV tag.
 
        W\bWi\bil\bld\bdc\bca\bar\brd\bds\bs
 
-       s\bsu\bud\bdo\bo allows shell-style _\bw_\bi_\bl_\bd_\bc_\ba_\br_\bd_\bs (aka meta or glob char­
-       acters) to be used in pathnames as well as command line
-       arguments in the _\bs_\bu_\bd_\bo_\be_\br_\bs file.  Wildcard matching is done
-       via the P\bPO\bOS\bSI\bIX\bX _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3) routine.  Note that these are _\bn_\bo_\bt
-       regular expressions.
+       s\bsu\bud\bdo\bo allows shell-style _\bw_\bi_\bl_\bd_\bc_\ba_\br_\bd_\bs (aka meta or glob characters) to be
+       used in hostnames, pathnames and command line arguments in the _\bs_\bu_\bd_\bo_\be_\br_\bs
+       file.  Wildcard matching is done via the P\bPO\bOS\bSI\bIX\bX _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3) routine.
+       Note that these are _\bn_\bo_\bt regular expressions.
 
        *       Matches any set of zero or more characters.
 
@@ -420,14 +423,20 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
        [!...]  Matches any character n\bno\bot\bt in the specified range.
 
-       \x      For any character "x", evaluates to "x".  This is
-               used to escape special characters such as: "*",
-               "?", "[", and "}".
+       \x      For any character "x", evaluates to "x".  This is used to
+               escape special characters such as: "*", "?", "[", and "}".
+
+       POSIX character classes may also be used if your system's _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3)
+       function supports them.  However, because the ':' character has special
+       meaning in _\bs_\bu_\bd_\bo_\be_\br_\bs, it must be escaped.  For example:
+
+           /bin/ls [[\:alpha\:]]*
 
-       Note that a forward slash ('/') will n\bno\bot\bt be matched by
-       wildcards used in the pathname.  When matching the command
-       line arguments, however, a slash d\bdo\boe\bes\bs get matched by wild­
-       cards.  This is to make a path like:
+       Would match any filename beginning with a letter.
+
+       Note that a forward slash ('/') will n\bno\bot\bt be matched by wildcards used
+       in the pathname.  When matching the command line arguments, however, a
+       slash d\bdo\boe\bes\bs get matched by wildcards.  This is to make a path like:
 
            /usr/bin/*
 
@@ -437,27 +446,18 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
        The following exceptions apply to the above rules:
 
-       ""      If the empty string "" is the only command line
-               argument in the _\bs_\bu_\bd_\bo_\be_\br_\bs entry it means that com­
-               mand is not allowed to be run with a\ban\bny\by arguments.
-
-       O\bOt\bth\bhe\ber\br s\bsp\bpe\bec\bci\bia\bal\bl c\bch\bha\bar\bra\bac\bct\bte\ber\brs\bs a\ban\bnd\bd r\bre\bes\bse\ber\brv\bve\bed\bd w\bwo\bor\brd\bds\bs
+       ""      If the empty string "" is the only command line argument in the
+               _\bs_\bu_\bd_\bo_\be_\br_\bs entry it means that command is not allowed to be run
+               with a\ban\bny\by arguments.
 
-       The pound sign ('#') is used to indicate a comment (unless
-       it is part of a #include directive or unless it occurs in
-       the context of a user name and is followed by one or more
-       digits, in which case it is treated as a uid).  Both the
-       comment character and any text after it, up to the end of
-       the line, are ignored.
+       I\bIn\bnc\bcl\blu\bud\bdi\bin\bng\bg o\bot\bth\bhe\ber\br f\bfi\bil\ble\bes\bs f\bfr\bro\bom\bm w\bwi\bit\bth\bhi\bin\bn s\bsu\bud\bdo\boe\ber\brs\bs
 
-       The reserved word A\bAL\bLL\bL is a built-in _\ba_\bl_\bi_\ba_\bs that always
-       causes a match to succeed.  It can be used wherever one
-       might otherwise use a Cmnd_Alias, User_Alias, Runas_Alias,
-       or Host_Alias.  You should not try to define your own
+       It is possible to include other _\bs_\bu_\bd_\bo_\be_\br_\bs files from within the _\bs_\bu_\bd_\bo_\be_\br_\bs
+       file currently being parsed using the #include directive, similar to
 
 
 
-1.6.9p17                   Jun 21, 2008                         7
+1.7.0                   December  3, 2008                       7
 
 
 
@@ -466,64 +466,64 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-       _\ba_\bl_\bi_\ba_\bs called A\bAL\bLL\bL as the built-in alias will be used in
-       preference to your own.  Please note that using A\bAL\bLL\bL can be
-       dangerous since in a command context, it allows the user
-       to run a\ban\bny\by command on the system.
+       the one used by the C preprocessor.  This is useful, for example, for
+       keeping a site-wide _\bs_\bu_\bd_\bo_\be_\br_\bs file in addition to a per-machine local
+       one.  For the sake of this example the site-wide _\bs_\bu_\bd_\bo_\be_\br_\bs will be
+       _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs and the per-machine one will be _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bl_\bo_\bc_\ba_\bl.  To
+       include _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bl_\bo_\bc_\ba_\bl from _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs we would use the following
+       line in _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs:
 
-       An exclamation point ('!') can be used as a logical _\bn_\bo_\bt
-       operator both in an _\ba_\bl_\bi_\ba_\bs and in front of a Cmnd.  This
-       allows one to exclude certain values.  Note, however, that
-       using a ! in conjunction with the built-in ALL alias to
-       allow a user to run "all but a few" commands rarely works
-       as intended (see SECURITY NOTES below).
+        #include /etc/sudoers.local
 
-       Long lines can be continued with a backslash ('\') as the
-       last character on the line.
+       When s\bsu\bud\bdo\bo reaches this line it will suspend processing of the current
+       file (_\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs) and switch to _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bl_\bo_\bc_\ba_\bl.  Upon reaching
+       the end of _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bl_\bo_\bc_\ba_\bl, the rest of _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs will be
+       processed.  Files that are included may themselves include other files.
+       A hard limit of 128 nested include files is enforced to prevent include
+       file loops.
 
-       Whitespace between elements in a list as well as special
-       syntactic characters in a _\bU_\bs_\be_\br _\bS_\bp_\be_\bc_\bi_\bf_\bi_\bc_\ba_\bt_\bi_\bo_\bn ('=', ':',
-       '(', ')') is optional.
+       O\bOt\bth\bhe\ber\br s\bsp\bpe\bec\bci\bia\bal\bl c\bch\bha\bar\bra\bac\bct\bte\ber\brs\bs a\ban\bnd\bd r\bre\bes\bse\ber\brv\bve\bed\bd w\bwo\bor\brd\bds\bs
 
-       The following characters must be escaped with a backslash
-       ('\') when used as part of a word (e.g. a username or
-       hostname): '@', '!', '=', ':', ',', '(', ')', '\'.
+       The pound sign ('#') is used to indicate a comment (unless it is part
+       of a #include directive or unless it occurs in the context of a user
+       name and is followed by one or more digits, in which case it is treated
+       as a uid).  Both the comment character and any text after it, up to the
+       end of the line, are ignored.
+
+       The reserved word A\bAL\bLL\bL is a built-in _\ba_\bl_\bi_\ba_\bs that always causes a match to
+       succeed.  It can be used wherever one might otherwise use a Cmnd_Alias,
+       User_Alias, Runas_Alias, or Host_Alias.  You should not try to define
+       your own _\ba_\bl_\bi_\ba_\bs called A\bAL\bLL\bL as the built-in alias will be used in
+       preference to your own.  Please note that using A\bAL\bLL\bL can be dangerous
+       since in a command context, it allows the user to run a\ban\bny\by command on
+       the system.
+
+       An exclamation point ('!') can be used as a logical _\bn_\bo_\bt operator both
+       in an _\ba_\bl_\bi_\ba_\bs and in front of a Cmnd.  This allows one to exclude certain
+       values.  Note, however, that using a ! in conjunction with the built-in
+       ALL alias to allow a user to run "all but a few" commands rarely works
+       as intended (see SECURITY NOTES below).
 
-S\bSU\bUD\bDO\bOE\bER\bRS\bS O\bOP\bPT\bTI\bIO\bON\bNS\bS
-       s\bsu\bud\bdo\bo's behavior can be modified by Default_Entry lines, as
-       explained earlier.  A list of all supported Defaults
-       parameters, grouped by type, are listed below.
+       Long lines can be continued with a backslash ('\') as the last
+       character on the line.
 
-       F\bFl\bla\bag\bgs\bs:
+       Whitespace between elements in a list as well as special syntactic
+       characters in a _\bU_\bs_\be_\br _\bS_\bp_\be_\bc_\bi_\bf_\bi_\bc_\ba_\bt_\bi_\bo_\bn ('=', ':', '(', ')') is optional.
 
-       always_set_home If set, s\bsu\bud\bdo\bo will set the HOME environment
-                       variable to the home directory of the tar­
-                       get user (which is root unless the -\b-u\bu
-                       option is used).  This effectively means
-                       that the -\b-H\bH flag is always implied.  This
-                       flag is _\bo_\bf_\bf by default.
+       The following characters must be escaped with a backslash ('\') when
+       used as part of a word (e.g. a username or hostname): '@', '!', '=',
+       ':', ',', '(', ')', '\'.
 
-       authenticate    If set, users must authenticate themselves
-                       via a password (or other means of authen­
-                       tication) before they may run commands.
-                       This default may be overridden via the
-                       PASSWD and NOPASSWD tags.  This flag is _\bo_\bn
-                       by default.
+S\bSU\bUD\bDO\bOE\bER\bRS\bS O\bOP\bPT\bTI\bIO\bON\bNS\bS
+       s\bsu\bud\bdo\bo's behavior can be modified by Default_Entry lines, as explained
+       earlier.  A list of all supported Defaults parameters, grouped by type,
+       are listed below.
 
-       env_editor      If set, v\bvi\bis\bsu\bud\bdo\bo will use the value of the
-                       EDITOR or VISUAL environment variables
-                       before falling back on the default editor
-                       list.  Note that this may create a secu­
-                       rity hole as it allows the user to run any
-                       arbitrary command as root without logging.
-                       A safer alternative is to place a colon-
-                       separated list of editors in the editor
-                       variable.  v\bvi\bis\bsu\bud\bdo\bo will then only use the
-                       EDITOR or VISUAL if they match a value
+       F\bFl\bla\bag\bgs\bs:
 
 
 
-1.6.9p17                   Jun 21, 2008                         8
+1.7.0                   December  3, 2008                       8
 
 
 
@@ -532,64 +532,64 @@ S\bSU\bUD\bDO\bOE\bER\bRS\bS O\bOP\bPT\bTI\bIO\bON\bNS\bS
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-                       specified in editor.  This flag is _\bo_\bf_\bf by
-                       default.
+       always_set_home If set, s\bsu\bud\bdo\bo will set the HOME environment variable to
+                       the home directory of the target user (which is root
+                       unless the -\b-u\bu option is used).  This effectively means
+                       that the -\b-H\bH option is always implied.  This flag is _\bo_\bf_\bf
+                       by default.
 
-       env_reset       If set, s\bsu\bud\bdo\bo will reset the environment to
-                       only contain the LOGNAME, SHELL, USER,
-                       USERNAME and the SUDO_* variables.  Any
-                       variables in the caller's environment that
-                       match the env_keep and env_check lists are
-                       then added.  The default contents of the
-                       env_keep and env_check lists are displayed
-                       when s\bsu\bud\bdo\bo is run by root with the _\b-_\bV
-                       option.  If s\bsu\bud\bdo\bo was compiled with the
-                       SECURE_PATH option, its value will be used
-                       for the PATH environment variable.  This
-                       flag is _\bo_\bn by default.
+       authenticate    If set, users must authenticate themselves via a
+                       password (or other means of authentication) before they
+                       may run commands.  This default may be overridden via
+                       the PASSWD and NOPASSWD tags.  This flag is _\bo_\bn by
+                       default.
 
-       fqdn            Set this flag if you want to put fully
-                       qualified hostnames in the _\bs_\bu_\bd_\bo_\be_\br_\bs file.
-                       I.e., instead of myhost you would use
-                       myhost.mydomain.edu.  You may still use
-                       the short form if you wish (and even mix
-                       the two).  Beware that turning on _\bf_\bq_\bd_\bn
-                       requires s\bsu\bud\bdo\bo to make DNS lookups which
-                       may make s\bsu\bud\bdo\bo unusable if DNS stops work­
-                       ing (for example if the machine is not
-                       plugged into the network).  Also note that
-                       you must use the host's official name as
-                       DNS knows it.  That is, you may not use a
-                       host alias (CNAME entry) due to perfor­
-                       mance issues and the fact that there is no
-                       way to get all aliases from DNS.  If your
-                       machine's hostname (as returned by the
-                       hostname command) is already fully quali­
-                       fied you shouldn't need to set _\bf_\bq_\bd_\bn.  This
-                       flag is _\bo_\bf_\bf by default.
+       closefrom_override
+                       If set, the user may use s\bsu\bud\bdo\bo's -\b-C\bC option which
+                       overrides the default starting point at which s\bsu\bud\bdo\bo
+                       begins closing open file descriptors.  This flag is _\bo_\bf_\bf
+                       by default.
 
-       ignore_dot      If set, s\bsu\bud\bdo\bo will ignore '.' or '' (cur­
-                       rent dir) in the PATH environment vari­
-                       able; the PATH itself is not modified.
-                       This flag is _\bo_\bf_\bf by default.  Currently,
-                       while it is possible to set _\bi_\bg_\bn_\bo_\br_\be_\b__\bd_\bo_\bt in
-                       _\bs_\bu_\bd_\bo_\be_\br_\bs, its value is not used.  This
-                       option should be considered read-only (it
-                       will be fixed in a future version of
-                       s\bsu\bud\bdo\bo).
+       env_editor      If set, v\bvi\bis\bsu\bud\bdo\bo will use the value of the EDITOR or
+                       VISUAL environment variables before falling back on the
+                       default editor list.  Note that this may create a
+                       security hole as it allows the user to run any
+                       arbitrary command as root without logging.  A safer
+                       alternative is to place a colon-separated list of
+                       editors in the editor variable.  v\bvi\bis\bsu\bud\bdo\bo will then only
+                       use the EDITOR or VISUAL if they match a value
+                       specified in editor.  This flag is _\bo_\bf_\bf by default.
+
+       env_reset       If set, s\bsu\bud\bdo\bo will reset the environment to only contain
+                       the LOGNAME, SHELL, USER, USERNAME and the SUDO_*
+                       variables.  Any variables in the caller's environment
+                       that match the env_keep and env_check lists are then
+                       added.  The default contents of the env_keep and
+                       env_check lists are displayed when s\bsu\bud\bdo\bo is run by root
+                       with the _\b-_\bV option.  If the _\bs_\be_\bc_\bu_\br_\be_\b__\bp_\ba_\bt_\bh option is set,
+                       its value will be used for the PATH environment
+                       variable.  This flag is _\bo_\bn by default.
+
+       fqdn            Set this flag if you want to put fully qualified
+                       hostnames in the _\bs_\bu_\bd_\bo_\be_\br_\bs file.  I.e., instead of myhost
+                       you would use myhost.mydomain.edu.  You may still use
+                       the short form if you wish (and even mix the two).
+                       Beware that turning on _\bf_\bq_\bd_\bn requires s\bsu\bud\bdo\bo to make DNS
+                       lookups which may make s\bsu\bud\bdo\bo unusable if DNS stops
+                       working (for example if the machine is not plugged into
+                       the network).  Also note that you must use the host's
+                       official name as DNS knows it.  That is, you may not
+                       use a host alias (CNAME entry) due to performance
+                       issues and the fact that there is no way to get all
+                       aliases from DNS.  If your machine's hostname (as
+                       returned by the hostname command) is already fully
+                       qualified you shouldn't need to set _\bf_\bq_\bd_\bn.  This flag is
+                       _\bo_\bf_\bf by default.
 
-       ignore_local_sudoers
-                       If set via LDAP, parsing of _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs
-                       will be skipped.  This is intended for
-                       Enterprises that wish to prevent the usage
-                       of local sudoers files so that only LDAP
-                       is used.  This thwarts the efforts of
-                       rogue operators who would attempt to add
-                       roles to _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs.  When this option
 
 
 
-1.6.9p17                   Jun 21, 2008                         9
+1.7.0                   December  3, 2008                       9
 
 
 
@@ -598,196 +598,196 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-                       is present, _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs does not even
-                       need to exist. Since this option tells
-                       s\bsu\bud\bdo\bo how to behave when no specific LDAP
-                       entries have been matched, this sudoOption
-                       is only meaningful for the cn=defaults
-                       section.  This flag is _\bo_\bf_\bf by default.
+       ignore_dot      If set, s\bsu\bud\bdo\bo will ignore '.' or '' (current dir) in the
+                       PATH environment variable; the PATH itself is not
+                       modified.  This flag is _\bo_\bf_\bf by default.
 
-       insults         If set, s\bsu\bud\bdo\bo will insult users when they
-                       enter an incorrect password.  This flag is
-                       _\bo_\bf_\bf by default.
-
-       log_host        If set, the hostname will be logged in the
-                       (non-syslog) s\bsu\bud\bdo\bo log file.  This flag is
+       ignore_local_sudoers
+                       If set via LDAP, parsing of _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs will be
+                       skipped.  This is intended for Enterprises that wish to
+                       prevent the usage of local sudoers files so that only
+                       LDAP is used.  This thwarts the efforts of rogue
+                       operators who would attempt to add roles to
+                       _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs.  When this option is present,
+                       _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs does not even need to exist. Since this
+                       option tells s\bsu\bud\bdo\bo how to behave when no specific LDAP
+                       entries have been matched, this sudoOption is only
+                       meaningful for the cn=defaults section.  This flag is
                        _\bo_\bf_\bf by default.
 
-       log_year        If set, the four-digit year will be logged
-                       in the (non-syslog) s\bsu\bud\bdo\bo log file.  This
-                       flag is _\bo_\bf_\bf by default.
+       insults         If set, s\bsu\bud\bdo\bo will insult users when they enter an
+                       incorrect password.  This flag is _\bo_\bf_\bf by default.
 
-       long_otp_prompt When validating with a One Time Password
-                       (OPT) scheme such as S\bS/\b/K\bKe\bey\by or O\bOP\bPI\bIE\bE, a two-
-                       line prompt is used to make it easier to
-                       cut and paste the challenge to a local
-                       window.  It's not as pretty as the default
-                       but some people find it more convenient.
-                       This flag is _\bo_\bf_\bf by default.
+       log_host        If set, the hostname will be logged in the (non-syslog)
+                       s\bsu\bud\bdo\bo log file.  This flag is _\bo_\bf_\bf by default.
 
-       mail_always     Send mail to the _\bm_\ba_\bi_\bl_\bt_\bo user every time a
-                       users runs s\bsu\bud\bdo\bo.  This flag is _\bo_\bf_\bf by
-                       default.
+       log_year        If set, the four-digit year will be logged in the (non-
+                       syslog) s\bsu\bud\bdo\bo log file.  This flag is _\bo_\bf_\bf by default.
 
-       mail_badpass    Send mail to the _\bm_\ba_\bi_\bl_\bt_\bo user if the user
-                       running s\bsu\bud\bdo\bo does not enter the correct
-                       password.  This flag is _\bo_\bf_\bf by default.
+       long_otp_prompt When validating with a One Time Password (OPT) scheme
+                       such as S\bS/\b/K\bKe\bey\by or O\bOP\bPI\bIE\bE, a two-line prompt is used to
+                       make it easier to cut and paste the challenge to a
+                       local window.  It's not as pretty as the default but
+                       some people find it more convenient.  This flag is _\bo_\bf_\bf
+                       by default.
 
-       mail_no_host    If set, mail will be sent to the _\bm_\ba_\bi_\bl_\bt_\bo
-                       user if the invoking user exists in the
-                       _\bs_\bu_\bd_\bo_\be_\br_\bs file, but is not allowed to run
-                       commands on the current host.  This flag
-                       is _\bo_\bf_\bf by default.
+       mail_always     Send mail to the _\bm_\ba_\bi_\bl_\bt_\bo user every time a users runs
+                       s\bsu\bud\bdo\bo.  This flag is _\bo_\bf_\bf by default.
 
-       mail_no_perms   If set, mail will be sent to the _\bm_\ba_\bi_\bl_\bt_\bo
-                       user if the invoking user is allowed to
-                       use s\bsu\bud\bdo\bo but the command they are trying
-                       is not listed in their _\bs_\bu_\bd_\bo_\be_\br_\bs file entry
-                       or is explicitly denied.  This flag is _\bo_\bf_\bf
+       mail_badpass    Send mail to the _\bm_\ba_\bi_\bl_\bt_\bo user if the user running s\bsu\bud\bdo\bo
+                       does not enter the correct password.  This flag is _\bo_\bf_\bf
                        by default.
 
-       mail_no_user    If set, mail will be sent to the _\bm_\ba_\bi_\bl_\bt_\bo
-                       user if the invoking user is not in the
-                       _\bs_\bu_\bd_\bo_\be_\br_\bs file.  This flag is _\bo_\bn by default.
+       mail_no_host    If set, mail will be sent to the _\bm_\ba_\bi_\bl_\bt_\bo user if the
+                       invoking user exists in the _\bs_\bu_\bd_\bo_\be_\br_\bs file, but is not
+                       allowed to run commands on the current host.  This flag
+                       is _\bo_\bf_\bf by default.
 
-       noexec          If set, all commands run via s\bsu\bud\bdo\bo will
-                       behave as if the NOEXEC tag has been set,
+       mail_no_perms   If set, mail will be sent to the _\bm_\ba_\bi_\bl_\bt_\bo user if the
+                       invoking user is allowed to use s\bsu\bud\bdo\bo but the command
+                       they are trying is not listed in their _\bs_\bu_\bd_\bo_\be_\br_\bs file
+                       entry or is explicitly denied.  This flag is _\bo_\bf_\bf by
+                       default.
 
+       mail_no_user    If set, mail will be sent to the _\bm_\ba_\bi_\bl_\bt_\bo user if the
+                       invoking user is not in the _\bs_\bu_\bd_\bo_\be_\br_\bs file.  This flag is
+                       _\bo_\bn by default.
 
 
-1.6.9p17                   Jun 21, 2008                        10
 
+1.7.0                   December  3, 2008                      10
 
 
 
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
-                       unless overridden by a EXEC tag.  See the
-                       description of _\bN_\bO_\bE_\bX_\bE_\bC _\ba_\bn_\bd _\bE_\bX_\bE_\bC below as
-                       well as the "PREVENTING SHELL ESCAPES"
-                       section at the end of this manual.  This
-                       flag is _\bo_\bf_\bf by default.
 
-       path_info       Normally, s\bsu\bud\bdo\bo will tell the user when a
-                       command could not be found in their PATH
-                       environment variable.  Some sites may wish
-                       to disable this as it could be used to
-                       gather information on the location of exe­
-                       cutables that the normal user does not
-                       have access to.  The disadvantage is that
-                       if the executable is simply not in the
-                       user's PATH, s\bsu\bud\bdo\bo will tell the user that
-                       they are not allowed to run it, which can
-                       be confusing.  This flag is _\bo_\bn by default.
+       noexec          If set, all commands run via s\bsu\bud\bdo\bo will behave as if the
+                       NOEXEC tag has been set, unless overridden by a EXEC
+                       tag.  See the description of _\bN_\bO_\bE_\bX_\bE_\bC _\ba_\bn_\bd _\bE_\bX_\bE_\bC below as
+                       well as the "PREVENTING SHELL ESCAPES" section at the
+                       end of this manual.  This flag is _\bo_\bf_\bf by default.
+
+       path_info       Normally, s\bsu\bud\bdo\bo will tell the user when a command could
+                       not be found in their PATH environment variable.  Some
+                       sites may wish to disable this as it could be used to
+                       gather information on the location of executables that
+                       the normal user does not have access to.  The
+                       disadvantage is that if the executable is simply not in
+                       the user's PATH, s\bsu\bud\bdo\bo will tell the user that they are
+                       not allowed to run it, which can be confusing.  This
+                       flag is _\bo_\bn by default.
 
        passprompt_override
-                       The password prompt specified by
-                       _\bp_\ba_\bs_\bs_\bp_\br_\bo_\bm_\bp_\bt will normally only be used if
-                       the passwod prompt provided by systems
-                       such as PAM matches the string "Pass­
-                       word:".  If _\bp_\ba_\bs_\bs_\bp_\br_\bo_\bm_\bp_\bt_\b__\bo_\bv_\be_\br_\br_\bi_\bd_\be is set,
-                       _\bp_\ba_\bs_\bs_\bp_\br_\bo_\bm_\bp_\bt will always be used.  This flag
-                       is _\bo_\bf_\bf by default.
-
-       preserve_groups By default s\bsu\bud\bdo\bo will initialize the group
-                       vector to the list of groups the target
-                       user is in.  When _\bp_\br_\be_\bs_\be_\br_\bv_\be_\b__\bg_\br_\bo_\bu_\bp_\bs is set,
-                       the user's existing group vector is left
-                       unaltered.  The real and effective group
-                       IDs, however, are still set to match the
-                       target user.  This flag is _\bo_\bf_\bf by default.
-
-       requiretty      If set, s\bsu\bud\bdo\bo will only run when the user
-                       is logged in to a real tty.  This will
-                       disallow things like "rsh somehost sudo
-                       ls" since _\br_\bs_\bh(1) does not allocate a tty.
-                       Because it is not possible to turn off
-                       echo when there is no tty present, some
-                       sites may wish to set this flag to prevent
-                       a user from entering a visible password.
+                       The password prompt specified by _\bp_\ba_\bs_\bs_\bp_\br_\bo_\bm_\bp_\bt will
+                       normally only be used if the passwod prompt provided by
+                       systems such as PAM matches the string "Password:".  If
+                       _\bp_\ba_\bs_\bs_\bp_\br_\bo_\bm_\bp_\bt_\b__\bo_\bv_\be_\br_\br_\bi_\bd_\be is set, _\bp_\ba_\bs_\bs_\bp_\br_\bo_\bm_\bp_\bt will always be
+                       used.  This flag is _\bo_\bf_\bf by default.
+
+       preserve_groups By default s\bsu\bud\bdo\bo will initialize the group vector to the
+                       list of groups the target user is in.  When
+                       _\bp_\br_\be_\bs_\be_\br_\bv_\be_\b__\bg_\br_\bo_\bu_\bp_\bs is set, the user's existing group
+                       vector is left unaltered.  The real and effective group
+                       IDs, however, are still set to match the target user.
                        This flag is _\bo_\bf_\bf by default.
 
-       root_sudo       If set, root is allowed to run s\bsu\bud\bdo\bo too.
-                       Disabling this prevents users from "chain­
-                       ing" s\bsu\bud\bdo\bo commands to get a root shell by
-                       doing something like "sudo sudo /bin/sh".
-                       Note, however, that turning off _\br_\bo_\bo_\bt_\b__\bs_\bu_\bd_\bo
-                       will also prevent root and from running
-                       s\bsu\bud\bdo\boe\bed\bdi\bit\bt.  Disabling _\br_\bo_\bo_\bt_\b__\bs_\bu_\bd_\bo provides no
-                       real additional security; it exists purely
-                       for historical reasons.  This flag is _\bo_\bn
-
+       requiretty      If set, s\bsu\bud\bdo\bo will only run when the user is logged in
+                       to a real tty.  When this flag is set, s\bsu\bud\bdo\bo can only be
+                       run from a login session and not via other means such
+                       as _\bc_\br_\bo_\bn(1m) or cgi-bin scripts.  This flag is _\bo_\bf_\bf by
+                       default.
 
+       root_sudo       If set, root is allowed to run s\bsu\bud\bdo\bo too.  Disabling
+                       this prevents users from "chaining" s\bsu\bud\bdo\bo commands to
+                       get a root shell by doing something like "sudo sudo
+                       /bin/sh".  Note, however, that turning off _\br_\bo_\bo_\bt_\b__\bs_\bu_\bd_\bo
+                       will also prevent root and from running s\bsu\bud\bdo\boe\bed\bdi\bit\bt.
+                       Disabling _\br_\bo_\bo_\bt_\b__\bs_\bu_\bd_\bo provides no real additional
+                       security; it exists purely for historical reasons.
+                       This flag is _\bo_\bn by default.
+
+       rootpw          If set, s\bsu\bud\bdo\bo will prompt for the root password instead
+                       of the password of the invoking user.  This flag is _\bo_\bf_\bf
+                       by default.
 
-1.6.9p17                   Jun 21, 2008                        11
+       runaspw         If set, s\bsu\bud\bdo\bo will prompt for the password of the user
+                       defined by the _\br_\bu_\bn_\ba_\bs_\b__\bd_\be_\bf_\ba_\bu_\bl_\bt option (defaults to root)
+                       instead of the password of the invoking user.  This
+                       flag is _\bo_\bf_\bf by default.
 
 
 
 
+1.7.0                   December  3, 2008                      11
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-                       by default.
 
-       rootpw          If set, s\bsu\bud\bdo\bo will prompt for the root
-                       password instead of the password of the
-                       invoking user.  This flag is _\bo_\bf_\bf by
-                       default.
 
-       runaspw         If set, s\bsu\bud\bdo\bo will prompt for the password
-                       of the user defined by the _\br_\bu_\bn_\ba_\bs_\b__\bd_\be_\bf_\ba_\bu_\bl_\bt
-                       option (defaults to root) instead of the
-                       password of the invoking user.  This flag
-                       is _\bo_\bf_\bf by default.
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
-       set_home        If set and s\bsu\bud\bdo\bo is invoked with the -\b-s\bs
-                       flag the HOME environment variable will be
-                       set to the home directory of the target
-                       user (which is root unless the -\b-u\bu option
-                       is used).  This effectively makes the -\b-s\bs
-                       flag imply -\b-H\bH.  This flag is _\bo_\bf_\bf by
-                       default.
 
-       set_logname     Normally, s\bsu\bud\bdo\bo will set the LOGNAME, USER
-                       and USERNAME environment variables to the
-                       name of the target user (usually root
-                       unless the -\b-u\bu flag is given).  However,
-                       since some programs (including the RCS
-                       revision control system) use LOGNAME to
-                       determine the real identity of the user,
-                       it may be desirable to change this behav­
-                       ior.  This can be done by negating the
-                       set_logname option.  Note that if the
-                       _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option has not been disabled,
-                       entries in the _\be_\bn_\bv_\b__\bk_\be_\be_\bp list will override
-                       the value of _\bs_\be_\bt_\b__\bl_\bo_\bg_\bn_\ba_\bm_\be.  This flag is
+       set_home        If set and s\bsu\bud\bdo\bo is invoked with the -\b-s\bs option the HOME
+                       environment variable will be set to the home directory
+                       of the target user (which is root unless the -\b-u\bu option
+                       is used).  This effectively makes the -\b-s\bs option imply
+                       -\b-H\bH.  This flag is _\bo_\bf_\bf by default.
+
+       set_logname     Normally, s\bsu\bud\bdo\bo will set the LOGNAME, USER and USERNAME
+                       environment variables to the name of the target user
+                       (usually root unless the -\b-u\bu option is given).  However,
+                       since some programs (including the RCS revision control
+                       system) use LOGNAME to determine the real identity of
+                       the user, it may be desirable to change this behavior.
+                       This can be done by negating the set_logname option.
+                       Note that if the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option has not been
+                       disabled, entries in the _\be_\bn_\bv_\b__\bk_\be_\be_\bp list will override
+                       the value of _\bs_\be_\bt_\b__\bl_\bo_\bg_\bn_\ba_\bm_\be.  This flag is _\bo_\bf_\bf by default.
+
+       setenv          Allow the user to disable the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option from the
+                       command line.  Additionally, environment variables set
+                       via the command line are not subject to the
+                       restrictions imposed by _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk, _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be, or
+                       _\be_\bn_\bv_\b__\bk_\be_\be_\bp.  As such, only trusted users should be
+                       allowed to set variables in this manner.  This flag is
                        _\bo_\bf_\bf by default.
 
-       setenv          Allow the user to disable the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt
-                       option from the command line.  Addition­
-                       ally, environment variables set via the
-                       command line are not subject to the
-                       restrictions imposed by _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk,
-                       _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be, or _\be_\bn_\bv_\b__\bk_\be_\be_\bp.  As such, only
-                       trusted users should be allowed to set
-                       variables in this manner.  This flag is
+       shell_noargs    If set and s\bsu\bud\bdo\bo is invoked with no arguments it acts as
+                       if the -\b-s\bs option had been given.  That is, it runs a
+                       shell as root (the shell is determined by the SHELL
+                       environment variable if it is set, falling back on the
+                       shell listed in the invoking user's /etc/passwd entry
+                       if not).  This flag is _\bo_\bf_\bf by default.
+
+       stay_setuid     Normally, when s\bsu\bud\bdo\bo executes a command the real and
+                       effective UIDs are set to the target user (root by
+                       default).  This option changes that behavior such that
+                       the real UID is left as the invoking user's UID.  In
+                       other words, this makes s\bsu\bud\bdo\bo act as a setuid wrapper.
+                       This can be useful on systems that disable some
+                       potentially dangerous functionality when a program is
+                       run setuid.  This option is only effective on systems
+                       with either the _\bs_\be_\bt_\br_\be_\bu_\bi_\bd_\b(_\b) or _\bs_\be_\bt_\br_\be_\bs_\bu_\bi_\bd_\b(_\b) function.
+                       This flag is _\bo_\bf_\bf by default.
+
+       targetpw        If set, s\bsu\bud\bdo\bo will prompt for the password of the user
+                       specified by the -\b-u\bu option (defaults to root) instead
+                       of the password of the invoking user.  Note that this
+                       precludes the use of a uid not listed in the passwd
+                       database as an argument to the -\b-u\bu option.  This flag is
                        _\bo_\bf_\bf by default.
 
-       shell_noargs    If set and s\bsu\bud\bdo\bo is invoked with no argu­
-                       ments it acts as if the -\b-s\bs flag had been
-                       given.  That is, it runs a shell as root
-                       (the shell is determined by the SHELL
-                       environment variable if it is set, falling
-                       back on the shell listed in the invoking
-                       user's /etc/passwd entry if not).  This
-                       flag is _\bo_\bf_\bf by default.
+       tty_tickets     If set, users must authenticate on a per-tty basis.
+                       Normally, s\bsu\bud\bdo\bo uses a directory in the ticket dir with
+                       the same name as the user running it.  With this flag
+                       enabled, s\bsu\bud\bdo\bo will use a file named for the tty the
 
 
 
-1.6.9p17                   Jun 21, 2008                        12
+1.7.0                   December  3, 2008                      12
 
 
 
@@ -796,64 +796,64 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-       stay_setuid     Normally, when s\bsu\bud\bdo\bo executes a command the
-                       real and effective UIDs are set to the
-                       target user (root by default).  This
-                       option changes that behavior such that the
-                       real UID is left as the invoking user's
-                       UID.  In other words, this makes s\bsu\bud\bdo\bo act
-                       as a setuid wrapper.  This can be useful
-                       on systems that disable some potentially
-                       dangerous functionality when a program is
-                       run setuid.  This option is only effective
-                       on systems with either the _\bs_\be_\bt_\br_\be_\bu_\bi_\bd_\b(_\b) or
-                       _\bs_\be_\bt_\br_\be_\bs_\bu_\bi_\bd_\b(_\b) function.  This flag is _\bo_\bf_\bf by
-                       default.
+                       user is logged in on in that directory.  This flag is
+                       _\bo_\bf_\bf by default.
 
-       targetpw        If set, s\bsu\bud\bdo\bo will prompt for the password
-                       of the user specified by the -\b-u\bu flag
-                       (defaults to root) instead of the password
-                       of the invoking user.  Note that this pre­
-                       cludes the use of a uid not listed in the
-                       passwd database as an argument to the -\b-u\bu
-                       flag.  This flag is _\bo_\bf_\bf by default.
-
-       tty_tickets     If set, users must authenticate on a per-
-                       tty basis.  Normally, s\bsu\bud\bdo\bo uses a direc­
-                       tory in the ticket dir with the same name
-                       as the user running it.  With this flag
-                       enabled, s\bsu\bud\bdo\bo will use a file named for
-                       the tty the user is logged in on in that
-                       directory.  This flag is _\bo_\bf_\bf by default.
-
-       use_loginclass  If set, s\bsu\bud\bdo\bo will apply the defaults spec­
-                       ified for the target user's login class if
-                       one exists.  Only available if s\bsu\bud\bdo\bo is
-                       configured with the --with-logincap
-                       option.  This flag is _\bo_\bf_\bf by default.
+       use_loginclass  If set, s\bsu\bud\bdo\bo will apply the defaults specified for the
+                       target user's login class if one exists.  Only
+                       available if s\bsu\bud\bdo\bo is configured with the
+                       --with-logincap option.  This flag is _\bo_\bf_\bf by default.
+
+       visiblepw       By default, s\bsu\bud\bdo\bo will refuse to run if the user must
+                       enter a password but it is not possible to disable echo
+                       on the terminal.  If the _\bv_\bi_\bs_\bi_\bb_\bl_\be_\bp_\bw flag is set, s\bsu\bud\bdo\bo
+                       will prompt for a password even when it would be
+                       visible on the screen.  This makes it possible to run
+                       things like "rsh somehost sudo ls" since _\br_\bs_\bh(1) does
+                       not allocate a tty.  This flag is _\bo_\bf_\bf by default.
 
        I\bIn\bnt\bte\beg\bge\ber\brs\bs:
 
-       passwd_tries    The number of tries a user gets to enter
-                       his/her password before s\bsu\bud\bdo\bo logs the
-                       failure and exits.  The default is 3.
+       closefrom       Before it executes a command, s\bsu\bud\bdo\bo will close all open
+                       file descriptors other than standard input, standard
+                       output and standard error (ie: file descriptors 0-2).
+                       The _\bc_\bl_\bo_\bs_\be_\bf_\br_\bo_\bm option can be used to specify a different
+                       file descriptor at which to start closing.  The default
+                       is 3.
+
+       passwd_tries    The number of tries a user gets to enter his/her
+                       password before s\bsu\bud\bdo\bo logs the failure and exits.  The
+                       default is 3.
 
        I\bIn\bnt\bte\beg\bge\ber\brs\bs t\bth\bha\bat\bt c\bca\ban\bn b\bbe\be u\bus\bse\bed\bd i\bin\bn a\ba b\bbo\boo\bol\ble\bea\ban\bn c\bco\bon\bnt\bte\bex\bxt\bt:
 
-       loglinelen      Number of characters per line for the file
-                       log.  This value is used to decide when to
-                       wrap lines for nicer log files.  This has
-                       no effect on the syslog log file, only the
-                       file log.  The default is 80 (use 0 or
-                       negate the option to disable word wrap).
+       loglinelen      Number of characters per line for the file log.  This
+                       value is used to decide when to wrap lines for nicer
+                       log files.  This has no effect on the syslog log file,
+                       only the file log.  The default is 80 (use 0 or negate
+                       the option to disable word wrap).
 
-       passwd_timeout  Number of minutes before the s\bsu\bud\bdo\bo password
-                       prompt times out.  The default is 5; set
-                       this to 0 for no password timeout.
+       passwd_timeout  Number of minutes before the s\bsu\bud\bdo\bo password prompt times
+                       out.  The default is 5; set this to 0 for no password
+                       timeout.
+
+       timestamp_timeout
+                       Number of minutes that can elapse before s\bsu\bud\bdo\bo will ask
+                       for a passwd again.  The default is 5.  Set this to 0
+                       to always prompt for a password.  If set to a value
+                       less than 0 the user's timestamp will never expire.
+                       This can be used to allow users to create or delete
+                       their own timestamps via sudo -v and sudo -k
+                       respectively.
 
+       umask           Umask to use when running the command.  Negate this
+                       option or set it to 0777 to preserve the user's umask.
+                       The actual umask that is used will be the union of the
+                       user's umask and 0022.  This guarantees that s\bsu\bud\bdo\bo never
 
 
-1.6.9p17                   Jun 21, 2008                        13
+
+1.7.0                   December  3, 2008                      13
 
 
 
@@ -862,196 +862,196 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-       timestamp_timeout
-                       Number of minutes that can elapse before
-                       s\bsu\bud\bdo\bo will ask for a passwd again.  The
-                       default is 5.  Set this to 0 to always
-                       prompt for a password.  If set to a value
-                       less than 0 the user's timestamp will
-                       never expire.  This can be used to allow
-                       users to create or delete their own times­
-                       tamps via sudo -v and sudo -k respec­
-                       tively.
-
-       umask           Umask to use when running the command.
-                       Negate this option or set it to 0777 to
-                       preserve the user's umask.  The default is
-                       0022.
+                       lowers the umask when running a command.  Note on
+                       systems that use PAM, the default PAM configuration may
+                       specify its own umask which will override the value set
+                       in _\bs_\bu_\bd_\bo_\be_\br_\bs.
 
        S\bSt\btr\bri\bin\bng\bgs\bs:
 
-       badpass_message Message that is displayed if a user enters
-                       an incorrect password.  The default is
-                       Sorry, try again. unless insults are
-                       enabled.
-
-       editor          A colon (':') separated list of editors
-                       allowed to be used with v\bvi\bis\bsu\bud\bdo\bo.  v\bvi\bis\bsu\bud\bdo\bo
-                       will choose the editor that matches the
-                       user's EDITOR environment variable if pos­
-                       sible, or the first editor in the list
-                       that exists and is executable.  The
-                       default is the path to vi on your system.
-
-       mailsub         Subject of the mail sent to the _\bm_\ba_\bi_\bl_\bt_\bo
-                       user. The escape %h will expand to the
-                       hostname of the machine.  Default is ***
-                       SECURITY information for %h ***.
-
-       noexec_file     Path to a shared library containing dummy
-                       versions of the _\be_\bx_\be_\bc_\bv_\b(_\b), _\be_\bx_\be_\bc_\bv_\be_\b(_\b) and _\bf_\be_\bx_\b­
-                       _\be_\bc_\bv_\be_\b(_\b) library functions that just return
-                       an error.  This is used to implement the
-                       _\bn_\bo_\be_\bx_\be_\bc functionality on systems that sup­
-                       port LD_PRELOAD or its equivalent.
-                       Defaults to
+       badpass_message Message that is displayed if a user enters an incorrect
+                       password.  The default is Sorry, try again. unless
+                       insults are enabled.
+
+       editor          A colon (':') separated list of editors allowed to be
+                       used with v\bvi\bis\bsu\bud\bdo\bo.  v\bvi\bis\bsu\bud\bdo\bo will choose the editor that
+                       matches the user's EDITOR environment variable if
+                       possible, or the first editor in the list that exists
+                       and is executable.  The default is the path to vi on
+                       your system.
+
+       mailsub         Subject of the mail sent to the _\bm_\ba_\bi_\bl_\bt_\bo user. The escape
+                       %h will expand to the hostname of the machine.  Default
+                       is *** SECURITY information for %h ***.
+
+       noexec_file     Path to a shared library containing dummy versions of
+                       the _\be_\bx_\be_\bc_\bv_\b(_\b), _\be_\bx_\be_\bc_\bv_\be_\b(_\b) and _\bf_\be_\bx_\be_\bc_\bv_\be_\b(_\b) library functions
+                       that just return an error.  This is used to implement
+                       the _\bn_\bo_\be_\bx_\be_\bc functionality on systems that support
+                       LD_PRELOAD or its equivalent.  Defaults to
                        _\b/_\bu_\bs_\br_\b/_\bl_\bo_\bc_\ba_\bl_\b/_\bl_\bi_\bb_\be_\bx_\be_\bc_\b/_\bs_\bu_\bd_\bo_\b__\bn_\bo_\be_\bx_\be_\bc_\b._\bs_\bo.
 
-       passprompt      The default prompt to use when asking for
-                       a password; can be overridden via the -\b-p\bp
-                       option or the SUDO_PROMPT environment
-                       variable.  The following percent (`%')
+       passprompt      The default prompt to use when asking for a password;
+                       can be overridden via the -\b-p\bp option or the SUDO_PROMPT
+                       environment variable.  The following percent (`%')
                        escapes are supported:
 
-                       %H  expanded to the local hostname includ­
-                           ing the domain name (on if the
-                           machine's hostname is fully qualified
-
+                       %H  expanded to the local hostname including the domain
+                           name (on if the machine's hostname is fully
+                           qualified or the _\bf_\bq_\bd_\bn option is set)
 
+                       %h  expanded to the local hostname without the domain
+                           name
 
-1.6.9p17                   Jun 21, 2008                        14
+                       %p  expanded to the user whose password is being asked
+                           for (respects the _\br_\bo_\bo_\bt_\bp_\bw, _\bt_\ba_\br_\bg_\be_\bt_\bp_\bw and _\br_\bu_\bn_\ba_\bs_\bp_\bw
+                           flags in _\bs_\bu_\bd_\bo_\be_\br_\bs)
 
+                       %U  expanded to the login name of the user the command
+                           will be run as (defaults to root)
 
+                       %u  expanded to the invoking user's login name
 
+                       %%  two consecutive % characters are collapsed into a
+                           single % character
 
+                       The default value is Password:.
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-                           or the _\bf_\bq_\bd_\bn option is set)
+1.7.0                   December  3, 2008                      14
 
-                       %h  expanded to the local hostname without
-                           the domain name
 
-                       %p  expanded to the user whose password is
-                           being asked for (respects the _\br_\bo_\bo_\bt_\bp_\bw,
-                           _\bt_\ba_\br_\bg_\be_\bt_\bp_\bw and _\br_\bu_\bn_\ba_\bs_\bp_\bw flags in _\bs_\bu_\bd_\bo_\be_\br_\bs)
 
-                       %U  expanded to the login name of the user
-                           the command will be run as (defaults
-                           to root)
 
-                       %u  expanded to the invoking user's login
-                           name
 
-                       %%  two consecutive % characters are col­
-                           lapsed into a single % character
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
-                       The default value is Password:.
 
-       runas_default   The default user to run commands as if the
-                       -\b-u\bu flag is not specified on the command
-                       line.  This defaults to root.  Note that
-                       if _\br_\bu_\bn_\ba_\bs_\b__\bd_\be_\bf_\ba_\bu_\bl_\bt is set it m\bmu\bus\bst\bt occur
+       runas_default   The default user to run commands as if the -\b-u\bu option is
+                       not specified on the command line.  This defaults to
+                       root.  Note that if _\br_\bu_\bn_\ba_\bs_\b__\bd_\be_\bf_\ba_\bu_\bl_\bt is set it m\bmu\bus\bst\bt occur
                        before any Runas_Alias specifications.
 
-       syslog_badpri   Syslog priority to use when user authenti­
-                       cates unsuccessfully.  Defaults to alert.
+       syslog_badpri   Syslog priority to use when user authenticates
+                       unsuccessfully.  Defaults to alert.
 
-       syslog_goodpri  Syslog priority to use when user authenti­
-                       cates successfully.  Defaults to notice.
+       syslog_goodpri  Syslog priority to use when user authenticates
+                       successfully.  Defaults to notice.
 
-       timestampdir    The directory in which s\bsu\bud\bdo\bo stores its
-                       timestamp files.  The default is
-                       _\b/_\bv_\ba_\br_\b/_\br_\bu_\bn_\b/_\bs_\bu_\bd_\bo.
+       sudoers_locale  Locale to use when parsing the sudoers file.  Note that
+                       changing the locale may affect how sudoers is
+                       interpreted.  Defaults to "C".
 
-       timestampowner  The owner of the timestamp directory and
-                       the timestamps stored therein.  The
-                       default is root.
+       timestampdir    The directory in which s\bsu\bud\bdo\bo stores its timestamp files.
+                       The default is _\b/_\bv_\ba_\br_\b/_\br_\bu_\bn_\b/_\bs_\bu_\bd_\bo.
+
+       timestampowner  The owner of the timestamp directory and the timestamps
+                       stored therein.  The default is root.
 
        S\bSt\btr\bri\bin\bng\bgs\bs t\bth\bha\bat\bt c\bca\ban\bn b\bbe\be u\bus\bse\bed\bd i\bin\bn a\ba b\bbo\boo\bol\ble\bea\ban\bn c\bco\bon\bnt\bte\bex\bxt\bt:
 
+       askpass     The _\ba_\bs_\bk_\bp_\ba_\bs_\bs option specifies the fully qualified path to a
+                   helper program used to read the user's password when no
+                   terminal is available.  This may be the case when s\bsu\bud\bdo\bo is
+                   executed from a graphical (as opposed to text-based)
+                   application.  The program specified by _\ba_\bs_\bk_\bp_\ba_\bs_\bs should
+                   display the argument passed to it as the prompt and write
+                   the user's password to the standard output.  The value of
+                   _\ba_\bs_\bk_\bp_\ba_\bs_\bs may be overridden by the SUDO_ASKPASS environment
+                   variable.
+
+       env_file    The _\be_\bn_\bv_\b__\bf_\bi_\bl_\be options specifies the fully qualified path to
+                   a file containing variables to be set in the environment of
+                   the program being run.  Entries in this file should be of
+                   the form VARIABLE=value.  Variables in this file are
+                   subject to other s\bsu\bud\bdo\bo environment settings such as _\be_\bn_\bv_\b__\bk_\be_\be_\bp
+                   and _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk.
+
        exempt_group
-                   Users in this group are exempt from password
-                   and PATH requirements.  This is not set by
-                   default.
+                   Users in this group are exempt from password and PATH
+                   requirements.  This is not set by default.
 
-       lecture     This option controls when a short lecture will
-                   be printed along with the password prompt.  It
-                   has the following possible values:
+       lecture     This option controls when a short lecture will be printed
+                   along with the password prompt.  It has the following
+                   possible values:
 
                    always  Always lecture the user.
 
+                   never   Never lecture the user.
 
+                   once    Only lecture the user the first time they run s\bsu\bud\bdo\bo.
 
 
-1.6.9p17                   Jun 21, 2008                        15
 
 
+1.7.0                   December  3, 2008                      15
 
 
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-                   never   Never lecture the user.
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
-                   once    Only lecture the user the first time
-                           they run s\bsu\bud\bdo\bo.
 
-                   If no value is specified, a value of _\bo_\bn_\bc_\be is
-                   implied.  Negating the option results in a
-                   value of _\bn_\be_\bv_\be_\br being used.  The default value
-                   is _\bo_\bn_\bc_\be.
+                   If no value is specified, a value of _\bo_\bn_\bc_\be is implied.
+                   Negating the option results in a value of _\bn_\be_\bv_\be_\br being used.
+                   The default value is _\bo_\bn_\bc_\be.
 
        lecture_file
-                   Path to a file containing an alternate s\bsu\bud\bdo\bo
-                   lecture that will be used in place of the
-                   standard lecture if the named file exists.  By
-                   default, s\bsu\bud\bdo\bo uses a built-in lecture.
+                   Path to a file containing an alternate s\bsu\bud\bdo\bo lecture that
+                   will be used in place of the standard lecture if the named
+                   file exists.  By default, s\bsu\bud\bdo\bo uses a built-in lecture.
+
+       listpw      This option controls when a password will be required when
+                   a user runs s\bsu\bud\bdo\bo with the -\b-l\bl option.  It has the following
+                   possible values:
 
-       listpw      This option controls when a password will be
-                   required when a user runs s\bsu\bud\bdo\bo with the -\b-l\bl
-                   flag.  It has the following possible values:
+                   all     All the user's _\bs_\bu_\bd_\bo_\be_\br_\bs entries for the current host
+                           must have the NOPASSWD flag set to avoid entering a
+                           password.
 
-                   all     All the user's _\bs_\bu_\bd_\bo_\be_\br_\bs entries for the
-                           current host must have the NOPASSWD
-                           flag set to avoid entering a password.
+                   always  The user must always enter a password to use the -\b-l\bl
+                           option.
 
-                   always  The user must always enter a password
-                           to use the -\b-l\bl flag.
+                   any     At least one of the user's _\bs_\bu_\bd_\bo_\be_\br_\bs entries for the
+                           current host must have the NOPASSWD flag set to
+                           avoid entering a password.
 
-                   any     At least one of the user's _\bs_\bu_\bd_\bo_\be_\br_\bs
-                           entries for the current host must have
-                           the NOPASSWD flag set to avoid enter­
-                           ing a password.
+                   never   The user need never enter a password to use the -\b-l\bl
+                           option.
 
-                   never   The user need never enter a password
-                           to use the -\b-l\bl flag.
+                   If no value is specified, a value of _\ba_\bn_\by is implied.
+                   Negating the option results in a value of _\bn_\be_\bv_\be_\br being used.
+                   The default value is _\ba_\bn_\by.
 
-                   If no value is specified, a value of _\ba_\bn_\by is
-                   implied.  Negating the option results in a
-                   value of _\bn_\be_\bv_\be_\br being used.  The default value
-                   is _\ba_\bn_\by.
+       logfile     Path to the s\bsu\bud\bdo\bo log file (not the syslog log file).
+                   Setting a path turns on logging to a file; negating this
+                   option turns it off.  By default, s\bsu\bud\bdo\bo logs via syslog.
 
-       logfile     Path to the s\bsu\bud\bdo\bo log file (not the syslog log
-                   file).  Setting a path turns on logging to a
-                   file; negating this option turns it off.  By
-                   default, s\bsu\bud\bdo\bo logs via syslog.
+       mailerflags Flags to use when invoking mailer. Defaults to -\b-t\bt.
 
-       mailerflags Flags to use when invoking mailer. Defaults to
-                   -\b-t\bt.
+       mailerpath  Path to mail program used to send warning mail.  Defaults
+                   to the path to sendmail found at configure time.
 
-       mailerpath  Path to mail program used to send warning
-                   mail.  Defaults to the path to sendmail found
-                   at configure time.
+       mailfrom    Address to use for the "from" address when sending warning
+                   and error mail.  The address should be enclosed in double
+                   quotes (") to protect against s\bsu\bud\bdo\bo interpreting the @ sign.
+                   Defaults to the name of the user running s\bsu\bud\bdo\bo.
 
-       mailto      Address to send warning and error mail to.
-                   The address should be enclosed in double
+       mailto      Address to send warning and error mail to.  The address
+                   should be enclosed in double quotes (") to protect against
+                   s\bsu\bud\bdo\bo interpreting the @ sign.  Defaults to root.
 
+       secure_path Path used for every command run from s\bsu\bud\bdo\bo.  If you don't
+                   trust the people running s\bsu\bud\bdo\bo to have a sane PATH
+                   environment variable you may want to use this.  Another use
+                   is if you want to have the "root path" be separate from the
+                   "user path."  Users in the group specified by the
 
 
-1.6.9p17                   Jun 21, 2008                        16
+
+1.7.0                   December  3, 2008                      16
 
 
 
@@ -1060,64 +1060,64 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-                   quotes (") to protect against s\bsu\bud\bdo\bo interpret­
-                   ing the @ sign.  Defaults to root.
+                   _\be_\bx_\be_\bm_\bp_\bt_\b__\bg_\br_\bo_\bu_\bp option are not affected by _\bs_\be_\bc_\bu_\br_\be_\b__\bp_\ba_\bt_\bh.  This
+                   is not set by default.
 
-       syslog      Syslog facility if syslog is being used for
-                   logging (negate to disable syslog logging).
-                   Defaults to local2.
+       syslog      Syslog facility if syslog is being used for logging (negate
+                   to disable syslog logging).  Defaults to local2.
 
-       verifypw    This option controls when a password will be
-                   required when a user runs s\bsu\bud\bdo\bo with the -\b-v\bv
-                   flag.  It has the following possible values:
+       verifypw    This option controls when a password will be required when
+                   a user runs s\bsu\bud\bdo\bo with the -\b-v\bv option.  It has the following
+                   possible values:
 
-                   all     All the user's _\bs_\bu_\bd_\bo_\be_\br_\bs entries for the
-                           current host must have the NOPASSWD
-                           flag set to avoid entering a password.
+                   all     All the user's _\bs_\bu_\bd_\bo_\be_\br_\bs entries for the current host
+                           must have the NOPASSWD flag set to avoid entering a
+                           password.
 
-                   always  The user must always enter a password
-                           to use the -\b-v\bv flag.
+                   always  The user must always enter a password to use the -\b-v\bv
+                           option.
 
-                   any     At least one of the user's _\bs_\bu_\bd_\bo_\be_\br_\bs
-                           entries for the current host must have
-                           the NOPASSWD flag set to avoid enter­
-                           ing a password.
+                   any     At least one of the user's _\bs_\bu_\bd_\bo_\be_\br_\bs entries for the
+                           current host must have the NOPASSWD flag set to
+                           avoid entering a password.
 
-                   never   The user need never enter a password
-                           to use the -\b-v\bv flag.
+                   never   The user need never enter a password to use the -\b-v\bv
+                           option.
 
-                   If no value is specified, a value of _\ba_\bl_\bl is
-                   implied.  Negating the option results in a
-                   value of _\bn_\be_\bv_\be_\br being used.  The default value
-                   is _\ba_\bl_\bl.
+                   If no value is specified, a value of _\ba_\bl_\bl is implied.
+                   Negating the option results in a value of _\bn_\be_\bv_\be_\br being used.
+                   The default value is _\ba_\bl_\bl.
 
        L\bLi\bis\bst\bts\bs t\bth\bha\bat\bt c\bca\ban\bn b\bbe\be u\bus\bse\bed\bd i\bin\bn a\ba b\bbo\boo\bol\ble\bea\ban\bn c\bco\bon\bnt\bte\bex\bxt\bt:
 
-       env_check       Environment variables to be removed from
-                       the user's environment if the variable's
-                       value contains % or / characters.  This
-                       can be used to guard against printf-style
-                       format vulnerabilities in poorly-written
-                       programs.  The argument may be a dou­
-                       ble-quoted, space-separated list or a sin­
-                       gle value without double-quotes.  The list
-                       can be replaced, added to, deleted from,
-                       or disabled by using the =, +=, -=, and !
-                       operators respectively.  Regardless of
-                       whether the env_reset option is enabled or
-                       disabled, variables specified by env_check
-                       will be preserved in the environment if
-                       they pass the aforementioned check.  The
-                       default list of environment variables to
-                       check is displayed when s\bsu\bud\bdo\bo is run by
-                       root with the _\b-_\bV option.
+       env_check       Environment variables to be removed from the user's
+                       environment if the variable's value contains % or /
+                       characters.  This can be used to guard against printf-
+                       style format vulnerabilities in poorly-written
+                       programs.  The argument may be a double-quoted, space-
+                       separated list or a single value without double-quotes.
+                       The list can be replaced, added to, deleted from, or
+                       disabled by using the =, +=, -=, and ! operators
+                       respectively.  Regardless of whether the env_reset
+                       option is enabled or disabled, variables specified by
+                       env_check will be preserved in the environment if they
+                       pass the aforementioned check.  The default list of
+                       environment variables to check is displayed when s\bsu\bud\bdo\bo
+                       is run by root with the _\b-_\bV option.
 
-       env_delete      Environment variables to be removed from
-                       the user's environment.  The argument may
+       env_delete      Environment variables to be removed from the user's
+                       environment.  The argument may be a double-quoted,
+                       space-separated list or a single value without double-
+                       quotes.  The list can be replaced, added to, deleted
+                       from, or disabled by using the =, +=, -=, and !
+                       operators respectively.  The default list of
+                       environment variables to remove is displayed when s\bsu\bud\bdo\bo
+                       is run by root with the _\b-_\bV option.  Note that many
+                       operating systems will remove potentially dangerous
 
 
 
-1.6.9p17                   Jun 21, 2008                        17
+1.7.0                   December  3, 2008                      17
 
 
 
@@ -1126,39 +1126,26 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-                       be a double-quoted, space-separated list
-                       or a single value without double-quotes.
-                       The list can be replaced, added to,
-                       deleted from, or disabled by using the =,
-                       +=, -=, and ! operators respectively.  The
-                       default list of environment variables to
-                       remove is displayed when s\bsu\bud\bdo\bo is run by
-                       root with the _\b-_\bV option.  Note that many
-                       operating systems will remove potentially
-                       dangerous variables from the environment
-                       of any setuid process (such as s\bsu\bud\bdo\bo).
-
-       env_keep        Environment variables to be preserved in
-                       the user's environment when the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt
-                       option is in effect.  This allows fine-
-                       grained control over the environment
-                       s\bsu\bud\bdo\bo-spawned processes will receive.  The
-                       argument may be a double-quoted, space-
-                       separated list or a single value without
-                       double-quotes.  The list can be replaced,
-                       added to, deleted from, or disabled by
-                       using the =, +=, -=, and ! operators
-                       respectively.  The default list of vari­
-                       ables to keep is displayed when s\bsu\bud\bdo\bo is
-                       run by root with the _\b-_\bV option.
-
-       When logging via _\bs_\by_\bs_\bl_\bo_\bg(3), s\bsu\bud\bdo\bo accepts the following
-       values for the syslog facility (the value of the s\bsy\bys\bsl\blo\bog\bg
-       Parameter): a\bau\but\bth\bhp\bpr\bri\biv\bv (if your OS supports it), a\bau\but\bth\bh, d\bda\bae\b\b­
-       m\bmo\bon\bn, u\bus\bse\ber\br, l\blo\boc\bca\bal\bl0\b0, l\blo\boc\bca\bal\bl1\b1, l\blo\boc\bca\bal\bl2\b2, l\blo\boc\bca\bal\bl3\b3, l\blo\boc\bca\bal\bl4\b4, l\blo\boc\bca\bal\bl5\b5,
-       l\blo\boc\bca\bal\bl6\b6, and l\blo\boc\bca\bal\bl7\b7.  The following syslog priorities are
-       supported: a\bal\ble\ber\brt\bt, c\bcr\bri\bit\bt, d\bde\beb\bbu\bug\bg, e\bem\bme\ber\brg\bg, e\ber\brr\br, i\bin\bnf\bfo\bo, n\bno\bot\bti\bic\bce\be,
-       and w\bwa\bar\brn\bni\bin\bng\bg.
+                       variables from the environment of any setuid process
+                       (such as s\bsu\bud\bdo\bo).
+
+       env_keep        Environment variables to be preserved in the user's
+                       environment when the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is in effect.
+                       This allows fine-grained control over the environment
+                       s\bsu\bud\bdo\bo-spawned processes will receive.  The argument may
+                       be a double-quoted, space-separated list or a single
+                       value without double-quotes.  The list can be replaced,
+                       added to, deleted from, or disabled by using the =, +=,
+                       -=, and ! operators respectively.  The default list of
+                       variables to keep is displayed when s\bsu\bud\bdo\bo is run by root
+                       with the _\b-_\bV option.
+
+       When logging via _\bs_\by_\bs_\bl_\bo_\bg(3), s\bsu\bud\bdo\bo accepts the following values for the
+       syslog facility (the value of the s\bsy\bys\bsl\blo\bog\bg Parameter): a\bau\but\bth\bhp\bpr\bri\biv\bv (if your
+       OS supports it), a\bau\but\bth\bh, d\bda\bae\bem\bmo\bon\bn, u\bus\bse\ber\br, l\blo\boc\bca\bal\bl0\b0, l\blo\boc\bca\bal\bl1\b1, l\blo\boc\bca\bal\bl2\b2, l\blo\boc\bca\bal\bl3\b3,
+       l\blo\boc\bca\bal\bl4\b4, l\blo\boc\bca\bal\bl5\b5, l\blo\boc\bca\bal\bl6\b6, and l\blo\boc\bca\bal\bl7\b7.  The following syslog priorities
+       are supported: a\bal\ble\ber\brt\bt, c\bcr\bri\bit\bt, d\bde\beb\bbu\bug\bg, e\bem\bme\ber\brg\bg, e\ber\brr\br, i\bin\bnf\bfo\bo, n\bno\bot\bti\bic\bce\be, and
+       w\bwa\bar\brn\bni\bin\bng\bg.
 
 F\bFI\bIL\bLE\bES\bS
        _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs            List of who can run what
@@ -1168,29 +1155,8 @@ F\bFI\bIL\bLE\bES\bS
        _\b/_\be_\bt_\bc_\b/_\bn_\be_\bt_\bg_\br_\bo_\bu_\bp           List of network groups
 
 E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
-       Since the _\bs_\bu_\bd_\bo_\be_\br_\bs file is parsed in a single pass, order
-       is important.  In general, you should structure _\bs_\bu_\bd_\bo_\be_\br_\bs
-       such that the Host_Alias, User_Alias, and Cmnd_Alias spec­
-       ifications come first, followed by any Default_Entry
-       lines, and finally the Runas_Alias and user specifica­
-       tions.  The basic rule of thumb is you cannot reference an
-       Alias that has not already been defined.
-
-       Below are example _\bs_\bu_\bd_\bo_\be_\br_\bs entries.  Admittedly, some of
-       these are a bit contrived.  First, we define our _\ba_\bl_\bi_\ba_\bs_\be_\bs:
-
-
-
-
-
-1.6.9p17                   Jun 21, 2008                        18
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
+       Below are example _\bs_\bu_\bd_\bo_\be_\br_\bs entries.  Admittedly, some of these are a bit
+       contrived.  First, we define our _\ba_\bl_\bi_\ba_\bs_\be_\bs:
 
         # User alias specification
         User_Alias     FULLTIMERS = millert, mikef, dowdy
@@ -1214,6 +1180,18 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
         # Cmnd alias specification
         Cmnd_Alias     DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\
                                /usr/sbin/restore, /usr/sbin/rrestore
+
+
+
+1.7.0                   December  3, 2008                      18
+
+
+
+
+
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
+
+
         Cmnd_Alias     KILL = /usr/bin/kill
         Cmnd_Alias     PRINTING = /usr/sbin/lpc, /usr/bin/lprm
         Cmnd_Alias     SHUTDOWN = /usr/sbin/shutdown
@@ -1225,17 +1203,15 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
         Cmnd_Alias     SU = /usr/bin/su
         Cmnd_Alias     PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less
 
-       Here we override some of the compiled in default values.
-       We want s\bsu\bud\bdo\bo to log via _\bs_\by_\bs_\bl_\bo_\bg(3) using the _\ba_\bu_\bt_\bh facility
-       in all cases.  We don't want to subject the full time
-       staff to the s\bsu\bud\bdo\bo lecture, user m\bmi\bil\bll\ble\ber\brt\bt need not give a
-       password, and we don't want to reset the LOGNAME, USER or
-       USERNAME environment variables when running commands as
-       root.  Additionally, on the machines in the _\bS_\bE_\bR_\bV_\bE_\bR_\bS
-       Host_Alias, we keep an additional local log file and make
-       sure we log the year in each log line since the log
-       entries will be kept around for several years.  Lastly, we
-       disable shell escapes for the commands in the PAGERS
+       Here we override some of the compiled in default values.  We want s\bsu\bud\bdo\bo
+       to log via _\bs_\by_\bs_\bl_\bo_\bg(3) using the _\ba_\bu_\bt_\bh facility in all cases.  We don't
+       want to subject the full time staff to the s\bsu\bud\bdo\bo lecture, user m\bmi\bil\bll\ble\ber\brt\bt
+       need not give a password, and we don't want to reset the LOGNAME, USER
+       or USERNAME environment variables when running commands as root.
+       Additionally, on the machines in the _\bS_\bE_\bR_\bV_\bE_\bR_\bS Host_Alias, we keep an
+       additional local log file and make sure we log the year in each log
+       line since the log entries will be kept around for several years.
+       Lastly, we disable shell escapes for the commands in the PAGERS
        Cmnd_Alias (_\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bm_\bo_\br_\be, _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bp_\bg and _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bl_\be_\bs_\bs).
 
         # Override built-in defaults
@@ -1246,121 +1222,116 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
         Defaults@SERVERS       log_year, logfile=/var/log/sudo.log
         Defaults!PAGERS        noexec
 
+       The _\bU_\bs_\be_\br _\bs_\bp_\be_\bc_\bi_\bf_\bi_\bc_\ba_\bt_\bi_\bo_\bn is the part that actually determines who may run
+       what.
 
+        root           ALL = (ALL) ALL
+        %wheel         ALL = (ALL) ALL
 
+       We let r\bro\boo\bot\bt and any user in group w\bwh\bhe\bee\bel\bl run any command on any host as
+       any user.
 
-1.6.9p17                   Jun 21, 2008                        19
+        FULLTIMERS     ALL = NOPASSWD: ALL
 
+       Full time sysadmins (m\bmi\bil\bll\ble\ber\brt\bt, m\bmi\bik\bke\bef\bf, and d\bdo\bow\bwd\bdy\by) may run any command on
+       any host without authenticating themselves.
 
+        PARTTIMERS     ALL = ALL
 
+       Part time sysadmins (b\bbo\bos\bst\btl\ble\bey\by, j\bjw\bwf\bfo\box\bx, and c\bcr\bra\baw\bwl\bl) may run any command on
+       any host but they must authenticate themselves first (since the entry
+       lacks the NOPASSWD tag).
 
+        jack           CSNETS = ALL
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
+       The user j\bja\bac\bck\bk may run any command on the machines in the _\bC_\bS_\bN_\bE_\bT_\bS alias
+       (the networks 128.138.243.0, 128.138.204.0, and 128.138.242.0).  Of
 
 
-       The _\bU_\bs_\be_\br _\bs_\bp_\be_\bc_\bi_\bf_\bi_\bc_\ba_\bt_\bi_\bo_\bn is the part that actually deter­
-       mines who may run what.
 
-        root           ALL = (ALL) ALL
-        %wheel         ALL = (ALL) ALL
+1.7.0                   December  3, 2008                      19
 
-       We let r\bro\boo\bot\bt and any user in group w\bwh\bhe\bee\bel\bl run any command on
-       any host as any user.
 
-        FULLTIMERS     ALL = NOPASSWD: ALL
 
-       Full time sysadmins (m\bmi\bil\bll\ble\ber\brt\bt, m\bmi\bik\bke\bef\bf, and d\bdo\bow\bwd\bdy\by) may run
-       any command on any host without authenticating themselves.
 
-        PARTTIMERS     ALL = ALL
 
-       Part time sysadmins (b\bbo\bos\bst\btl\ble\bey\by, j\bjw\bwf\bfo\box\bx, and c\bcr\bra\baw\bwl\bl) may run
-       any command on any host but they must authenticate them­
-       selves first (since the entry lacks the NOPASSWD tag).
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
-        jack           CSNETS = ALL
 
-       The user j\bja\bac\bck\bk may run any command on the machines in the
-       _\bC_\bS_\bN_\bE_\bT_\bS alias (the networks 128.138.243.0, 128.138.204.0,
-       and 128.138.242.0).  Of those networks, only 128.138.204.0
-       has an explicit netmask (in CIDR notation) indicating it
-       is a class C network.  For the other networks in _\bC_\bS_\bN_\bE_\bT_\bS,
-       the local machine's netmask will be used during matching.
+       those networks, only 128.138.204.0 has an explicit netmask (in CIDR
+       notation) indicating it is a class C network.  For the other networks
+       in _\bC_\bS_\bN_\bE_\bT_\bS, the local machine's netmask will be used during matching.
 
         lisa           CUNETS = ALL
 
-       The user l\bli\bis\bsa\ba may run any command on any host in the
-       _\bC_\bU_\bN_\bE_\bT_\bS alias (the class B network 128.138.0.0).
+       The user l\bli\bis\bsa\ba may run any command on any host in the _\bC_\bU_\bN_\bE_\bT_\bS alias (the
+       class B network 128.138.0.0).
 
         operator       ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\
                        sudoedit /etc/printcap, /usr/oper/bin/
 
-       The o\bop\bpe\ber\bra\bat\bto\bor\br user may run commands limited to simple main­
-       tenance.  Here, those are commands related to backups,
-       killing processes, the printing system, shutting down the
-       system, and any commands in the directory _\b/_\bu_\bs_\br_\b/_\bo_\bp_\be_\br_\b/_\bb_\bi_\bn_\b/.
+       The o\bop\bpe\ber\bra\bat\bto\bor\br user may run commands limited to simple maintenance.
+       Here, those are commands related to backups, killing processes, the
+       printing system, shutting down the system, and any commands in the
+       directory _\b/_\bu_\bs_\br_\b/_\bo_\bp_\be_\br_\b/_\bb_\bi_\bn_\b/.
 
         joe            ALL = /usr/bin/su operator
 
        The user j\bjo\boe\be may only _\bs_\bu(1) to operator.
 
-        pete           HPPA = /usr/bin/passwd [A-z]*, !/usr/bin/passwd root
+        pete           HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root
 
-       The user p\bpe\bet\bte\be is allowed to change anyone's password
-       except for root on the _\bH_\bP_\bP_\bA machines.  Note that this
-       assumes _\bp_\ba_\bs_\bs_\bw_\bd(1) does not take multiple usernames on the
-       command line.
+       The user p\bpe\bet\bte\be is allowed to change anyone's password except for root on
+       the _\bH_\bP_\bP_\bA machines.  Note that this assumes _\bp_\ba_\bs_\bs_\bw_\bd(1) does not take
+       multiple usernames on the command line.
 
         bob            SPARC = (OP) ALL : SGI = (OP) ALL
 
+       The user b\bbo\bob\bb may run anything on the _\bS_\bP_\bA_\bR_\bC and _\bS_\bG_\bI machines as any user
+       listed in the _\bO_\bP Runas_Alias (r\bro\boo\bot\bt and o\bop\bpe\ber\bra\bat\bto\bor\br).
 
+        jim            +biglab = ALL
 
-1.6.9p17                   Jun 21, 2008                        20
+       The user j\bji\bim\bm may run any command on machines in the _\bb_\bi_\bg_\bl_\ba_\bb netgroup.
+       s\bsu\bud\bdo\bo knows that "biglab" is a netgroup due to the '+' prefix.
 
+        +secretaries   ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser
 
+       Users in the s\bse\bec\bcr\bre\bet\bta\bar\bri\bie\bes\bs netgroup need to help manage the printers as
+       well as add and remove users, so they are allowed to run those commands
+       on all machines.
 
+        fred           ALL = (DB) NOPASSWD: ALL
 
+       The user f\bfr\bre\bed\bd can run commands as any user in the _\bD_\bB Runas_Alias
+       (o\bor\bra\bac\bcl\ble\be or s\bsy\byb\bba\bas\bse\be) without giving a password.
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
+        john           ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
 
+       On the _\bA_\bL_\bP_\bH_\bA machines, user j\bjo\boh\bhn\bn may su to anyone except root but he is
+       not allowed to specify any options to the _\bs_\bu(1) command.
 
-       The user b\bbo\bob\bb may run anything on the _\bS_\bP_\bA_\bR_\bC and _\bS_\bG_\bI
-       machines as any user listed in the _\bO_\bP Runas_Alias (r\bro\boo\bot\bt
-       and o\bop\bpe\ber\bra\bat\bto\bor\br).
+        jen            ALL, !SERVERS = ALL
 
-        jim            +biglab = ALL
 
-       The user j\bji\bim\bm may run any command on machines in the _\bb_\bi_\bg_\bl_\ba_\bb
-       netgroup.  s\bsu\bud\bdo\bo knows that "biglab" is a netgroup due to
-       the '+' prefix.
 
-        +secretaries   ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser
+1.7.0                   December  3, 2008                      20
 
-       Users in the s\bse\bec\bcr\bre\bet\bta\bar\bri\bie\bes\bs netgroup need to help manage the
-       printers as well as add and remove users, so they are
-       allowed to run those commands on all machines.
 
-        fred           ALL = (DB) NOPASSWD: ALL
 
-       The user f\bfr\bre\bed\bd can run commands as any user in the _\bD_\bB
-       Runas_Alias (o\bor\bra\bac\bcl\ble\be or s\bsy\byb\bba\bas\bse\be) without giving a password.
 
-        john           ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
 
-       On the _\bA_\bL_\bP_\bH_\bA machines, user j\bjo\boh\bhn\bn may su to anyone except
-       root but he is not allowed to give _\bs_\bu(1) any flags.
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
-        jen            ALL, !SERVERS = ALL
 
-       The user j\bje\ben\bn may run any command on any machine except for
-       those in the _\bS_\bE_\bR_\bV_\bE_\bR_\bS Host_Alias (master, mail, www and
-       ns).
+       The user j\bje\ben\bn may run any command on any machine except for those in the
+       _\bS_\bE_\bR_\bV_\bE_\bR_\bS Host_Alias (master, mail, www and ns).
 
         jill           SERVERS = /usr/bin/, !SU, !SHELLS
 
-       For any machine in the _\bS_\bE_\bR_\bV_\bE_\bR_\bS Host_Alias, j\bji\bil\bll\bl may run
-       any commands in the directory _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/ except for those
-       commands belonging to the _\bS_\band _\bS_\bH_\bE_\bL_\bL_\bS Cmnd_Aliases.
+       For any machine in the _\bS_\bE_\bR_\bV_\bE_\bR_\bS Host_Alias, j\bji\bil\bll\bl may run any commands in
+       the directory _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/ except for those commands belonging to the _\bS_\bU
+       and _\bS_\bH_\bE_\bL_\bL_\bS Cmnd_Aliases.
 
         steve          CSNETS = (operator) /usr/local/op_commands/
 
@@ -1369,85 +1340,48 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
         matt           valkyrie = KILL
 
-       On his personal workstation, valkyrie, m\bma\bat\btt\bt needs to be
-       able to kill hung processes.
+       On his personal workstation, valkyrie, m\bma\bat\btt\bt needs to be able to kill
+       hung processes.
 
         WEBMASTERS     www = (www) ALL, (root) /usr/bin/su www
 
-       On the host www, any user in the _\bW_\bE_\bB_\bM_\bA_\bS_\bT_\bE_\bR_\bS User_Alias
-       (will, wendy, and wim), may run any command as user www
-       (which owns the web pages) or simply _\bs_\bu(1) to www.
-
-
-
-
-1.6.9p17                   Jun 21, 2008                        21
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
+       On the host www, any user in the _\bW_\bE_\bB_\bM_\bA_\bS_\bT_\bE_\bR_\bS User_Alias (will, wendy,
+       and wim), may run any command as user www (which owns the web pages) or
+       simply _\bs_\bu(1) to www.
 
         ALL            CDROM = NOPASSWD: /sbin/umount /CDROM,\
                        /sbin/mount -o nosuid\,nodev /dev/cd0a /CDROM
 
-       Any user may mount or unmount a CD-ROM on the machines in
-       the CDROM Host_Alias (orion, perseus, hercules) without
-       entering a password.  This is a bit tedious for users to
-       type, so it is a prime candidate for encapsulating in a
-       shell script.
+       Any user may mount or unmount a CD-ROM on the machines in the CDROM
+       Host_Alias (orion, perseus, hercules) without entering a password.
+       This is a bit tedious for users to type, so it is a prime candidate for
+       encapsulating in a shell script.
 
 S\bSE\bEC\bCU\bUR\bRI\bIT\bTY\bY N\bNO\bOT\bTE\bES\bS
-       It is generally not effective to "subtract" commands from
-       ALL using the '!' operator.  A user can trivially circum­
-       vent this by copying the desired command to a different
-       name and then executing that.  For example:
+       It is generally not effective to "subtract" commands from ALL using the
+       '!' operator.  A user can trivially circumvent this by copying the
+       desired command to a different name and then executing that.  For
+       example:
 
            bill        ALL = ALL, !SU, !SHELLS
 
-       Doesn't really prevent b\bbi\bil\bll\bl from running the commands
-       listed in _\bS_\bU or _\bS_\bH_\bE_\bL_\bL_\bS since he can simply copy those com­
-       mands to a different name, or use a shell escape from an
-       editor or other program.  Therefore, these kind of
-       restrictions should be considered advisory at best (and
+       Doesn't really prevent b\bbi\bil\bll\bl from running the commands listed in _\bS_\bU or
+       _\bS_\bH_\bE_\bL_\bL_\bS since he can simply copy those commands to a different name, or
+       use a shell escape from an editor or other program.  Therefore, these
+       kind of restrictions should be considered advisory at best (and
        reinforced by policy).
 
 P\bPR\bRE\bEV\bVE\bEN\bNT\bTI\bIN\bNG\bG S\bSH\bHE\bEL\bLL\bL E\bES\bSC\bCA\bAP\bPE\bES\bS
-       Once s\bsu\bud\bdo\bo executes a program, that program is free to do
-       whatever it pleases, including run other programs.  This
-       can be a security issue since it is not uncommon for a
-       program to allow shell escapes, which lets a user bypass
-       s\bsu\bud\bdo\bo's access control and logging.  Common programs that
-       permit shell escapes include shells (obviously), editors,
+       Once s\bsu\bud\bdo\bo executes a program, that program is free to do whatever it
+       pleases, including run other programs.  This can be a security issue
+       since it is not uncommon for a program to allow shell escapes, which
+       lets a user bypass s\bsu\bud\bdo\bo's access control and logging.  Common programs
+       that permit shell escapes include shells (obviously), editors,
        paginators, mail and terminal programs.
 
-       There are two basic approaches to this problem:
-
-       restrict  Avoid giving users access to commands that allow
-                 the user to run arbitrary commands.  Many edi­
-                 tors have a restricted mode where shell escapes
-                 are disabled, though s\bsu\bud\bdo\boe\bed\bdi\bit\bt is a better solu­
-                 tion to running editors via s\bsu\bud\bdo\bo.  Due to the
-                 large number of programs that offer shell
-                 escapes, restricting users to the set of pro­
-                 grams that do not if often unworkable.
 
-       noexec    Many systems that support shared libraries have
-                 the ability to override default library func­
-                 tions by pointing an environment variable (usu­
-                 ally LD_PRELOAD) to an alternate shared library.
-                 On such systems, s\bsu\bud\bdo\bo's _\bn_\bo_\be_\bx_\be_\bc functionality can
-                 be used to prevent a program run by s\bsu\bud\bdo\bo from
-                 executing any other programs.  Note, however,
-                 that this applies only to native dynamically-
-                 linked executables.  Statically-linked executa­
-                 bles and foreign executables running under
 
-
-
-1.6.9p17                   Jun 21, 2008                        22
+1.7.0                   December  3, 2008                      21
 
 
 
@@ -1456,64 +1390,64 @@ P\bPR\bRE\bEV\bVE\bEN\bNT\bTI\bIN\bNG\bG S\bSH\bHE\bEL\bLL\bL E\bES\bSC\bCA\bAP\bPE\bES\bS
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-                 binary emulation are not affected.
+       There are two basic approaches to this problem:
 
-                 To tell whether or not s\bsu\bud\bdo\bo supports _\bn_\bo_\be_\bx_\be_\bc, you
-                 can run the following as root:
+       restrict  Avoid giving users access to commands that allow the user to
+                 run arbitrary commands.  Many editors have a restricted mode
+                 where shell escapes are disabled, though s\bsu\bud\bdo\boe\bed\bdi\bit\bt is a better
+                 solution to running editors via s\bsu\bud\bdo\bo.  Due to the large
+                 number of programs that offer shell escapes, restricting
+                 users to the set of programs that do not if often unworkable.
+
+       noexec    Many systems that support shared libraries have the ability
+                 to override default library functions by pointing an
+                 environment variable (usually LD_PRELOAD) to an alternate
+                 shared library.  On such systems, s\bsu\bud\bdo\bo's _\bn_\bo_\be_\bx_\be_\bc functionality
+                 can be used to prevent a program run by s\bsu\bud\bdo\bo from executing
+                 any other programs.  Note, however, that this applies only to
+                 native dynamically-linked executables.  Statically-linked
+                 executables and foreign executables running under binary
+                 emulation are not affected.
+
+                 To tell whether or not s\bsu\bud\bdo\bo supports _\bn_\bo_\be_\bx_\be_\bc, you can run the
+                 following as root:
 
                      sudo -V | grep "dummy exec"
 
-                 If the resulting output contains a line that
-                 begins with:
+                 If the resulting output contains a line that begins with:
 
                      File containing dummy exec functions:
 
-                 then s\bsu\bud\bdo\bo may be able to replace the exec family
-                 of functions in the standard library with its
-                 own that simply return an error.  Unfortunately,
-                 there is no foolproof way to know whether or not
-                 _\bn_\bo_\be_\bx_\be_\bc will work at compile-time.  _\bn_\bo_\be_\bx_\be_\bc should
-                 work on SunOS, Solaris, *BSD, Linux, IRIX, Tru64
-                 UNIX, MacOS X, and HP-UX 11.x.  It is known n\bno\bot\bt
-                 to work on AIX and UnixWare.  _\bn_\bo_\be_\bx_\be_\bc is expected
-                 to work on most operating systems that support
-                 the LD_PRELOAD environment variable.  Check your
-                 operating system's manual pages for the dynamic
-                 linker (usually ld.so, ld.so.1, dyld, dld.sl,
-                 rld, or loader) to see if LD_PRELOAD is sup­
-                 ported.
-
-                 To enable _\bn_\bo_\be_\bx_\be_\bc for a command, use the NOEXEC
-                 tag as documented in the User Specification sec­
-                 tion above.  Here is that example again:
+                 then s\bsu\bud\bdo\bo may be able to replace the exec family of functions
+                 in the standard library with its own that simply return an
+                 error.  Unfortunately, there is no foolproof way to know
+                 whether or not _\bn_\bo_\be_\bx_\be_\bc will work at compile-time.  _\bn_\bo_\be_\bx_\be_\bc
+                 should work on SunOS, Solaris, *BSD, Linux, IRIX, Tru64 UNIX,
+                 MacOS X, and HP-UX 11.x.  It is known n\bno\bot\bt to work on AIX and
+                 UnixWare.  _\bn_\bo_\be_\bx_\be_\bc is expected to work on most operating
+                 systems that support the LD_PRELOAD environment variable.
+                 Check your operating system's manual pages for the dynamic
+                 linker (usually ld.so, ld.so.1, dyld, dld.sl, rld, or loader)
+                 to see if LD_PRELOAD is supported.
+
+                 To enable _\bn_\bo_\be_\bx_\be_\bc for a command, use the NOEXEC tag as
+                 documented in the User Specification section above.  Here is
+                 that example again:
 
                   aaron  shanty = NOEXEC: /usr/bin/more, /usr/bin/vi
 
-                 This allows user a\baa\bar\bro\bon\bn to run _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bm_\bo_\br_\be and
-                 _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bv_\bi with _\bn_\bo_\be_\bx_\be_\bc enabled.  This will pre­
-                 vent those two commands from executing other
-                 commands (such as a shell).  If you are unsure
-                 whether or not your system is capable of sup­
-                 porting _\bn_\bo_\be_\bx_\be_\bc you can always just try it out
-                 and see if it works.
-
-       Note that restricting shell escapes is not a panacea.
-       Programs running as root are still capable of many poten­
-       tially hazardous operations (such as changing or overwrit­
-       ing files) that could lead to unintended privilege escala­
-       tion.  In the specific case of an editor, a safer approach
-       is to give the user permission to run s\bsu\bud\bdo\boe\bed\bdi\bit\bt.
+                 This allows user a\baa\bar\bro\bon\bn to run _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bm_\bo_\br_\be and _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bv_\bi
+                 with _\bn_\bo_\be_\bx_\be_\bc enabled.  This will prevent those two commands
+                 from executing other commands (such as a shell).  If you are
+                 unsure whether or not your system is capable of supporting
+                 _\bn_\bo_\be_\bx_\be_\bc you can always just try it out and see if it works.
 
-S\bSE\bEE\bE A\bAL\bLS\bSO\bO
-       _\br_\bs_\bh(1), _\bs_\bu(1), _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3), _\bs_\bu_\bd_\bo(1m), _\bv_\bi_\bs_\bu_\bd_\bo(8)
+       Note that restricting shell escapes is not a panacea.  Programs running
+       as root are still capable of many potentially hazardous operations
 
-C\bCA\bAV\bVE\bEA\bAT\bTS\bS
-       The _\bs_\bu_\bd_\bo_\be_\br_\bs file should a\bal\blw\bwa\bay\bys\bs be edited by the v\bvi\bis\bsu\bud\bdo\bo
-       command which locks the file and does grammatical
 
 
-
-1.6.9p17                   Jun 21, 2008                        23
+1.7.0                   December  3, 2008                      22
 
 
 
@@ -1522,39 +1456,39 @@ C\bCA\bAV\bVE\bEA\bAT\bTS\bS
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-       checking. It is imperative that _\bs_\bu_\bd_\bo_\be_\br_\bs be free of syntax
-       errors since s\bsu\bud\bdo\bo will not run with a syntactically incor­
-       rect _\bs_\bu_\bd_\bo_\be_\br_\bs file.
+       (such as changing or overwriting files) that could lead to unintended
+       privilege escalation.  In the specific case of an editor, a safer
+       approach is to give the user permission to run s\bsu\bud\bdo\boe\bed\bdi\bit\bt.
+
+S\bSE\bEE\bE A\bAL\bLS\bSO\bO
+       _\br_\bs_\bh(1), _\bs_\bu(1), _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3), _\bs_\bu_\bd_\bo(1m), _\bv_\bi_\bs_\bu_\bd_\bo(8)
+
+C\bCA\bAV\bVE\bEA\bAT\bTS\bS
+       The _\bs_\bu_\bd_\bo_\be_\br_\bs file should a\bal\blw\bwa\bay\bys\bs be edited by the v\bvi\bis\bsu\bud\bdo\bo command which
+       locks the file and does grammatical checking. It is imperative that
+       _\bs_\bu_\bd_\bo_\be_\br_\bs be free of syntax errors since s\bsu\bud\bdo\bo will not run with a
+       syntactically incorrect _\bs_\bu_\bd_\bo_\be_\br_\bs file.
 
-       When using netgroups of machines (as opposed to users), if
-       you store fully qualified hostnames in the netgroup (as is
-       usually the case), you either need to have the machine's
-       hostname be fully qualified as returned by the hostname
-       command or use the _\bf_\bq_\bd_\bn option in _\bs_\bu_\bd_\bo_\be_\br_\bs.
+       When using netgroups of machines (as opposed to users), if you store
+       fully qualified hostnames in the netgroup (as is usually the case), you
+       either need to have the machine's hostname be fully qualified as
+       returned by the hostname command or use the _\bf_\bq_\bd_\bn option in _\bs_\bu_\bd_\bo_\be_\br_\bs.
 
 B\bBU\bUG\bGS\bS
-       If you feel you have found a bug in s\bsu\bud\bdo\bo, please submit a
-       bug report at http://www.sudo.ws/sudo/bugs/
+       If you feel you have found a bug in s\bsu\bud\bdo\bo, please submit a bug report at
+       http://www.sudo.ws/sudo/bugs/
 
 S\bSU\bUP\bPP\bPO\bOR\bRT\bT
-       Limited free support is available via the sudo-users mail­
-       ing list, see http://www.sudo.ws/mail­
-       man/listinfo/sudo-users to subscribe or search the
-       archives.
+       Limited free support is available via the sudo-users mailing list, see
+       http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search
+       the archives.
 
 D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
-       s\bsu\bud\bdo\bo is provided ``AS IS'' and any express or implied war­
-       ranties, including, but not limited to, the implied war­
-       ranties of merchantability and fitness for a particular
-       purpose are disclaimed.  See the LICENSE file distributed
-       with s\bsu\bud\bdo\bo or http://www.sudo.ws/sudo/license.html for com­
-       plete details.
-
-
-
-
-
-
+       s\bsu\bud\bdo\bo 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.
+       See the LICENSE file distributed with s\bsu\bud\bdo\bo or
+       http://www.sudo.ws/sudo/license.html for complete details.
 
 
 
@@ -1579,6 +1513,6 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
 
 
 
-1.6.9p17                   Jun 21, 2008                        24
+1.7.0                   December  3, 2008                      23
 
 
diff --git a/sudoers.ldap.cat b/sudoers.ldap.cat
new file mode 100644 (file)
index 0000000..8b581ff
--- /dev/null
@@ -0,0 +1,792 @@
+
+
+
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
+
+
+N\bNA\bAM\bME\bE
+       sudoers.ldap - sudo LDAP configuration
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+       In addition to the standard _\bs_\bu_\bd_\bo_\be_\br_\bs file, s\bsu\bud\bdo\bo may be configured via
+       LAP.  This can be especially useful for synchronizing _\bs_\bu_\bd_\bo_\be_\br_\bs in a
+       large, distributed environment.
+
+       Using LDAP for _\bs_\bu_\bd_\bo_\be_\br_\bs has several benefits:
+
+       +\bo   s\bsu\bud\bdo\bo no longer needs to read _\bs_\bu_\bd_\bo_\be_\br_\bs in its entirety.  When LDAP is
+           used, there are only two or three LDAP queries per invocation.
+           This makes it especially fast and particularly usable in LDAP
+           environments.
+
+       +\bo   s\bsu\bud\bdo\bo no longer exits if there is a typo in _\bs_\bu_\bd_\bo_\be_\br_\bs.  It is not
+           possible to load LDAP data into the server that does not conform to
+           the sudoers schema, so proper syntax is guaranteed.  It is still
+           possible to have typos in a user or host name, but this will not
+           prevent s\bsu\bud\bdo\bo from running.
+
+       +\bo   It is possible to specify per-entry options that override the
+           global default options.  _\b@_\bs_\by_\bs_\bc_\bo_\bn_\bf_\bd_\bi_\br_\b@_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs only supports default
+           options and limited options associated with
+           user/host/commands/aliases.  The syntax is complicated and can be
+           difficult for users to understand.  Placing the options directly in
+           the entry is more natural.
+
+       +\bo   The v\bvi\bis\bsu\bud\bdo\bo program is no longer needed.  v\bvi\bis\bsu\bud\bdo\bo provides locking
+           and syntax checking of the _\b@_\bs_\by_\bs_\bc_\bo_\bn_\bf_\bd_\bi_\br_\b@_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs file.  Since LDAP
+           updates are atomic, locking is no longer necessary.  Because syntax
+           is checked when the data is inserted into LDAP, there is no need
+           for a specialized tool to check syntax.
+
+       Another major difference between LDAP and file-based _\bs_\bu_\bd_\bo_\be_\br_\bs is that in
+       LDAP, s\bsu\bud\bdo\bo-specific Aliases are not supported.
+
+       For the most part, there is really no need for s\bsu\bud\bdo\bo-specific Aliases.
+       Unix groups or user netgroups can be used in place of User_Aliases and
+       RunasAliases.  Host netgroups can be used in place of HostAliases.
+       Since Unix groups and netgroups can also be stored in LDAP there is no
+       real need for s\bsu\bud\bdo\bo-specific aliases.
+
+       Cmnd_Aliases are not really required either since it is possible to
+       have multiple users listed in a sudoRole.  Instead of defining a
+       Cmnd_Alias that is referenced by multiple users, one can create a
+       sudoRole that contains the commands and assign multiple users to it.
+
+       S\bSU\bUD\bDO\bOe\ber\brs\bs L\bLD\bDA\bAP\bP c\bco\bon\bnt\bta\bai\bin\bne\ber\br
+
+       The _\bs_\bu_\bd_\bo_\be_\br_\bs configuration is contained in the ou=SUDOers LDAP
+       container.
+
+       Sudo first looks for the cn=default entry in the SUDOers container.  If
+
+
+
+1.7.0                    October 24, 2008                       1
+
+
+
+
+
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
+
+
+       found, the multi-valued sudoOption attribute is parsed in the same
+       manner as a global Defaults line in _\b@_\bs_\by_\bs_\bc_\bo_\bn_\bf_\bd_\bi_\br_\b@_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs.  In the
+       following example, the SSH_AUTH_SOCK variable will be preserved in the
+       environment for all users.
+
+           dn: cn=defaults,ou=SUDOers,dc=example,dc=com
+           objectClass: top
+           objectClass: sudoRole
+           cn: defaults
+           description: Default sudoOption's go here
+           sudoOption: env_keep+=SSH_AUTH_SOCK
+
+       The equivalent of a sudoer in LDAP is a sudoRole.  It consists of the
+       following components:
+
+       s\bsu\bud\bdo\boU\bUs\bse\ber\br
+           A user name, uid (prefixed with '#'), Unix group (prefixed with a
+           '%') or user netgroup (prefixed with a '+').
+
+       s\bsu\bud\bdo\boH\bHo\bos\bst\bt
+           A host name, IP address, IP network, or host netgroup (prefixed
+           with a '+').  The special value ALL will match any host.
+
+       s\bsu\bud\bdo\boC\bCo\bom\bmm\bma\ban\bnd\bd
+           A Unix command with optional command line arguments, potentially
+           including globbing characters (aka wild cards).  The special value
+           ALL will match any command.  If a command is prefixed with an
+           exclamation point '!', the user will be prohibited from running
+           that command.
+
+       s\bsu\bud\bdo\boO\bOp\bpt\bti\bio\bon\bn
+           Identical in function to the global options described above, but
+           specific to the sudoRole in which it resides.
+
+       s\bsu\bud\bdo\boR\bRu\bun\bnA\bAs\bsU\bUs\bse\ber\br
+           A user name or uid (prefixed with '#') that commands may be run as
+           or a Unix group (prefixed with a '%') or user netgroup (prefixed
+           with a '+') that contains a list of users that commands may be run
+           as.  The special value ALL will match any user.
+
+       s\bsu\bud\bdo\boR\bRu\bun\bnA\bAs\bsG\bGr\bro\bou\bup\bp
+           A Unix group or gid (prefixed with '#') that commands may be run
+           as.  The special value ALL will match any group.
+
+       Each component listed above should contain a single value, but there
+       may be multiple instances of each component type.  A sudoRole must
+       contain at least one sudoUser, sudoHost and sudoCommand.
+
+       The following example allows users in group wheel to run any command on
+       any host via s\bsu\bud\bdo\bo:
+
+
+
+
+
+
+
+1.7.0                    October 24, 2008                       2
+
+
+
+
+
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
+
+
+           dn: cn=%wheel,ou=SUDOers,dc=example,dc=com
+           objectClass: top
+           objectClass: sudoRole
+           cn: %wheel
+           sudoUser: %wheel
+           sudoHost: ALL
+           sudoCommand: ALL
+
+       A\bAn\bna\bat\bto\bom\bmy\by o\bof\bf L\bLD\bDA\bAP\bP s\bsu\bud\bdo\boe\ber\brs\bs l\blo\boo\bok\bku\bup\bp
+
+       When looking up a sudoer using LDAP there are only two or three LDAP
+       queries per invocation.  The first query is to parse the global
+       options.  The second is to match against the user's name and the groups
+       that the user belongs to.  (The special ALL tag is matched in this
+       query too.)  If no match is returned for the user's name and groups, a
+       third query returns all entries containing user netgroups and checks to
+       see if the user belongs to any of them.
+
+       D\bDi\bif\bff\bfe\ber\bre\ben\bnc\bce\bes\bs b\bbe\bet\btw\bwe\bee\ben\bn L\bLD\bDA\bAP\bP a\ban\bnd\bd n\bno\bon\bn-\b-L\bLD\bDA\bAP\bP s\bsu\bud\bdo\boe\ber\brs\bs
+
+       There are some subtle differences in the way sudoers is handled once in
+       LDAP.  Probably the biggest is that according to the RFC, LDAP ordering
+       is arbitrary and you cannot expect that Attributes and Entries are
+       returned in any specific order.  If there are conflicting command rules
+       on an entry, the negative takes precedence.  This is called paranoid
+       behavior (not necessarily the most specific match).
+
+       Here is an example:
+
+           # /etc/sudoers:
+           # Allow all commands except shell
+           johnny  ALL=(root) ALL,!/bin/sh
+           # Always allows all commands because ALL is matched last
+           puddles ALL=(root) !/bin/sh,ALL
+
+           # LDAP equivalent of johnny
+           # Allows all commands except shell
+           dn: cn=role1,ou=Sudoers,dc=my-domain,dc=com
+           objectClass: sudoRole
+           objectClass: top
+           cn: role1
+           sudoUser: johnny
+           sudoHost: ALL
+           sudoCommand: ALL
+           sudoCommand: !/bin/sh
+
+           # LDAP equivalent of puddles
+           # Notice that even though ALL comes last, it still behaves like
+           # role1 since the LDAP code assumes the more paranoid configuration
+           dn: cn=role2,ou=Sudoers,dc=my-domain,dc=com
+           objectClass: sudoRole
+           objectClass: top
+           cn: role2
+           sudoUser: puddles
+
+
+
+1.7.0                    October 24, 2008                       3
+
+
+
+
+
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
+
+
+           sudoHost: ALL
+           sudoCommand: !/bin/sh
+           sudoCommand: ALL
+
+       Another difference is that negations on the Host, User or Runas are
+       currently ignorred.  For example, the following attributes do not
+       behave the way one might expect.
+
+           # does not match all but joe
+           # rather, does not match anyone
+           sudoUser: !joe
+
+           # does not match all but joe
+           # rather, matches everyone including Joe
+           sudoUser: ALL
+           sudoUser: !joe
+
+           # does not match all but web01
+           # rather, matches all hosts including web01
+           sudoHost: ALL
+           sudoHost: !web01
+
+       S\bSu\bud\bdo\boe\ber\brs\bs S\bSc\bch\bhe\bem\bma\ba
+
+       In order to use s\bsu\bud\bdo\bo's LDAP support, the s\bsu\bud\bdo\bo schema must be installed
+       on your LDAP server.  In addition, be sure to index the 'sudoUser'
+       attribute.
+
+       Three versions of the schema: one for OpenLDAP servers
+       (_\bs_\bc_\bh_\be_\bm_\ba_\b._\bO_\bp_\be_\bn_\bL_\bD_\bA_\bP), one for Netscape-derived servers (_\bs_\bc_\bh_\be_\bm_\ba_\b._\bi_\bP_\bl_\ba_\bn_\be_\bt),
+       and one for Microsoft Active Directory (_\bs_\bc_\bh_\be_\bm_\ba_\b._\bA_\bc_\bt_\bi_\bv_\be_\bD_\bi_\br_\be_\bc_\bt_\bo_\br_\by) may be
+       found in the s\bsu\bud\bdo\bo distribution.
+
+       The schema for s\bsu\bud\bdo\bo in OpenLDAP form is included in the EXAMPLES
+       section.
+
+       C\bCo\bon\bnf\bfi\big\bgu\bur\bri\bin\bng\bg l\bld\bda\bap\bp.\b.c\bco\bon\bnf\bf
+
+       Sudo reads the _\b@_\bl_\bd_\ba_\bp_\b__\bc_\bo_\bn_\bf_\b@ file for LDAP-specific configuration.
+       Typically, this file is shared amongst different LDAP-aware clients.
+       As such, most of the settings are not s\bsu\bud\bdo\bo-specific.  Note that s\bsu\bud\bdo\bo
+       parses _\b@_\bl_\bd_\ba_\bp_\b__\bc_\bo_\bn_\bf_\b@ itself and may support options that differ from
+       those described in the _\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf(4) manual.
+
+       Also note that on systems using the OpenLDAP libraries, default values
+       specified in _\b/_\be_\bt_\bc_\b/_\bo_\bp_\be_\bn_\bl_\bd_\ba_\bp_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf or the user's _\b._\bl_\bd_\ba_\bp_\br_\bc files are
+       not used.
+
+       Only those options explicitly listed in _\b@_\bl_\bd_\ba_\bp_\b__\bc_\bo_\bn_\bf_\b@ that are supported
+       by s\bsu\bud\bdo\bo are honored.  Configuration options are listed below in upper
+       case but are parsed in a case-independent manner.
+
+       U\bUR\bRI\bI ldap[s]://[hostname[:port]] ...
+           Specifies a whitespace-delimited list of one or more URIs
+
+
+
+1.7.0                    October 24, 2008                       4
+
+
+
+
+
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
+
+
+           describing the LDAP server(s) to connect to.  The _\bp_\br_\bo_\bt_\bo_\bc_\bo_\bl may be
+           either l\bld\bda\bap\bp or l\bld\bda\bap\bps\bs, the latter being for servers that support TLS
+           (SSL) encryption.  If no _\bp_\bo_\br_\bt is specified, the default is port 389
+           for ldap:// or port 636 for ldaps://.  If no _\bh_\bo_\bs_\bt_\bn_\ba_\bm_\be is specified,
+           s\bsu\bud\bdo\bo will connect to l\blo\boc\bca\bal\blh\bho\bos\bst\bt.  Only systems using the OpenSSL
+           libraries support the mixing of ldap:// and ldaps:// URIs.  The
+           Netscape-derived libraries used on most commercial versions of Unix
+           are only capable of supporting one or the other.
+
+       H\bHO\bOS\bST\bT name[:port] ...
+           If no U\bUR\bRI\bI is specified, the H\bHO\bOS\bST\bT parameter specifies a whitespace-
+           delimited list of LDAP servers to connect to.  Each host may
+           include an optional _\bp_\bo_\br_\bt separated by a colon (':').  The H\bHO\bOS\bST\bT
+           parameter is deprecated in favor of the U\bUR\bRI\bI specification and is
+           included for backwards compatibility.
+
+       P\bPO\bOR\bRT\bT port_number
+           If no U\bUR\bRI\bI is specified, the P\bPO\bOR\bRT\bT parameter specifies the default
+           port to connect to on the LDAP server if a H\bHO\bOS\bST\bT parameter does not
+           specify the port itself.  If no P\bPO\bOR\bRT\bT parameter is used, the default
+           is port 389 for LDAP and port 636 for LDAP over TLS (SSL).  The
+           P\bPO\bOR\bRT\bT parameter is deprecated in favor of the U\bUR\bRI\bI specification and
+           is included for backwards compatibility.
+
+       B\bBI\bIN\bND\bD_\b_T\bTI\bIM\bME\bEL\bLI\bIM\bMI\bIT\bT seconds
+           The B\bBI\bIN\bND\bD_\b_T\bTI\bIM\bME\bEL\bLI\bIM\bMI\bIT\bT parameter specifies the amount of time, in
+           seconds, to wait while trying to connect to an LDAP server.  If
+           multiple U\bUR\bRI\bIs or H\bHO\bOS\bST\bTs are specified, this is the amount of time to
+           wait before trying the next one in the list.
+
+       T\bTI\bIM\bME\bEL\bLI\bIM\bMI\bIT\bT seconds
+           The T\bTI\bIM\bME\bEL\bLI\bIM\bMI\bIT\bT parameter specifies the amount of time, in seconds,
+           to wait for a response to an LDAP query.
+
+       S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_B\bBA\bAS\bSE\bE base
+           The base DN to use when performing s\bsu\bud\bdo\bo LDAP queries.  Typically
+           this is of the form ou=SUDOers,dc=example,dc=com for the domain
+           example.com.
+
+       S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_D\bDE\bEB\bBU\bUG\bG debug_level
+           This sets the debug level for s\bsu\bud\bdo\bo LDAP queries.  Debugging
+           information is printed to the standard error.  A value of 1 results
+           in a moderate amount of debugging information.  A value of 2 shows
+           the results of the matches themselves.  This parameter should not
+           be set in a production environment as the extra information is
+           likely to confuse users.
+
+       B\bBI\bIN\bND\bDD\bDN\bN DN
+           The B\bBI\bIN\bND\bDD\bDN\bN parameter specifies the identity, in the form of a
+           Distinguished Name (DN), to use when performing LDAP operations.
+           If not specified, LDAP operations are performed with an anonymous
+           identity.  By default, most LDAP servers will allow anonymous
+           access.
+
+
+
+
+1.7.0                    October 24, 2008                       5
+
+
+
+
+
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
+
+
+       B\bBI\bIN\bND\bDP\bPW\bW secret
+           The B\bBI\bIN\bND\bDP\bPW\bW parameter specifies the password to use when performing
+           LDAP operations.  This is typically used in conjunction with the
+           B\bBI\bIN\bND\bDD\bDN\bN parameter.
+
+       R\bRO\bOO\bOT\bTB\bBI\bIN\bND\bDD\bDN\bN DN
+           The R\bRO\bOO\bOT\bTB\bBI\bIN\bND\bDD\bDN\bN parameter specifies the identity, in the form of a
+           Distinguished Name (DN), to use when performing privileged LDAP
+           operations, such as _\bs_\bu_\bd_\bo_\be_\br_\bs queries.  The password corresponding to
+           the identity should be stored in _\b@_\bl_\bd_\ba_\bp_\b__\bs_\be_\bc_\br_\be_\bt_\b@.  If not specified,
+           the B\bBI\bIN\bND\bDD\bDN\bN identity is used (if any).
+
+       L\bLD\bDA\bAP\bP_\b_V\bVE\bER\bRS\bSI\bIO\bON\bN number
+           The version of the LDAP protocol to use when connecting to the
+           server.  The default value is protocol version 3.
+
+       S\bSS\bSL\bL on/true/yes/off/false/no
+           If the S\bSS\bSL\bL parameter is set to on, true or yes, TLS (SSL)
+           encryption is always used when communicating with the LDAP server.
+           Typically, this involves connecting to the server on port 636
+           (ldaps).
+
+       S\bSS\bSL\bL start_tls
+           If the S\bSS\bSL\bL parameter is set to start_tls, the LDAP server
+           connection is initiated normally and TLS encryption is begun before
+           the bind credentials are sent.  This has the advantage of not
+           requiring a dedicated port for encrypted communications.  This
+           parameter is only supported by LDAP servers that honor the
+           start_tls extension, such as the OpenLDAP server.
+
+       T\bTL\bLS\bS_\b_C\bCH\bHE\bEC\bCK\bKP\bPE\bEE\bER\bR on/true/yes/off/false/no
+           If enabled, T\bTL\bLS\bS_\b_C\bCH\bHE\bEC\bCK\bKP\bPE\bEE\bER\bR will cause the LDAP server's TLS
+           certificated to be verified.  If the server's TLS certificate
+           cannot be verified (usually because it is signed by an unknown
+           certificate authority), s\bsu\bud\bdo\bo will be unable to connect to it.  If
+           T\bTL\bLS\bS_\b_C\bCH\bHE\bEC\bCK\bKP\bPE\bEE\bER\bR is disabled, no check is made.
+
+       T\bTL\bLS\bS_\b_C\bCA\bAC\bCE\bER\bRT\bTF\bFI\bIL\bLE\bE file name
+           The path to a certificate authority bundle which contains the
+           certificates for all the Certificate Authorities the client knows
+           to be valid, e.g. _\b/_\be_\bt_\bc_\b/_\bs_\bs_\bl_\b/_\bc_\ba_\b-_\bb_\bu_\bn_\bd_\bl_\be_\b._\bp_\be_\bm.  This option is only
+           supported by the OpenLDAP libraries.
+
+       T\bTL\bLS\bS_\b_C\bCA\bAC\bCE\bER\bRT\bTD\bDI\bIR\bR directory
+           Similar to T\bTL\bLS\bS_\b_C\bCA\bAC\bCE\bER\bRT\bTF\bFI\bIL\bLE\bE but instead of a file, it is a directory
+           containing individual Certificate Authority certificates, e.g.
+           _\b/_\be_\bt_\bc_\b/_\bs_\bs_\bl_\b/_\bc_\be_\br_\bt_\bs.  The directory specified by T\bTL\bLS\bS_\b_C\bCA\bAC\bCE\bER\bRT\bTD\bDI\bIR\bR is
+           checked after T\bTL\bLS\bS_\b_C\bCA\bAC\bCE\bER\bRT\bTF\bFI\bIL\bLE\bE.  This option is only supported by the
+           OpenLDAP libraries.
+
+       T\bTL\bLS\bS_\b_C\bCE\bER\bRT\bT file name
+           The path to a file containing the client certificate which can be
+           used to authenticate the client to the LDAP server.  The
+           certificate type depends on the LDAP libraries used.
+
+
+
+1.7.0                    October 24, 2008                       6
+
+
+
+
+
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
+
+
+           OpenLDAP:
+               tls_cert /etc/ssl/client_cert.pem
+
+           Netscape-derived:
+               tls_cert /var/ldap/cert7.db
+
+           When using Netscape-derived libraries, this file may also contain
+           Certificate Authority certificates.
+
+       T\bTL\bLS\bS_\b_K\bKE\bEY\bY file name
+           The path to a file containing the private key which matches the
+           certificate specified by T\bTL\bLS\bS_\b_C\bCE\bER\bRT\bT.  The private key must not be
+           password-protected.  The key type depends on the LDAP libraries
+           used.
+
+           OpenLDAP:
+               tls_key /etc/ssl/client_key.pem
+
+           Netscape-derived:
+               tls_key /var/ldap/key3.db
+
+       T\bTL\bLS\bS_\b_R\bRA\bAN\bND\bDF\bFI\bIL\bLE\bE file name
+           The T\bTL\bLS\bS_\b_R\bRA\bAN\bND\bDF\bFI\bIL\bLE\bE parameter specifies the path to an entropy source
+           for systems that lack a random device.  It is generally used in
+           conjunction with _\bp_\br_\bn_\bg_\bd or _\be_\bg_\bd.  This option is only supported by
+           the OpenLDAP libraries.
+
+       T\bTL\bLS\bS_\b_C\bCI\bIP\bPH\bHE\bER\bRS\bS cipher list
+           The T\bTL\bLS\bS_\b_C\bCI\bIP\bPH\bHE\bER\bRS\bS parameter allows the administer to restrict which
+           encryption algorithms may be used for TLS (SSL) connections.  See
+           the OpenSSL manual for a list of valid ciphers.  This option is
+           only supported by the OpenLDAP libraries.
+
+       U\bUS\bSE\bE_\b_S\bSA\bAS\bSL\bL on/true/yes/off/false/no
+           Enable U\bUS\bSE\bE_\b_S\bSA\bAS\bSL\bL for LDAP servers that support SASL authentication.
+
+       S\bSA\bAS\bSL\bL_\b_A\bAU\bUT\bTH\bH_\b_I\bID\bD identity
+           The SASL user name to use when connecting to the LDAP server.  By
+           default, s\bsu\bud\bdo\bo will use an anonymous connection.
+
+       R\bRO\bOO\bOT\bTU\bUS\bSE\bE_\b_S\bSA\bAS\bSL\bL on/true/yes/off/false/no
+           Enable R\bRO\bOO\bOT\bTU\bUS\bSE\bE_\b_S\bSA\bAS\bSL\bL to enable SASL authentication when connecting
+           to an LDAP server from a privileged process, such as s\bsu\bud\bdo\bo.
+
+       R\bRO\bOO\bOT\bTS\bSA\bAS\bSL\bL_\b_A\bAU\bUT\bTH\bH_\b_I\bID\bD identity
+           The SASL user name to use when R\bRO\bOO\bOT\bTU\bUS\bSE\bE_\b_S\bSA\bAS\bSL\bL is enabled.
+
+       S\bSA\bAS\bSL\bL_\b_S\bSE\bEC\bCP\bPR\bRO\bOP\bPS\bS none/properties
+           SASL security properties or _\bn_\bo_\bn_\be for no properties.  See the SASL
+           programmer's manual for details.
+
+       K\bKR\bRB\bB5\b5_\b_C\bCC\bCN\bNA\bAM\bME\bE file name
+           The path to the Kerberos 5 credential cache to use when
+           authenticating with the remote server.
+
+
+
+1.7.0                    October 24, 2008                       7
+
+
+
+
+
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
+
+
+       See the ldap.conf entry in the EXAMPLES section.
+
+       C\bCo\bon\bnf\bfi\big\bgu\bur\bri\bin\bng\bg n\bns\bss\bsw\bwi\bit\btc\bch\bh.\b.c\bco\bon\bnf\bf
+
+       Unless it is disabled at build time, s\bsu\bud\bdo\bo consults the Name Service
+       Switch file, _\b@_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b__\bc_\bo_\bn_\bf_\b@, to specify the _\bs_\bu_\bd_\bo_\be_\br_\bs search order.
+       Sudo looks for a line beginning with sudoers: and uses this to
+       determine the search order.  Note that s\bsu\bud\bdo\bo does not stop searching
+       after the first match and later matches take precedence over earlier
+       ones.
+
+       The following sources are recognized:
+
+           files       read sudoers from F</etc/sudoers>
+           ldap        read sudoers from LDAP
+
+       In addition, the entry [NOTFOUND=return] will short-circuit the search
+       if the user was not found in the preceding source.
+
+       To consult LDAP first followed by the local sudoers file (if it
+       exists), use:
+
+           sudoers: ldap files
+
+       The local _\bs_\bu_\bd_\bo_\be_\br_\bs file can be ignored completely by using:
+
+           sudoers: ldap
+
+       If the _\b@_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b__\bc_\bo_\bn_\bf_\b@ file is not present or there is no sudoers line,
+       the following default is assumed:
+
+           sudoers: files
+
+       Note that _\b@_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b__\bc_\bo_\bn_\bf_\b@ is supported even when the underlying
+       operating system does not use an nsswitch.conf file.
+
+F\bFI\bIL\bLE\bES\bS
+       _\b@_\bl_\bd_\ba_\bp_\b__\bc_\bo_\bn_\bf_\b@             LDAP configuration file
+
+       _\b@_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b__\bc_\bo_\bn_\bf_\b@         determines sudoers source order
+
+E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
+       E\bEx\bxa\bam\bmp\bpl\ble\be l\bld\bda\bap\bp.\b.c\bco\bon\bnf\bf
+
+         # Either specify one or more URIs or one or more host:port pairs.
+         # If neither is specified sudo will default to localhost, port 389.
+         #
+         #host          ldapserver
+         #host          ldapserver1 ldapserver2:390
+         #
+         # Default port if host is specified without one, defaults to 389.
+         #port          389
+         #
+         # URI will override the host and port settings.
+
+
+
+1.7.0                    October 24, 2008                       8
+
+
+
+
+
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
+
+
+         uri            ldap://ldapserver
+         #uri            ldaps://secureldapserver
+         #uri            ldaps://secureldapserver ldap://ldapserver
+         #
+         # The amount of time, in seconds, to wait while trying to connect to
+         # an LDAP server.
+         bind_timelimit 30
+         #
+         # The amount of time, in seconds, to wait while performing an LDAP query.
+         timelimit 30
+         #
+         # must be set or sudo will ignore LDAP
+         sudoers_base   ou=SUDOers,dc=example,dc=com
+         #
+         # verbose sudoers matching from ldap
+         #sudoers_debug 2
+         #
+         # optional proxy credentials
+         #binddn        <who to search as>
+         #bindpw        <password>
+         #rootbinddn    <who to search as, uses /etc/ldap.secret for bindpw>
+         #
+         # LDAP protocol version, defaults to 3
+         #ldap_version 3
+         #
+         # Define if you want to use an encrypted LDAP connection.
+         # Typically, you must also set the port to 636 (ldaps).
+         #ssl on
+         #
+         # Define if you want to use port 389 and switch to
+         # encryption before the bind credentials are sent.
+         # Only supported by LDAP servers that support the start_tls
+         # extension such as OpenLDAP.
+         #ssl start_tls
+         #
+         # Additional TLS options follow that allow tweaking of the
+         # SSL/TLS connection.
+         #
+         #tls_checkpeer yes # verify server SSL certificate
+         #tls_checkpeer no  # ignore server SSL certificate
+         #
+         # If you enable tls_checkpeer, specify either tls_cacertfile
+         # or tls_cacertdir.  Only supported when using OpenLDAP.
+         #
+         #tls_cacertfile /etc/certs/trusted_signers.pem
+         #tls_cacertdir  /etc/certs
+         #
+         # For systems that don't have /dev/random
+         # use this along with PRNGD or EGD.pl to seed the
+         # random number pool to generate cryptographic session keys.
+         # Only supported when using OpenLDAP.
+         #
+         #tls_randfile /etc/egd-pool
+         #
+
+
+
+1.7.0                    October 24, 2008                       9
+
+
+
+
+
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
+
+
+         # You may restrict which ciphers are used.  Consult your SSL
+         # documentation for which options go here.
+         # Only supported when using OpenLDAP.
+         #
+         #tls_ciphers <cipher-list>
+         #
+         # Sudo can provide a client certificate when communicating to
+         # the LDAP server.
+         # Tips:
+         #   * Enable both lines at the same time.
+         #   * Do not password protect the key file.
+         #   * Ensure the keyfile is only readable by root.
+         #
+         # For OpenLDAP:
+         #tls_cert /etc/certs/client_cert.pem
+         #tls_key  /etc/certs/client_key.pem
+         #
+         # For SunONE or iPlanet LDAP, the file specified by tls_cert may
+         # contain CA certs and/or the client's cert.  If the client's
+         # cert is included, tls_key should be specified as well.
+         # For backward compatibility, sslpath may be used in place of tls_cert.
+         #tls_cert /var/ldap/cert7.db
+         #tls_key /var/ldap/key3.db
+         #
+         # If using SASL authentication for LDAP (OpenSSL)
+         # use_sasl yes
+         # sasl_auth_id <SASL username>
+         # rootuse_sasl yes
+         # rootsasl_auth_id <SASL username for root access>
+         # sasl_secprops none
+         # krb5_ccname /etc/.ldapcache
+
+       S\bSu\bud\bdo\bo s\bsc\bch\bhe\bem\bma\ba f\bfo\bor\br O\bOp\bpe\ben\bnL\bLD\bDA\bAP\bP
+
+       The following schema is in OpenLDAP format.  Simply copy it to the
+       schema directory (e.g. _\b/_\be_\bt_\bc_\b/_\bo_\bp_\be_\bn_\bl_\bd_\ba_\bp_\b/_\bs_\bc_\bh_\be_\bm_\ba), add the proper include
+       line in slapd.conf and restart s\bsl\bla\bap\bpd\bd.
+
+        attributetype ( 1.3.6.1.4.1.15953.9.1.1
+           NAME 'sudoUser'
+           DESC 'User(s) who may  run sudo'
+           EQUALITY caseExactIA5Match
+           SUBSTR caseExactIA5SubstringsMatch
+           SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+        attributetype ( 1.3.6.1.4.1.15953.9.1.2
+           NAME 'sudoHost'
+           DESC 'Host(s) who may run sudo'
+           EQUALITY caseExactIA5Match
+           SUBSTR caseExactIA5SubstringsMatch
+           SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+        attributetype ( 1.3.6.1.4.1.15953.9.1.3
+           NAME 'sudoCommand'
+
+
+
+1.7.0                    October 24, 2008                      10
+
+
+
+
+
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
+
+
+           DESC 'Command(s) to be executed by sudo'
+           EQUALITY caseExactIA5Match
+           SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+        attributetype ( 1.3.6.1.4.1.15953.9.1.4
+           NAME 'sudoRunAs'
+           DESC 'User(s) impersonated by sudo'
+           EQUALITY caseExactIA5Match
+           SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+        attributetype ( 1.3.6.1.4.1.15953.9.1.5
+           NAME 'sudoOption'
+           DESC 'Options(s) followed by sudo'
+           EQUALITY caseExactIA5Match
+           SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+        attributetype ( 1.3.6.1.4.1.15953.9.1.6
+           NAME 'sudoRunAsUser'
+           DESC 'User(s) impersonated by sudo'
+           EQUALITY caseExactIA5Match
+           SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+        attributetype ( 1.3.6.1.4.1.15953.9.1.7
+           NAME 'sudoRunAsGroup'
+           DESC 'Group(s) impersonated by sudo'
+           EQUALITY caseExactIA5Match
+           SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+        objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL
+           DESC 'Sudoer Entries'
+           MUST ( cn )
+           MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $
+                 sudoRunAsGroup $ sudoOption $ description )
+           )
+
+       Add nsswitch.conf example?  Add more exhaustive sudoers ldif example?
+
+S\bSE\bEE\bE A\bAL\bLS\bSO\bO
+       _\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf(4), _\bs_\bu_\bd_\bo_\be_\br_\bs(5)
+
+C\bCA\bAV\bVE\bEA\bAT\bTS\bS
+       The way that _\bs_\bu_\bd_\bo_\be_\br_\bs is parsed differs between Note that there are
+       differences in the way that LDAP-based _\bs_\bu_\bd_\bo_\be_\br_\bs is parsed compared to
+       file-based _\bs_\bu_\bd_\bo_\be_\br_\bs.  See the "Differences between LDAP and non-LDAP
+       sudoers" section for more information.
+
+B\bBU\bUG\bGS\bS
+       If you feel you have found a bug in s\bsu\bud\bdo\bo, please submit a bug report at
+       http://www.sudo.ws/sudo/bugs/
+
+S\bSU\bUP\bPP\bPO\bOR\bRT\bT
+       Limited free support is available via the sudo-users mailing list, see
+       http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search
+       the archives.
+
+
+
+1.7.0                    October 24, 2008                      11
+
+
+
+
+
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
+
+
+D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
+       s\bsu\bud\bdo\bo 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.
+       See the LICENSE file distributed with s\bsu\bud\bdo\bo or
+       http://www.sudo.ws/sudo/license.html for complete details.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1.7.0                    October 24, 2008                      12
+
+
diff --git a/sudoers.ldap.man.in b/sudoers.ldap.man.in
new file mode 100644 (file)
index 0000000..998786c
--- /dev/null
@@ -0,0 +1,778 @@
+.\" Copyright (c) 2003-2008
+.\"    Todd C. Miller <Todd.Miller@courtesan.com>
+.\" 
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\" 
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\" 
+.\" $Sudo: sudoers.ldap.man.in,v 1.11 2008/10/24 13:52:19 millert Exp $
+.\" Automatically generated by Pod::Man 2.16 (Pod::Simple 3.05)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sh \" Subsection heading
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings.  \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
+.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+.    ds -- \(*W-
+.    ds PI pi
+.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
+.    ds L" ""
+.    ds R" ""
+.    ds C` 
+.    ds C' 
+'br\}
+.el\{\
+.    ds -- \|\(em\|
+.    ds PI \(*p
+.    ds L" ``
+.    ds R" ''
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
+.\" entries marked with X<> in POD.  Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.ie \nF \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
+..
+.    nr % 0
+.    rr F
+.\}
+.el \{\
+.    de IX
+..
+.\}
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear.  Run.  Save yourself.  No user-serviceable parts.
+.    \" fudge factors for nroff and troff
+.if n \{\
+.    ds #H 0
+.    ds #V .8m
+.    ds #F .3m
+.    ds #[ \f1
+.    ds #] \fP
+.\}
+.if t \{\
+.    ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+.    ds #V .6m
+.    ds #F 0
+.    ds #[ \&
+.    ds #] \&
+.\}
+.    \" simple accents for nroff and troff
+.if n \{\
+.    ds ' \&
+.    ds ` \&
+.    ds ^ \&
+.    ds , \&
+.    ds ~ ~
+.    ds /
+.\}
+.if t \{\
+.    ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+.    ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+.    ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+.    ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+.    ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+.    ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+.    \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+.    \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+.    \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+.    ds : e
+.    ds 8 ss
+.    ds o a
+.    ds d- d\h'-1'\(ga
+.    ds D- D\h'-1'\(hy
+.    ds th \o'bp'
+.    ds Th \o'LP'
+.    ds ae ae
+.    ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "SUDOERS.LDAP @mansectform@"
+.TH SUDOERS.LDAP @mansectform@ "October 24, 2008" "1.7.0" "MAINTENANCE COMMANDS"
+.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH "NAME"
+sudoers.ldap \- sudo LDAP configuration
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+In addition to the standard \fIsudoers\fR file, \fBsudo\fR may be configured
+via \s-1LAP\s0.  This can be especially useful for synchronizing \fIsudoers\fR
+in a large, distributed environment.
+.PP
+Using \s-1LDAP\s0 for \fIsudoers\fR has several benefits:
+.IP "\(bu" 4
+\&\fBsudo\fR no longer needs to read \fIsudoers\fR in its entirety.  When
+\&\s-1LDAP\s0 is used, there are only two or three \s-1LDAP\s0 queries per invocation.
+This makes it especially fast and particularly usable in \s-1LDAP\s0
+environments.
+.IP "\(bu" 4
+\&\fBsudo\fR no longer exits if there is a typo in \fIsudoers\fR.
+It is not possible to load \s-1LDAP\s0 data into the server that does
+not conform to the sudoers schema, so proper syntax is guaranteed.
+It is still possible to have typos in a user or host name, but
+this will not prevent \fBsudo\fR from running.
+.IP "\(bu" 4
+It is possible to specify per-entry options that override the global
+default options.  \fI\f(CI@sysconfdir\fI@/sudoers\fR only supports default options and
+limited options associated with user/host/commands/aliases.  The
+syntax is complicated and can be difficult for users to understand.
+Placing the options directly in the entry is more natural.
+.IP "\(bu" 4
+The \fBvisudo\fR program is no longer needed.  \fBvisudo\fR provides
+locking and syntax checking of the \fI\f(CI@sysconfdir\fI@/sudoers\fR file.
+Since \s-1LDAP\s0 updates are atomic, locking is no longer necessary.
+Because syntax is checked when the data is inserted into \s-1LDAP\s0, there
+is no need for a specialized tool to check syntax.
+.PP
+Another major difference between \s-1LDAP\s0 and file-based \fIsudoers\fR
+is that in \s-1LDAP\s0, \fBsudo\fR\-specific Aliases are not supported.
+.PP
+For the most part, there is really no need for \fBsudo\fR\-specific
+Aliases.  Unix groups or user netgroups can be used in place of
+User_Aliases and RunasAliases.  Host netgroups can be used in place
+of HostAliases.  Since Unix groups and netgroups can also be stored
+in \s-1LDAP\s0 there is no real need for \fBsudo\fR\-specific aliases.
+.PP
+Cmnd_Aliases are not really required either since it is possible
+to have multiple users listed in a sudoRole.  Instead of defining
+a Cmnd_Alias that is referenced by multiple users, one can create
+a sudoRole that contains the commands and assign multiple users
+to it.
+.Sh "SUDOers \s-1LDAP\s0 container"
+.IX Subsection "SUDOers LDAP container"
+The \fIsudoers\fR configuration is contained in the \f(CW\*(C`ou=SUDOers\*(C'\fR \s-1LDAP\s0
+container.
+.PP
+Sudo first looks for the \f(CW\*(C`cn=default\*(C'\fR entry in the SUDOers container.
+If found, the multi-valued \f(CW\*(C`sudoOption\*(C'\fR attribute is parsed in the
+same manner as a global \f(CW\*(C`Defaults\*(C'\fR line in \fI\f(CI@sysconfdir\fI@/sudoers\fR.  In
+the following example, the \f(CW\*(C`SSH_AUTH_SOCK\*(C'\fR variable will be preserved
+in the environment for all users.
+.PP
+.Vb 6
+\&    dn: cn=defaults,ou=SUDOers,dc=example,dc=com
+\&    objectClass: top
+\&    objectClass: sudoRole
+\&    cn: defaults
+\&    description: Default sudoOption\*(Aqs go here
+\&    sudoOption: env_keep+=SSH_AUTH_SOCK
+.Ve
+.PP
+The equivalent of a sudoer in \s-1LDAP\s0 is a \f(CW\*(C`sudoRole\*(C'\fR.  It consists of
+the following components:
+.IP "\fBsudoUser\fR" 4
+.IX Item "sudoUser"
+A user name, uid (prefixed with \f(CW\*(Aq#\*(Aq\fR), Unix group (prefixed with
+a \f(CW\*(Aq%\*(Aq\fR) or user netgroup (prefixed with a \f(CW\*(Aq+\*(Aq\fR).
+.IP "\fBsudoHost\fR" 4
+.IX Item "sudoHost"
+A host name, \s-1IP\s0 address, \s-1IP\s0 network, or host netgroup (prefixed
+with a \f(CW\*(Aq+\*(Aq\fR).
+The special value \f(CW\*(C`ALL\*(C'\fR will match any host.
+.IP "\fBsudoCommand\fR" 4
+.IX Item "sudoCommand"
+A Unix command with optional command line arguments, potentially
+including globbing characters (aka wild cards).
+The special value \f(CW\*(C`ALL\*(C'\fR will match any command.
+If a command is prefixed with an exclamation point \f(CW\*(Aq!\*(Aq\fR, the
+user will be prohibited from running that command.
+.IP "\fBsudoOption\fR" 4
+.IX Item "sudoOption"
+Identical in function to the global options described above, but
+specific to the \f(CW\*(C`sudoRole\*(C'\fR in which it resides.
+.IP "\fBsudoRunAsUser\fR" 4
+.IX Item "sudoRunAsUser"
+A user name or uid (prefixed with \f(CW\*(Aq#\*(Aq\fR) that commands may be run
+as or a Unix group (prefixed with a \f(CW\*(Aq%\*(Aq\fR) or user netgroup (prefixed
+with a \f(CW\*(Aq+\*(Aq\fR) that contains a list of users that commands may be
+run as.
+The special value \f(CW\*(C`ALL\*(C'\fR will match any user.
+.IP "\fBsudoRunAsGroup\fR" 4
+.IX Item "sudoRunAsGroup"
+A Unix group or gid (prefixed with \f(CW\*(Aq#\*(Aq\fR) that commands may be run as.
+The special value \f(CW\*(C`ALL\*(C'\fR will match any group.
+.PP
+Each component listed above should contain a single value, but there
+may be multiple instances of each component type.  A sudoRole must
+contain at least one \f(CW\*(C`sudoUser\*(C'\fR, \f(CW\*(C`sudoHost\*(C'\fR and \f(CW\*(C`sudoCommand\*(C'\fR.
+.PP
+The following example allows users in group wheel to run any command
+on any host via \fBsudo\fR:
+.PP
+.Vb 7
+\&    dn: cn=%wheel,ou=SUDOers,dc=example,dc=com
+\&    objectClass: top
+\&    objectClass: sudoRole
+\&    cn: %wheel
+\&    sudoUser: %wheel
+\&    sudoHost: ALL
+\&    sudoCommand: ALL
+.Ve
+.Sh "Anatomy of \s-1LDAP\s0 sudoers lookup"
+.IX Subsection "Anatomy of LDAP sudoers lookup"
+When looking up a sudoer using \s-1LDAP\s0 there are only two or three
+\&\s-1LDAP\s0 queries per invocation.  The first query is to parse the global
+options.  The second is to match against the user's name and the
+groups that the user belongs to.  (The special \s-1ALL\s0 tag is matched
+in this query too.)  If no match is returned for the user's name
+and groups, a third query returns all entries containing user
+netgroups and checks to see if the user belongs to any of them.
+.Sh "Differences between \s-1LDAP\s0 and non-LDAP sudoers"
+.IX Subsection "Differences between LDAP and non-LDAP sudoers"
+There are some subtle differences in the way sudoers is handled
+once in \s-1LDAP\s0.  Probably the biggest is that according to the \s-1RFC\s0,
+\&\s-1LDAP\s0 ordering is arbitrary and you cannot expect that Attributes
+and Entries are returned in any specific order.  If there are
+conflicting command rules on an entry, the negative takes precedence.
+This is called paranoid behavior (not necessarily the most specific
+match).
+.PP
+Here is an example:
+.PP
+.Vb 5
+\&    # /etc/sudoers:
+\&    # Allow all commands except shell
+\&    johnny  ALL=(root) ALL,!/bin/sh
+\&    # Always allows all commands because ALL is matched last
+\&    puddles ALL=(root) !/bin/sh,ALL
+\&
+\&    # LDAP equivalent of johnny
+\&    # Allows all commands except shell
+\&    dn: cn=role1,ou=Sudoers,dc=my\-domain,dc=com
+\&    objectClass: sudoRole
+\&    objectClass: top
+\&    cn: role1
+\&    sudoUser: johnny
+\&    sudoHost: ALL
+\&    sudoCommand: ALL
+\&    sudoCommand: !/bin/sh
+\&
+\&    # LDAP equivalent of puddles
+\&    # Notice that even though ALL comes last, it still behaves like
+\&    # role1 since the LDAP code assumes the more paranoid configuration
+\&    dn: cn=role2,ou=Sudoers,dc=my\-domain,dc=com
+\&    objectClass: sudoRole
+\&    objectClass: top
+\&    cn: role2
+\&    sudoUser: puddles
+\&    sudoHost: ALL
+\&    sudoCommand: !/bin/sh
+\&    sudoCommand: ALL
+.Ve
+.PP
+Another difference is that negations on the Host, User or Runas are
+currently ignorred.  For example, the following attributes do not
+behave the way one might expect.
+.PP
+.Vb 3
+\&    # does not match all but joe
+\&    # rather, does not match anyone
+\&    sudoUser: !joe
+\&
+\&    # does not match all but joe
+\&    # rather, matches everyone including Joe
+\&    sudoUser: ALL
+\&    sudoUser: !joe
+\&
+\&    # does not match all but web01
+\&    # rather, matches all hosts including web01
+\&    sudoHost: ALL
+\&    sudoHost: !web01
+.Ve
+.Sh "Sudoers Schema"
+.IX Subsection "Sudoers Schema"
+In order to use \fBsudo\fR's \s-1LDAP\s0 support, the \fBsudo\fR schema must be
+installed on your \s-1LDAP\s0 server.  In addition, be sure to index the
+\&'sudoUser' attribute.
+.PP
+Three versions of the schema: one for OpenLDAP servers (\fIschema.OpenLDAP\fR),
+one for Netscape-derived servers (\fIschema.iPlanet\fR), and one for
+Microsoft Active Directory (\fIschema.ActiveDirectory\fR) may
+be found in the \fBsudo\fR distribution.
+.PP
+The schema for \fBsudo\fR in OpenLDAP form is included in the \s-1EXAMPLES\s0
+section.
+.Sh "Configuring ldap.conf"
+.IX Subsection "Configuring ldap.conf"
+Sudo reads the \fI\f(CI@ldap_conf\fI@\fR file for LDAP-specific configuration.
+Typically, this file is shared amongst different LDAP-aware clients.
+As such, most of the settings are not \fBsudo\fR\-specific.  Note that
+\&\fBsudo\fR parses \fI\f(CI@ldap_conf\fI@\fR itself and may support options
+that differ from those described in the \fIldap.conf\fR\|(@mansectform@) manual.
+.PP
+Also note that on systems using the OpenLDAP libraries, default
+values specified in \fI/etc/openldap/ldap.conf\fR or the user's
+\&\fI.ldaprc\fR files are not used.
+.PP
+Only those options explicitly listed in \fI\f(CI@ldap_conf\fI@\fR that are
+supported by \fBsudo\fR are honored.  Configuration options are listed
+below in upper case but are parsed in a case-independent manner.
+.IP "\fB\s-1URI\s0\fR ldap[s]://[hostname[:port]] ..." 4
+.IX Item "URI ldap[s]://[hostname[:port]] ..."
+Specifies a whitespace-delimited list of one or more URIs describing
+the \s-1LDAP\s0 server(s) to connect to.  The \fIprotocol\fR may be either \fBldap\fR
+or \fBldaps\fR, the latter being for servers that support \s-1TLS\s0 (\s-1SSL\s0)
+encryption.  If no \fIport\fR is specified, the default is port 389 for
+\&\f(CW\*(C`ldap://\*(C'\fR or port 636 for \f(CW\*(C`ldaps://\*(C'\fR.  If no \fIhostname\fR is specified,
+\&\fBsudo\fR will connect to \fBlocalhost\fR.  Only systems using the OpenSSL
+libraries support the mixing of \f(CW\*(C`ldap://\*(C'\fR and \f(CW\*(C`ldaps://\*(C'\fR URIs.
+The Netscape-derived libraries used on most commercial versions of
+Unix are only capable of supporting one or the other.
+.IP "\fB\s-1HOST\s0\fR name[:port] ..." 4
+.IX Item "HOST name[:port] ..."
+If no \fB\s-1URI\s0\fR is specified, the \fB\s-1HOST\s0\fR parameter specifies a
+whitespace-delimited list of \s-1LDAP\s0 servers to connect to.  Each host
+may include an optional \fIport\fR separated by a colon (':').  The
+\&\fB\s-1HOST\s0\fR parameter is deprecated in favor of the \fB\s-1URI\s0\fR specification
+and is included for backwards compatibility.
+.IP "\fB\s-1PORT\s0\fR port_number" 4
+.IX Item "PORT port_number"
+If no \fB\s-1URI\s0\fR is specified, the \fB\s-1PORT\s0\fR parameter specifies the
+default port to connect to on the \s-1LDAP\s0 server if a \fB\s-1HOST\s0\fR parameter
+does not specify the port itself.  If no \fB\s-1PORT\s0\fR parameter is used,
+the default is port 389 for \s-1LDAP\s0 and port 636 for \s-1LDAP\s0 over \s-1TLS\s0
+(\s-1SSL\s0).  The \fB\s-1PORT\s0\fR parameter is deprecated in favor of the \fB\s-1URI\s0\fR
+specification and is included for backwards compatibility.
+.IP "\fB\s-1BIND_TIMELIMIT\s0\fR seconds" 4
+.IX Item "BIND_TIMELIMIT seconds"
+The \fB\s-1BIND_TIMELIMIT\s0\fR parameter specifies the amount of time, in seconds,
+to wait while trying to connect to an \s-1LDAP\s0 server.  If multiple \fB\s-1URI\s0\fRs or
+\&\fB\s-1HOST\s0\fRs are specified, this is the amount of time to wait before trying
+the next one in the list.
+.IP "\fB\s-1TIMELIMIT\s0\fR seconds" 4
+.IX Item "TIMELIMIT seconds"
+The \fB\s-1TIMELIMIT\s0\fR parameter specifies the amount of time, in seconds,
+to wait for a response to an \s-1LDAP\s0 query.
+.IP "\fB\s-1SUDOERS_BASE\s0\fR base" 4
+.IX Item "SUDOERS_BASE base"
+The base \s-1DN\s0 to use when performing \fBsudo\fR \s-1LDAP\s0 queries.  Typically
+this is of the form \f(CW\*(C`ou=SUDOers,dc=example,dc=com\*(C'\fR for the domain
+\&\f(CW\*(C`example.com\*(C'\fR.
+.IP "\fB\s-1SUDOERS_DEBUG\s0\fR debug_level" 4
+.IX Item "SUDOERS_DEBUG debug_level"
+This sets the debug level for \fBsudo\fR \s-1LDAP\s0 queries.  Debugging
+information is printed to the standard error.  A value of 1 results
+in a moderate amount of debugging information.  A value of 2 shows
+the results of the matches themselves.  This parameter should not
+be set in a production environment as the extra information is
+likely to confuse users.
+.IP "\fB\s-1BINDDN\s0\fR \s-1DN\s0" 4
+.IX Item "BINDDN DN"
+The \fB\s-1BINDDN\s0\fR parameter specifies the identity, in the form of a
+Distinguished Name (\s-1DN\s0), to use when performing \s-1LDAP\s0 operations.
+If not specified, \s-1LDAP\s0 operations are performed with an anonymous
+identity.  By default, most \s-1LDAP\s0 servers will allow anonymous access.
+.IP "\fB\s-1BINDPW\s0\fR secret" 4
+.IX Item "BINDPW secret"
+The \fB\s-1BINDPW\s0\fR parameter specifies the password to use when performing
+\&\s-1LDAP\s0 operations.  This is typically used in conjunction with the
+\&\fB\s-1BINDDN\s0\fR parameter.
+.IP "\fB\s-1ROOTBINDDN\s0\fR \s-1DN\s0" 4
+.IX Item "ROOTBINDDN DN"
+The \fB\s-1ROOTBINDDN\s0\fR parameter specifies the identity, in the form of
+a Distinguished Name (\s-1DN\s0), to use when performing privileged \s-1LDAP\s0
+operations, such as \fIsudoers\fR queries.  The password corresponding
+to the identity should be stored in \fI\f(CI@ldap_secret\fI@\fR.
+If not specified, the \fB\s-1BINDDN\s0\fR identity is used (if any).
+.IP "\fB\s-1LDAP_VERSION\s0\fR number" 4
+.IX Item "LDAP_VERSION number"
+The version of the \s-1LDAP\s0 protocol to use when connecting to the server.
+The default value is protocol version 3.
+.IP "\fB\s-1SSL\s0\fR on/true/yes/off/false/no" 4
+.IX Item "SSL on/true/yes/off/false/no"
+If the \fB\s-1SSL\s0\fR parameter is set to \f(CW\*(C`on\*(C'\fR, \f(CW\*(C`true\*(C'\fR or \f(CW\*(C`yes\*(C'\fR, \s-1TLS\s0
+(\s-1SSL\s0) encryption is always used when communicating with the \s-1LDAP\s0
+server.  Typically, this involves connecting to the server on port
+636 (ldaps).
+.IP "\fB\s-1SSL\s0\fR start_tls" 4
+.IX Item "SSL start_tls"
+If the \fB\s-1SSL\s0\fR parameter is set to \f(CW\*(C`start_tls\*(C'\fR, the \s-1LDAP\s0 server
+connection is initiated normally and \s-1TLS\s0 encryption is begun before
+the bind credentials are sent.  This has the advantage of not
+requiring a dedicated port for encrypted communications.  This
+parameter is only supported by \s-1LDAP\s0 servers that honor the \f(CW\*(C`start_tls\*(C'\fR
+extension, such as the OpenLDAP server.
+.IP "\fB\s-1TLS_CHECKPEER\s0\fR on/true/yes/off/false/no" 4
+.IX Item "TLS_CHECKPEER on/true/yes/off/false/no"
+If enabled, \fB\s-1TLS_CHECKPEER\s0\fR will cause the \s-1LDAP\s0 server's \s-1TLS\s0
+certificated to be verified.  If the server's \s-1TLS\s0 certificate cannot
+be verified (usually because it is signed by an unknown certificate
+authority), \fBsudo\fR will be unable to connect to it.  If \fB\s-1TLS_CHECKPEER\s0\fR
+is disabled, no check is made.
+.IP "\fB\s-1TLS_CACERTFILE\s0\fR file name" 4
+.IX Item "TLS_CACERTFILE file name"
+The path to a certificate authority bundle which contains the certificates
+for all the Certificate Authorities the client knows to be valid,
+e.g. \fI/etc/ssl/ca\-bundle.pem\fR.
+This option is only supported by the OpenLDAP libraries.
+.IP "\fB\s-1TLS_CACERTDIR\s0\fR directory" 4
+.IX Item "TLS_CACERTDIR directory"
+Similar to \fB\s-1TLS_CACERTFILE\s0\fR but instead of a file, it is a
+directory containing individual Certificate Authority certificates,
+e.g. \fI/etc/ssl/certs\fR.
+The directory specified by \fB\s-1TLS_CACERTDIR\s0\fR is checked after
+\&\fB\s-1TLS_CACERTFILE\s0\fR.
+This option is only supported by the OpenLDAP libraries.
+.IP "\fB\s-1TLS_CERT\s0\fR file name" 4
+.IX Item "TLS_CERT file name"
+The path to a file containing the client certificate which can
+be used to authenticate the client to the \s-1LDAP\s0 server.
+The certificate type depends on the \s-1LDAP\s0 libraries used.
+.Sp
+OpenLDAP:
+    \f(CW\*(C`tls_cert /etc/ssl/client_cert.pem\*(C'\fR
+.Sp
+Netscape-derived:
+    \f(CW\*(C`tls_cert /var/ldap/cert7.db\*(C'\fR
+.Sp
+When using Netscape-derived libraries, this file may also contain
+Certificate Authority certificates.
+.IP "\fB\s-1TLS_KEY\s0\fR file name" 4
+.IX Item "TLS_KEY file name"
+The path to a file containing the private key which matches the
+certificate specified by \fB\s-1TLS_CERT\s0\fR.  The private key must not be
+password-protected.  The key type depends on the \s-1LDAP\s0 libraries
+used.
+.Sp
+OpenLDAP:
+    \f(CW\*(C`tls_key /etc/ssl/client_key.pem\*(C'\fR
+.Sp
+Netscape-derived:
+    \f(CW\*(C`tls_key /var/ldap/key3.db\*(C'\fR
+.IP "\fB\s-1TLS_RANDFILE\s0\fR file name" 4
+.IX Item "TLS_RANDFILE file name"
+The \fB\s-1TLS_RANDFILE\s0\fR parameter specifies the path to an entropy
+source for systems that lack a random device.  It is generally used
+in conjunction with \fIprngd\fR or \fIegd\fR.
+This option is only supported by the OpenLDAP libraries.
+.IP "\fB\s-1TLS_CIPHERS\s0\fR cipher list" 4
+.IX Item "TLS_CIPHERS cipher list"
+The \fB\s-1TLS_CIPHERS\s0\fR parameter allows the administer to restrict
+which encryption algorithms may be used for \s-1TLS\s0 (\s-1SSL\s0) connections.
+See the OpenSSL manual for a list of valid ciphers.
+This option is only supported by the OpenLDAP libraries.
+.IP "\fB\s-1USE_SASL\s0\fR on/true/yes/off/false/no" 4
+.IX Item "USE_SASL on/true/yes/off/false/no"
+Enable \fB\s-1USE_SASL\s0\fR for \s-1LDAP\s0 servers that support \s-1SASL\s0 authentication.
+.IP "\fB\s-1SASL_AUTH_ID\s0\fR identity" 4
+.IX Item "SASL_AUTH_ID identity"
+The \s-1SASL\s0 user name to use when connecting to the \s-1LDAP\s0 server.
+By default, \fBsudo\fR will use an anonymous connection.
+.IP "\fB\s-1ROOTUSE_SASL\s0\fR on/true/yes/off/false/no" 4
+.IX Item "ROOTUSE_SASL on/true/yes/off/false/no"
+Enable \fB\s-1ROOTUSE_SASL\s0\fR to enable \s-1SASL\s0 authentication when connecting
+to an \s-1LDAP\s0 server from a privileged process, such as \fBsudo\fR.
+.IP "\fB\s-1ROOTSASL_AUTH_ID\s0\fR identity" 4
+.IX Item "ROOTSASL_AUTH_ID identity"
+The \s-1SASL\s0 user name to use when \fB\s-1ROOTUSE_SASL\s0\fR is enabled.
+.IP "\fB\s-1SASL_SECPROPS\s0\fR none/properties" 4
+.IX Item "SASL_SECPROPS none/properties"
+\&\s-1SASL\s0 security properties or \fInone\fR for no properties.  See the
+\&\s-1SASL\s0 programmer's manual for details.
+.IP "\fB\s-1KRB5_CCNAME\s0\fR file name" 4
+.IX Item "KRB5_CCNAME file name"
+The path to the Kerberos 5 credential cache to use when authenticating
+with the remote server.
+.PP
+See the \f(CW\*(C`ldap.conf\*(C'\fR entry in the \s-1EXAMPLES\s0 section.
+.Sh "Configuring nsswitch.conf"
+.IX Subsection "Configuring nsswitch.conf"
+Unless it is disabled at build time, \fBsudo\fR consults the Name
+Service Switch file, \fI\f(CI@nsswitch_conf\fI@\fR, to specify the \fIsudoers\fR
+search order.  Sudo looks for a line beginning with \f(CW\*(C`sudoers:\*(C'\fR and
+uses this to determine the search order.  Note that \fBsudo\fR does
+not stop searching after the first match and later matches take
+precedence over earlier ones.
+.PP
+The following sources are recognized:
+.PP
+.Vb 2
+\&    files       read sudoers from F<@sysconfdir@/sudoers>
+\&    ldap        read sudoers from LDAP
+.Ve
+.PP
+In addition, the entry \f(CW\*(C`[NOTFOUND=return]\*(C'\fR will short-circuit the
+search if the user was not found in the preceding source.
+.PP
+To consult \s-1LDAP\s0 first followed by the local sudoers file (if it
+exists), use:
+.PP
+.Vb 1
+\&    sudoers: ldap files
+.Ve
+.PP
+The local \fIsudoers\fR file can be ignored completely by using:
+.PP
+.Vb 1
+\&    sudoers: ldap
+.Ve
+.PP
+If the \fI\f(CI@nsswitch_conf\fI@\fR file is not present or there is no
+sudoers line, the following default is assumed:
+.PP
+.Vb 1
+\&    sudoers: files
+.Ve
+.PP
+Note that \fI\f(CI@nsswitch_conf\fI@\fR is supported even when the underlying
+operating system does not use an nsswitch.conf file.
+.SH "FILES"
+.IX Header "FILES"
+.ie n .IP "\fI\fI@ldap_conf\fI@\fR" 24
+.el .IP "\fI\f(CI@ldap_conf\fI@\fR" 24
+.IX Item "@ldap_conf@"
+\&\s-1LDAP\s0 configuration file
+.ie n .IP "\fI\fI@nsswitch_conf\fI@\fR" 24
+.el .IP "\fI\f(CI@nsswitch_conf\fI@\fR" 24
+.IX Item "@nsswitch_conf@"
+determines sudoers source order
+.SH "EXAMPLES"
+.IX Header "EXAMPLES"
+.Sh "Example ldap.conf"
+.IX Subsection "Example ldap.conf"
+.Vb 10
+\&  # Either specify one or more URIs or one or more host:port pairs.
+\&  # If neither is specified sudo will default to localhost, port 389.
+\&  #
+\&  #host          ldapserver
+\&  #host          ldapserver1 ldapserver2:390
+\&  #
+\&  # Default port if host is specified without one, defaults to 389.
+\&  #port          389
+\&  #
+\&  # URI will override the host and port settings.
+\&  uri            ldap://ldapserver
+\&  #uri            ldaps://secureldapserver
+\&  #uri            ldaps://secureldapserver ldap://ldapserver
+\&  #
+\&  # The amount of time, in seconds, to wait while trying to connect to
+\&  # an LDAP server.
+\&  bind_timelimit 30
+\&  #
+\&  # The amount of time, in seconds, to wait while performing an LDAP query.
+\&  timelimit 30
+\&  #
+\&  # must be set or sudo will ignore LDAP
+\&  sudoers_base   ou=SUDOers,dc=example,dc=com
+\&  #
+\&  # verbose sudoers matching from ldap
+\&  #sudoers_debug 2
+\&  #
+\&  # optional proxy credentials
+\&  #binddn        <who to search as>
+\&  #bindpw        <password>
+\&  #rootbinddn    <who to search as, uses /etc/ldap.secret for bindpw>
+\&  #
+\&  # LDAP protocol version, defaults to 3
+\&  #ldap_version 3
+\&  #
+\&  # Define if you want to use an encrypted LDAP connection.
+\&  # Typically, you must also set the port to 636 (ldaps).
+\&  #ssl on
+\&  #
+\&  # Define if you want to use port 389 and switch to
+\&  # encryption before the bind credentials are sent.
+\&  # Only supported by LDAP servers that support the start_tls
+\&  # extension such as OpenLDAP.
+\&  #ssl start_tls
+\&  #
+\&  # Additional TLS options follow that allow tweaking of the
+\&  # SSL/TLS connection.
+\&  #
+\&  #tls_checkpeer yes # verify server SSL certificate
+\&  #tls_checkpeer no  # ignore server SSL certificate
+\&  #
+\&  # If you enable tls_checkpeer, specify either tls_cacertfile
+\&  # or tls_cacertdir.  Only supported when using OpenLDAP.
+\&  #
+\&  #tls_cacertfile /etc/certs/trusted_signers.pem
+\&  #tls_cacertdir  /etc/certs
+\&  #
+\&  # For systems that don\*(Aqt have /dev/random
+\&  # use this along with PRNGD or EGD.pl to seed the
+\&  # random number pool to generate cryptographic session keys.
+\&  # Only supported when using OpenLDAP.
+\&  #
+\&  #tls_randfile /etc/egd\-pool
+\&  #
+\&  # You may restrict which ciphers are used.  Consult your SSL
+\&  # documentation for which options go here.
+\&  # Only supported when using OpenLDAP.
+\&  #
+\&  #tls_ciphers <cipher\-list>
+\&  #
+\&  # Sudo can provide a client certificate when communicating to
+\&  # the LDAP server.
+\&  # Tips:
+\&  #   * Enable both lines at the same time.
+\&  #   * Do not password protect the key file.
+\&  #   * Ensure the keyfile is only readable by root.
+\&  #
+\&  # For OpenLDAP:
+\&  #tls_cert /etc/certs/client_cert.pem
+\&  #tls_key  /etc/certs/client_key.pem
+\&  #
+\&  # For SunONE or iPlanet LDAP, the file specified by tls_cert may
+\&  # contain CA certs and/or the client\*(Aqs cert.  If the client\*(Aqs
+\&  # cert is included, tls_key should be specified as well.
+\&  # For backward compatibility, sslpath may be used in place of tls_cert.
+\&  #tls_cert /var/ldap/cert7.db
+\&  #tls_key /var/ldap/key3.db
+\&  #
+\&  # If using SASL authentication for LDAP (OpenSSL)
+\&  # use_sasl yes
+\&  # sasl_auth_id <SASL username>
+\&  # rootuse_sasl yes
+\&  # rootsasl_auth_id <SASL username for root access>
+\&  # sasl_secprops none
+\&  # krb5_ccname /etc/.ldapcache
+.Ve
+.Sh "Sudo schema for OpenLDAP"
+.IX Subsection "Sudo schema for OpenLDAP"
+The following schema is in OpenLDAP format.  Simply copy it to the
+schema directory (e.g. \fI/etc/openldap/schema\fR), add the proper
+\&\f(CW\*(C`include\*(C'\fR line in \f(CW\*(C`slapd.conf\*(C'\fR and restart \fBslapd\fR.
+.PP
+.Vb 6
+\& attributetype ( 1.3.6.1.4.1.15953.9.1.1
+\&    NAME \*(AqsudoUser\*(Aq
+\&    DESC \*(AqUser(s) who may  run sudo\*(Aq
+\&    EQUALITY caseExactIA5Match
+\&    SUBSTR caseExactIA5SubstringsMatch
+\&    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+\&
+\& attributetype ( 1.3.6.1.4.1.15953.9.1.2
+\&    NAME \*(AqsudoHost\*(Aq
+\&    DESC \*(AqHost(s) who may run sudo\*(Aq
+\&    EQUALITY caseExactIA5Match
+\&    SUBSTR caseExactIA5SubstringsMatch
+\&    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+\&
+\& attributetype ( 1.3.6.1.4.1.15953.9.1.3
+\&    NAME \*(AqsudoCommand\*(Aq
+\&    DESC \*(AqCommand(s) to be executed by sudo\*(Aq
+\&    EQUALITY caseExactIA5Match
+\&    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+\&
+\& attributetype ( 1.3.6.1.4.1.15953.9.1.4
+\&    NAME \*(AqsudoRunAs\*(Aq
+\&    DESC \*(AqUser(s) impersonated by sudo\*(Aq
+\&    EQUALITY caseExactIA5Match
+\&    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+\&
+\& attributetype ( 1.3.6.1.4.1.15953.9.1.5
+\&    NAME \*(AqsudoOption\*(Aq
+\&    DESC \*(AqOptions(s) followed by sudo\*(Aq
+\&    EQUALITY caseExactIA5Match
+\&    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+\&
+\& attributetype ( 1.3.6.1.4.1.15953.9.1.6
+\&    NAME \*(AqsudoRunAsUser\*(Aq
+\&    DESC \*(AqUser(s) impersonated by sudo\*(Aq
+\&    EQUALITY caseExactIA5Match
+\&    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+\&
+\& attributetype ( 1.3.6.1.4.1.15953.9.1.7
+\&    NAME \*(AqsudoRunAsGroup\*(Aq
+\&    DESC \*(AqGroup(s) impersonated by sudo\*(Aq
+\&    EQUALITY caseExactIA5Match
+\&    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+\&
+\& objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME \*(AqsudoRole\*(Aq SUP top STRUCTURAL
+\&    DESC \*(AqSudoer Entries\*(Aq
+\&    MUST ( cn )
+\&    MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $
+\&          sudoRunAsGroup $ sudoOption $ description )
+\&    )
+.Ve
+.PP
+Add nsswitch.conf example?
+Add more exhaustive sudoers ldif example?
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fIldap.conf\fR\|(@mansectform@), \fIsudoers\fR\|(5)
+.SH "CAVEATS"
+.IX Header "CAVEATS"
+The way that \fIsudoers\fR is parsed differs between Note that there
+are differences in the way that LDAP-based \fIsudoers\fR is parsed
+compared to file-based \fIsudoers\fR.  See the \*(L"Differences between
+\&\s-1LDAP\s0 and non-LDAP sudoers\*(R" section for more information.
+.SH "BUGS"
+.IX Header "BUGS"
+If you feel you have found a bug in \fBsudo\fR, please submit a bug report
+at http://www.sudo.ws/sudo/bugs/
+.SH "SUPPORT"
+.IX Header "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see http://www.sudo.ws/mailman/listinfo/sudo\-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+.IX Header "DISCLAIMER"
+\&\fBsudo\fR is provided ``\s-1AS\s0 \s-1IS\s0'' and any express or implied warranties,
+including, but not limited to, the implied warranties of merchantability
+and fitness for a particular purpose are disclaimed.  See the \s-1LICENSE\s0
+file distributed with \fBsudo\fR or http://www.sudo.ws/sudo/license.html
+for complete details.
diff --git a/sudoers.ldap.pod b/sudoers.ldap.pod
new file mode 100644 (file)
index 0000000..3b36ddd
--- /dev/null
@@ -0,0 +1,694 @@
+Copyright (c) 2003-2008
+       Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+$Sudo: sudoers.ldap.pod,v 1.10 2008/05/10 13:18:47 millert Exp $
+=pod
+
+=head1 NAME
+
+sudoers.ldap - sudo LDAP configuration
+
+=head1 DESCRIPTION
+
+In addition to the standard I<sudoers> file, B<sudo> may be configured
+via LAP.  This can be especially useful for synchronizing I<sudoers>
+in a large, distributed environment.
+
+Using LDAP for I<sudoers> has several benefits:
+
+=over 4
+
+=item *
+
+B<sudo> no longer needs to read I<sudoers> in its entirety.  When
+LDAP is used, there are only two or three LDAP queries per invocation.
+This makes it especially fast and particularly usable in LDAP
+environments.
+
+=item *
+
+B<sudo> no longer exits if there is a typo in I<sudoers>.
+It is not possible to load LDAP data into the server that does
+not conform to the sudoers schema, so proper syntax is guaranteed.
+It is still possible to have typos in a user or host name, but
+this will not prevent B<sudo> from running.
+
+=item *
+
+It is possible to specify per-entry options that override the global
+default options.  F<@sysconfdir@/sudoers> only supports default options and
+limited options associated with user/host/commands/aliases.  The
+syntax is complicated and can be difficult for users to understand.
+Placing the options directly in the entry is more natural.
+
+=item *
+
+The B<visudo> program is no longer needed.  B<visudo> provides
+locking and syntax checking of the F<@sysconfdir@/sudoers> file.
+Since LDAP updates are atomic, locking is no longer necessary.
+Because syntax is checked when the data is inserted into LDAP, there
+is no need for a specialized tool to check syntax.
+
+=back
+
+Another major difference between LDAP and file-based I<sudoers>
+is that in LDAP, B<sudo>-specific Aliases are not supported.
+
+For the most part, there is really no need for B<sudo>-specific
+Aliases.  Unix groups or user netgroups can be used in place of
+User_Aliases and RunasAliases.  Host netgroups can be used in place
+of HostAliases.  Since Unix groups and netgroups can also be stored
+in LDAP there is no real need for B<sudo>-specific aliases.
+
+Cmnd_Aliases are not really required either since it is possible
+to have multiple users listed in a sudoRole.  Instead of defining
+a Cmnd_Alias that is referenced by multiple users, one can create
+a sudoRole that contains the commands and assign multiple users
+to it.
+
+=head2 SUDOers LDAP container
+
+The I<sudoers> configuration is contained in the C<ou=SUDOers> LDAP
+container.
+
+Sudo first looks for the C<cn=default> entry in the SUDOers container.
+If found, the multi-valued C<sudoOption> attribute is parsed in the
+same manner as a global C<Defaults> line in F<@sysconfdir@/sudoers>.  In
+the following example, the C<SSH_AUTH_SOCK> variable will be preserved
+in the environment for all users.
+
+    dn: cn=defaults,ou=SUDOers,dc=example,dc=com
+    objectClass: top
+    objectClass: sudoRole
+    cn: defaults
+    description: Default sudoOption's go here
+    sudoOption: env_keep+=SSH_AUTH_SOCK
+The equivalent of a sudoer in LDAP is a C<sudoRole>.  It consists of
+the following components:
+
+=over 4
+
+=item B<sudoUser>
+
+A user name, uid (prefixed with C<'#'>), Unix group (prefixed with
+a C<'%'>) or user netgroup (prefixed with a C<'+'>).
+
+=item B<sudoHost>
+
+A host name, IP address, IP network, or host netgroup (prefixed
+with a C<'+'>).
+The special value C<ALL> will match any host.
+
+=item B<sudoCommand>
+
+A Unix command with optional command line arguments, potentially
+including globbing characters (aka wild cards).
+The special value C<ALL> will match any command.
+If a command is prefixed with an exclamation point C<'!'>, the
+user will be prohibited from running that command.
+
+=item B<sudoOption>
+
+Identical in function to the global options described above, but
+specific to the C<sudoRole> in which it resides.
+
+=item B<sudoRunAsUser>
+
+A user name or uid (prefixed with C<'#'>) that commands may be run
+as or a Unix group (prefixed with a C<'%'>) or user netgroup (prefixed
+with a C<'+'>) that contains a list of users that commands may be
+run as.
+The special value C<ALL> will match any user.
+
+=item B<sudoRunAsGroup>
+
+A Unix group or gid (prefixed with C<'#'>) that commands may be run as.
+The special value C<ALL> will match any group.
+
+=back
+
+Each component listed above should contain a single value, but there
+may be multiple instances of each component type.  A sudoRole must
+contain at least one C<sudoUser>, C<sudoHost> and C<sudoCommand>.
+
+The following example allows users in group wheel to run any command
+on any host via B<sudo>:
+
+    dn: cn=%wheel,ou=SUDOers,dc=example,dc=com
+    objectClass: top
+    objectClass: sudoRole
+    cn: %wheel
+    sudoUser: %wheel
+    sudoHost: ALL
+    sudoCommand: ALL
+
+=head2 Anatomy of LDAP sudoers lookup
+
+When looking up a sudoer using LDAP there are only two or three
+LDAP queries per invocation.  The first query is to parse the global
+options.  The second is to match against the user's name and the
+groups that the user belongs to.  (The special ALL tag is matched
+in this query too.)  If no match is returned for the user's name
+and groups, a third query returns all entries containing user
+netgroups and checks to see if the user belongs to any of them.
+
+=head2 Differences between LDAP and non-LDAP sudoers
+
+There are some subtle differences in the way sudoers is handled
+once in LDAP.  Probably the biggest is that according to the RFC,
+LDAP ordering is arbitrary and you cannot expect that Attributes
+and Entries are returned in any specific order.  If there are
+conflicting command rules on an entry, the negative takes precedence.
+This is called paranoid behavior (not necessarily the most specific
+match).
+
+Here is an example:
+
+    # /etc/sudoers:
+    # Allow all commands except shell
+    johnny  ALL=(root) ALL,!/bin/sh
+    # Always allows all commands because ALL is matched last
+    puddles ALL=(root) !/bin/sh,ALL
+
+    # LDAP equivalent of johnny
+    # Allows all commands except shell
+    dn: cn=role1,ou=Sudoers,dc=my-domain,dc=com
+    objectClass: sudoRole
+    objectClass: top
+    cn: role1
+    sudoUser: johnny
+    sudoHost: ALL
+    sudoCommand: ALL
+    sudoCommand: !/bin/sh
+
+    # LDAP equivalent of puddles
+    # Notice that even though ALL comes last, it still behaves like
+    # role1 since the LDAP code assumes the more paranoid configuration
+    dn: cn=role2,ou=Sudoers,dc=my-domain,dc=com
+    objectClass: sudoRole
+    objectClass: top
+    cn: role2
+    sudoUser: puddles
+    sudoHost: ALL
+    sudoCommand: !/bin/sh
+    sudoCommand: ALL
+
+Another difference is that negations on the Host, User or Runas are
+currently ignorred.  For example, the following attributes do not
+behave the way one might expect.
+
+    # does not match all but joe
+    # rather, does not match anyone
+    sudoUser: !joe
+
+    # does not match all but joe
+    # rather, matches everyone including Joe
+    sudoUser: ALL
+    sudoUser: !joe
+
+    # does not match all but web01
+    # rather, matches all hosts including web01
+    sudoHost: ALL
+    sudoHost: !web01
+
+=head2 Sudoers Schema
+
+In order to use B<sudo>'s LDAP support, the B<sudo> schema must be
+installed on your LDAP server.  In addition, be sure to index the
+'sudoUser' attribute.
+
+Three versions of the schema: one for OpenLDAP servers (F<schema.OpenLDAP>),
+one for Netscape-derived servers (F<schema.iPlanet>), and one for
+Microsoft Active Directory (F<schema.ActiveDirectory>) may
+be found in the B<sudo> distribution.
+
+The schema for B<sudo> in OpenLDAP form is included in the L<EXAMPLES>
+section.
+
+=head2 Configuring ldap.conf
+
+Sudo reads the F<@ldap_conf@> file for LDAP-specific configuration.
+Typically, this file is shared amongst different LDAP-aware clients.
+As such, most of the settings are not B<sudo>-specific.  Note that
+B<sudo> parses F<@ldap_conf@> itself and may support options
+that differ from those described in the L<ldap.conf(5)> manual.
+
+Also note that on systems using the OpenLDAP libraries, default
+values specified in F</etc/openldap/ldap.conf> or the user's
+F<.ldaprc> files are not used.
+
+Only those options explicitly listed in F<@ldap_conf@> that are
+supported by B<sudo> are honored.  Configuration options are listed
+below in upper case but are parsed in a case-independent manner.
+
+=over 4
+
+=item B<URI> ldap[s]://[hostname[:port]] ...
+
+Specifies a whitespace-delimited list of one or more URIs describing
+the LDAP server(s) to connect to.  The I<protocol> may be either B<ldap>
+or B<ldaps>, the latter being for servers that support TLS (SSL)
+encryption.  If no I<port> is specified, the default is port 389 for
+C<ldap://> or port 636 for C<ldaps://>.  If no I<hostname> is specified,
+B<sudo> will connect to B<localhost>.  Only systems using the OpenSSL
+libraries support the mixing of C<ldap://> and C<ldaps://> URIs.
+The Netscape-derived libraries used on most commercial versions of
+Unix are only capable of supporting one or the other.
+
+=item B<HOST> name[:port] ...
+
+If no B<URI> is specified, the B<HOST> parameter specifies a
+whitespace-delimited list of LDAP servers to connect to.  Each host
+may include an optional I<port> separated by a colon (':').  The
+B<HOST> parameter is deprecated in favor of the B<URI> specification
+and is included for backwards compatibility.
+
+=item B<PORT> port_number
+
+If no B<URI> is specified, the B<PORT> parameter specifies the
+default port to connect to on the LDAP server if a B<HOST> parameter
+does not specify the port itself.  If no B<PORT> parameter is used,
+the default is port 389 for LDAP and port 636 for LDAP over TLS
+(SSL).  The B<PORT> parameter is deprecated in favor of the B<URI>
+specification and is included for backwards compatibility.
+
+=item B<BIND_TIMELIMIT> seconds
+
+The B<BIND_TIMELIMIT> parameter specifies the amount of time, in seconds,
+to wait while trying to connect to an LDAP server.  If multiple B<URI>s or
+B<HOST>s are specified, this is the amount of time to wait before trying
+the next one in the list.
+
+=item B<TIMELIMIT> seconds
+
+The B<TIMELIMIT> parameter specifies the amount of time, in seconds,
+to wait for a response to an LDAP query.
+
+=item B<SUDOERS_BASE> base
+
+The base DN to use when performing B<sudo> LDAP queries.  Typically
+this is of the form C<ou=SUDOers,dc=example,dc=com> for the domain
+C<example.com>.
+
+=item B<SUDOERS_DEBUG> debug_level
+
+This sets the debug level for B<sudo> LDAP queries.  Debugging
+information is printed to the standard error.  A value of 1 results
+in a moderate amount of debugging information.  A value of 2 shows
+the results of the matches themselves.  This parameter should not
+be set in a production environment as the extra information is
+likely to confuse users.
+
+=item B<BINDDN> DN
+
+The B<BINDDN> parameter specifies the identity, in the form of a
+Distinguished Name (DN), to use when performing LDAP operations.
+If not specified, LDAP operations are performed with an anonymous
+identity.  By default, most LDAP servers will allow anonymous access.
+
+=item B<BINDPW> secret
+
+The B<BINDPW> parameter specifies the password to use when performing
+LDAP operations.  This is typically used in conjunction with the
+B<BINDDN> parameter.
+
+=item B<ROOTBINDDN> DN
+
+The B<ROOTBINDDN> parameter specifies the identity, in the form of
+a Distinguished Name (DN), to use when performing privileged LDAP
+operations, such as I<sudoers> queries.  The password corresponding
+to the identity should be stored in F<@ldap_secret@>.
+If not specified, the B<BINDDN> identity is used (if any).
+
+=item B<LDAP_VERSION> number
+
+The version of the LDAP protocol to use when connecting to the server.
+The default value is protocol version 3.
+
+=item B<SSL> on/true/yes/off/false/no
+
+If the B<SSL> parameter is set to C<on>, C<true> or C<yes>, TLS
+(SSL) encryption is always used when communicating with the LDAP
+server.  Typically, this involves connecting to the server on port
+636 (ldaps).
+
+=item B<SSL> start_tls
+
+If the B<SSL> parameter is set to C<start_tls>, the LDAP server
+connection is initiated normally and TLS encryption is begun before
+the bind credentials are sent.  This has the advantage of not
+requiring a dedicated port for encrypted communications.  This
+parameter is only supported by LDAP servers that honor the C<start_tls>
+extension, such as the OpenLDAP server.
+
+=item B<TLS_CHECKPEER> on/true/yes/off/false/no
+
+If enabled, B<TLS_CHECKPEER> will cause the LDAP server's TLS
+certificated to be verified.  If the server's TLS certificate cannot
+be verified (usually because it is signed by an unknown certificate
+authority), B<sudo> will be unable to connect to it.  If B<TLS_CHECKPEER>
+is disabled, no check is made.
+
+=item B<TLS_CACERTFILE> file name
+
+The path to a certificate authority bundle which contains the certificates
+for all the Certificate Authorities the client knows to be valid,
+e.g. F</etc/ssl/ca-bundle.pem>.
+This option is only supported by the OpenLDAP libraries.
+
+=item B<TLS_CACERTDIR> directory
+
+Similar to B<TLS_CACERTFILE> but instead of a file, it is a
+directory containing individual Certificate Authority certificates,
+e.g. F</etc/ssl/certs>.
+The directory specified by B<TLS_CACERTDIR> is checked after
+B<TLS_CACERTFILE>.
+This option is only supported by the OpenLDAP libraries.
+
+=item B<TLS_CERT> file name
+
+The path to a file containing the client certificate which can
+be used to authenticate the client to the LDAP server.
+The certificate type depends on the LDAP libraries used.
+
+OpenLDAP:
+    C<tls_cert /etc/ssl/client_cert.pem>
+
+Netscape-derived:
+    C<tls_cert /var/ldap/cert7.db>
+
+When using Netscape-derived libraries, this file may also contain
+Certificate Authority certificates.
+
+=item B<TLS_KEY> file name
+
+The path to a file containing the private key which matches the
+certificate specified by B<TLS_CERT>.  The private key must not be
+password-protected.  The key type depends on the LDAP libraries
+used.
+
+OpenLDAP:
+    C<tls_key /etc/ssl/client_key.pem>
+
+Netscape-derived:
+    C<tls_key /var/ldap/key3.db>
+
+=item B<TLS_RANDFILE> file name
+
+The B<TLS_RANDFILE> parameter specifies the path to an entropy
+source for systems that lack a random device.  It is generally used
+in conjunction with I<prngd> or I<egd>.
+This option is only supported by the OpenLDAP libraries.
+
+=item B<TLS_CIPHERS> cipher list
+
+The B<TLS_CIPHERS> parameter allows the administer to restrict
+which encryption algorithms may be used for TLS (SSL) connections.
+See the OpenSSL manual for a list of valid ciphers.
+This option is only supported by the OpenLDAP libraries.
+
+=item B<USE_SASL> on/true/yes/off/false/no
+
+Enable B<USE_SASL> for LDAP servers that support SASL authentication.
+
+=item B<SASL_AUTH_ID> identity
+
+The SASL user name to use when connecting to the LDAP server.
+By default, B<sudo> will use an anonymous connection.
+
+=item B<ROOTUSE_SASL> on/true/yes/off/false/no
+
+Enable B<ROOTUSE_SASL> to enable SASL authentication when connecting
+to an LDAP server from a privileged process, such as B<sudo>.
+
+=item B<ROOTSASL_AUTH_ID> identity
+
+The SASL user name to use when B<ROOTUSE_SASL> is enabled.
+
+=item B<SASL_SECPROPS> none/properties
+
+SASL security properties or I<none> for no properties.  See the
+SASL programmer's manual for details.
+
+=item B<KRB5_CCNAME> file name
+
+The path to the Kerberos 5 credential cache to use when authenticating
+with the remote server.
+
+=back
+
+See the C<ldap.conf> entry in the L<EXAMPLES> section.
+
+=head2 Configuring nsswitch.conf
+
+Unless it is disabled at build time, B<sudo> consults the Name
+Service Switch file, F<@nsswitch_conf@>, to specify the I<sudoers>
+search order.  Sudo looks for a line beginning with C<sudoers:> and
+uses this to determine the search order.  Note that B<sudo> does
+not stop searching after the first match and later matches take
+precedence over earlier ones.
+
+The following sources are recognized:
+
+    files      read sudoers from F<@sysconfdir@/sudoers>
+    ldap       read sudoers from LDAP
+
+In addition, the entry C<[NOTFOUND=return]> will short-circuit the
+search if the user was not found in the preceding source.
+
+To consult LDAP first followed by the local sudoers file (if it
+exists), use:
+
+    sudoers: ldap files
+
+The local I<sudoers> file can be ignored completely by using:
+
+    sudoers: ldap
+
+If the F<@nsswitch_conf@> file is not present or there is no
+sudoers line, the following default is assumed:
+
+    sudoers: files
+
+Note that F<@nsswitch_conf@> is supported even when the underlying
+operating system does not use an nsswitch.conf file.
+
+=head1 FILES
+
+=over 24
+
+=item F<@ldap_conf@>
+
+LDAP configuration file
+
+=item F<@nsswitch_conf@>
+
+determines sudoers source order
+
+=back
+
+=head1 EXAMPLES
+
+=head2 Example ldap.conf
+
+  # Either specify one or more URIs or one or more host:port pairs.
+  # If neither is specified sudo will default to localhost, port 389.
+  #
+  #host          ldapserver
+  #host          ldapserver1 ldapserver2:390
+  #
+  # Default port if host is specified without one, defaults to 389.
+  #port          389
+  #
+  # URI will override the host and port settings.
+  uri            ldap://ldapserver
+  #uri            ldaps://secureldapserver
+  #uri            ldaps://secureldapserver ldap://ldapserver
+  #
+  # The amount of time, in seconds, to wait while trying to connect to
+  # an LDAP server.
+  bind_timelimit 30
+  #
+  # The amount of time, in seconds, to wait while performing an LDAP query.
+  timelimit 30
+  #
+  # must be set or sudo will ignore LDAP
+  sudoers_base   ou=SUDOers,dc=example,dc=com
+  #
+  # verbose sudoers matching from ldap
+  #sudoers_debug 2
+  #
+  # optional proxy credentials
+  #binddn        <who to search as>
+  #bindpw        <password>
+  #rootbinddn    <who to search as, uses /etc/ldap.secret for bindpw>
+  #
+  # LDAP protocol version, defaults to 3
+  #ldap_version 3
+  #
+  # Define if you want to use an encrypted LDAP connection.
+  # Typically, you must also set the port to 636 (ldaps).
+  #ssl on
+  #
+  # Define if you want to use port 389 and switch to
+  # encryption before the bind credentials are sent.
+  # Only supported by LDAP servers that support the start_tls
+  # extension such as OpenLDAP.
+  #ssl start_tls
+  #
+  # Additional TLS options follow that allow tweaking of the
+  # SSL/TLS connection.
+  #
+  #tls_checkpeer yes # verify server SSL certificate
+  #tls_checkpeer no  # ignore server SSL certificate
+  #
+  # If you enable tls_checkpeer, specify either tls_cacertfile
+  # or tls_cacertdir.  Only supported when using OpenLDAP.
+  #
+  #tls_cacertfile /etc/certs/trusted_signers.pem
+  #tls_cacertdir  /etc/certs
+  #
+  # For systems that don't have /dev/random
+  # use this along with PRNGD or EGD.pl to seed the
+  # random number pool to generate cryptographic session keys.
+  # Only supported when using OpenLDAP.
+  #
+  #tls_randfile /etc/egd-pool
+  #
+  # You may restrict which ciphers are used.  Consult your SSL
+  # documentation for which options go here.
+  # Only supported when using OpenLDAP.
+  #
+  #tls_ciphers <cipher-list>
+  #
+  # Sudo can provide a client certificate when communicating to
+  # the LDAP server.
+  # Tips:
+  #   * Enable both lines at the same time.
+  #   * Do not password protect the key file.
+  #   * Ensure the keyfile is only readable by root.
+  #
+  # For OpenLDAP:
+  #tls_cert /etc/certs/client_cert.pem
+  #tls_key  /etc/certs/client_key.pem
+  #
+  # For SunONE or iPlanet LDAP, the file specified by tls_cert may
+  # contain CA certs and/or the client's cert.  If the client's
+  # cert is included, tls_key should be specified as well.
+  # For backward compatibility, sslpath may be used in place of tls_cert.
+  #tls_cert /var/ldap/cert7.db
+  #tls_key /var/ldap/key3.db
+  #
+  # If using SASL authentication for LDAP (OpenSSL)
+  # use_sasl yes
+  # sasl_auth_id <SASL username>
+  # rootuse_sasl yes
+  # rootsasl_auth_id <SASL username for root access>
+  # sasl_secprops none
+  # krb5_ccname /etc/.ldapcache
+
+=head2 Sudo schema for OpenLDAP 
+
+The following schema is in OpenLDAP format.  Simply copy it to the
+schema directory (e.g. F</etc/openldap/schema>), add the proper
+C<include> line in C<slapd.conf> and restart B<slapd>.
+
+ attributetype ( 1.3.6.1.4.1.15953.9.1.1
+    NAME 'sudoUser'
+    DESC 'User(s) who may  run sudo'
+    EQUALITY caseExactIA5Match
+    SUBSTR caseExactIA5SubstringsMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+ attributetype ( 1.3.6.1.4.1.15953.9.1.2
+    NAME 'sudoHost'
+    DESC 'Host(s) who may run sudo'
+    EQUALITY caseExactIA5Match
+    SUBSTR caseExactIA5SubstringsMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+ attributetype ( 1.3.6.1.4.1.15953.9.1.3
+    NAME 'sudoCommand'
+    DESC 'Command(s) to be executed by sudo'
+    EQUALITY caseExactIA5Match
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+ attributetype ( 1.3.6.1.4.1.15953.9.1.4
+    NAME 'sudoRunAs'
+    DESC 'User(s) impersonated by sudo'
+    EQUALITY caseExactIA5Match
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+ attributetype ( 1.3.6.1.4.1.15953.9.1.5
+    NAME 'sudoOption'
+    DESC 'Options(s) followed by sudo'
+    EQUALITY caseExactIA5Match
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+ attributetype ( 1.3.6.1.4.1.15953.9.1.6
+    NAME 'sudoRunAsUser'
+    DESC 'User(s) impersonated by sudo'
+    EQUALITY caseExactIA5Match
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+ attributetype ( 1.3.6.1.4.1.15953.9.1.7
+    NAME 'sudoRunAsGroup'
+    DESC 'Group(s) impersonated by sudo'
+    EQUALITY caseExactIA5Match
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+ objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL
+    DESC 'Sudoer Entries'
+    MUST ( cn )
+    MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $
+         sudoRunAsGroup $ sudoOption $ description )
+    )
+
+=for comment
+
+Add nsswitch.conf example?
+Add more exhaustive sudoers ldif example?
+
+=head1 SEE ALSO
+
+L<ldap.conf(5)>, L<sudoers(5)>
+
+=head1 CAVEATS
+
+The way that I<sudoers> is parsed differs between Note that there
+are differences in the way that LDAP-based I<sudoers> is parsed
+compared to file-based I<sudoers>.  See the L<Differences between
+LDAP and non-LDAP sudoers> section for more information.
+
+=head1 BUGS
+
+If you feel you have found a bug in B<sudo>, please submit a bug report
+at http://www.sudo.ws/sudo/bugs/
+
+=head1 SUPPORT
+
+Limited free support is available via the sudo-users mailing list,
+see http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+
+=head1 DISCLAIMER
+
+B<sudo> 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.  See the LICENSE
+file distributed with B<sudo> or http://www.sudo.ws/sudo/license.html
+for complete details.
index 9184006f5ceef09aa58f0ad655578c4876973ace..533c8c70ce76d19160226e10e25d43b7c96edc5b 100644 (file)
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1994-1996, 1998-2005, 2007
+.\" Copyright (c) 1994-1996, 1998-2005, 2007-2008
 .\"    Todd C. Miller <Todd.Miller@courtesan.com>
 .\" 
 .\" Permission to use, copy, modify, and distribute this software for any
@@ -18,8 +18,8 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\" 
-.\" $Sudo: sudoers.man.in,v 1.45.2.29 2008/06/22 20:29:03 millert Exp $
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
+.\" $Sudo: sudoers.man.in,v 1.74 2008/12/03 20:58:41 millert Exp $
+.\" Automatically generated by Pod::Man 2.16 (Pod::Simple 3.05)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
 ..
 .\" Set up some character translations and predefined strings.  \*(-- will
 .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote.  | will give a
-.\" real vertical bar.  \*(C+ will give a nicer C++.  Capital omega is used to
-.\" do unbreakable dashes and therefore won't be available.  \*(C` and \*(C'
-.\" expand to `' in nroff, nothing in troff, for use with C<>.
-.tr \(*W-|\(bv\*(Tr
+.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
+.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
 .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
 .ie n \{\
 .    ds -- \(*W-
 .    ds R" ''
 'br\}
 .\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\"
 .\" If the F register is turned on, we'll generate index entries on stderr for
 .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
-.if \nF \{\
+.ie \nF \{\
 .    de IX
 .    tm Index:\\$1\t\\n%\t"\\$2"
 ..
 .    nr % 0
 .    rr F
 .\}
-.\"
-.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
+.el \{\
+.    de IX
+..
+.\}
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
 .\" ========================================================================
 .\"
 .IX Title "SUDOERS @mansectform@"
-.TH SUDOERS @mansectform@ "Jun 21, 2008" "1.6.9p17" "MAINTENANCE COMMANDS"
+.TH SUDOERS @mansectform@ "December  3, 2008" "1.7.0" "MAINTENANCE COMMANDS"
+.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
 .SH "NAME"
 sudoers \- list of which users may execute what
 .SH "DESCRIPTION"
@@ -205,30 +212,20 @@ There are four kinds of aliases: \f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_A
 \&\f(CW\*(C`Host_Alias\*(C'\fR and \f(CW\*(C`Cmnd_Alias\*(C'\fR.
 .PP
 .Vb 4
-\& Alias ::= 'User_Alias'  User_Alias (':' User_Alias)* |
-\&           'Runas_Alias' Runas_Alias (':' Runas_Alias)* |
-\&           'Host_Alias'  Host_Alias (':' Host_Alias)* |
-\&           'Cmnd_Alias'  Cmnd_Alias (':' Cmnd_Alias)*
-.Ve
-.PP
-.Vb 1
-\& User_Alias ::= NAME '=' User_List
-.Ve
-.PP
-.Vb 1
-\& Runas_Alias ::= NAME '=' Runas_List
-.Ve
-.PP
-.Vb 1
-\& Host_Alias ::= NAME '=' Host_List
-.Ve
-.PP
-.Vb 1
-\& Cmnd_Alias ::= NAME '=' Cmnd_List
-.Ve
-.PP
-.Vb 1
-\& NAME ::= [A-Z]([A-Z][0-9]_)*
+\& Alias ::= \*(AqUser_Alias\*(Aq  User_Alias (\*(Aq:\*(Aq User_Alias)* |
+\&           \*(AqRunas_Alias\*(Aq Runas_Alias (\*(Aq:\*(Aq Runas_Alias)* |
+\&           \*(AqHost_Alias\*(Aq  Host_Alias (\*(Aq:\*(Aq Host_Alias)* |
+\&           \*(AqCmnd_Alias\*(Aq  Cmnd_Alias (\*(Aq:\*(Aq Cmnd_Alias)*
+\&
+\& User_Alias ::= NAME \*(Aq=\*(Aq User_List
+\&
+\& Runas_Alias ::= NAME \*(Aq=\*(Aq Runas_List
+\&
+\& Host_Alias ::= NAME \*(Aq=\*(Aq Host_List
+\&
+\& Cmnd_Alias ::= NAME \*(Aq=\*(Aq Cmnd_List
+\&
+\& NAME ::= [A\-Z]([A\-Z][0\-9]_)*
 .Ve
 .PP
 Each \fIalias\fR definition is of the form
@@ -251,54 +248,48 @@ The definitions of what constitutes a valid \fIalias\fR member follow.
 .PP
 .Vb 2
 \& User_List ::= User |
-\&               User ',' User_List
-.Ve
-.PP
-.Vb 4
-\& User ::= '!'* username |
-\&          '!'* '%'group |
-\&          '!'* '+'netgroup |
-\&          '!'* User_Alias
+\&               User \*(Aq,\*(Aq User_List
+\&
+\& User ::= \*(Aq!\*(Aq* username |
+\&          \*(Aq!\*(Aq* \*(Aq#\*(Aquid |
+\&          \*(Aq!\*(Aq* \*(Aq%\*(Aqgroup |
+\&          \*(Aq!\*(Aq* \*(Aq+\*(Aqnetgroup |
+\&          \*(Aq!\*(Aq* User_Alias
 .Ve
 .PP
-A \f(CW\*(C`User_List\*(C'\fR is made up of one or more usernames, system groups
-(prefixed with '%'), netgroups (prefixed with '+') and other aliases.
-Each list item may be prefixed with one or more '!' operators.
-An odd number of '!' operators negate the value of the item; an even
-number just cancel each other out.
+A \f(CW\*(C`User_List\*(C'\fR is made up of one or more usernames, uids (prefixed
+with '#'), system groups (prefixed with '%'), netgroups (prefixed
+with '+') and \f(CW\*(C`User_Alias\*(C'\fRes.  Each list item may be prefixed with
+zero or more '!' operators.  An odd number of '!' operators negate
+the value of the item; an even number just cancel each other out.
 .PP
 .Vb 2
-\& Runas_List ::= Runas_User |
-\&                Runas_User ',' Runas_List
+\& Runas_List ::= Runas_Member |
+\&                Runas_Member \*(Aq,\*(Aq Runas_List
+\&
+\& Runas_Member ::= \*(Aq!\*(Aq* username |
+\&                  \*(Aq!\*(Aq* \*(Aq#\*(Aquid |
+\&                  \*(Aq!\*(Aq* \*(Aq%\*(Aqgroup |
+\&                  \*(Aq!\*(Aq* +netgroup |
+\&                  \*(Aq!\*(Aq* Runas_Alias
 .Ve
 .PP
-.Vb 5
-\& Runas_User ::= '!'* username |
-\&                '!'* '#'uid |
-\&                '!'* '%'group |
-\&                '!'* +netgroup |
-\&                '!'* Runas_Alias
-.Ve
-.PP
-A \f(CW\*(C`Runas_List\*(C'\fR is similar to a \f(CW\*(C`User_List\*(C'\fR except that it can
-also contain uids (prefixed with '#') and instead of \f(CW\*(C`User_Alias\*(C'\fRes
-it can contain \f(CW\*(C`Runas_Alias\*(C'\fRes.  Note that usernames and groups
-are matched as strings.  In other words, two users (groups) with
-the same uid (gid) are considered to be distinct.  If you wish to
-match all usernames with the same uid (e.g.\ root and toor), you
-can use a uid instead (#0 in the example given).
+A \f(CW\*(C`Runas_List\*(C'\fR is similar to a \f(CW\*(C`User_List\*(C'\fR except that instead
+of \f(CW\*(C`User_Alias\*(C'\fRes it can contain \f(CW\*(C`Runas_Alias\*(C'\fRes.  Note that
+usernames and groups are matched as strings.  In other words, two
+users (groups) with the same uid (gid) are considered to be distinct.
+If you wish to match all usernames with the same uid (e.g.\ root
+and toor), you can use a uid instead (#0 in the example given).
 .PP
 .Vb 2
 \& Host_List ::= Host |
-\&               Host ',' Host_List
-.Ve
-.PP
-.Vb 5
-\& Host ::= '!'* hostname |
-\&          '!'* ip_addr |
-\&          '!'* network(/netmask)? |
-\&          '!'* '+'netgroup |
-\&          '!'* Host_Alias
+\&               Host \*(Aq,\*(Aq Host_List
+\&
+\& Host ::= \*(Aq!\*(Aq* hostname |
+\&          \*(Aq!\*(Aq* ip_addr |
+\&          \*(Aq!\*(Aq* network(/netmask)? |
+\&          \*(Aq!\*(Aq* \*(Aq+\*(Aqnetgroup |
+\&          \*(Aq!\*(Aq* Host_Alias
 .Ve
 .PP
 A \f(CW\*(C`Host_List\*(C'\fR is made up of one or more hostnames, \s-1IP\s0 addresses,
@@ -318,20 +309,16 @@ wildcards to be useful.
 .PP
 .Vb 2
 \& Cmnd_List ::= Cmnd |
-\&               Cmnd ',' Cmnd_List
-.Ve
-.PP
-.Vb 3
+\&               Cmnd \*(Aq,\*(Aq Cmnd_List
+\&
 \& commandname ::= filename |
 \&                 filename args |
-\&                 filename '""'
-.Ve
-.PP
-.Vb 4
-\& Cmnd ::= '!'* commandname |
-\&          '!'* directory |
-\&          '!'* "sudoedit" |
-\&          '!'* Cmnd_Alias
+\&                 filename \*(Aq""\*(Aq
+\&
+\& Cmnd ::= \*(Aq!\*(Aq* commandname |
+\&          \*(Aq!\*(Aq* directory |
+\&          \*(Aq!\*(Aq* "sudoedit" |
+\&          \*(Aq!\*(Aq* Cmnd_Alias
 .Ve
 .PP
 A \f(CW\*(C`Cmnd_List\*(C'\fR is a list of one or more commandnames, directories, and other
@@ -350,7 +337,7 @@ in the \f(CW\*(C`Cmnd\*(C'\fR must match exactly those given by the user on the
 (or match the wildcards if there are any).  Note that the following
 characters must be escaped with a '\e' if they are used in command
 arguments: ',', ':', '=', '\e'.  The special command \f(CW"sudoedit"\fR
-is used to permit a user to run \fBsudo\fR with the \fB\-e\fR flag (or
+is used to permit a user to run \fBsudo\fR with the \fB\-e\fR option (or
 as \fBsudoedit\fR).  It may take command line arguments just as
 a normal command does.
 .Sh "Defaults"
@@ -358,29 +345,27 @@ a normal command does.
 Certain configuration options may be changed from their default
 values at runtime via one or more \f(CW\*(C`Default_Entry\*(C'\fR lines.  These
 may affect all users on any host, all users on a specific host, a
-specific user, or commands being run as a specific user.
+specific user, a specific command, or commands being run as a specific user.
+Note that per-command entries may not include command line arguments.
+If you need to specify arguments, define a \f(CW\*(C`Cmnd_Alias\*(C'\fR and reference
+that instead.
 .PP
-.Vb 4
-\& Default_Type ::= 'Defaults' |
-\&                  'Defaults' '@' Host_List |
-\&                  'Defaults' ':' User_List |
-\&                  'Defaults' '>' Runas_List
-.Ve
-.PP
-.Vb 1
+.Vb 5
+\& Default_Type ::= \*(AqDefaults\*(Aq |
+\&                  \*(AqDefaults\*(Aq \*(Aq@\*(Aq Host_List |
+\&                  \*(AqDefaults\*(Aq \*(Aq:\*(Aq User_List |
+\&                  \*(AqDefaults\*(Aq \*(Aq!\*(Aq Cmnd_List |
+\&                  \*(AqDefaults\*(Aq \*(Aq>\*(Aq Runas_List
+\&
 \& Default_Entry ::= Default_Type Parameter_List
-.Ve
-.PP
-.Vb 2
+\&
 \& Parameter_List ::= Parameter |
-\&                    Parameter ',' Parameter_List
-.Ve
-.PP
-.Vb 4
-\& Parameter ::= Parameter '=' Value |
-\&               Parameter '+=' Value |
-\&               Parameter '-=' Value |
-\&               '!'* Parameter
+\&                    Parameter \*(Aq,\*(Aq Parameter_List
+\&
+\& Parameter ::= Parameter \*(Aq=\*(Aq Value |
+\&               Parameter \*(Aq+=\*(Aq Value |
+\&               Parameter \*(Aq\-=\*(Aq Value |
+\&               \*(Aq!\*(Aq* Parameter
 .Ve
 .PP
 Parameters may be \fBflags\fR, \fBinteger\fR values, \fBstrings\fR, or \fBlists\fR.
@@ -395,30 +380,26 @@ These operators are used to add to and delete from a list respectively.
 It is not an error to use the \f(CW\*(C`\-=\*(C'\fR operator to remove an element
 that does not exist in a list.
 .PP
+Defaults entries are parsed in the following order: generic, host
+and user Defaults first, then runas Defaults and finally command
+defaults.
+.PP
 See \*(L"\s-1SUDOERS\s0 \s-1OPTIONS\s0\*(R" for a list of supported Defaults parameters.
 .Sh "User Specification"
 .IX Subsection "User Specification"
 .Vb 2
-\& User_Spec ::= User_List Host_List '=' Cmnd_Spec_List \e
-\&               (':' Host_List '=' Cmnd_Spec_List)*
-.Ve
-.PP
-.Vb 2
+\& User_Spec ::= User_List Host_List \*(Aq=\*(Aq Cmnd_Spec_List \e
+\&               (\*(Aq:\*(Aq Host_List \*(Aq=\*(Aq Cmnd_Spec_List)*
+\&
 \& Cmnd_Spec_List ::= Cmnd_Spec |
-\&                    Cmnd_Spec ',' Cmnd_Spec_List
-.Ve
-.PP
-.Vb 1
+\&                    Cmnd_Spec \*(Aq,\*(Aq Cmnd_Spec_List
+\&
 \& Cmnd_Spec ::= Runas_Spec? Tag_Spec* Cmnd
-.Ve
-.PP
-.Vb 1
-\& Runas_Spec ::= '(' Runas_List ')'
-.Ve
-.PP
-.Vb 2
-\& Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' |
-\&               'SETENV:' | 'NOSETENV:')
+\&
+\& Runas_Spec ::= \*(Aq(\*(Aq Runas_List? (: Runas_List)? \*(Aq)\*(Aq
+\&
+\& Tag_Spec ::= (\*(AqNOPASSWD:\*(Aq | \*(AqPASSWD:\*(Aq | \*(AqNOEXEC:\*(Aq | \*(AqEXEC:\*(Aq |
+\&               \*(AqSETENV:\*(Aq | \*(AqNOSETENV:\*(Aq )
 .Ve
 .PP
 A \fBuser specification\fR determines which commands a user may run
@@ -428,11 +409,24 @@ run as \fBroot\fR, but this can be changed on a per-command basis.
 Let's break that down into its constituent parts:
 .Sh "Runas_Spec"
 .IX Subsection "Runas_Spec"
-A \f(CW\*(C`Runas_Spec\*(C'\fR is simply a \f(CW\*(C`Runas_List\*(C'\fR (as defined above)
-enclosed in a set of parentheses.  If you do not specify a
-\&\f(CW\*(C`Runas_Spec\*(C'\fR in the user specification, a default \f(CW\*(C`Runas_Spec\*(C'\fR
-of \fBroot\fR will be used.  A \f(CW\*(C`Runas_Spec\*(C'\fR sets the default for
-commands that follow it.  What this means is that for the entry:
+A \f(CW\*(C`Runas_Spec\*(C'\fR determines the user and/or the group that a command
+may be run as.  A fully-specified \f(CW\*(C`Runas_Spec\*(C'\fR consists of two
+\&\f(CW\*(C`Runas_List\*(C'\fRs (as defined above) separated by a colon (':') and
+enclosed in a set of parentheses.  The first \f(CW\*(C`Runas_List\*(C'\fR indicates
+which users the command may be run as via \fBsudo\fR's \fB\-u\fR option.
+The second defines a list of groups that can be specified via
+\&\fBsudo\fR's \fB\-g\fR option.  If both \f(CW\*(C`Runas_List\*(C'\fRs are specified, the
+command may be run with any combination of users and groups listed
+in their respective \f(CW\*(C`Runas_List\*(C'\fRs.  If only the first is specified,
+the command may be run as any user in the list but no \fB\-g\fR option
+may be specified.  If the first \f(CW\*(C`Runas_List\*(C'\fR is empty but the
+second is specified, the command may be run as the invoking user
+with the group set to any listed in the \f(CW\*(C`Runas_List\*(C'\fR.  If no
+\&\f(CW\*(C`Runas_Spec\*(C'\fR is specified the command may be run as \fBroot\fR and
+no group may be specified.
+.PP
+A \f(CW\*(C`Runas_Spec\*(C'\fR sets the default for the commands that follow it.
+What this means is that for the entry:
 .PP
 .Vb 1
 \& dgb    boulder = (operator) /bin/ls, /bin/kill, /usr/bin/lprm
@@ -442,7 +436,7 @@ The user \fBdgb\fR may run \fI/bin/ls\fR, \fI/bin/kill\fR, and
 \&\fI/usr/bin/lprm\fR \*(-- but only as \fBoperator\fR.  E.g.,
 .PP
 .Vb 1
-\& $ sudo -u operator /bin/ls.
+\& $ sudo \-u operator /bin/ls.
 .Ve
 .PP
 It is also possible to override a \f(CW\*(C`Runas_Spec\*(C'\fR later on in an
@@ -454,10 +448,27 @@ entry.  If we modify the entry like so:
 .PP
 Then user \fBdgb\fR is now allowed to run \fI/bin/ls\fR as \fBoperator\fR,
 but  \fI/bin/kill\fR and \fI/usr/bin/lprm\fR as \fBroot\fR.
+.PP
+We can extend this to allow \fBdgb\fR to run \f(CW\*(C`/bin/ls\*(C'\fR with either
+the user or group set to \fBoperator\fR:
+.PP
+.Vb 2
+\& dgb    boulder = (operator : operator) /bin/ls, (root) /bin/kill, \e
+\&        /usr/bin/lprm
+.Ve
+.PP
+In the following example, user \fBtcm\fR may run commands that access
+a modem device file with the dialer group.  Note that in this example
+only the group will be set, the command still runs as user \fBtcm\fR.
+.PP
+.Vb 2
+\& tcm    boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \e
+\&        /usr/local/bin/minicom
+.Ve
 .Sh "Tag_Spec"
 .IX Subsection "Tag_Spec"
 A command may have zero or more tags associated with it.  There are
-six possible tag values, \f(CW\*(C`NOPASSWD\*(C'\fR, \f(CW\*(C`PASSWD\*(C'\fR, \f(CW\*(C`NOEXEC\*(C'\fR, \f(CW\*(C`EXEC\*(C'\fR,
+eight possible tag values, \f(CW\*(C`NOPASSWD\*(C'\fR, \f(CW\*(C`PASSWD\*(C'\fR, \f(CW\*(C`NOEXEC\*(C'\fR, \f(CW\*(C`EXEC\*(C'\fR,
 \&\f(CW\*(C`SETENV\*(C'\fR and \f(CW\*(C`NOSETENV\*(C'\fR.
 Once a tag is set on a \f(CW\*(C`Cmnd\*(C'\fR, subsequent \f(CW\*(C`Cmnd\*(C'\fRs in the
 \&\f(CW\*(C`Cmnd_Spec_List\*(C'\fR, inherit the tag unless it is overridden by the
@@ -479,7 +490,7 @@ For example:
 .Ve
 .PP
 would allow the user \fBray\fR to run \fI/bin/kill\fR, \fI/bin/ls\fR, and
-\&\fI/usr/bin/lprm\fR as root on the machine rushmore as \fBroot\fR without
+\&\fI/usr/bin/lprm\fR as \fBroot\fR on the machine rushmore without
 authenticating himself.  If we only want \fBray\fR to be able to
 run \fI/bin/kill\fR without a password the entry would be:
 .PP
@@ -528,7 +539,7 @@ be overridden by use of the \f(CW\*(C`UNSETENV\*(C'\fR tag.
 .Sh "Wildcards"
 .IX Subsection "Wildcards"
 \&\fBsudo\fR allows shell-style \fIwildcards\fR (aka meta or glob characters)
-to be used in pathnames as well as command line arguments in the
+to be used in hostnames, pathnames and command line arguments in the
 \&\fIsudoers\fR file.  Wildcard matching is done via the \fB\s-1POSIX\s0\fR
 \&\fIfnmatch\fR\|(3) routine.  Note that these are \fInot\fR regular expressions.
 .ie n .IP "\*(C`*\*(C'" 8
@@ -553,6 +564,17 @@ Matches any character \fBnot\fR in the specified range.
 For any character \*(L"x\*(R", evaluates to \*(L"x\*(R".  This is used to
 escape special characters such as: \*(L"*\*(R", \*(L"?\*(R", \*(L"[\*(R", and \*(L"}\*(R".
 .PP
+\&\s-1POSIX\s0 character classes may also be used if your system's
+\&\fIfnmatch\fR\|(3) function supports them.  However, because the
+\&\f(CW\*(Aq:\*(Aq\fR character has special meaning in \fIsudoers\fR, it must
+be escaped.  For example:
+.PP
+.Vb 1
+\&    /bin/ls [[\e:alpha\e:]]*
+.Ve
+.PP
+Would match any filename beginning with a letter.
+.PP
 Note that a forward slash ('/') will \fBnot\fR be matched by
 wildcards used in the pathname.  When matching the command
 line arguments, however, a slash \fBdoes\fR get matched by
@@ -572,6 +594,27 @@ The following exceptions apply to the above rules:
 If the empty string \f(CW""\fR is the only command line argument in the
 \&\fIsudoers\fR entry it means that command is not allowed to be run
 with \fBany\fR arguments.
+.Sh "Including other files from within sudoers"
+.IX Subsection "Including other files from within sudoers"
+It is possible to include other \fIsudoers\fR files from within the
+\&\fIsudoers\fR file currently being parsed using the \f(CW\*(C`#include\*(C'\fR
+directive, similar to the one used by the C preprocessor.  This is
+useful, for example, for keeping a site-wide \fIsudoers\fR file in
+addition to a per-machine local one.  For the sake of this example
+the site-wide \fIsudoers\fR will be \fI/etc/sudoers\fR and the per-machine
+one will be \fI/etc/sudoers.local\fR.  To include \fI/etc/sudoers.local\fR
+from \fI/etc/sudoers\fR we would use the following line in \fI/etc/sudoers\fR:
+.PP
+.Vb 1
+\& #include /etc/sudoers.local
+.Ve
+.PP
+When \fBsudo\fR reaches this line it will suspend processing of the
+current file (\fI/etc/sudoers\fR) and switch to \fI/etc/sudoers.local\fR.
+Upon reaching the end of \fI/etc/sudoers.local\fR, the rest of
+\&\fI/etc/sudoers\fR will be processed.  Files that are included may
+themselves include other files.  A hard limit of 128 nested include
+files is enforced to prevent include file loops.
 .Sh "Other special characters and reserved words"
 .IX Subsection "Other special characters and reserved words"
 The pound sign ('#') is used to indicate a comment (unless it is
@@ -615,7 +658,7 @@ grouped by type, are listed below.
 .IX Item "always_set_home"
 If set, \fBsudo\fR will set the \f(CW\*(C`HOME\*(C'\fR environment variable to the home
 directory of the target user (which is root unless the \fB\-u\fR option is used).
-This effectively means that the \fB\-H\fR flag is always implied.
+This effectively means that the \fB\-H\fR option is always implied.
 This flag is \fIoff\fR by default.
 .IP "authenticate" 16
 .IX Item "authenticate"
@@ -623,6 +666,11 @@ If set, users must authenticate themselves via a password (or other
 means of authentication) before they may run commands.  This default
 may be overridden via the \f(CW\*(C`PASSWD\*(C'\fR and \f(CW\*(C`NOPASSWD\*(C'\fR tags.
 This flag is \fIon\fR by default.
+.IP "closefrom_override" 16
+.IX Item "closefrom_override"
+If set, the user may use \fBsudo\fR's \fB\-C\fR option which
+overrides the default starting point at which \fBsudo\fR begins
+closing open file descriptors.  This flag is \fIoff\fR by default.
 .IP "env_editor" 16
 .IX Item "env_editor"
 If set, \fBvisudo\fR will use the value of the \s-1EDITOR\s0 or \s-1VISUAL\s0
@@ -640,9 +688,9 @@ If set, \fBsudo\fR will reset the environment to only contain the
 variables in the caller's environment that match the \f(CW\*(C`env_keep\*(C'\fR
 and \f(CW\*(C`env_check\*(C'\fR lists are then added.  The default contents of the
 \&\f(CW\*(C`env_keep\*(C'\fR and \f(CW\*(C`env_check\*(C'\fR lists are displayed when \fBsudo\fR is
-run by root with the \fI\-V\fR option.  If \fBsudo\fR was compiled with
-the \f(CW\*(C`SECURE_PATH\*(C'\fR option, its value will be used for the \f(CW\*(C`PATH\*(C'\fR
-environment variable.  This flag is \fIon\fR by default.
+run by root with the \fI\-V\fR option.  If the \fIsecure_path\fR option
+is set, its value will be used for the \f(CW\*(C`PATH\*(C'\fR environment variable.
+This flag is \fIon\fR by default.
 .IP "fqdn" 16
 .IX Item "fqdn"
 Set this flag if you want to put fully qualified hostnames in the
@@ -661,10 +709,7 @@ command) is already fully qualified you shouldn't need to set
 .IX Item "ignore_dot"
 If set, \fBsudo\fR will ignore '.' or '' (current dir) in the \f(CW\*(C`PATH\*(C'\fR
 environment variable; the \f(CW\*(C`PATH\*(C'\fR itself is not modified.  This
-flag is \fI@ignore_dot@\fR by default.  Currently, while it is possible
-to set \fIignore_dot\fR in \fIsudoers\fR, its value is not used.  This option
-should be considered read-only (it will be fixed in a future version
-of \fBsudo\fR).
+flag is \fI@ignore_dot@\fR by default.
 .IP "ignore_local_sudoers" 16
 .IX Item "ignore_local_sudoers"
 If set via \s-1LDAP\s0, parsing of \fI@sysconfdir@/sudoers\fR will be skipped.
@@ -681,11 +726,11 @@ If set, \fBsudo\fR will insult users when they enter an incorrect
 password.  This flag is \fI@insults@\fR by default.
 .IP "log_host" 16
 .IX Item "log_host"
-If set, the hostname will be logged in the (non\-syslog) \fBsudo\fR log file.
+If set, the hostname will be logged in the (non-syslog) \fBsudo\fR log file.
 This flag is \fIoff\fR by default.
 .IP "log_year" 16
 .IX Item "log_year"
-If set, the four-digit year will be logged in the (non\-syslog) \fBsudo\fR log file.
+If set, the four-digit year will be logged in the (non-syslog) \fBsudo\fR log file.
 This flag is \fIoff\fR by default.
 .IP "long_otp_prompt" 16
 .IX Item "long_otp_prompt"
@@ -722,7 +767,8 @@ by default.
 .IX Item "noexec"
 If set, all commands run via \fBsudo\fR will behave as if the \f(CW\*(C`NOEXEC\*(C'\fR
 tag has been set, unless overridden by a \f(CW\*(C`EXEC\*(C'\fR tag.  See the
-description of \fI\s-1NOEXEC\s0 and \s-1EXEC\s0\fR below as well as the \*(L"\s-1PREVENTING\s0 \s-1SHELL\s0 \s-1ESCAPES\s0\*(R" section at the end of this manual.  This flag is \fIoff\fR by default.
+description of \fI\s-1NOEXEC\s0 and \s-1EXEC\s0\fR below as well as the \*(L"\s-1PREVENTING\s0 \s-1SHELL\s0
+\&\s-1ESCAPES\s0\*(R" section at the end of this manual.  This flag is \fIoff\fR by default.
 .IP "path_info" 16
 .IX Item "path_info"
 Normally, \fBsudo\fR will tell the user when a command could not be
@@ -749,11 +795,9 @@ user.  This flag is \fIoff\fR by default.
 .IP "requiretty" 16
 .IX Item "requiretty"
 If set, \fBsudo\fR will only run when the user is logged in to a real
-tty.  This will disallow things like \f(CW"rsh somehost sudo ls"\fR since
-\&\fIrsh\fR\|(1) does not allocate a tty.  Because it is not possible to turn
-off echo when there is no tty present, some sites may wish to set
-this flag to prevent a user from entering a visible password.  This
-flag is \fIoff\fR by default.
+tty.  When this flag is set, \fBsudo\fR can only be run from a login
+session and not via other means such as \fIcron\fR\|(@mansectsu@) or cgi-bin scripts.
+This flag is \fIoff\fR by default.
 .IP "root_sudo" 16
 .IX Item "root_sudo"
 If set, root is allowed to run \fBsudo\fR too.  Disabling this prevents users
@@ -774,15 +818,15 @@ If set, \fBsudo\fR will prompt for the password of the user defined by the
 password of the invoking user.  This flag is \fIoff\fR by default.
 .IP "set_home" 16
 .IX Item "set_home"
-If set and \fBsudo\fR is invoked with the \fB\-s\fR flag the \f(CW\*(C`HOME\*(C'\fR
+If set and \fBsudo\fR is invoked with the \fB\-s\fR option the \f(CW\*(C`HOME\*(C'\fR
 environment variable will be set to the home directory of the target
 user (which is root unless the \fB\-u\fR option is used).  This effectively
-makes the \fB\-s\fR flag imply \fB\-H\fR.  This flag is \fIoff\fR by default.
+makes the \fB\-s\fR option imply \fB\-H\fR.  This flag is \fIoff\fR by default.
 .IP "set_logname" 16
 .IX Item "set_logname"
 Normally, \fBsudo\fR will set the \f(CW\*(C`LOGNAME\*(C'\fR, \f(CW\*(C`USER\*(C'\fR and \f(CW\*(C`USERNAME\*(C'\fR
 environment variables to the name of the target user (usually root
-unless the \fB\-u\fR flag is given).  However, since some programs
+unless the \fB\-u\fR option is given).  However, since some programs
 (including the \s-1RCS\s0 revision control system) use \f(CW\*(C`LOGNAME\*(C'\fR to
 determine the real identity of the user, it may be desirable to
 change this behavior.  This can be done by negating the set_logname
@@ -800,7 +844,7 @@ by default.
 .IP "shell_noargs" 16
 .IX Item "shell_noargs"
 If set and \fBsudo\fR is invoked with no arguments it acts as if the
-\&\fB\-s\fR flag had been given.  That is, it runs a shell as root (the
+\&\fB\-s\fR option had been given.  That is, it runs a shell as root (the
 shell is determined by the \f(CW\*(C`SHELL\*(C'\fR environment variable if it is
 set, falling back on the shell listed in the invoking user's
 /etc/passwd entry if not).  This flag is \fIoff\fR by default.
@@ -817,9 +861,9 @@ function.  This flag is \fIoff\fR by default.
 .IP "targetpw" 16
 .IX Item "targetpw"
 If set, \fBsudo\fR will prompt for the password of the user specified by
-the \fB\-u\fR flag (defaults to \f(CW\*(C`root\*(C'\fR) instead of the password of the
+the \fB\-u\fR option (defaults to \f(CW\*(C`root\*(C'\fR) instead of the password of the
 invoking user.  Note that this precludes the use of a uid not listed
-in the passwd database as an argument to the \fB\-u\fR flag.
+in the passwd database as an argument to the \fB\-u\fR option.
 This flag is \fIoff\fR by default.
 .IP "tty_tickets" 16
 .IX Item "tty_tickets"
@@ -833,8 +877,23 @@ This flag is \fI@tty_tickets@\fR by default.
 @LCMAN@If set, \fBsudo\fR will apply the defaults specified for the target user's
 @LCMAN@login class if one exists.  Only available if \fBsudo\fR is configured with
 @LCMAN@the \-\-with\-logincap option.  This flag is \fIoff\fR by default.
+.IP "visiblepw" 16
+.IX Item "visiblepw"
+By default, \fBsudo\fR will refuse to run if the user must enter a
+password but it is not possible to disable echo on the terminal.
+If the \fIvisiblepw\fR flag is set, \fBsudo\fR will prompt for a password
+even when it would be visible on the screen.  This makes it possible
+to run things like \f(CW"rsh somehost sudo ls"\fR since \fIrsh\fR\|(1) does
+not allocate a tty.  This flag is \fIoff\fR by default.
 .PP
 \&\fBIntegers\fR:
+.IP "closefrom" 16
+.IX Item "closefrom"
+Before it executes a command, \fBsudo\fR will close all open file
+descriptors other than standard input, standard output and standard
+error (ie: file descriptors 0\-2).  The \fIclosefrom\fR option can be used
+to specify a different file descriptor at which to start closing.
+The default is \f(CW3\fR.
 .IP "passwd_tries" 16
 .IX Item "passwd_tries"
 The number of tries a user gets to enter his/her password before
@@ -862,7 +921,12 @@ own timestamps via \f(CW\*(C`sudo \-v\*(C'\fR and \f(CW\*(C`sudo \-k\*(C'\fR res
 .IP "umask" 16
 .IX Item "umask"
 Umask to use when running the command.  Negate this option or set
-it to 0777 to preserve the user's umask.  The default is \f(CW\*(C`@sudo_umask@\*(C'\fR.
+it to 0777 to preserve the user's umask.  The actual umask that is
+used will be the union of the user's umask and \f(CW\*(C`@sudo_umask@\*(C'\fR.
+This guarantees that \fBsudo\fR never lowers the umask when running a
+command.  Note on systems that use \s-1PAM\s0, the default \s-1PAM\s0 configuration
+may specify its own umask which will override the value set in
+\&\fIsudoers\fR.
 .PP
 \&\fBStrings\fR:
 .IP "badpass_message" 16
@@ -934,7 +998,7 @@ The default value is \f(CW\*(C`@passprompt@\*(C'\fR.
 @SEMAN@This option is only available whe \fBsudo\fR is built with SELinux support.
 .IP "runas_default" 16
 .IX Item "runas_default"
-The default user to run commands as if the \fB\-u\fR flag is not specified
+The default user to run commands as if the \fB\-u\fR option is not specified
 on the command line.  This defaults to \f(CW\*(C`@runas_default@\*(C'\fR.
 Note that if \fIrunas_default\fR is set it \fBmust\fR occur before
 any \f(CW\*(C`Runas_Alias\*(C'\fR specifications.
@@ -946,6 +1010,11 @@ Defaults to \f(CW\*(C`@badpri@\*(C'\fR.
 .IX Item "syslog_goodpri"
 Syslog priority to use when user authenticates successfully.
 Defaults to \f(CW\*(C`@goodpri@\*(C'\fR.
+.IP "sudoers_locale" 16
+.IX Item "sudoers_locale"
+Locale to use when parsing the sudoers file.  Note that changing
+the locale may affect how sudoers is interpreted.
+Defaults to \f(CW"C"\fR.
 .IP "timestampdir" 16
 .IX Item "timestampdir"
 The directory in which \fBsudo\fR stores its timestamp files.
@@ -962,6 +1031,23 @@ The default is \f(CW\*(C`root\*(C'\fR.
 @SEMAN@This option is only available whe \fBsudo\fR is built with SELinux support.
 .PP
 \&\fBStrings that can be used in a boolean context\fR:
+.IP "askpass" 12
+.IX Item "askpass"
+The \fIaskpass\fR option specifies the fully qualified path to a helper
+program used to read the user's password when no terminal is
+available.  This may be the case when \fBsudo\fR is executed from a
+graphical (as opposed to text-based) application.  The program
+specified by \fIaskpass\fR should display the argument passed to it
+as the prompt and write the user's password to the standard output.
+The value of \fIaskpass\fR may be overridden by the \f(CW\*(C`SUDO_ASKPASS\*(C'\fR
+environment variable.
+.IP "env_file" 12
+.IX Item "env_file"
+The \fIenv_file\fR options specifies the fully qualified path to a file
+containing variables to be set in the environment of the program
+being run.  Entries in this file should be of the form \f(CW\*(C`VARIABLE=value\*(C'\fR.
+Variables in this file are subject to other \fBsudo\fR environment
+settings such as \fIenv_keep\fR and \fIenv_check\fR.
 .IP "exempt_group" 12
 .IX Item "exempt_group"
 Users in this group are exempt from password and \s-1PATH\s0 requirements.
@@ -995,7 +1081,7 @@ By default, \fBsudo\fR uses a built-in lecture.
 .IP "listpw" 12
 .IX Item "listpw"
 This option controls when a password will be required when a
-user runs \fBsudo\fR with the \fB\-l\fR flag.  It has the following possible values:
+user runs \fBsudo\fR with the \fB\-l\fR option.  It has the following possible values:
 .RS 12
 .IP "all" 8
 .IX Item "all"
@@ -1003,14 +1089,14 @@ All the user's \fIsudoers\fR entries for the current host must have
 the \f(CW\*(C`NOPASSWD\*(C'\fR flag set to avoid entering a password.
 .IP "always" 8
 .IX Item "always"
-The user must always enter a password to use the \fB\-l\fR flag.
+The user must always enter a password to use the \fB\-l\fR option.
 .IP "any" 8
 .IX Item "any"
 At least one of the user's \fIsudoers\fR entries for the current host
 must have the \f(CW\*(C`NOPASSWD\*(C'\fR flag set to avoid entering a password.
 .IP "never" 8
 .IX Item "never"
-The user need never enter a password to use the \fB\-l\fR flag.
+The user need never enter a password to use the \fB\-l\fR option.
 .RE
 .RS 12
 .Sp
@@ -1030,11 +1116,25 @@ Flags to use when invoking mailer. Defaults to \fB\-t\fR.
 .IX Item "mailerpath"
 Path to mail program used to send warning mail.
 Defaults to the path to sendmail found at configure time.
+.IP "mailfrom" 12
+.IX Item "mailfrom"
+Address to use for the \*(L"from\*(R" address when sending warning and error
+mail.  The address should be enclosed in double quotes (\f(CW\*(C`"\*(C'\fR) to
+protect against \fBsudo\fR interpreting the \f(CW\*(C`@\*(C'\fR sign.  Defaults to
+the name of the user running \fBsudo\fR.
 .IP "mailto" 12
 .IX Item "mailto"
 Address to send warning and error mail to.  The address should
 be enclosed in double quotes (\f(CW\*(C`"\*(C'\fR) to protect against \fBsudo\fR
 interpreting the \f(CW\*(C`@\*(C'\fR sign.  Defaults to \f(CW\*(C`@mailto@\*(C'\fR.
+.IP "secure_path" 12
+.IX Item "secure_path"
+Path used for every command run from \fBsudo\fR.  If you don't trust the
+people running \fBsudo\fR to have a sane \f(CW\*(C`PATH\*(C'\fR environment variable you may
+want to use this.  Another use is if you want to have the \*(L"root path\*(R"
+be separate from the \*(L"user path.\*(R"  Users in the group specified by the
+\&\fIexempt_group\fR option are not affected by \fIsecure_path\fR.
+This is not set by default.
 .IP "syslog" 12
 .IX Item "syslog"
 Syslog facility if syslog is being used for logging (negate to
@@ -1042,7 +1142,7 @@ disable syslog logging).  Defaults to \f(CW\*(C`@logfac@\*(C'\fR.
 .IP "verifypw" 12
 .IX Item "verifypw"
 This option controls when a password will be required when a user runs
-\&\fBsudo\fR with the \fB\-v\fR flag.  It has the following possible values:
+\&\fBsudo\fR with the \fB\-v\fR option.  It has the following possible values:
 .RS 12
 .IP "all" 8
 .IX Item "all"
@@ -1050,14 +1150,14 @@ All the user's \fIsudoers\fR entries for the current host must have
 the \f(CW\*(C`NOPASSWD\*(C'\fR flag set to avoid entering a password.
 .IP "always" 8
 .IX Item "always"
-The user must always enter a password to use the \fB\-v\fR flag.
+The user must always enter a password to use the \fB\-v\fR option.
 .IP "any" 8
 .IX Item "any"
 At least one of the user's \fIsudoers\fR entries for the current host
 must have the \f(CW\*(C`NOPASSWD\*(C'\fR flag set to avoid entering a password.
 .IP "never" 8
 .IX Item "never"
-The user need never enter a password to use the \fB\-v\fR flag.
+The user need never enter a password to use the \fB\-v\fR option.
 .RE
 .RS 12
 .Sp
@@ -1072,8 +1172,8 @@ The default value is \fIall\fR.
 Environment variables to be removed from the user's environment if
 the variable's value contains \f(CW\*(C`%\*(C'\fR or \f(CW\*(C`/\*(C'\fR characters.  This can
 be used to guard against printf-style format vulnerabilities in
-poorly-written programs.  The argument may be a double\-quoted,
-space-separated list or a single value without double\-quotes.  The
+poorly-written programs.  The argument may be a double-quoted,
+space-separated list or a single value without double-quotes.  The
 list can be replaced, added to, deleted from, or disabled by using
 the \f(CW\*(C`=\*(C'\fR, \f(CW\*(C`+=\*(C'\fR, \f(CW\*(C`\-=\*(C'\fR, and \f(CW\*(C`!\*(C'\fR operators respectively.  Regardless
 of whether the \f(CW\*(C`env_reset\*(C'\fR option is enabled or disabled, variables
@@ -1084,8 +1184,8 @@ the \fI\-V\fR option.
 .IP "env_delete" 16
 .IX Item "env_delete"
 Environment variables to be removed from the user's environment.
-The argument may be a double\-quoted, space-separated list or a
-single value without double\-quotes.  The list can be replaced, added
+The argument may be a double-quoted, space-separated list or a
+single value without double-quotes.  The list can be replaced, added
 to, deleted from, or disabled by using the \f(CW\*(C`=\*(C'\fR, \f(CW\*(C`+=\*(C'\fR, \f(CW\*(C`\-=\*(C'\fR, and
 \&\f(CW\*(C`!\*(C'\fR operators respectively.  The default list of environment
 variables to remove is displayed when \fBsudo\fR is run by root with the
@@ -1097,8 +1197,8 @@ as \fBsudo\fR).
 Environment variables to be preserved in the user's environment
 when the \fIenv_reset\fR option is in effect.  This allows fine-grained
 control over the environment \fBsudo\fR\-spawned processes will receive.
-The argument may be a double\-quoted, space-separated list or a
-single value without double\-quotes.  The list can be replaced, added
+The argument may be a double-quoted, space-separated list or a
+single value without double-quotes.  The list can be replaced, added
 to, deleted from, or disabled by using the \f(CW\*(C`=\*(C'\fR, \f(CW\*(C`+=\*(C'\fR, \f(CW\*(C`\-=\*(C'\fR, and
 \&\f(CW\*(C`!\*(C'\fR operators respectively.  The default list of variables to keep
 is displayed when \fBsudo\fR is run by root with the \fI\-V\fR option.
@@ -1112,7 +1212,8 @@ supported: \fBalert\fR, \fBcrit\fR, \fBdebug\fR, \fBemerg\fR, \fBerr\fR, \fBinfo
 \&\fBnotice\fR, and \fBwarning\fR.
 .SH "FILES"
 .IX Header "FILES"
-.IP "\fI@sysconfdir@/sudoers\fR" 24
+.ie n .IP "\fI@sysconfdir@/sudoers\fR" 24
+.el .IP "\fI@sysconfdir@/sudoers\fR" 24
 .IX Item "@sysconfdir@/sudoers"
 List of who can run what
 .IP "\fI/etc/group\fR" 24
@@ -1123,13 +1224,6 @@ Local groups file
 List of network groups
 .SH "EXAMPLES"
 .IX Header "EXAMPLES"
-Since the \fIsudoers\fR file is parsed in a single pass, order is
-important.  In general, you should structure \fIsudoers\fR such that
-the \f(CW\*(C`Host_Alias\*(C'\fR, \f(CW\*(C`User_Alias\*(C'\fR, and \f(CW\*(C`Cmnd_Alias\*(C'\fR specifications
-come first, followed by any \f(CW\*(C`Default_Entry\*(C'\fR lines, and finally the
-\&\f(CW\*(C`Runas_Alias\*(C'\fR and user specifications.  The basic rule of thumb
-is you cannot reference an Alias that has not already been defined.
-.PP
 Below are example \fIsudoers\fR entries.  Admittedly, some of
 these are a bit contrived.  First, we define our \fIaliases\fR:
 .PP
@@ -1138,15 +1232,11 @@ these are a bit contrived.  First, we define our \fIaliases\fR:
 \& User_Alias     FULLTIMERS = millert, mikef, dowdy
 \& User_Alias     PARTTIMERS = bostley, jwfox, crawl
 \& User_Alias     WEBMASTERS = will, wendy, wim
-.Ve
-.PP
-.Vb 3
+\&
 \& # Runas alias specification
 \& Runas_Alias    OP = root, operator
 \& Runas_Alias    DB = oracle, sybase
-.Ve
-.PP
-.Vb 9
+\&
 \& # Host alias specification
 \& Host_Alias     SPARC = bigtime, eclipse, moet, anchor :\e
 \&                SGI = grolsch, dandelion, black :\e
@@ -1156,9 +1246,7 @@ these are a bit contrived.  First, we define our \fIaliases\fR:
 \& Host_Alias     CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0
 \& Host_Alias     SERVERS = master, mail, www, ns
 \& Host_Alias     CDROM = orion, perseus, hercules
-.Ve
-.PP
-.Vb 13
+\&
 \& # Cmnd alias specification
 \& Cmnd_Alias     DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\e
 \&                        /usr/sbin/restore, /usr/sbin/rrestore
@@ -1187,7 +1275,7 @@ disable shell escapes for the commands in the \s-1PAGERS\s0 \f(CW\*(C`Cmnd_Alias
 (\fI/usr/bin/more\fR, \fI/usr/bin/pg\fR and \fI/usr/bin/less\fR).
 .PP
 .Vb 7
-\& # Override built-in defaults
+\& # Override built\-in defaults
 \& Defaults               syslog=auth
 \& Defaults>root          !set_logname
 \& Defaults:FULLTIMERS    !lecture
@@ -1257,7 +1345,7 @@ directory \fI/usr/oper/bin/\fR.
 The user \fBjoe\fR may only \fIsu\fR\|(1) to operator.
 .PP
 .Vb 1
-\& pete           HPPA = /usr/bin/passwd [A-z]*, !/usr/bin/passwd root
+\& pete           HPPA = /usr/bin/passwd [A\-Za\-z]*, !/usr/bin/passwd root
 .Ve
 .PP
 The user \fBpete\fR is allowed to change anyone's password except for
@@ -1294,11 +1382,11 @@ The user \fBfred\fR can run commands as any user in the \fI\s-1DB\s0\fR \f(CW\*(
 (\fBoracle\fR or \fBsybase\fR) without giving a password.
 .PP
 .Vb 1
-\& john           ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
+\& john           ALPHA = /usr/bin/su [!\-]*, !/usr/bin/su *root*
 .Ve
 .PP
 On the \fI\s-1ALPHA\s0\fR machines, user \fBjohn\fR may su to anyone except root
-but he is not allowed to give \fIsu\fR\|(1) any flags.
+but he is not allowed to specify any options to the \fIsu\fR\|(1) command.
 .PP
 .Vb 1
 \& jen            ALL, !SERVERS = ALL
@@ -1339,7 +1427,7 @@ web pages) or simply \fIsu\fR\|(1) to www.
 .PP
 .Vb 2
 \& ALL            CDROM = NOPASSWD: /sbin/umount /CDROM,\e
-\&                /sbin/mount -o nosuid\e,nodev /dev/cd0a /CDROM
+\&                /sbin/mount \-o nosuid\e,nodev /dev/cd0a /CDROM
 .Ve
 .PP
 Any user may mount or unmount a CD-ROM on the machines in the \s-1CDROM\s0
@@ -1395,7 +1483,7 @@ To tell whether or not \fBsudo\fR supports \fInoexec\fR, you can run
 the following as root:
 .Sp
 .Vb 1
-\&    sudo -V | grep "dummy exec"
+\&    sudo \-V | grep "dummy exec"
 .Ve
 .Sp
 If the resulting output contains a line that begins with:
@@ -1407,7 +1495,7 @@ If the resulting output contains a line that begins with:
 then \fBsudo\fR may be able to replace the exec family of functions
 in the standard library with its own that simply return an error.
 Unfortunately, there is no foolproof way to know whether or not
-\&\fInoexec\fR will work at compile\-time.  \fInoexec\fR should work on
+\&\fInoexec\fR will work at compile-time.  \fInoexec\fR should work on
 SunOS, Solaris, *BSD, Linux, \s-1IRIX\s0, Tru64 \s-1UNIX\s0, MacOS X, and HP-UX
 11.x.  It is known \fBnot\fR to work on \s-1AIX\s0 and UnixWare.  \fInoexec\fR
 is expected to work on most operating systems that support the
index f65db6b51de6e8c318041b52a00468812f00feeb..63c49cf7d88e1155f81f3212aa2265aec293e2b9 100644 (file)
@@ -1,4 +1,4 @@
-Copyright (c) 1994-1996, 1998-2005, 2007
+Copyright (c) 1994-1996, 1998-2005, 2007-2008
        Todd C. Miller <Todd.Miller@courtesan.com>
 
 Permission to use, copy, modify, and distribute this software for any
@@ -18,7 +18,7 @@ Sponsored in part by the Defense Advanced Research Projects
 Agency (DARPA) and Air Force Research Laboratory, Air Force
 Materiel Command, USAF, under agreement number F39502-99-1-0512.
 
-$Sudo: sudoers.pod,v 1.95.2.26 2008/02/19 18:13:17 millert Exp $
+$Sudo: sudoers.pod,v 1.155 2008/12/03 20:57:13 millert Exp $
 =pod
 
 =head1 NAME
@@ -113,32 +113,32 @@ The definitions of what constitutes a valid I<alias> member follow.
               User ',' User_List
 
  User ::= '!'* username |
+         '!'* '#'uid |
          '!'* '%'group |
          '!'* '+'netgroup |
          '!'* User_Alias
 
-A C<User_List> is made up of one or more usernames, system groups
-(prefixed with '%'), netgroups (prefixed with '+') and other aliases.
-Each list item may be prefixed with one or more '!' operators.
-An odd number of '!' operators negate the value of the item; an even
-number just cancel each other out.
-
- Runas_List ::= Runas_User |
-               Runas_User ',' Runas_List
-
- Runas_User ::= '!'* username |
-               '!'* '#'uid |
-               '!'* '%'group |
-               '!'* +netgroup |
-               '!'* Runas_Alias
-
-A C<Runas_List> is similar to a C<User_List> except that it can
-also contain uids (prefixed with '#') and instead of C<User_Alias>es
-it can contain C<Runas_Alias>es.  Note that usernames and groups
-are matched as strings.  In other words, two users (groups) with
-the same uid (gid) are considered to be distinct.  If you wish to
-match all usernames with the same uid (e.g.E<nbsp>root and toor), you
-can use a uid instead (#0 in the example given).
+A C<User_List> is made up of one or more usernames, uids (prefixed
+with '#'), system groups (prefixed with '%'), netgroups (prefixed
+with '+') and C<User_Alias>es.  Each list item may be prefixed with
+zero or more '!' operators.  An odd number of '!' operators negate
+the value of the item; an even number just cancel each other out.
+
+ Runas_List ::= Runas_Member |
+               Runas_Member ',' Runas_List
+
+ Runas_Member ::= '!'* username |
+                 '!'* '#'uid |
+                 '!'* '%'group |
+                 '!'* +netgroup |
+                 '!'* Runas_Alias
+
+A C<Runas_List> is similar to a C<User_List> except that instead
+of C<User_Alias>es it can contain C<Runas_Alias>es.  Note that
+usernames and groups are matched as strings.  In other words, two
+users (groups) with the same uid (gid) are considered to be distinct.
+If you wish to match all usernames with the same uid (e.g.E<nbsp>root
+and toor), you can use a uid instead (#0 in the example given).
 
  Host_List ::= Host |
               Host ',' Host_List
@@ -192,7 +192,7 @@ in the C<Cmnd> must match exactly those given by the user on the command line
 (or match the wildcards if there are any).  Note that the following
 characters must be escaped with a '\' if they are used in command
 arguments: ',', ':', '=', '\'.  The special command C<"sudoedit">
-is used to permit a user to run B<sudo> with the B<-e> flag (or
+is used to permit a user to run B<sudo> with the B<-e> option (or
 as B<sudoedit>).  It may take command line arguments just as
 a normal command does.
 
@@ -201,11 +201,15 @@ a normal command does.
 Certain configuration options may be changed from their default
 values at runtime via one or more C<Default_Entry> lines.  These
 may affect all users on any host, all users on a specific host, a
-specific user, or commands being run as a specific user.
+specific user, a specific command, or commands being run as a specific user.
+Note that per-command entries may not include command line arguments.
+If you need to specify arguments, define a C<Cmnd_Alias> and reference
+that instead.
 
  Default_Type ::= 'Defaults' |
                  'Defaults' '@' Host_List |
                  'Defaults' ':' User_List |
+                 'Defaults' '!' Cmnd_List |
                  'Defaults' '>' Runas_List
 
  Default_Entry ::= Default_Type Parameter_List
@@ -230,6 +234,10 @@ These operators are used to add to and delete from a list respectively.
 It is not an error to use the C<-=> operator to remove an element
 that does not exist in a list.
 
+Defaults entries are parsed in the following order: generic, host
+and user Defaults first, then runas Defaults and finally command
+defaults.
+
 See L</"SUDOERS OPTIONS"> for a list of supported Defaults parameters.
 
 =head2 User Specification
@@ -242,10 +250,10 @@ See L</"SUDOERS OPTIONS"> for a list of supported Defaults parameters.
 
  Cmnd_Spec ::= Runas_Spec? Tag_Spec* Cmnd
 
- Runas_Spec ::= '(' Runas_List ')'
+ Runas_Spec ::= '(' Runas_List? (: Runas_List)? ')'
 
  Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' |
-              'SETENV:' | 'NOSETENV:')
+              'SETENV:' | 'NOSETENV:' )
 
 A B<user specification> determines which commands a user may run
 (and as what user) on specified hosts.  By default, commands are
@@ -255,11 +263,24 @@ Let's break that down into its constituent parts:
 
 =head2 Runas_Spec
 
-A C<Runas_Spec> is simply a C<Runas_List> (as defined above)
-enclosed in a set of parentheses.  If you do not specify a
-C<Runas_Spec> in the user specification, a default C<Runas_Spec>
-of B<root> will be used.  A C<Runas_Spec> sets the default for
-commands that follow it.  What this means is that for the entry:
+A C<Runas_Spec> determines the user and/or the group that a command
+may be run as.  A fully-specified C<Runas_Spec> consists of two
+C<Runas_List>s (as defined above) separated by a colon (':') and
+enclosed in a set of parentheses.  The first C<Runas_List> indicates
+which users the command may be run as via B<sudo>'s B<-u> option.
+The second defines a list of groups that can be specified via
+B<sudo>'s B<-g> option.  If both C<Runas_List>s are specified, the
+command may be run with any combination of users and groups listed
+in their respective C<Runas_List>s.  If only the first is specified,
+the command may be run as any user in the list but no B<-g> option
+may be specified.  If the first C<Runas_List> is empty but the
+second is specified, the command may be run as the invoking user
+with the group set to any listed in the C<Runas_List>.  If no
+C<Runas_Spec> is specified the command may be run as B<root> and
+no group may be specified.
+
+A C<Runas_Spec> sets the default for the commands that follow it.
+What this means is that for the entry:
 
  dgb   boulder = (operator) /bin/ls, /bin/kill, /usr/bin/lprm
 
@@ -276,10 +297,23 @@ entry.  If we modify the entry like so:
 Then user B<dgb> is now allowed to run F</bin/ls> as B<operator>,
 but  F</bin/kill> and F</usr/bin/lprm> as B<root>.
 
+We can extend this to allow B<dgb> to run C</bin/ls> with either
+the user or group set to B<operator>:
+
+ dgb   boulder = (operator : operator) /bin/ls, (root) /bin/kill, \
+       /usr/bin/lprm
+
+In the following example, user B<tcm> may run commands that access
+a modem device file with the dialer group.  Note that in this example
+only the group will be set, the command still runs as user B<tcm>.
+
+ tcm   boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \
+       /usr/local/bin/minicom
+
 =head2 Tag_Spec
 
 A command may have zero or more tags associated with it.  There are
-six possible tag values, C<NOPASSWD>, C<PASSWD>, C<NOEXEC>, C<EXEC>,
+eight possible tag values, C<NOPASSWD>, C<PASSWD>, C<NOEXEC>, C<EXEC>,
 C<SETENV> and C<NOSETENV>.
 Once a tag is set on a C<Cmnd>, subsequent C<Cmnd>s in the
 C<Cmnd_Spec_List>, inherit the tag unless it is overridden by the
@@ -298,7 +332,7 @@ For example:
  ray   rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm
 
 would allow the user B<ray> to run F</bin/kill>, F</bin/ls>, and
-F</usr/bin/lprm> as root on the machine rushmore as B<root> without
+F</usr/bin/lprm> as B<root> on the machine rushmore without
 authenticating himself.  If we only want B<ray> to be able to
 run F</bin/kill> without a password the entry would be:
 
@@ -342,7 +376,7 @@ be overridden by use of the C<UNSETENV> tag.
 =head2 Wildcards
 
 B<sudo> allows shell-style I<wildcards> (aka meta or glob characters)
-to be used in pathnames as well as command line arguments in the
+to be used in hostnames, pathnames and command line arguments in the
 I<sudoers> file.  Wildcard matching is done via the B<POSIX>
 L<fnmatch(3)> routine.  Note that these are I<not> regular expressions.
 
@@ -371,6 +405,15 @@ escape special characters such as: "*", "?", "[", and "}".
 
 =back
 
+POSIX character classes may also be used if your system's
+L<fnmatch(3)> function supports them.  However, because the
+C<':'> character has special meaning in I<sudoers>, it must
+be escaped.  For example:
+
+    /bin/ls [[\:alpha\:]]*
+
+Would match any filename beginning with a letter.
+
 Note that a forward slash ('/') will B<not> be matched by
 wildcards used in the pathname.  When matching the command
 line arguments, however, a slash B<does> get matched by
@@ -394,6 +437,26 @@ with B<any> arguments.
 
 =back
 
+=head2 Including other files from within sudoers
+
+It is possible to include other I<sudoers> files from within the
+I<sudoers> file currently being parsed using the C<#include>
+directive, similar to the one used by the C preprocessor.  This is
+useful, for example, for keeping a site-wide I<sudoers> file in
+addition to a per-machine local one.  For the sake of this example
+the site-wide I<sudoers> will be F</etc/sudoers> and the per-machine
+one will be F</etc/sudoers.local>.  To include F</etc/sudoers.local>
+from F</etc/sudoers> we would use the following line in F</etc/sudoers>:
+
+ #include /etc/sudoers.local
+
+When B<sudo> reaches this line it will suspend processing of the
+current file (F</etc/sudoers>) and switch to F</etc/sudoers.local>.
+Upon reaching the end of F</etc/sudoers.local>, the rest of
+F</etc/sudoers> will be processed.  Files that are included may
+themselves include other files.  A hard limit of 128 nested include
+files is enforced to prevent include file loops.
+
 =head2 Other special characters and reserved words
 
 The pound sign ('#') is used to indicate a comment (unless it is
@@ -441,7 +504,7 @@ B<Flags>:
 
 If set, B<sudo> will set the C<HOME> environment variable to the home
 directory of the target user (which is root unless the B<-u> option is used).
-This effectively means that the B<-H> flag is always implied.
+This effectively means that the B<-H> option is always implied.
 This flag is I<off> by default.
 
 =item authenticate
@@ -451,6 +514,12 @@ means of authentication) before they may run commands.  This default
 may be overridden via the C<PASSWD> and C<NOPASSWD> tags.
 This flag is I<on> by default.
 
+=item closefrom_override
+
+If set, the user may use B<sudo>'s B<-C> option which
+overrides the default starting point at which B<sudo> begins
+closing open file descriptors.  This flag is I<off> by default.
+
 =item env_editor
 
 If set, B<visudo> will use the value of the EDITOR or VISUAL
@@ -469,9 +538,9 @@ LOGNAME, SHELL, USER, USERNAME and the C<SUDO_*> variables.  Any
 variables in the caller's environment that match the C<env_keep>
 and C<env_check> lists are then added.  The default contents of the
 C<env_keep> and C<env_check> lists are displayed when B<sudo> is
-run by root with the I<-V> option.  If B<sudo> was compiled with
-the C<SECURE_PATH> option, its value will be used for the C<PATH>
-environment variable.  This flag is I<on> by default.
+run by root with the I<-V> option.  If the I<secure_path> option
+is set, its value will be used for the C<PATH> environment variable.
+This flag is I<on> by default.
 
 =item fqdn
 
@@ -492,10 +561,7 @@ I<fqdn>.  This flag is I<@fqdn@> by default.
 
 If set, B<sudo> will ignore '.' or '' (current dir) in the C<PATH>
 environment variable; the C<PATH> itself is not modified.  This
-flag is I<@ignore_dot@> by default.  Currently, while it is possible
-to set I<ignore_dot> in I<sudoers>, its value is not used.  This option
-should be considered read-only (it will be fixed in a future version
-of B<sudo>).
+flag is I<@ignore_dot@> by default.
 
 =item ignore_local_sudoers
 
@@ -596,11 +662,9 @@ user.  This flag is I<off> by default.
 =item requiretty
 
 If set, B<sudo> will only run when the user is logged in to a real
-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 wish to set
-this flag to prevent a user from entering a visible password.  This
-flag is I<off> by default.
+tty.  When this flag is set, B<sudo> can only be run from a login
+session and not via other means such as L<cron(8)> or cgi-bin scripts.
+This flag is I<off> by default.
 
 =item root_sudo
 
@@ -625,16 +689,16 @@ password of the invoking user.  This flag is I<off> by default.
 
 =item set_home
 
-If set and B<sudo> is invoked with the B<-s> flag the C<HOME>
+If set and B<sudo> is invoked with the B<-s> option 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> option imply B<-H>.  This flag is I<off> by default.
 
 =item set_logname
 
 Normally, B<sudo> will set the C<LOGNAME>, C<USER> and C<USERNAME>
 environment variables to the name of the target user (usually root
-unless the B<-u> flag is given).  However, since some programs
+unless the B<-u> option is given).  However, since some programs
 (including the RCS revision control system) use C<LOGNAME> to
 determine the real identity of the user, it may be desirable to
 change this behavior.  This can be done by negating the set_logname
@@ -654,7 +718,7 @@ by default.
 =item shell_noargs
 
 If set and B<sudo> is invoked with no arguments it acts as if the
-B<-s> flag had been given.  That is, it runs a shell as root (the
+B<-s> option had been given.  That is, it runs a shell as root (the
 shell is determined by the C<SHELL> environment variable if it is
 set, falling back on the shell listed in the invoking user's
 /etc/passwd entry if not).  This flag is I<off> by default.
@@ -673,9 +737,9 @@ function.  This flag is I<off> by default.
 =item targetpw
 
 If set, B<sudo> will prompt for the password of the user specified by
-the B<-u> flag (defaults to C<root>) instead of the password of the
+the B<-u> option (defaults to C<root>) instead of the password of the
 invoking user.  Note that this precludes the use of a uid not listed
-in the passwd database as an argument to the B<-u> flag.
+in the passwd database as an argument to the B<-u> option.
 This flag is I<off> by default.
 
 =item tty_tickets
@@ -692,12 +756,29 @@ If set, B<sudo> will apply the defaults specified for the target user's
 login class if one exists.  Only available if B<sudo> is configured with
 the --with-logincap option.  This flag is I<off> by default.
 
+=item visiblepw
+
+By default, B<sudo> will refuse to run if the user must enter a
+password but it is not possible to disable echo on the terminal.
+If the I<visiblepw> flag is set, B<sudo> will prompt for a password
+even when it would be visible on the screen.  This makes it possible
+to run things like C<"rsh somehost sudo ls"> since L<rsh(1)> does
+not allocate a tty.  This flag is I<off> by default.
+
 =back
 
 B<Integers>:
 
 =over 16
 
+=item closefrom
+
+Before it executes a command, B<sudo> will close all open file
+descriptors other than standard input, standard output and standard
+error (ie: file descriptors 0-2).  The I<closefrom> option can be used
+to specify a different file descriptor at which to start closing.
+The default is C<3>.
+
 =item passwd_tries
 
 The number of tries a user gets to enter his/her password before
@@ -733,7 +814,12 @@ own timestamps via C<sudo -v> and C<sudo -k> respectively.
 =item umask
 
 Umask to use when running the command.  Negate this option or set
-it to 0777 to preserve the user's umask.  The default is C<@sudo_umask@>.
+it to 0777 to preserve the user's umask.  The actual umask that is
+used will be the union of the user's umask and C<@sudo_umask@>.
+This guarantees that B<sudo> never lowers the umask when running a
+command.  Note on systems that use PAM, the default PAM configuration
+may specify its own umask which will override the value set in
+I<sudoers>.
 
 =back
 
@@ -816,7 +902,7 @@ This option is only available whe B<sudo> is built with SELinux support.
 
 =item runas_default
 
-The default user to run commands as if the B<-u> flag is not specified
+The default user to run commands as if the B<-u> option is not specified
 on the command line.  This defaults to C<@runas_default@>.
 Note that if I<runas_default> is set it B<must> occur before
 any C<Runas_Alias> specifications.
@@ -831,6 +917,12 @@ Defaults to C<@badpri@>.
 Syslog priority to use when user authenticates successfully.
 Defaults to C<@goodpri@>.
 
+=item sudoers_locale
+
+Locale to use when parsing the sudoers file.  Note that changing
+the locale may affect how sudoers is interpreted.
+Defaults to C<"C">.
+
 =item timestampdir
 
 The directory in which B<sudo> stores its timestamp files.
@@ -854,6 +946,25 @@ B<Strings that can be used in a boolean context>:
 
 =over 12
 
+=item askpass
+
+The I<askpass> option specifies the fully qualified path to a helper
+program used to read the user's password when no terminal is
+available.  This may be the case when B<sudo> is executed from a
+graphical (as opposed to text-based) application.  The program
+specified by I<askpass> should display the argument passed to it
+as the prompt and write the user's password to the standard output.
+The value of I<askpass> may be overridden by the C<SUDO_ASKPASS>
+environment variable.
+
+=item env_file
+
+The I<env_file> options specifies the fully qualified path to a file
+containing variables to be set in the environment of the program
+being run.  Entries in this file should be of the form C<VARIABLE=value>.
+Variables in this file are subject to other B<sudo> environment
+settings such as I<env_keep> and I<env_check>.
+
 =item exempt_group
 
 Users in this group are exempt from password and PATH requirements.
@@ -893,7 +1004,7 @@ By default, B<sudo> uses a built-in lecture.
 =item listpw
 
 This option controls when a password will be required when a
-user runs B<sudo> with the B<-l> flag.  It has the following possible values:
+user runs B<sudo> with the B<-l> option.  It has the following possible values:
 
 =over 8
 
@@ -904,7 +1015,7 @@ the C<NOPASSWD> flag set to avoid entering a password.
 
 =item always
 
-The user must always enter a password to use the B<-l> flag.
+The user must always enter a password to use the B<-l> option.
 
 =item any
 
@@ -913,7 +1024,7 @@ must have the C<NOPASSWD> flag set to avoid entering a password.
 
 =item never
 
-The user need never enter a password to use the B<-l> flag.
+The user need never enter a password to use the B<-l> option.
 
 =back
 
@@ -936,12 +1047,28 @@ Flags to use when invoking mailer. Defaults to B<-t>.
 Path to mail program used to send warning mail.
 Defaults to the path to sendmail found at configure time.
 
+=item mailfrom
+
+Address to use for the "from" address when sending warning and error
+mail.  The address should be enclosed in double quotes (C<">) to
+protect against B<sudo> interpreting the C<@> sign.  Defaults to
+the name of the user running B<sudo>.
+
 =item mailto
 
 Address to send warning and error mail to.  The address should
 be enclosed in double quotes (C<">) to protect against B<sudo>
 interpreting the C<@> sign.  Defaults to C<@mailto@>.
 
+=item secure_path
+
+Path used for every command run from B<sudo>.  If you don't trust the
+people running B<sudo> to have a sane C<PATH> environment variable you may
+want to use this.  Another use is if you want to have the "root path"
+be separate from the "user path."  Users in the group specified by the
+I<exempt_group> option are not affected by I<secure_path>.
+This is not set by default.
+
 =item syslog
 
 Syslog facility if syslog is being used for logging (negate to
@@ -950,7 +1077,7 @@ disable syslog logging).  Defaults to C<@logfac@>.
 =item verifypw
 
 This option controls when a password will be required when a user runs
-B<sudo> with the B<-v> flag.  It has the following possible values:
+B<sudo> with the B<-v> option.  It has the following possible values:
 
 =over 8
 
@@ -961,7 +1088,7 @@ the C<NOPASSWD> flag set to avoid entering a password.
 
 =item always
 
-The user must always enter a password to use the B<-v> flag.
+The user must always enter a password to use the B<-v> option.
 
 =item any
 
@@ -970,7 +1097,7 @@ must have the C<NOPASSWD> flag set to avoid entering a password.
 
 =item never
 
-The user need never enter a password to use the B<-v> flag.
+The user need never enter a password to use the B<-v> option.
 
 =back
 
@@ -1052,13 +1179,6 @@ List of network groups
 
 =head1 EXAMPLES
 
-Since the I<sudoers> file is parsed in a single pass, order is
-important.  In general, you should structure I<sudoers> such that
-the C<Host_Alias>, C<User_Alias>, and C<Cmnd_Alias> specifications
-come first, followed by any C<Default_Entry> lines, and finally the
-C<Runas_Alias> and user specifications.  The basic rule of thumb
-is you cannot reference an Alias that has not already been defined.
-
 Below are example I<sudoers> entries.  Admittedly, some of
 these are a bit contrived.  First, we define our I<aliases>:
 
@@ -1161,7 +1281,7 @@ directory F</usr/oper/bin/>.
 
 The user B<joe> may only L<su(1)> to operator.
 
- pete          HPPA = /usr/bin/passwd [A-z]*, !/usr/bin/passwd root
+ pete          HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root
 
 The user B<pete> is allowed to change anyone's password except for
 root on the I<HPPA> machines.  Note that this assumes L<passwd(1)>
@@ -1191,7 +1311,7 @@ The user B<fred> can run commands as any user in the I<DB> C<Runas_Alias>
  john          ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
 
 On the I<ALPHA> machines, user B<john> may su to anyone except root
-but he is not allowed to give L<su(1)> any flags.
+but he is not allowed to specify any options to the L<su(1)> command.
 
  jen           ALL, !SERVERS = ALL
 
index da5bb97607af129dc00ff81b2502715f9e8a2199..df51b9f2c35a401dcfc239efe3c1df5ae3651846 100644 (file)
@@ -5,7 +5,7 @@ use strict;
 # Converts a sudoers file to LDIF format in prepration for loading into
 # the LDAP server.
 #
-# $Sudo: sudoers2ldif,v 1.2.2.1 2007/06/28 14:45:19 millert Exp $
+# $Sudo: sudoers2ldif,v 1.5 2007/12/08 00:09:28 millert Exp $
 #
 
 # BUGS:
@@ -14,9 +14,12 @@ use strict;
 #   Does not yet escape + at the beginning of a dn
 #   Does not yet handle line wraps correctly
 #   Does not yet handle multiple roles with same name (needs tiebreaker)
-#   Sudoers entries can have multiple Runas entries that override former ones,
-#      with LDAP sudoRunas applies to all commands in a sudoRole
+#
+# CAVEATS:
+#   Sudoers entries can have multiple RunAs entries that override former ones,
+#      with LDAP sudoRunAs{Group,User} applies to all commands in a sudoRole
 
+my %RA;
 my %UA;
 my %HA;
 my %CA;
@@ -51,8 +54,10 @@ while (<>){
     $p2=~s/\s+$//; # remove trailing whitespace
     $p3=~s/\s+$//; # remove trailing whitespace
 
-    if      ($p1 eq "User_Alias") {
+    if ($p1 eq "User_Alias") {
       $UA{$p2}=$p3;
+    } elsif ($p1 eq "Runas_Alias") {
+      $RA{$p2}=$p3;
     } elsif ($p1 eq "Host_Alias") {
       $HA{$p2}=$p3;
     } elsif ($p1 eq "Cmnd_Alias") {
@@ -80,10 +85,15 @@ while (<>){
       # will clobber options
       print "sudoUser: $_\n"   foreach expand(\%UA,@users);
       print "sudoHost: $_\n"   foreach expand(\%HA,@hosts);
-      my $runas = undef;
       foreach (@cmds) {
        if (s/^\(([^\)]+)\)\s*//) {
-         print "sudoRunas: $_\n" foreach expand(\%UA, split(/,\s*/, $1));
+         my @runas = split(/:\s*/, $1);
+         if (defined($runas[0])) {
+           print "sudoRunAsUser: $_\n" foreach expand(\%RA, split(/,\s*/, $runas[0]));
+         }
+         if (defined($runas[1])) {
+           print "sudoRunAsGroup: $_\n" foreach expand(\%RA, split(/,\s*/, $runas[1]));
+         }
        }
       }
       print "sudoCommand: $_\n" foreach expand(\%CA,@cmds);
index 3b213f36f2bb4602e7458b0216bfccf890820284..0eaf1d737cf55ba0fd0da47a78b0d4fc5802260d 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1996, 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1996, 1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #ifdef HAVE_NETGROUP_H
 # include <netgroup.h>
 #endif /* HAVE_NETGROUP_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <ctype.h>
 #include <pwd.h>
 #include <grp.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
-#include <dirent.h>
 
 #include "sudo.h"
-#include "parse.h"
 #include "interfaces.h"
+#include "parse.h"
+#include <gram.h>
 
 #ifndef HAVE_FNMATCH
 # include "emul/fnmatch.h"
 #endif /* HAVE_FNMATCH */
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: testsudoers.c,v 1.88.2.7 2008/02/09 14:44:49 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: testsudoers.c,v 1.128 2008/11/19 17:01:20 millert Exp $";
 #endif /* lint */
 
 
-/*
- * Prototypes
- */
-void init_parser       __P((void));
-void dumpaliases       __P((void));
-
 /*
  * Globals
  */
 int  Argc, NewArgc;
 char **Argv, **NewArgv;
-int parse_error = FALSE;
 int num_interfaces;
 struct interface *interfaces;
 struct sudo_user sudo_user;
-extern int clearaliases;
-extern int pedantic;
-
-/*
- * Returns TRUE if "s" has shell meta characters in it,
- * else returns FALSE.
- */
-int
-has_meta(s)
-    char *s;
-{
-    char *t;
+struct passwd *list_pw;
+extern int parse_error;
+
+/* passwd/group redirection for pwutil.c */
+void (*my_setgrent) __P((void)) = setgrent;
+void (*my_endgrent) __P((void)) = endgrent;
+struct group *(*my_getgrnam) __P((const char *)) = getgrnam;
+struct group *(*my_getgrgid) __P((gid_t)) = getgrgid;
+void (*my_setpwent) __P((void)) = setpwent;
+void (*my_endpwent) __P((void)) = endpwent;
+struct passwd *(*my_getpwnam) __P((const char *)) = getpwnam;
+struct passwd *(*my_getpwuid) __P((uid_t)) = getpwuid;
+
+/* For getopt(3) */
+extern char *optarg;
+extern int optind;
+
+#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
+extern char *malloc_options;
+#endif
+#ifdef YYDEBUG
+extern int yydebug;
+#endif
 
-    for (t = s; *t; t++) {
-       if (*t == '\\' || *t == '?' || *t == '*' || *t == '[' || *t == ']')
-           return(TRUE);
-    }
-    return(FALSE);
-}
+int  print_alias __P((void *, void *));
+void dump_sudoers __P((void));
+void print_defaults __P((void));
+void print_privilege __P((struct privilege *));
+void print_userspecs __P((void));
+void usage __P((void)) __attribute__((__noreturn__));
+void set_runasgr __P((char *));
+void set_runaspw __P((char *));
+
+extern void ts_setgrfile __P((const char *));
+extern void ts_setgrent __P((void));
+extern void ts_endgrent __P((void));
+extern struct group *ts_getgrent __P((void));
+extern struct group *ts_getgrnam __P((const char *));
+extern struct group *ts_getgrgid __P((gid_t));
+extern void ts_setpwfile __P((const char *));
+extern void ts_setpwent __P((void));
+extern void ts_endpwent __P((void));
+extern struct passwd *ts_getpwent __P((void));
+extern struct passwd *ts_getpwnam __P((const char *));
+extern struct passwd *ts_getpwuid __P((uid_t));
 
-/*
- * Returns TRUE if user_cmnd matches, in the sudo sense,
- * the pathname in path; otherwise, return FALSE
- */
 int
-command_matches(path, sudoers_args)
-    char *path;
-    char *sudoers_args;
+main(argc, argv)
+    int argc;
+    char **argv;
 {
-    int clen, plen;
-    char *args;
-
-    if (user_cmnd == NULL)
-       return(FALSE);
-
-    if ((args = strchr(path, ' ')))
-       *args++ = '\0';
-
-    if (has_meta(path)) {
-       if (fnmatch(path, user_cmnd, FNM_PATHNAME))
-           return(FALSE);
-       if (!sudoers_args)
-           return(TRUE);
-       else if (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))
-           return(TRUE);
-       else if (sudoers_args)
-           return((fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0));
-       else
-           return(FALSE);
-    } else {
-       plen = strlen(path);
-       if (path[plen - 1] != '/') {
-           if (strcmp(user_cmnd, path))
-               return(FALSE);
-           if (!sudoers_args)
-               return(TRUE);
-           else if (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))
-               return(TRUE);
-           else if (sudoers_args)
-               return((fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0));
-           else
-               return(FALSE);
-       }
+    struct cmndspec *cs;
+    struct privilege *priv;
+    struct userspec *us;
+    char *p, *grfile, *pwfile, *runas_group, *runas_user;
+    char hbuf[MAXHOSTNAMELEN + 1];
+    int ch, dflag, rval, matched;
+
+#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
+    malloc_options = "AFGJPR";
+#endif
+#ifdef YYDEBUG
+    yydebug = 1;
+#endif
 
-       clen = strlen(user_cmnd);
-       if (clen < plen + 1)
-           /* path cannot be the parent dir of user_cmnd */
-           return(FALSE);
+    Argv = argv;
+    Argc = argc;
 
-       if (strchr(user_cmnd + plen + 1, '/') != NULL)
-           /* path could only be an anscestor of user_cmnd -- */
-           /* ignoring, of course, things like // & /./  */
-           return(FALSE);
+    dflag = 0;
+    grfile = pwfile = runas_group = runas_user = NULL;
+    while ((ch = getopt(argc, argv, "dg:G:h:p:u:")) != -1) {
+       switch (ch) {
+           case 'd':
+               dflag = 1;
+               break;
+           case 'h':
+               user_host = optarg;
+               break;
+           case 'G':
+               grfile = optarg;
+               break;
+           case 'g':
+               runas_group = optarg;
+               break;
+           case 'p':
+               pwfile = optarg;
+               break;
+           case 'u':
+               runas_user = optarg;
+               break;
+           default:
+               usage();
+               break;
+       }
+    }
+    argc -= optind;
+    argv += optind;
+    NewArgc = argc;
+    NewArgv = argv;
+
+    /* Set group/passwd file and init the cache. */
+    if (grfile) {
+       my_setgrent = ts_setgrent;
+       my_endgrent = ts_endgrent;
+       my_getgrnam = ts_getgrnam;
+       my_getgrgid = ts_getgrgid;
+       ts_setgrfile(grfile);
+    }
+    if (pwfile) {
+       my_setpwent = ts_setpwent;
+       my_endpwent = ts_endpwent;
+       my_getpwnam = ts_getpwnam;
+       my_getpwuid = ts_getpwuid;
+       ts_setpwfile(pwfile);
+    }
+    sudo_setpwent();
+    sudo_setgrent();
+
+    if (argc < 2) {
+       if (!dflag)
+           usage();
+       if ((sudo_user.pw = sudo_getpwnam("nobody")) == NULL)
+            errorx(1, "no passwd entry for nobody!");
+       user_cmnd = user_base = "true";
+    } else {
+       if ((sudo_user.pw = sudo_getpwnam(*argv)) == NULL)
+            errorx(1, "no passwd entry for %s!", *argv);
+       user_cmnd = *++argv;
+       if ((p = strrchr(user_cmnd, '/')) != NULL)
+           user_base = p + 1;
+       else
+           user_base = user_cmnd;
+       NewArgc -= 2;
+    }
 
-       /* see whether path is the prefix of user_cmnd */
-       return((strncmp(user_cmnd, path, plen) == 0));
+    if (user_host == NULL) {
+       if (gethostname(hbuf, sizeof(hbuf)) != 0)
+           error(1, "gethostname");
+       hbuf[sizeof(hbuf) - 1] = '\0';
+       user_host = hbuf;
+    }
+    if ((p = strchr(user_host, '.'))) {
+       *p = '\0';
+       user_shost = estrdup(user_host);
+       *p = '.';
+    } else {
+       user_shost = user_host;
     }
-}
 
-static int
-addr_matches_if(n)
-    char *n;
-{
-    int i;
-    struct in_addr addr;
-    struct interface *ifp;
-#ifdef HAVE_IN6_ADDR
-    struct in6_addr addr6;
-    int j;
-#endif
-    int family;
+    /* Fill in user_args from NewArgv. */
+    if (NewArgc > 1) {
+       char *to, **from;
+       size_t size, n;
 
-#ifdef HAVE_IN6_ADDR
-    if (inet_pton(AF_INET6, n, &addr6) > 0) {
-       family = AF_INET6;
-    } else
-#endif
-    {
-       family = AF_INET;
-       addr.s_addr = inet_addr(n);
-    }
+       for (size = 0, from = NewArgv + 1; *from; from++)
+           size += strlen(*from) + 1;
 
-    for (i = 0; i < num_interfaces; i++) {
-       ifp = &interfaces[i];
-       if (ifp->family != family)
-           continue;
-       switch(family) {
-           case AF_INET:
-               if (ifp->addr.ip4.s_addr == addr.s_addr ||
-                   (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr)
-                   == addr.s_addr)
-                   return(TRUE);
-               break;
-#ifdef HAVE_IN6_ADDR
-           case AF_INET6:
-               if (memcmp(ifp->addr.ip6.s6_addr, addr6.s6_addr,
-                   sizeof(addr6.s6_addr)) == 0)
-                   return(TRUE);
-               for (j = 0; j < sizeof(addr6.s6_addr); j++) {
-                   if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr6.s6_addr[j])
-                       break;
-               }
-               if (j == sizeof(addr6.s6_addr))
-                   return(TRUE);
-#endif /* HAVE_IN6_ADDR */
+       user_args = (char *) emalloc(size);
+       for (to = user_args, from = NewArgv + 1; *from; from++) {
+           n = strlcpy(to, *from, size - (to - user_args));
+           if (n >= size - (to - user_args))
+                   errorx(1, "internal error, init_vars() overflow");
+           to += n;
+           *to++ = ' ';
        }
+       *--to = '\0';
     }
 
-    return(FALSE);
-}
+    /* Initialize default values. */
+    init_defaults();
 
-static int
-addr_matches_if_netmask(n, m)
-    char *n;
-    char *m;
-{
-    int i;
-    struct in_addr addr, mask;
-    struct interface *ifp;
-#ifdef HAVE_IN6_ADDR
-    struct in6_addr addr6, mask6;
-    int j;
-#endif
-    int family;
+    /* Load ip addr/mask for each interface. */
+    load_interfaces();
 
-#ifdef HAVE_IN6_ADDR
-    if (inet_pton(AF_INET6, n, &addr6) > 0)
-       family = AF_INET6;
+    /* Allocate space for data structures in the parser. */
+    init_parser("sudoers", 0);
+
+    if (yyparse() != 0 || parse_error)
+       (void) fputs("Does not parse", stdout);
     else
-#endif
-    {
-       family = AF_INET;
-       addr.s_addr = inet_addr(n);
-    }
+       (void) fputs("Parses OK", stdout);
 
-    if (family == AF_INET) {
-       if (strchr(m, '.'))
-           mask.s_addr = inet_addr(m);
-       else {
-           i = 32 - atoi(m);
-           mask.s_addr = 0xffffffff;
-           mask.s_addr >>= i;
-           mask.s_addr <<= i;
-           mask.s_addr = htonl(mask.s_addr);
-       }
-    }
-#ifdef HAVE_IN6_ADDR
-    else {
-       if (inet_pton(AF_INET6, m, &mask6) <= 0) {
-           j = atoi(m);
-           for (i = 0; i < 16; i++) {
-               if (j < i * 8)
-                   mask6.s6_addr[i] = 0;
-               else if (i * 8 + 8 <= j)
-                   mask6.s6_addr[i] = 0xff;
-               else
-                   mask6.s6_addr[i] = 0xff00 >> (j - i * 8);
-           }
-       }
+    if (!update_defaults(SETDEF_ALL))
+       (void) fputs(" (problem with defaults entries)", stdout);
+    puts(".");
+
+    /*
+     * Set runas passwd/group entries based on command line or sudoers.
+     * Note that if runas_group was specified without runas_user we
+     * defer setting runas_pw so the match routines know to ignore it.
+     */
+    if (runas_group != NULL) {
+        set_runasgr(runas_group);
+        if (runas_user != NULL)
+            set_runaspw(runas_user);
+    } else
+        set_runaspw(runas_user ? runas_user : def_runas_default);
+
+    if (dflag) {
+       (void) putchar('\n');
+       dump_sudoers();
+       if (argc < 2)
+           exit(0);
     }
-#endif /* HAVE_IN6_ADDR */
 
-    for (i = 0; i < num_interfaces; i++) {
-       ifp = &interfaces[i];
-       if (ifp->family != family)
+    /* This loop must match the one in sudoers_lookup() */
+    printf("\nEntries for user %s:\n", user_name);
+    matched = UNSPEC;
+    tq_foreach_rev(&userspecs, us) {
+       if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
            continue;
-       switch(family) {
-           case AF_INET:
-               if ((ifp->addr.ip4.s_addr & mask.s_addr) == addr.s_addr)
-                   return(TRUE);
-#ifdef HAVE_IN6_ADDR
-           case AF_INET6:
-               for (j = 0; j < sizeof(addr6.s6_addr); j++) {
-                   if ((ifp->addr.ip6.s6_addr[j] & mask6.s6_addr[j]) != addr6.s6_addr[j])
-                       break;
+       tq_foreach_rev(&us->privileges, priv) {
+           putchar('\n');
+           print_privilege(priv); /* XXX */
+           putchar('\n');
+           if (hostlist_matches(&priv->hostlist) == ALLOW) {
+               puts("\thost  matched");
+               tq_foreach_rev(&priv->cmndlist, cs) {
+                   if (runaslist_matches(&cs->runasuserlist,
+                       &cs->runasgrouplist) == ALLOW) {
+                       puts("\trunas matched");
+                       rval = cmnd_matches(cs->cmnd);
+                       if (rval != UNSPEC)
+                           matched = rval;
+                       printf("\tcmnd  %s\n", rval == ALLOW ? "allowed" :
+                           rval == DENY ? "denied" : "unmatched");
+                   }
                }
-               if (j == sizeof(addr6.s6_addr))
-                   return(TRUE);
-#endif /* HAVE_IN6_ADDR */
+           } else
+               puts("\thost  unmatched");
        }
     }
+    printf("\nCommand %s\n", matched == ALLOW ? "allowed" :
+       matched == DENY ? "denied" : "unmatched");
 
-    return(FALSE);
-}
-
-/*
- * Returns TRUE if "n" is one of our ip addresses or if
- * "n" is a network that we are on, else returns FALSE.
- */
-int
-addr_matches(n)
-    char *n;
-{
-    char *m;
-    int retval;
-
-    /* If there's an explicit netmask, use it. */
-    if ((m = strchr(n, '/'))) {
-       *m++ = '\0';
-       retval = addr_matches_if_netmask(n, m);
-       *(m - 1) = '/';
-    } else
-       retval = addr_matches_if(n);
-
-    return(retval);
-}
-
-int
-hostname_matches(shost, lhost, pattern)
-    char *shost;
-    char *lhost;
-    char *pattern;
-{
-    if (has_meta(pattern)) {
-        if (strchr(pattern, '.'))
-            return(fnmatch(pattern, lhost, FNM_CASEFOLD));
-        else
-            return(fnmatch(pattern, shost, FNM_CASEFOLD));
-    } else {
-        if (strchr(pattern, '.'))
-            return(strcasecmp(lhost, pattern));
-        else
-            return(strcasecmp(shost, pattern));
-    }
+    exit(0);
 }
 
-int
-userpw_matches(sudoers_user, user, pw)
-    char *sudoers_user;
+void
+set_runaspw(user)
     char *user;
-    struct passwd *pw;
 {
-    if (pw != NULL && *sudoers_user == '#') {
-       uid_t uid = atoi(sudoers_user + 1);
-       if (uid == pw->pw_uid)
-           return(1);
+    if (*user == '#') {
+       if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
+           runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
+    } else {
+       if ((runas_pw = sudo_getpwnam(user)) == NULL)
+           errorx(1, "unknown user: %s", user);
     }
-    return(strcmp(sudoers_user, user) == 0);
 }
 
-int
-usergr_matches(group, user, pw)
+void
+set_runasgr(group)
     char *group;
-    char *user;
-    struct passwd *pw;
 {
-    struct group *grp;
-    char **cur;
-
-    /* Make sure we have a valid usergroup, sudo style. */
-    if (*group++ != '%')
-       return(FALSE);
-
-    if ((grp = getgrnam(group)) == NULL)
-       return(FALSE);
-
-    /*
-     * Check against user's real gid as well as group's user list
-     */
-    if (getgid() == grp->gr_gid)
-       return(TRUE);
-
-    for (cur=grp->gr_mem; *cur; cur++) {
-       if (strcmp(*cur, user) == 0)
-           return(TRUE);
+    if (*group == '#') {
+       if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)
+           runas_gr = sudo_fakegrnam(group);
+    } else {
+       if ((runas_gr = sudo_getgrnam(group)) == NULL)
+           errorx(1, "unknown group: %s", group);
     }
-
-    return(FALSE);
 }
 
-int
-netgr_matches(netgr, host, shost, user)
-    char *netgr;
-    char *host;
-    char *shost;
-    char *user;
+void
+sudo_setspent()
 {
-#ifdef HAVE_GETDOMAINNAME
-    static char *domain = (char *) -1;
-#else
-    static char *domain = NULL;
-#endif /* HAVE_GETDOMAINNAME */
-
-    /* Make sure we have a valid netgroup, sudo style. */
-    if (*netgr++ != '+')
-       return(FALSE);
-
-#ifdef HAVE_GETDOMAINNAME
-    /* Get the domain name (if any). */
-    if (domain == (char *) -1) {
-       domain = (char *) emalloc(MAXHOSTNAMELEN);
-
-       if (getdomainname(domain, MAXHOSTNAMELEN) != 0 || *domain == '\0') {
-           efree(domain);
-           domain = NULL;
-       }
-    }
-#endif /* HAVE_GETDOMAINNAME */
-
-#ifdef HAVE_INNETGR
-    if (innetgr(netgr, host, user, domain))
-       return(TRUE);
-    else if (host != shost && innetgr(netgr, shost, user, domain))
-       return(TRUE);
-#endif /* HAVE_INNETGR */
-
-    return(FALSE);
+    return;
 }
 
 void
-set_perms(i)
-    int i;
+sudo_endspent()
 {
     return;
 }
 
+char *
+sudo_getepw(pw)
+    const struct passwd *pw;
+{
+    return (pw->pw_passwd);
+}
+
 void
 set_fqdn()
 {
     return;
 }
 
-int
-set_runaspw(user)
-    char *user;
+FILE *
+open_sudoers(path, keepopen)
+    const char *path;
+    int *keepopen;
 {
-    return(TRUE);
+    return(fopen(path, "r"));
 }
 
 void
@@ -449,110 +386,194 @@ init_envtables()
     return;
 }
 
-int
-main(argc, argv)
-    int argc;
-    char **argv;
+void
+set_perms(perm)
+    int perm;
 {
-    struct passwd pw;
-    char *p;
-#ifdef YYDEBUG
-    extern int yydebug;
-    yydebug = 1;
-#endif
-
-    Argv = argv;
-    Argc = argc;
+    return;
+}
 
-    if (Argc >= 6 && strcmp(Argv[1], "-u") == 0) {
-       user_runas = &Argv[2];
-       pw.pw_name = Argv[3];
-       user_host = Argv[4];
-       user_cmnd = Argv[5];
-
-       NewArgv = &Argv[5];
-       NewArgc = Argc - 5;
-    } else if (Argc >= 4) {
-       pw.pw_name = Argv[1];
-       user_host = Argv[2];
-       user_cmnd = Argv[3];
-
-       NewArgv = &Argv[3];
-       NewArgc = Argc - 3;
-    } else {
-       (void) fprintf(stderr,
-           "usage: sudo [-u user] <user> <host> <command> [args]\n");
-       exit(1);
+void
+cleanup(gotsignal)
+    int gotsignal;
+{
+    if (!gotsignal) {
+       sudo_endpwent();
+       sudo_endgrent();
     }
+}
 
-    sudo_user.pw = &pw;                /* user_name needs to be defined */
-
-    if ((p = strchr(user_host, '.'))) {
-       *p = '\0';
-       user_shost = estrdup(user_host);
-       *p = '.';
-    } else {
-       user_shost = user_host;
+void
+print_member(m)    
+    struct member *m;
+{
+    struct sudo_command *c;
+
+    if (m->negated)
+       putchar('!');
+    if (m->name == NULL)
+       fputs("ALL", stdout);
+    else if (m->type != COMMAND)
+       fputs(m->name, stdout);
+    else {
+       c = (struct sudo_command *) m->name;
+       printf("%s%s%s", c->cmnd, c->args ? " " : "",
+           c->args ? c->args : "");
     }
+}
 
-    /* Fill in user_args from NewArgv. */
-    if (NewArgc > 1) {
-       char *to, **from;
-       size_t size, n;
-
-       size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
-               strlen(NewArgv[NewArgc-1]) + 1;
-       user_args = (char *) emalloc(size);
-       for (to = user_args, from = NewArgv + 1; *from; from++) {
-           n = strlcpy(to, *from, size - (to - user_args));
-           if (n >= size - (to - user_args))
-                   errx(1, "internal error, init_vars() overflow");
-           to += n;
-           *to++ = ' ';
+void
+print_defaults()
+{
+    struct defaults *d;
+    struct member *m;
+
+    tq_foreach_fwd(&defaults, d) {
+       (void) fputs("Defaults", stdout);
+       switch (d->type) {
+           case DEFAULTS_HOST:
+               putchar('@');
+               break;
+           case DEFAULTS_USER:
+               putchar(':');
+               break;
+           case DEFAULTS_RUNAS:
+               putchar('>');
+               break;
+           case DEFAULTS_CMND:
+               putchar('!');
+               break;
        }
-       *--to = '\0';
+       tq_foreach_fwd(&d->binding, m) {
+           if (m != tq_first(&d->binding))
+               putchar(',');
+           print_member(m);
+       }
+       printf("\t%s%s", d->op == FALSE ? "!" : "", d->var);
+       if (d->val != NULL) {
+           printf("%c%s", d->op == TRUE ? '=' : d->op, d->val);
+       }
+       putchar('\n');
     }
+}
 
-    /* Initialize default values. */
-    init_defaults();
-
-    /* Warn about aliases that are used before being defined. */
-    pedantic = TRUE;
-
-    /* Need to keep aliases around for dumpaliases(). */
-    clearaliases = FALSE;
-
-    /* Load ip addr/mask for each interface. */
-    load_interfaces();
+int
+print_alias(v1, v2)
+    void *v1, *v2;
+{
+    struct alias *a = (struct alias *)v1;
+    struct member *m;
+    struct sudo_command *c;
+
+    switch (a->type) {
+       case HOSTALIAS:
+           (void) printf("Host_Alias\t%s = ", a->name);
+           break;
+       case CMNDALIAS:
+           (void) printf("Cmnd_Alias\t%s = ", a->name);
+           break;
+       case USERALIAS:
+           (void) printf("User_Alias\t%s = ", a->name);
+           break;
+       case RUNASALIAS:
+           (void) printf("Runas_Alias\t%s = ", a->name);
+           break;
+    }
+    tq_foreach_fwd(&a->members, m) {
+       if (m != tq_first(&a->members))
+           fputs(", ", stdout);
+       if (m->type == COMMAND) {
+           c = (struct sudo_command *) m->name;
+           printf("%s%s%s", c->cmnd, c->args ? " " : "",
+               c->args ? c->args : "");
+       } else
+           fputs(m->name, stdout);
+    }
+    putchar('\n');
+    return(0);
+}
 
-    /* Allocate space for data structures in the parser. */
-    init_parser();
+void
+print_privilege(priv)
+    struct privilege *priv;
+{
+    struct cmndspec *cs;
+    struct member *m;
+    struct privilege *p;
+    struct cmndtag tags;
+
+    for (p = priv; p != NULL; p = p->next) {
+       if (p != priv)
+           fputs(" : ", stdout);
+       tq_foreach_fwd(&p->hostlist, m) {
+           if (m != tq_first(&p->hostlist))
+               fputs(", ", stdout);
+           print_member(m);
+       }
+       fputs(" = ", stdout);
+       tags.nopasswd = tags.noexec = UNSPEC;
+       tq_foreach_fwd(&p->cmndlist, cs) {
+           if (cs != tq_first(&p->cmndlist))
+               fputs(", ", stdout);
+           /* XXX - runasgrouplist too */
+           if (!tq_empty(&cs->runasuserlist)) {
+               fputs("(", stdout);
+               tq_foreach_fwd(&cs->runasuserlist, m) {
+                   if (m != tq_first(&cs->runasuserlist))
+                       fputs(", ", stdout);
+                   print_member(m);
+               }
+               fputs(") ", stdout);
+           }
+#ifdef HAVE_SELINUX
+           if (cs->role)
+               printf("ROLE=%s ", cs->role);
+           if (cs->type)
+               printf("TYPE=%s ", cs->type);
+#endif /* HAVE_SELINUX */
+           if (cs->tags.nopasswd != UNSPEC && cs->tags.nopasswd != tags.nopasswd)
+               printf("%sPASSWD: ", cs->tags.nopasswd ? "NO" : "");
+           if (cs->tags.noexec != UNSPEC && cs->tags.noexec != tags.noexec)
+               printf("%sEXEC: ", cs->tags.noexec ? "NO" : "");
+           print_member(cs->cmnd);
+           memcpy(&tags, &cs->tags, sizeof(tags));
+       }
+    }
+}
 
-    if (yyparse() || parse_error) {
-       (void) printf("doesn't parse.\n");
-    } else {
-       (void) printf("parses OK.\n\n");
-       if (top == 0)
-           (void) printf("User %s not found\n", pw.pw_name);
-       else while (top) {
-           (void) printf("[%d]\n", top-1);
-           (void) printf("user_match : %d\n", user_matches);
-           (void) printf("host_match : %d\n", host_matches);
-           (void) printf("cmnd_match : %d\n", cmnd_matches);
-           (void) printf("no_passwd  : %d\n", no_passwd);
-           (void) printf("runas_match: %d\n", runas_matches);
-           (void) printf("runas      : %s\n", *user_runas);
-           if (match[top-1].role)
-               (void) printf("role       : %s\n", match[top-1].role);
-           if (match[top-1].type)
-               (void) printf("type       : %s\n", match[top-1].type);
-           top--;
+void
+print_userspecs()
+{
+    struct member *m;
+    struct userspec *us;
+
+    tq_foreach_fwd(&userspecs, us) {
+       tq_foreach_fwd(&us->users, m) {
+           if (m != tq_first(&us->users))
+               fputs(", ", stdout);
+           print_member(m);
        }
+       putchar('\t');
+       print_privilege(us->privileges.first); /* XXX */
+       putchar('\n');
     }
+}
 
-    /* Dump aliases. */
-    (void) printf("Matching Aliases --\n");
-    dumpaliases();
+void
+dump_sudoers()
+{
+    print_defaults();
 
-    exit(0);
+    putchar('\n');
+    alias_apply(print_alias, NULL);
+
+    putchar('\n');
+    print_userspecs();
+}
+
+void
+usage()
+{
+    (void) fprintf(stderr, "usage: %s [-d] [-G grfile] [-g group] [-h host] [-p pwfile] [-u user] <user> <command> [args]\n", getprogname());
+    exit(1);
 }
index 2c94cdb11a26083cbaae183f56de0d823c4cfbaf..62faead2345f6c3d38cbbde484c0f6b42fde99f5 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1996, 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1996, 1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -70,7 +71,7 @@
 #include "sudo.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: tgetpass.c,v 1.111.2.7 2008/06/21 00:27:01 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: tgetpass.c,v 1.126 2008/12/09 20:55:49 millert Exp $";
 #endif /* lint */
 
 #ifndef TCSASOFT
@@ -114,6 +115,7 @@ static volatile sig_atomic_t signo;
 
 static void handler __P((int));
 static char *getln __P((int, char *, size_t));
+static char *sudo_askpass __P((const char *));
 
 /*
  * Like getpass(3) but with timeout and echo flags.
@@ -132,6 +134,11 @@ tgetpass(prompt, timeout, flags)
     int input, output, save_errno;
 
     (void) fflush(stdout);
+
+    /* If using a helper program to get the password, run it instead. */
+    if (ISSET(flags, TGP_ASKPASS) && user_askpass)
+       return(sudo_askpass(prompt));
+
 restart:
     signo = 0;
     pass = NULL;
@@ -147,6 +154,7 @@ restart:
      * Catch signals that would otherwise cause the user to end
      * up with echo turned off in the shell.
      */
+    zero_bytes(&sa, sizeof(sa));
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = SA_INTERRUPT;        /* don't restart system calls */
     sa.sa_handler = handler;
@@ -169,8 +177,8 @@ restart:
 #endif
        (void) tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
     } else {
-       memset(&term, 0, sizeof(term));
-       memset(&oterm, 0, sizeof(oterm));
+       zero_bytes(&term, sizeof(term));
+       zero_bytes(&oterm, sizeof(oterm));
     }
 
     /* No output if we are already backgrounded. */
@@ -224,26 +232,74 @@ restart:
     return(pass);
 }
 
+/*
+ * Fork a child and exec sudo-askpass to get the password from the user.
+ */
+static char *
+sudo_askpass(prompt)
+    const char *prompt;
+{
+    static char buf[SUDO_PASS_MAX + 1], *pass;
+    sigaction_t sa, saved_sa_pipe;
+    int pfd[2];
+    pid_t pid;
+
+    if (pipe(pfd) == -1)
+       error(1, "unable to create pipe");
+
+    if ((pid = fork()) == -1)
+       error(1, "unable to fork");
+
+    if (pid == 0) {
+       /* child, point stdout to output side of the pipe and exec askpass */
+       (void) dup2(pfd[1], STDOUT_FILENO);
+       set_perms(PERM_FULL_USER);
+       closefrom(STDERR_FILENO + 1);
+       execl(user_askpass, user_askpass, prompt, (char *)NULL);
+       warning("unable to run %s", user_askpass);
+       _exit(255);
+    }
+
+    /* Ignore SIGPIPE in case child exits prematurely */
+    zero_bytes(&sa, sizeof(sa));
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = SIG_IGN;
+    (void) sigaction(SIGPIPE, &sa, &saved_sa_pipe);
+
+    /* Get response from child (askpass) and restore SIGPIPE handler */
+    (void) close(pfd[1]);
+    pass = getln(pfd[0], buf, sizeof(buf));
+    (void) close(pfd[0]);
+    (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
+
+    return(pass);
+}
+
 static char *
 getln(fd, buf, bufsiz)
     int fd;
     char *buf;
     size_t bufsiz;
 {
-    char c, *cp;
-    ssize_t nr;
+    ssize_t nr = -1;
+    char *cp = buf;
+    char c = '\0';
 
     if (bufsiz == 0) {
        errno = EINVAL;
        return(NULL);                   /* sanity */
     }
 
-    cp = buf;
-    nr = -1;
-    while (--bufsiz && (nr = read(fd, &c, 1)) == 1 && c != '\n' && c != '\r')
+    while (--bufsiz) {
+       nr = read(fd, &c, 1);
+       if (nr != 1 || c == '\n' || c == '\r')
+           break;
        *cp++ = c;
+    }
     *cp = '\0';
-    return(nr == -1 ? NULL : buf);
+
+    return(nr == 1 ? buf : NULL);
 }
 
 static void
@@ -253,3 +309,13 @@ handler(s)
     if (s != SIGALRM)
        signo = s;
 }
+
+int
+tty_present()
+{
+    int fd;
+
+    if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1)
+       close(fd);
+    return(fd != -1);
+}
diff --git a/toke.c b/toke.c
new file mode 100644 (file)
index 0000000..0fd8ef9
--- /dev/null
+++ b/toke.c
@@ -0,0 +1,3300 @@
+/*     $OpenBSD: flex.skl,v 1.10 2007/01/26 14:38:19 tsi Exp $ */
+
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /home/cvs/courtesan/sudo/toke.c,v 1.27 2008/11/24 00:42:20 millert Exp $
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+#include <errno.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else  /* ! __cplusplus */
+
+#ifdef __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator).  This
+ * avoids problems with code like:
+ *
+ *     if ( condition_holds )
+ *             yyless( 5 );
+ *     else
+ *             do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+               *yy_cp = yy_hold_char; \
+               YY_RESTORE_YY_MORE_OFFSET \
+               yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+               YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+               } \
+       while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+       {
+       FILE *yy_input_file;
+
+       char *yy_ch_buf;                /* input buffer */
+       char *yy_buf_pos;               /* current position in input buffer */
+
+       /* Size of input buffer in bytes, not including room for EOB
+        * characters.
+        */
+       yy_size_t yy_buf_size;
+
+       /* Number of characters read into yy_ch_buf, not including EOB
+        * characters.
+        */
+       int yy_n_chars;
+
+       /* Whether we "own" the buffer - i.e., we know we created it,
+        * and can realloc() it to grow it, and should free() it to
+        * delete it.
+        */
+       int yy_is_our_buffer;
+
+       /* Whether this is an "interactive" input source; if so, and
+        * if we're using stdio for input, then we want to use getc()
+        * instead of fread(), to make sure we stop fetching input after
+        * each newline.
+        */
+       int yy_is_interactive;
+
+       /* Whether we're considered to be at the beginning of a line.
+        * If so, '^' rules will be active on the next match, otherwise
+        * not.
+        */
+       int yy_at_bol;
+
+       /* Whether to try to fill the input buffer when we reach the
+        * end of it.
+        */
+       int yy_fill_buffer;
+
+       int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+       /* When an EOF's been seen but there's still some text to process
+        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+        * shouldn't try reading from the input source any more.  We might
+        * still have a bunch of tokens to match, though, because of
+        * possible backing-up.
+        *
+        * When we actually see the EOF, we change the status to "new"
+        * (via yyrestart()), so that the user can continue scanning by
+        * just pointing yyin at a new input file.
+        */
+#define YY_BUFFER_EOF_PENDING 2
+       };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars;         /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;                /* whether we need to initialize */
+static int yy_start = 0;       /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+       { \
+       if ( ! yy_current_buffer ) \
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+       yy_current_buffer->yy_is_interactive = is_interactive; \
+       }
+
+#define yy_set_bol(at_bol) \
+       { \
+       if ( ! yy_current_buffer ) \
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+       yy_current_buffer->yy_at_bol = at_bol; \
+       }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+
+#define yywrap() 1
+#define YY_SKIP_YYWRAP
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+       yytext_ptr = yy_bp; \
+       yyleng = (int) (yy_cp - yy_bp); \
+       yy_hold_char = *yy_cp; \
+       *yy_cp = '\0'; \
+       yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 48
+#define YY_END_OF_BUFFER 49
+static yyconst short int yy_accept[534] =
+    {   0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,   49,   36,   44,   43,   42,   47,   36,   37,
+       38,   36,   39,   36,   36,   36,   36,   41,   40,   47,
+       32,   32,   32,   32,   32,   32,   47,   36,   36,   44,
+       47,   32,   32,   32,   32,   32,    1,   47,   36,   36,
+       16,   15,   16,   15,   15,   47,   47,   47,    2,    8,
+        7,    8,    3,    8,    4,   47,   12,   12,   12,   10,
+       11,   36,    0,   44,   42,    0,   46,    0,   36,   27,
+        0,   26,    0,   35,   35,    0,   36,   36,    0,   36,
+       36,   36,   36,    0,   30,   32,   32,   32,   32,   32,
+
+       32,   36,   45,   36,   44,    0,    0,    0,    0,    0,
+        0,   36,   36,   36,   36,   36,    1,   33,   33,    0,
+       36,   16,   16,   14,   13,   14,    0,    2,    8,    0,
+        5,    6,    8,    8,   12,    0,   12,   12,    0,    9,
+        0,    0,   36,   36,   36,   36,   36,    0,    0,   30,
+       30,   32,   32,   32,   32,   32,   32,   32,   36,    0,
+        0,    0,    0,    0,    0,   36,   36,   36,   36,   36,
+        0,   36,    9,   36,   36,   36,   36,   36,   36,    0,
+       31,   31,   31,    0,    0,   30,   30,   30,   30,   30,
+       30,   30,   32,   32,   32,   32,   32,   32,   32,   36,
+
+        0,    0,    0,    0,    0,    0,   36,   36,   36,   36,
+       36,   36,   36,    0,    0,   31,   31,   31,    0,   30,
+       30,    0,   30,   30,   30,   30,   30,   30,   30,   30,
+       30,   30,   30,    0,   23,   32,   32,   32,   32,   32,
+       36,    0,    0,    0,    0,   36,   36,   36,   36,   36,
+       36,   36,   36,    0,   31,    0,   30,   30,   30,    0,
+        0,    0,   30,   30,   30,   30,   30,   30,   30,   30,
+       30,   30,   30,   30,   30,   32,   32,   32,   32,   32,
+       36,    0,    0,    0,   36,   36,   36,   28,   28,   28,
+        0,    0,   30,   30,   30,   30,   30,   30,   30,    0,
+
+        0,    0,    0,    0,   30,   30,   30,   30,   30,   30,
+       30,   30,   30,   30,   30,   30,   30,   30,    0,   22,
+       32,   32,    0,   21,    0,   24,   36,    0,    0,    0,
+       36,   36,   36,   36,   28,   28,   28,   28,    0,   30,
+        0,   30,   30,   30,   30,   30,   30,   30,   30,   30,
+       30,   30,    0,    0,    0,   30,   30,   30,   30,   30,
+       30,   30,   30,   30,   30,   30,   30,   30,   32,   32,
+       34,    0,    0,    0,   36,   18,   33,   36,   29,   29,
+       29,   30,    0,    0,    0,   30,   30,   30,   30,   30,
+       30,   30,   30,   30,   30,   30,   30,   30,    0,    0,
+
+        0,    0,    0,   30,   30,   30,   30,   30,   30,   30,
+       30,    0,   20,    0,   25,    0,   18,    0,   36,    0,
+       36,   36,   36,   29,   29,   29,   29,   29,    0,    0,
+        0,    0,    0,   30,   30,   30,   30,   30,   30,   30,
+       30,   30,   30,   30,   30,   30,   30,   30,   30,   30,
+       30,   30,   30,    0,    0,   19,   18,    0,   18,    0,
+       36,   36,   36,   29,   29,    0,    0,    0,   30,   30,
+       30,   30,   30,   30,   30,   30,   30,   30,   30,   30,
+       30,   30,   30,   30,   30,   30,   19,    0,   17,   36,
+       36,   36,   36,   36,    0,    0,    0,    0,    0,   30,
+
+       30,   30,   30,   30,   30,   30,   30,   36,   36,   36,
+       30,   30,   30,   30,   30,   30,   36,   36,   36,   36,
+       36,   30,   30,   30,   30,   30,   28,   28,   28,   28,
+       28,   28,    0
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    4,    5,    6,    1,    7,    1,    1,    8,
+        9,   10,   11,   12,   13,   14,   15,   16,   17,   18,
+       19,   20,   21,   22,   22,   22,   23,   24,    1,    1,
+       25,   26,   10,   27,   28,   29,   30,   31,   32,   29,
+       33,   34,   33,   33,   33,   33,   33,   35,   36,   37,
+       33,   38,   39,   40,   41,   42,   43,   44,   33,   33,
+       10,   45,   10,    1,   46,    1,   47,   48,   49,   50,
+
+       51,   52,   53,   53,   54,   53,   53,   55,   56,   57,
+       58,   53,   53,   59,   60,   61,   62,   53,   53,   53,
+       53,   53,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[63] =
+    {   0,
+        1,    2,    3,    4,    5,    6,    1,    4,    4,    1,
+        1,    2,    1,    7,    8,    9,    9,    9,    9,    9,
+        9,    9,    9,   10,    6,    4,    1,    9,    9,    9,
+        9,    9,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,   11,   12,   13,   13,   13,   13,
+       13,   13,   12,   12,   12,   12,   12,   12,   12,   12,
+       12,   12
+    } ;
+
+static yyconst short int yy_base[594] =
+    {   0,
+        0,   61,   62,   63,   69,   84,  128,  189,  250,  294,
+       80,  101, 2227, 2181, 2223, 3353, 2220,  337, 2164, 3353,
+     3353, 2154, 3353,  107,  347,  119,  137, 2172, 3353, 3353,
+      399, 2143,  446, 2141, 2139, 2098,  497,  145,   35,  167,
+      521, 2073, 2042, 2034, 2019, 2010, 2065,  193,  256,   55,
+        0, 3353, 2062,    0, 3353,  264,  573,  110,    0, 2020,
+     3353,   73, 3353,   76, 3353,  117, 2016,  105,  106, 3353,
+      142, 2014,  306, 2056, 2053, 2051, 3353,  201,  209, 1993,
+      506, 1990,  543,  276, 1989,  554,  306,  581, 2002, 2002,
+      325,  364,  317, 1982,   55,  618,    0, 1971,  240, 1963,
+
+     1961,  125, 3353,   98,  523, 1936, 1923, 1913, 1908, 1909,
+      146,  115,  219,   29,  212,  149, 1966,  481, 1922,  649,
+      154,    0, 1954,  256, 3353, 3353,  284,    0, 1897,  674,
+     3353, 3353, 1875,  484, 1848, 1885,  271,  307,  288, 1860,
+     1858,  676,  688,  720,  752,  784, 1846, 1835,  821,  268,
+      859,  896, 1820, 1799, 1814, 1809, 1786, 1792,  236, 1765,
+     1754, 1745, 1726, 1698,  300,  157, 1701,  259,   79,  329,
+      691,  344, 1711,  598,  348,  935,  967,  703,  366, 1688,
+     1687,  733,  455, 1686, 1670,  464,  709,  999,  760,  606,
+     1037,  770, 1669,  401, 1643, 1635, 1632, 1613, 1620,  356,
+
+     1604, 1578, 1563, 1575, 1547,  369,  435,  503,  233,  466,
+     1076, 1108, 1140, 1581, 1580,  801, 1565, 1563, 1562, 1545,
+      467,  838,  557,  876,  559, 1172,    0,  915, 1183,  943,
+      742, 1221,  953,  511, 3353, 1538, 1515, 1521, 1521, 1509,
+      483, 1477, 1460, 1461,  543,  363,   21,  532,  979,  505,
+     1260, 1292,  989, 1496, 1479, 1468, 1467, 1322,  468, 1019,
+     1056, 1086,  630,  648,  670, 1094,  926, 1361,    0, 1118,
+     1372, 1127,  846, 1410, 1150,  582, 1447, 1438,  583,  640,
+      636, 1409, 1381,  641,  632,  459,  638, 1448, 1479, 1510,
+     1411, 1393, 1381, 1158, 1542, 1200,  884, 1579, 1240, 1268,
+
+     1385, 1278, 1302, 1312,  674,  720, 1067, 1251, 1339, 1383,
+     1618,    0, 1394, 1629, 1427, 1208, 1667, 1458,  694, 3353,
+     1318, 1306,  743, 3353,  806, 3353,  749, 1292, 1274,  605,
+      923,  751,  876, 1466,  784, 1705, 1736, 1489, 1280, 1243,
+     1496,  771, 1519,  968, 1768,    0,  565, 1779, 1527, 1347,
+     1816, 1561, 1598, 1648, 1686, 1047, 1231, 1677, 1715, 1715,
+     1746, 1855,    0, 1748, 1866, 1724, 1435, 1757,  824,  918,
+     1219, 1194, 1187,  657,  667, 1895, 1165, 1927, 1959, 1991,
+     2023, 1160, 1798, 1835, 1886, 1158,  980, 1127, 1907, 1141,
+     2055,    0,  724, 2066, 1915, 1935, 2103, 1943, 1967, 1069,
+
+     1977, 2001, 2011, 1278, 1312, 1877,  813,  832, 2142,    0,
+      862, 1099, 3353, 1116, 3353, 1033, 2029,  976,  878, 1019,
+     1000, 2083, 1018, 2152, 2184, 2216, 2248, 2046, 2120,  997,
+     2162, 2172, 2194,  969,  898, 1293, 1392, 2200, 1543, 2280,
+        0, 1003, 2291, 2224, 2031, 2328, 2234, 2257, 2266, 2309,
+     1561,  871, 1029,  749,  761,  668,  650, 2359,  626, 2384,
+     2397, 2429, 2461, 2381, 1894, 2411, 2439, 2449,  628,  546,
+     1599, 1649, 2469, 1780, 2493,    0, 1097, 2504, 2477, 2091,
+     2523,  544, 2542, 2551, 2420,  521, 3353,  513, 3353, 2559,
+     1138, 2591, 2623, 2570, 2576,  488, 2602, 2612, 2633,  460,
+
+      381, 1799,  359,  303, 2641,    0, 1186, 2655, 2687, 2719,
+     2663, 2671, 2695,  289,    0,  182, 2703, 1289, 2751, 2783,
+     2733, 3353, 2739, 2763, 2128, 3353, 2771, 2791, 2801,  126,
+     2821, 2813, 3353, 2866, 2879, 2892, 2905, 2918, 2931, 2944,
+     2957, 2970, 2975, 2988, 3001, 3003, 3016, 3029, 3042, 3055,
+     3068, 3073, 3079, 3092, 3097, 3103, 3108, 3113, 3118, 3124,
+     3129, 3134, 3139, 3145, 3152, 3157, 3162, 3167, 3173, 3180,
+     3185, 3190, 3196, 3203, 3208, 3215, 3221, 3228, 3233, 3240,
+     3246, 3253, 3266, 3279, 3284, 3291, 3297, 3310, 3315, 3322,
+     3327, 3334, 3339
+
+    } ;
+
+static yyconst short int yy_def[594] =
+    {   0,
+      533,    1,    1,    1,  534,  534,  535,  535,  536,  536,
+      537,  537,  533,  538,  533,  533,  533,  539,  540,  533,
+      533,  541,  533,  542,  538,   25,   25,  543,  533,  533,
+      533,   31,   31,   33,   33,   33,  538,   25,  538,  533,
+      539,   31,   31,   33,   33,   33,  533,  533,  544,  538,
+      545,  533,  545,  545,  533,  533,  539,  533,  546,  547,
+      533,  547,  533,  547,  533,  548,  549,  549,  549,  533,
+      533,  538,  538,  533,  533,  550,  533,  533,  533,  540,
+      540,  541,  541,  542,  551,  538,  538,   25,  543,   88,
+       88,   88,   88,  552,  553,   31,   33,   33,   33,   33,
+
+       33,  538,  533,  538,  533,  533,  533,  533,  533,  533,
+      550,  538,   88,  538,  538,  538,  533,  544,  554,  538,
+      538,  545,  545,  533,  533,  533,  533,  546,  547,  547,
+      533,  533,  547,  547,  549,  533,  549,  549,  533,  533,
+      550,  533,  538,  538,  538,   88,  146,  555,  533,  556,
+      533,   31,   33,   33,   33,   33,   33,   33,  538,  533,
+      533,  533,  533,  533,  550,  538,  146,  538,  538,  538,
+      533,  538,  533,  538,  538,  538,  538,  538,  538,  557,
+      558,  558,  182,  559,  558,  560,  151,  533,  188,  188,
+      533,  188,   33,   33,   33,   33,   33,   33,   33,  538,
+
+      533,  533,  533,  533,  533,  550,  538,  538,  538,  538,
+      538,  538,  538,  533,  561,  561,  216,  561,  562,  563,
+      564,  533,  565,  191,  565,  565,  226,  565,  533,  229,
+      229,  533,  229,  533,  533,   33,   33,   33,   33,   33,
+      538,  533,  533,  533,  550,  538,  538,  538,  538,  538,
+      538,  538,  538,  566,  566,  567,  568,  533,  533,  533,
+      533,  533,  569,  569,  570,  232,  570,  570,  268,  570,
+      533,  271,  271,  533,  271,   33,   33,   33,   33,   33,
+      538,  533,  533,  550,  538,  538,  538,  538,  538,  538,
+      533,  571,  572,  258,  533,  295,  295,  533,  295,  533,
+
+      533,  533,  533,  533,  533,  573,  573,  574,  274,  574,
+      574,  311,  574,  533,  314,  314,  533,  314,  533,  533,
+       33,   33,  533,  533,  533,  533,  538,  533,  533,  550,
+      538,  538,  538,  538,  538,  538,  538,  538,  533,  575,
+      533,  576,  298,  576,  576,  345,  345,  533,  348,  348,
+      533,  348,  533,  533,  533,  533,  577,  577,  578,  317,
+      578,  578,  362,  578,  533,  365,  365,  365,   33,   33,
+      538,  533,  533,  550,  538,  538,  538,  538,  538,  538,
+      538,  533,  533,  533,  533,  579,  579,  580,  351,  580,
+      580,  391,  391,  533,  394,  394,  533,  394,  533,  533,
+
+      533,  533,  533,  533,  581,  581,  582,  582,  582,  409,
+      409,  533,  533,  533,  533,  533,  533,  550,  538,  583,
+      584,  538,  538,  538,  538,  538,  538,  538,  533,  533,
+      533,  533,  533,  533,  585,  585,  586,  397,  586,  586,
+      440,  440,  533,  443,  443,  533,  443,  533,  533,  533,
+      533,  587,  587,  533,  588,  538,  583,  583,  584,  584,
+      538,  538,  538,  538,  538,  533,  533,  533,  533,  589,
+      589,  590,  446,  590,  590,  475,  475,  533,  478,  478,
+      478,  533,  533,  533,  533,  533,  533,  588,  533,  538,
+      538,  538,  538,  538,  533,  533,  533,  533,  533,  533,
+
+      591,  591,  592,  592,  592,  505,  505,  538,  538,  538,
+      533,  533,  533,  533,  593,  593,  538,  538,  538,  538,
+      538,  533,  533,  533,  533,  533,  538,  538,  538,  538,
+      538,  538,    0,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533
+
+    } ;
+
+static yyconst short int yy_nxt[3416] =
+    {   0,
+       14,   15,   16,   17,   14,   18,   19,   20,   21,   14,
+       22,   23,   14,   14,   24,   25,   26,   27,   25,   25,
+       25,   25,   25,   28,   29,   30,   14,   31,   31,   31,
+       31,   32,   33,   33,   34,   33,   35,   33,   36,   33,
+       33,   33,   33,   33,   37,   14,   38,   38,   38,   38,
+       38,   38,   14,   14,   14,   14,   14,   14,   14,   39,
+       14,   14,   40,   47,   47,   73,   41,   48,   48,  149,
+       15,   52,   53,   73,   54,  286,   49,   49,  151,   73,
+       55,   68,   16,   69,   70,   15,   52,   53,  168,   54,
+       42,   43,   55,   54,   44,   55,  104,  131,   45,   73,
+
+      132,   46,   68,   16,   69,   70,  137,   55,   54,  138,
+       85,  127,  103,   56,   85,   85,  121,  130,  134,  103,
+      130,   50,   50,   73,   71,  209,  127,  103,   56,   15,
+       16,   17,   85,   57,   91,   91,   91,   91,   91,   91,
+       91,   91,   73,  139,  140,   71,  135,  159,   77,  136,
+      136,   86,   92,   92,   92,   92,   92,   93,   72,   73,
+       90,   90,   90,   90,   90,   90,   90,   90,  105,   73,
+       73,  166,   58,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       15,   16,   17,   73,   57,  341,  106,  107,   73,  170,
+
+      108,   73,  165,  172,  109,   78,  207,  110,   79,   79,
+       79,   79,   79,   79,   79,   79,   79,   79,   79,   79,
+       79,   79,   79,   79,   79,   79,   79,   79,   79,   79,
+       79,   79,   72,   58,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   15,   16,   17,   61,   57,   73,  127,  103,  119,
+       62,   63,   64,  119,  119,  124,  103,  125,  169,  126,
+      167,  154,  137,  125,   65,  126,  155,   73,  156,   85,
+       73,  119,  149,   85,   85,  127,  103,  126,  126,  139,
+      140,  187,  207,  200,   66,   15,   16,   17,   61,   57,
+
+      120,   85,   77,   73,   62,   63,   64,   72,  126,   72,
+      138,   72,  473,   72,   72,  136,  533,   72,   65,  207,
+       86,  143,  144,  145,  143,  143,  143,  143,  143,   72,
+       72,   72,  147,  147,  147,  147,  147,  147,   66,   77,
+      147,  147,  147,  147,  147,  147,  147,  147,  206,   78,
+       73,  136,   79,   79,   79,   79,   79,   79,   79,   79,
+       87,  174,   88,   88,   88,   88,   88,   88,   88,   88,
+       89,   77,  341,   73,   90,   90,   90,   90,   90,  147,
+      147,  147,  147,  147,  147,  147,  147,  207,   73,   89,
+      285,   73,   73,   90,   90,   90,   90,   90,   90,   72,
+
+       73,  210,  234,   72,  473,   72,  241,   73,   72,   72,
+       73,   72,   72,   72,   96,   96,   96,   96,   96,   96,
+       96,   96,   89,  245,  235,   72,   96,   96,   96,   96,
+       96,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   73,   97,   90,   90,   90,   90,   90,
+       90,   72,   72,   72,   72,   72,   72,   72,   72,   72,
+       72,   97,   97,   97,   97,   97,   97,   97,   97,  533,
+      218,  218,  218,   97,   97,   97,   97,   97,  149,   73,
+      246,  149,  149,  438,  119,  127,  103,  187,  119,  119,
+      187,  187,   72,   72,   72,   72,   72,   72,  102,  103,
+
+       72,  495,   72,   73,   72,   72,  119,   80,   72,   80,
+       73,   80,  234,   80,   80,  489,  248,   80,  249,  332,
+       72,   72,   72,   77,  105,  120,   89,   73,  130,   80,
+       80,   80,  281,   78,  235,  149,   79,   79,   79,   79,
+       79,   79,   79,   79,   82,   77,   82,   73,   82,   73,
+       82,   82,  106,  107,   82,   84,  108,   72,  149,   84,
+      109,   72,   72,  110,  247,   84,   82,   82,   82,  438,
+      222,  149,  533,  149,  111,   77,   73,   84,   84,   72,
+      224,  287,  224,  319,  323,  533,  386,  386,  533,  533,
+      533,  533,  533,  533,  533,  533,  146,  146,  146,  146,
+
+      146,  146,  146,  146,  284,  320,  324,   77,  146,  146,
+      146,  146,  146,  211,  212,  213,  211,  211,  211,  211,
+      211,  227,  227,  227,  227,  227,  228,  146,  146,  146,
+      146,  146,  146,  152,  152,  152,  152,  152,  152,  152,
+      152,  325,   73,   77,  149,  152,  152,  152,  152,  152,
+      118,  389,   72,  224,  118,  374,   72,   72,  418,   77,
+      118,  222,  149,  326,  146,  146,  146,  146,  146,  146,
+      460,  224,  118,  118,   72,  129,   73,   85,  129,  129,
+       73,   85,   73,  222,  149,  129,  331,   85,  149,  327,
+      330,  333,  119,  266,  458,  319,  119,  224,  129,   85,
+
+       85,  174,  119,  175,  175,  175,  175,  175,  175,  175,
+      175,   73,   73,  419,  119,  119,  174,  320,  175,  175,
+      175,  175,  175,  175,  192,  192,  192,  192,  192,  192,
+      192,  192,   73,  174,  149,  176,  176,  176,  176,  176,
+      176,  176,  176,  266,  323,  435,  435,   73,  216,  216,
+      217,  218,  218,  218,  218,  218,  184,  269,  269,  269,
+      269,  269,  270,  489,   73,  174,  324,  177,  177,  177,
+      177,  177,  178,  175,  175,  226,  226,  226,  226,  226,
+      226,  226,  226,  533,  341,  225,  225,  225,  225,  225,
+      225,  225,  225,   73,  343,   73,   73,   72,  334,  179,
+
+      179,  179,  179,  179,  179,  179,  179,  325,  487,  371,
+      376,  179,  179,  179,  179,  179,  255,  255,  255,  255,
+      255,  255,  255,  255,  184,  412,  222,  149,   73,  326,
+      179,  179,  179,  179,  179,  179,  181,  182,  183,  183,
+      183,  183,  183,  183,  184,  533,  149,  413,  185,  185,
+      185,  185,  185,  260,  261,  262,  260,  260,  260,  260,
+      260,  312,  312,  312,  312,  312,  313,  185,  185,  185,
+      185,  185,  185,  149,  188,  189,  190,  188,  188,  188,
+      188,  188,  191,  452,  452,  149,  192,  192,  192,  192,
+      192,  233,  233,  233,  233,  233,  233,  233,  233,  346,
+
+      346,  346,  346,  346,  347,  192,  192,  192,  192,  192,
+      192,  193,  193,  193,  193,  193,  193,  193,  193,  414,
+       73,  389,   73,  193,  193,  193,  193,  193,  222,  149,
+      264,  264,  264,  264,  264,  264,  377,  456,  224,  533,
+      149,  415,  179,  179,  179,  179,  179,  179,  174,  266,
+      175,  175,  175,  175,  175,  175,  175,  175,  268,  268,
+      268,  268,  268,  268,  268,  268,  533,   73,  267,  267,
+      267,  267,  267,  267,  267,  267,  375,  418,   77,   73,
+      174,  533,  175,  175,  175,  175,  175,  175,  175,  175,
+      455,  343,  343,  341,  288,  289,  290,  288,  288,  288,
+
+      288,  288,  249,  343,  250,  250,  250,  250,  250,  250,
+      429,   73,  222,  149,  223,  223,  223,  223,  223,  223,
+      223,  223,  224,   73,  470,  470,  225,  225,  225,  225,
+      225,  422,  300,   73,  301,  301,  301,  301,  301,  301,
+      301,  301,  222,  149,  460,  225,  225,  225,  225,  225,
+      225,  149,  229,  230,  231,  229,  229,  229,  229,  229,
+      232,  149,   73,  458,  233,  233,  233,  233,  233,  300,
+      266,  302,  302,  302,  302,  302,  302,  302,  302,  454,
+      222,  149,  399,  233,  233,  233,  233,  233,  233,  249,
+      266,  250,  250,  250,  250,  250,  250,  250,  250,  300,
+
+      412,  303,  303,  303,  303,  303,  304,  301,  301,  275,
+      275,  275,  275,  275,  275,  275,  275,  414,  501,  501,
+       73,  249,  413,  251,  251,  251,  251,  251,  251,  251,
+      251,  222,  149,  307,  307,  307,  307,  307,  307,  415,
+      341,  266,  311,  311,  311,  311,  311,  311,  311,  311,
+      389,  490,   73,  249,  533,  252,  252,  252,  252,  252,
+      253,  250,  250,  533,  389,  310,  310,  310,  310,  310,
+      310,  310,  310,  299,  299,  299,  299,  299,  299,  299,
+      299,  343,   73,  294,   73,  222,  149,  264,  264,  264,
+      264,  264,  264,  264,  264,  224,  222,  149,  265,  265,
+
+      265,  265,  265,  265,  265,  265,  266,  515,  515,   73,
+      267,  267,  267,  267,  267,  345,  345,  345,  345,  345,
+      345,  345,  345,  363,  363,  363,  363,  363,  364,  267,
+      267,  267,  267,  267,  267,  149,  271,  272,  273,  271,
+      271,  271,  271,  271,  274,  149,  417,  416,  275,  275,
+      275,  275,  275,  533,  309,  344,  344,  344,  344,  344,
+      344,  344,  344,   73,  222,  149,  294,  275,  275,  275,
+      275,  275,  275,  249,  309,  250,  250,  250,  250,  250,
+      250,  250,  250,  353,  354,  355,  353,  353,  353,  353,
+      353,  300,  149,  301,  301,  301,  301,  301,  301,  301,
+
+      301,  309,  517,  220,   73,  249,  341,  250,  250,  250,
+      250,  250,  250,  250,  250,  300,  389,  301,  301,  301,
+      301,  301,  301,  301,  301,  300,  149,  301,  301,  301,
+      301,  301,  301,   73,  373,  360,   73,  295,  296,  297,
+      295,  295,  295,  295,  295,  298,  372,  370,  369,  299,
+      299,  299,  299,  299,  318,  318,  318,  318,  318,  318,
+      318,  318,  392,  392,  392,  392,  392,  393,  299,  299,
+      299,  299,  299,  299,  222,  149,  307,  307,  307,  307,
+      307,  307,  307,  307,  266,  222,  149,  308,  308,  308,
+      308,  308,  308,  308,  308,  309,  533,  149,  300,  310,
+
+      310,  310,  310,  310,  294,  341,  309,  222,  149,  358,
+      358,  358,  358,  358,  358,  438,  220,  309,  310,  310,
+      310,  310,  310,  310,  149,  314,  315,  316,  314,  314,
+      314,  314,  314,  317,  184,  329,  328,  318,  318,  318,
+      318,  318,  362,  362,  362,  362,  362,  362,  362,  362,
+      410,  410,  410,  410,  410,  411,  318,  318,  318,  318,
+      318,  318,  334,  335,  335,  335,  335,  335,  335,  335,
+      335,  533,  322,  361,  361,  361,  361,  361,  361,  361,
+      361,  378,  379,  380,  381,  378,  378,  378,  378,  321,
+      294,  220,   73,  334,  336,  336,  336,  336,  336,  336,
+
+      336,  336,  184,  334,  335,  335,  335,  335,  335,  335,
+       73,  383,  384,  385,  383,  383,  383,  383,  383,  184,
+      242,  283,  282,   73,  334,  337,  337,  337,  337,  337,
+      338,  335,  335,   73,  352,  352,  352,  352,  352,  352,
+      352,  352,  391,  391,  391,  391,  391,  391,  391,  391,
+      280,  279,  278,  277,   73,  341,  533,  342,  342,  342,
+      342,  342,  342,  342,  342,  343,  438,  276,  258,  344,
+      344,  344,  344,  344,  533,  149,  390,  390,  390,  390,
+      390,  390,  390,  390,  360,  220,  184,  254,  344,  344,
+      344,  344,  344,  344,  348,  349,  350,  348,  348,  348,
+
+      348,  348,  351,  184,   95,  242,  352,  352,  352,  352,
+      352,  399,  341,  400,  400,  400,  400,  400,  400,  400,
+      400,  244,  438,  242,  243,  352,  352,  352,  352,  352,
+      352,  222,  149,  358,  358,  358,  358,  358,  358,  358,
+      358,  309,  222,  149,  359,  359,  359,  359,  359,  359,
+      359,  359,  360,  242,  240,  239,  361,  361,  361,  361,
+      361,  399,  341,  401,  401,  401,  401,  401,  401,  401,
+      401,  238,  473,  237,  236,  361,  361,  361,  361,  361,
+      361,  149,  365,  366,  367,  365,  365,  365,  365,  365,
+      222,  149,   89,  184,  368,  368,  368,  368,  368,  399,
+
+      309,  402,  402,  402,  402,  402,  403,  400,  400,  220,
+      184,   95,  173,  368,  368,  368,  368,  368,  368,  334,
+      335,  335,  335,  335,  335,  335,  335,  335,  222,  149,
+      368,  368,  368,  368,  368,  368,  368,  368,  360,  409,
+      409,  409,  409,  409,  409,  409,  409,  208,  205,   73,
+      334,  335,  335,  335,  335,  335,  335,  335,  335,  533,
+      149,  222,  149,  406,  406,  406,  406,  406,  406,  360,
+      533,  360,  408,  408,  408,  408,  408,  408,  408,  408,
+       73,  341,  204,  387,  387,  387,  387,  387,  387,  387,
+      387,  343,  341,  533,  388,  388,  388,  388,  388,  388,
+
+      388,  388,  389,  473,  203,  202,  390,  390,  390,  390,
+      390,  429,  341,  430,  430,  430,  430,  430,  430,  430,
+      430,  201,  473,  199,  198,  390,  390,  390,  390,  390,
+      390,  394,  395,  396,  394,  394,  394,  394,  394,  397,
+      197,  196,  195,  398,  398,  398,  398,  398,  429,  194,
+      431,  431,  431,  431,  431,  431,  431,  431,   95,   87,
+       77,  173,  398,  398,  398,  398,  398,  398,  222,  149,
+      406,  406,  406,  406,  406,  406,  406,  406,  360,  222,
+      149,  407,  407,  407,  407,  407,  407,  407,  407,  135,
+      222,  149,  136,  408,  408,  408,  408,  408,  420,  429,
+
+      360,  432,  432,  432,  432,  432,  433,  430,  430,  465,
+      465,  465,  408,  408,  408,  408,  408,  408,  420,  130,
+      420,  421,  398,  398,  398,  398,  398,  398,  398,  398,
+      440,  440,  440,  440,  440,  440,  440,  440,   73,   73,
+      422,  130,  423,  423,  423,  423,  423,  423,  423,  423,
+      441,  441,  441,  441,  441,  442,  533,  123,  439,  439,
+      439,  439,  439,  439,  439,  439,  171,  117,  164,  163,
+      162,   73,  422,  161,  424,  424,  424,  424,  424,  424,
+      424,  424,  448,  449,  450,  448,  448,  448,  448,  448,
+      399,  160,  400,  400,  400,  400,  400,  400,  400,  400,
+
+      158,  157,  153,   73,  422,   95,  425,  425,  425,  425,
+      425,  426,  427,  427,  399,   72,  400,  400,  400,  400,
+      400,  400,  400,  400,  399,   95,  400,  400,  400,  400,
+      400,  400,  420,  142,   83,   73,  422,   81,  428,  428,
+      428,  423,  423,  423,  423,  423,  476,  476,  476,  476,
+      476,  477,  420,   77,  420,  420,   75,   74,   73,  422,
+      136,  465,  465,  465,  130,  123,  117,   73,  341,  116,
+      436,  436,  436,  436,  436,  436,  436,  436,  389,  341,
+      115,  437,  437,  437,  437,  437,  437,  437,  437,  438,
+       73,  114,  113,  439,  439,  439,  439,  439,  461,  462,
+
+      463,  461,  461,  461,  461,  461,  506,  506,  506,  506,
+      506,  507,  439,  439,  439,  439,  439,  439,  443,  444,
+      445,  443,  443,  443,  443,  443,  446,   73,  112,  101,
+      447,  447,  447,  447,  447,  466,  467,  468,  466,  466,
+      466,  466,  466,  522,  522,  522,  522,  522,  522,  447,
+      447,  447,  447,  447,  447,  222,  149,  453,  453,  453,
+      453,  453,  453,  453,  453,  422,  100,  427,  427,  427,
+      427,  427,  427,  427,  427,  429,   99,  430,  430,  430,
+      430,  430,  430,  430,  430,  429,   98,  430,  430,  430,
+      430,  430,  430,  430,  430,   95,   73,  422,   83,  427,
+
+      427,  427,  427,  427,  427,  427,  427,  429,   81,  430,
+      430,  430,  430,  430,  430,  447,  447,  447,  447,  447,
+      447,  447,  447,   75,   74,   73,  533,  533,   73,  422,
+      533,  427,  427,  427,  427,  427,  427,  464,  464,  475,
+      475,  475,  475,  475,  475,  475,  475,  533,  533,  474,
+      474,  474,  474,  474,  474,  474,  474,  533,  533,  533,
+       73,  422,  533,  464,  464,  464,  464,  464,  464,  464,
+      464,  149,  482,  482,  482,  482,  482,  482,  482,  482,
+      149,  483,  483,  483,  483,  483,  483,  483,  483,  533,
+      533,  533,   73,  341,  533,  471,  471,  471,  471,  471,
+
+      471,  471,  471,  438,  341,  533,  472,  472,  472,  472,
+      472,  472,  472,  472,  473,  533,  533,  533,  474,  474,
+      474,  474,  474,  149,  484,  484,  484,  484,  484,  485,
+      482,  482,  533,  533,  533,  533,  533,  474,  474,  474,
+      474,  474,  474,  478,  479,  480,  478,  478,  478,  478,
+      478,  533,  533,  533,  533,  481,  481,  481,  481,  481,
+      457,  533,  457,  533,  457,  533,  457,  457,  533,  533,
+      457,  533,  533,  533,  481,  481,  481,  481,  481,  481,
+      533,  533,  457,  457,  457,  459,  533,  459,  533,  459,
+      533,  459,  459,  533,  533,  459,  464,  464,  464,  464,
+
+      464,  464,  464,  464,  533,  533,  533,  459,  459,  459,
+      490,  533,  491,  491,  491,  491,  491,  491,  491,  491,
+      533,  533,  533,  533,  495,   73,  496,  496,  496,  496,
+      496,  496,  496,  496,  149,  482,  482,  482,  482,  482,
+      482,   73,  490,  533,  492,  492,  492,  492,  492,  492,
+      492,  492,  495,  533,  497,  497,  497,  497,  497,  497,
+      497,  497,  495,  533,  498,  498,  498,  498,  498,  499,
+      496,  496,  533,   73,  490,  533,  493,  493,  493,  493,
+      493,  494,  491,  491,  481,  481,  481,  481,  481,  481,
+      481,  481,  505,  505,  505,  505,  505,  505,  505,  505,
+
+      533,  533,  533,  533,  533,   73,  341,  533,  502,  502,
+      502,  502,  502,  502,  502,  502,  473,  341,  533,  503,
+      503,  503,  503,  503,  503,  503,  503,  533,  533,  533,
+      533,  504,  504,  504,  504,  504,  533,  533,  504,  504,
+      504,  504,  504,  504,  504,  504,  533,  533,  533,  533,
+      504,  504,  504,  504,  504,  504,  149,  482,  482,  482,
+      482,  482,  482,  482,  482,  149,  482,  482,  482,  482,
+      482,  482,  482,  482,  508,  509,  510,  508,  508,  508,
+      508,  508,  533,  490,  533,  491,  491,  491,  491,  491,
+      491,  511,  512,  513,  511,  511,  511,  511,  511,  533,
+
+      533,  533,  533,   73,  490,  533,  491,  491,  491,  491,
+      491,  491,  491,  491,   73,  495,  533,  496,  496,  496,
+      496,  496,  496,  496,  496,  495,  533,  496,  496,  496,
+      496,  496,  496,  496,  496,   73,  490,  533,  491,  491,
+      491,  491,  491,  491,  491,  491,  495,  533,  496,  496,
+      496,  496,  496,  496,  341,  533,  516,  516,  516,  516,
+      516,  516,  516,  516,  533,  533,  533,   73,  517,  533,
+      518,  518,  518,  518,  518,  518,  518,  518,  522,  522,
+      522,  522,  522,  522,  522,  522,  523,  523,  523,  523,
+      523,  523,  523,  523,  533,  533,  533,  533,  533,   73,
+
+      517,  533,  519,  519,  519,  519,  519,  519,  519,  519,
+      524,  524,  524,  524,  524,  525,  522,  522,  527,  528,
+      529,  527,  527,  527,  527,  527,  533,  533,  533,  533,
+      533,   73,  517,  533,  520,  520,  520,  520,  520,  521,
+      518,  518,  533,  533,  533,  533,  517,   73,  518,  518,
+      518,  518,  518,  518,  522,  522,  522,  522,  522,  522,
+      522,  522,  533,   73,  517,  533,  518,  518,  518,  518,
+      518,  518,  518,  518,  533,  533,  533,   73,  522,  522,
+      522,  522,  522,  522,  522,  522,  530,  530,  530,  530,
+      530,  530,  530,  530,  533,   73,  517,  533,  518,  518,
+
+      518,  518,  518,  518,  518,  518,  527,  527,  527,  527,
+      527,  527,  527,  527,  533,   73,  531,  531,  531,  531,
+      531,  532,  530,  530,  533,  533,  533,   73,  530,  530,
+      530,  530,  530,  530,  533,   73,  530,  530,  530,  530,
+      530,  530,  530,  530,  533,   73,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,   73,  533,  533,
+      533,  533,  533,  533,  533,   73,   51,   51,   51,   51,
+       51,   51,   51,   51,   51,   51,   51,   51,   51,   30,
+       30,   30,   30,   30,   30,   30,   30,   30,   30,   30,
+       30,   30,   60,   60,   60,   60,   60,   60,   60,   60,
+
+       60,   60,   60,   60,   60,   67,   67,   67,   67,   67,
+       67,   67,   67,   67,   67,   67,   67,   67,   72,  533,
+      533,  533,   72,  533,   72,   72,   72,  533,   72,   72,
+       72,   76,   76,   76,   76,   76,   76,   76,   76,   76,
+       76,   76,   76,   76,   80,  533,  533,  533,   80,  533,
+       80,   80,   80,  533,   80,   80,   80,   82,  533,  533,
+      533,   82,  533,   82,   82,   82,  533,   82,   82,   82,
+       84,  533,  533,   84,   84,  533,   84,   84,   84,  533,
+       84,   84,   84,   94,   94,  533,  533,   94,  118,  533,
+      533,  118,  118,  533,  118,  118,  118,  533,  118,  118,
+
+      118,  122,  533,  533,  122,  122,  122,  122,  122,  122,
+      533,  533,  122,  122,  128,  128,  129,  533,  533,  129,
+      533,  533,  129,  129,  129,  129,  129,  129,  129,  133,
+      133,  133,  133,  133,  133,  133,  133,  133,  133,  133,
+      133,  133,  135,  135,  533,  135,  533,  135,  135,  135,
+      135,  135,  135,  135,  135,  141,  141,  141,  141,  141,
+      141,  141,  141,  141,  141,  141,  141,  141,   85,  533,
+      533,   85,   85,  533,   85,   85,   85,  533,   85,   85,
+       85,  148,  148,  533,  533,  148,  150,  150,  150,  533,
+      533,  150,  119,  533,  533,  119,  119,  533,  119,  119,
+
+      119,  533,  119,  119,  119,  180,  180,  533,  533,  180,
+      186,  186,  186,  533,  533,  186,  214,  214,  533,  533,
+      214,  215,  215,  533,  533,  215,  219,  219,  533,  533,
+      219,  221,  221,  221,  533,  533,  221,  254,  254,  533,
+      533,  254,  256,  256,  533,  533,  256,  257,  257,  533,
+      533,  257,  259,  259,  259,  533,  533,  259,  263,  263,
+      263,  263,  533,  533,  263,  291,  291,  533,  533,  291,
+      292,  292,  533,  533,  292,  293,  293,  533,  533,  293,
+      305,  305,  305,  533,  533,  305,  306,  306,  306,  306,
+      533,  533,  306,  339,  339,  533,  533,  339,  340,  340,
+
+      533,  533,  340,  356,  356,  356,  533,  533,  356,  357,
+      357,  357,  357,  533,  533,  357,  382,  382,  533,  533,
+      382,  386,  533,  386,  386,  533,  533,  386,  404,  404,
+      404,  533,  533,  404,  405,  405,  405,  405,  533,  533,
+      405,  434,  434,  533,  533,  434,  435,  533,  435,  435,
+      533,  533,  435,  451,  451,  451,  533,  533,  451,  452,
+      452,  452,  533,  533,  533,  452,  457,  533,  533,  533,
+      457,  533,  457,  457,  457,  533,  457,  457,  457,  459,
+      533,  533,  533,  459,  533,  459,  459,  459,  533,  459,
+      459,  459,  469,  469,  533,  533,  469,  470,  533,  470,
+
+      470,  533,  533,  470,  486,  486,  533,  533,  533,  486,
+      488,  488,  488,  488,  488,  488,  488,  488,  488,  488,
+      488,  488,  488,  500,  500,  533,  533,  500,  501,  533,
+      501,  501,  533,  533,  501,  514,  514,  533,  533,  514,
+      515,  533,  515,  533,  533,  533,  515,  526,  533,  533,
+      533,  526,   13,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533
+    } ;
+
+static yyconst short int yy_chk[3416] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    2,    3,    4,  247,    2,    3,    4,   95,
+        5,    5,    5,  114,    5,  247,    3,    4,   95,   39,
+        5,   11,   11,   11,   11,    6,    6,    6,  114,    6,
+        2,    2,    5,    5,    2,    6,   39,   62,    2,   50,
+
+       64,    2,   12,   12,   12,   12,   68,    6,    6,   69,
+       24,   58,   58,    5,   24,   24,   50,   62,   66,   66,
+       64,    3,    4,  169,   11,  169,  102,  102,    6,    7,
+        7,    7,   24,    7,   26,   26,   26,   26,   26,   26,
+       26,   26,  104,   71,   71,   12,   71,  104,  111,   68,
+       69,   24,   27,   27,   27,   27,   27,   27,   38,  112,
+       38,   38,   38,   38,   38,   38,   38,   38,   40,  102,
+      530,  112,    7,    7,    7,    7,    7,    7,    7,    7,
+        7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
+        8,    8,    8,  116,    8,  516,   40,   40,  121,  116,
+
+       40,  166,  111,  121,   40,   48,  166,   40,   48,   48,
+       48,   48,   48,   48,   48,   48,   78,   78,   78,   78,
+       78,   78,   78,   78,   79,   79,   79,   79,   79,   79,
+       79,   79,  113,    8,    8,    8,    8,    8,    8,    8,
+        8,    8,    8,    8,    8,    8,    8,    8,    8,    8,
+        8,    9,    9,    9,    9,    9,  115,  124,  124,   49,
+        9,    9,    9,   49,   49,   56,   56,   56,  115,   56,
+      113,   99,  137,   56,    9,   56,   99,  209,   99,   84,
+      159,   49,  150,   84,   84,  127,  127,   56,   56,  139,
+      139,  150,  209,  159,    9,   10,   10,   10,   10,   10,
+
+       49,   84,  165,  168,   10,   10,   10,   73,   56,   73,
+      138,   73,  514,   73,   73,  137,  504,   73,   10,  168,
+       84,   87,   87,   87,   87,   87,   87,   87,   87,   73,
+       73,   73,   93,   93,   93,   93,   93,   93,   10,   18,
+       91,   91,   91,   91,   91,   91,   91,   91,  165,   18,
+       87,  138,   18,   18,   18,   18,   18,   18,   18,   18,
+       25,  175,   25,   25,   25,   25,   25,   25,   25,   25,
+       25,  206,  503,  170,   25,   25,   25,   25,   25,   92,
+       92,   92,   92,   92,   92,   92,   92,  170,  172,  179,
+      246,   25,  175,   25,   25,   25,   25,   25,   25,   31,
+
+      200,  172,  194,   31,  501,   31,  200,  246,   31,   31,
+      179,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,  206,  194,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   33,   33,   33,   33,   33,   33,   33,   33,   33,
+      183,  183,  183,   33,   33,   33,   33,   33,  186,  207,
+      207,  221,  259,  500,  118,  134,  134,  186,  118,  118,
+      221,  259,   33,   33,   33,   33,   33,   33,   37,   37,
+
+       37,  496,   37,  286,   37,   37,  118,   81,   37,   81,
+      210,   81,  234,   81,   81,  488,  210,   81,  250,  286,
+       37,   37,   37,   41,  105,  118,  208,  241,  134,   81,
+       81,   81,  241,   41,  234,  486,   41,   41,   41,   41,
+       41,   41,   41,   41,   83,  245,   83,  208,   83,  250,
+       83,   83,  105,  105,   83,   86,  105,   86,  482,   86,
+      105,   86,   86,  105,  208,   86,   83,   83,   83,  470,
+      223,  223,  225,  225,   41,   57,  248,   86,   86,   86,
+      223,  248,  225,  276,  279,   57,  347,  347,   57,   57,
+       57,   57,   57,   57,   57,   57,   88,   88,   88,   88,
+
+       88,   88,   88,   88,  245,  276,  279,  330,   88,   88,
+       88,   88,   88,  174,  174,  174,  174,  174,  174,  174,
+      174,  190,  190,  190,  190,  190,  190,   88,   88,   88,
+       88,   88,   88,   96,   96,   96,   96,   96,   96,   96,
+       96,  280,  174,  284,  263,   96,   96,   96,   96,   96,
+      120,  469,  120,  263,  120,  330,  120,  120,  374,  374,
+      120,  264,  264,  280,   96,   96,   96,   96,   96,   96,
+      459,  264,  120,  120,  120,  130,  285,  142,  130,  130,
+      281,  142,  287,  265,  265,  130,  285,  142,  305,  281,
+      284,  287,  171,  265,  457,  319,  171,  305,  130,  142,
+
+      142,  143,  171,  143,  143,  143,  143,  143,  143,  143,
+      143,  375,  456,  375,  171,  171,  178,  319,  178,  178,
+      178,  178,  178,  178,  187,  187,  187,  187,  187,  187,
+      187,  187,  143,  144,  306,  144,  144,  144,  144,  144,
+      144,  144,  144,  306,  323,  393,  393,  178,  182,  182,
+      182,  182,  182,  182,  182,  182,  182,  231,  231,  231,
+      231,  231,  231,  455,  144,  145,  323,  145,  145,  145,
+      145,  145,  145,  145,  145,  189,  189,  189,  189,  189,
+      189,  189,  189,  192,  342,  192,  192,  192,  192,  192,
+      192,  192,  192,  327,  342,  332,  145,  146,  335,  146,
+
+      146,  146,  146,  146,  146,  146,  146,  325,  454,  327,
+      332,  146,  146,  146,  146,  146,  216,  216,  216,  216,
+      216,  216,  216,  216,  216,  369,  407,  407,  335,  325,
+      146,  146,  146,  146,  146,  146,  149,  149,  149,  149,
+      149,  149,  149,  149,  149,  408,  408,  369,  149,  149,
+      149,  149,  149,  222,  222,  222,  222,  222,  222,  222,
+      222,  273,  273,  273,  273,  273,  273,  149,  149,  149,
+      149,  149,  149,  151,  151,  151,  151,  151,  151,  151,
+      151,  151,  151,  411,  411,  452,  151,  151,  151,  151,
+      151,  224,  224,  224,  224,  224,  224,  224,  224,  297,
+
+      297,  297,  297,  297,  297,  151,  151,  151,  151,  151,
+      151,  152,  152,  152,  152,  152,  152,  152,  152,  370,
+      333,  435,  419,  152,  152,  152,  152,  152,  228,  228,
+      228,  228,  228,  228,  228,  228,  333,  419,  228,  267,
+      267,  370,  152,  152,  152,  152,  152,  152,  176,  267,
+      176,  176,  176,  176,  176,  176,  176,  176,  230,  230,
+      230,  230,  230,  230,  230,  230,  233,  331,  233,  233,
+      233,  233,  233,  233,  233,  233,  331,  418,  418,  176,
+      177,  344,  177,  177,  177,  177,  177,  177,  177,  177,
+      418,  344,  434,  387,  249,  249,  249,  249,  249,  249,
+
+      249,  249,  253,  387,  253,  253,  253,  253,  253,  253,
+      430,  177,  188,  188,  188,  188,  188,  188,  188,  188,
+      188,  188,  188,  249,  442,  442,  188,  188,  188,  188,
+      188,  423,  260,  253,  260,  260,  260,  260,  260,  260,
+      260,  260,  453,  453,  421,  188,  188,  188,  188,  188,
+      188,  191,  191,  191,  191,  191,  191,  191,  191,  191,
+      191,  356,  423,  420,  191,  191,  191,  191,  191,  261,
+      356,  261,  261,  261,  261,  261,  261,  261,  261,  416,
+      307,  307,  400,  191,  191,  191,  191,  191,  191,  211,
+      307,  211,  211,  211,  211,  211,  211,  211,  211,  262,
+
+      412,  262,  262,  262,  262,  262,  262,  262,  262,  266,
+      266,  266,  266,  266,  266,  266,  266,  414,  477,  477,
+      211,  212,  412,  212,  212,  212,  212,  212,  212,  212,
+      212,  270,  270,  270,  270,  270,  270,  270,  270,  414,
+      388,  270,  272,  272,  272,  272,  272,  272,  272,  272,
+      388,  491,  212,  213,  390,  213,  213,  213,  213,  213,
+      213,  213,  213,  275,  390,  275,  275,  275,  275,  275,
+      275,  275,  275,  294,  294,  294,  294,  294,  294,  294,
+      294,  386,  491,  382,  213,  226,  226,  226,  226,  226,
+      226,  226,  226,  226,  226,  226,  229,  229,  229,  229,
+
+      229,  229,  229,  229,  229,  229,  229,  507,  507,  377,
+      229,  229,  229,  229,  229,  296,  296,  296,  296,  296,
+      296,  296,  296,  316,  316,  316,  316,  316,  316,  229,
+      229,  229,  229,  229,  229,  232,  232,  232,  232,  232,
+      232,  232,  232,  232,  232,  357,  373,  372,  232,  232,
+      232,  232,  232,  299,  357,  299,  299,  299,  299,  299,
+      299,  299,  299,  371,  308,  308,  340,  232,  232,  232,
+      232,  232,  232,  251,  308,  251,  251,  251,  251,  251,
+      251,  251,  251,  300,  300,  300,  300,  300,  300,  300,
+      300,  302,  404,  302,  302,  302,  302,  302,  302,  302,
+
+      302,  404,  518,  339,  251,  252,  436,  252,  252,  252,
+      252,  252,  252,  252,  252,  303,  436,  303,  303,  303,
+      303,  303,  303,  303,  303,  304,  405,  304,  304,  304,
+      304,  304,  304,  518,  329,  405,  252,  258,  258,  258,
+      258,  258,  258,  258,  258,  258,  328,  322,  321,  258,
+      258,  258,  258,  258,  309,  309,  309,  309,  309,  309,
+      309,  309,  350,  350,  350,  350,  350,  350,  258,  258,
+      258,  258,  258,  258,  268,  268,  268,  268,  268,  268,
+      268,  268,  268,  268,  268,  271,  271,  271,  271,  271,
+      271,  271,  271,  271,  271,  271,  310,  310,  301,  271,
+
+      271,  271,  271,  271,  293,  437,  310,  313,  313,  313,
+      313,  313,  313,  313,  313,  437,  292,  313,  271,  271,
+      271,  271,  271,  271,  274,  274,  274,  274,  274,  274,
+      274,  274,  274,  274,  291,  283,  282,  274,  274,  274,
+      274,  274,  315,  315,  315,  315,  315,  315,  315,  315,
+      367,  367,  367,  367,  367,  367,  274,  274,  274,  274,
+      274,  274,  288,  288,  288,  288,  288,  288,  288,  288,
+      288,  318,  278,  318,  318,  318,  318,  318,  318,  318,
+      318,  334,  334,  334,  334,  334,  334,  334,  334,  277,
+      257,  256,  288,  289,  289,  289,  289,  289,  289,  289,
+
+      289,  289,  255,  338,  338,  338,  338,  338,  338,  338,
+      334,  341,  341,  341,  341,  341,  341,  341,  341,  254,
+      244,  243,  242,  289,  290,  290,  290,  290,  290,  290,
+      290,  290,  290,  338,  343,  343,  343,  343,  343,  343,
+      343,  343,  349,  349,  349,  349,  349,  349,  349,  349,
+      240,  239,  238,  237,  290,  295,  439,  295,  295,  295,
+      295,  295,  295,  295,  295,  295,  439,  236,  220,  295,
+      295,  295,  295,  295,  352,  451,  352,  352,  352,  352,
+      352,  352,  352,  352,  451,  219,  218,  217,  295,  295,
+      295,  295,  295,  295,  298,  298,  298,  298,  298,  298,
+
+      298,  298,  298,  215,  214,  205,  298,  298,  298,  298,
+      298,  353,  471,  353,  353,  353,  353,  353,  353,  353,
+      353,  204,  471,  203,  202,  298,  298,  298,  298,  298,
+      298,  311,  311,  311,  311,  311,  311,  311,  311,  311,
+      311,  311,  314,  314,  314,  314,  314,  314,  314,  314,
+      314,  314,  314,  201,  199,  198,  314,  314,  314,  314,
+      314,  354,  472,  354,  354,  354,  354,  354,  354,  354,
+      354,  197,  472,  196,  195,  314,  314,  314,  314,  314,
+      314,  317,  317,  317,  317,  317,  317,  317,  317,  317,
+      358,  358,  193,  185,  317,  317,  317,  317,  317,  355,
+
+      358,  355,  355,  355,  355,  355,  355,  355,  355,  184,
+      181,  180,  173,  317,  317,  317,  317,  317,  317,  336,
+      336,  336,  336,  336,  336,  336,  336,  336,  359,  359,
+      360,  360,  360,  360,  360,  360,  360,  360,  359,  366,
+      366,  366,  366,  366,  366,  366,  366,  167,  164,  336,
+      337,  337,  337,  337,  337,  337,  337,  337,  337,  361,
+      361,  364,  364,  364,  364,  364,  364,  364,  364,  361,
+      368,  364,  368,  368,  368,  368,  368,  368,  368,  368,
+      337,  345,  163,  345,  345,  345,  345,  345,  345,  345,
+      345,  345,  348,  474,  348,  348,  348,  348,  348,  348,
+
+      348,  348,  348,  474,  162,  161,  348,  348,  348,  348,
+      348,  383,  502,  383,  383,  383,  383,  383,  383,  383,
+      383,  160,  502,  158,  157,  348,  348,  348,  348,  348,
+      348,  351,  351,  351,  351,  351,  351,  351,  351,  351,
+      156,  155,  154,  351,  351,  351,  351,  351,  384,  153,
+      384,  384,  384,  384,  384,  384,  384,  384,  148,  147,
+      141,  140,  351,  351,  351,  351,  351,  351,  362,  362,
+      362,  362,  362,  362,  362,  362,  362,  362,  362,  365,
+      365,  365,  365,  365,  365,  365,  365,  365,  365,  136,
+      406,  406,  135,  365,  365,  365,  365,  365,  376,  385,
+
+      406,  385,  385,  385,  385,  385,  385,  385,  385,  465,
+      465,  465,  365,  365,  365,  365,  365,  365,  376,  133,
+      376,  376,  389,  389,  389,  389,  389,  389,  389,  389,
+      395,  395,  395,  395,  395,  395,  395,  395,  465,  376,
+      378,  129,  378,  378,  378,  378,  378,  378,  378,  378,
+      396,  396,  396,  396,  396,  396,  398,  123,  398,  398,
+      398,  398,  398,  398,  398,  398,  119,  117,  110,  109,
+      108,  378,  379,  107,  379,  379,  379,  379,  379,  379,
+      379,  379,  399,  399,  399,  399,  399,  399,  399,  399,
+      401,  106,  401,  401,  401,  401,  401,  401,  401,  401,
+
+      101,  100,   98,  379,  380,   94,  380,  380,  380,  380,
+      380,  380,  380,  380,  402,   90,  402,  402,  402,  402,
+      402,  402,  402,  402,  403,   89,  403,  403,  403,  403,
+      403,  403,  417,   85,   82,  380,  381,   80,  381,  381,
+      381,  381,  381,  381,  381,  381,  445,  445,  445,  445,
+      445,  445,  417,   76,  417,  417,   75,   74,   72,  428,
+       67,  428,  428,  428,   60,   53,   47,  381,  391,   46,
+      391,  391,  391,  391,  391,  391,  391,  391,  391,  394,
+       45,  394,  394,  394,  394,  394,  394,  394,  394,  394,
+      428,   44,   43,  394,  394,  394,  394,  394,  422,  422,
+
+      422,  422,  422,  422,  422,  422,  480,  480,  480,  480,
+      480,  480,  394,  394,  394,  394,  394,  394,  397,  397,
+      397,  397,  397,  397,  397,  397,  397,  422,   42,   36,
+      397,  397,  397,  397,  397,  429,  429,  429,  429,  429,
+      429,  429,  429,  525,  525,  525,  525,  525,  525,  397,
+      397,  397,  397,  397,  397,  409,  409,  409,  409,  409,
+      409,  409,  409,  409,  409,  424,   35,  424,  424,  424,
+      424,  424,  424,  424,  424,  431,   34,  431,  431,  431,
+      431,  431,  431,  431,  431,  432,   32,  432,  432,  432,
+      432,  432,  432,  432,  432,   28,  424,  425,   22,  425,
+
+      425,  425,  425,  425,  425,  425,  425,  433,   19,  433,
+      433,  433,  433,  433,  433,  438,  438,  438,  438,  438,
+      438,  438,  438,   17,   15,   14,   13,    0,  425,  426,
+        0,  426,  426,  426,  426,  426,  426,  426,  426,  444,
+      444,  444,  444,  444,  444,  444,  444,  447,    0,  447,
+      447,  447,  447,  447,  447,  447,  447,    0,    0,    0,
+      426,  427,    0,  427,  427,  427,  427,  427,  427,  427,
+      427,  448,  448,  448,  448,  448,  448,  448,  448,  448,
+      449,  449,  449,  449,  449,  449,  449,  449,  449,    0,
+        0,    0,  427,  440,    0,  440,  440,  440,  440,  440,
+
+      440,  440,  440,  440,  443,    0,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,    0,    0,    0,  443,  443,
+      443,  443,  443,  450,  450,  450,  450,  450,  450,  450,
+      450,  450,    0,    0,    0,    0,    0,  443,  443,  443,
+      443,  443,  443,  446,  446,  446,  446,  446,  446,  446,
+      446,    0,    0,    0,    0,  446,  446,  446,  446,  446,
+      458,    0,  458,    0,  458,    0,  458,  458,    0,    0,
+      458,    0,    0,    0,  446,  446,  446,  446,  446,  446,
+        0,    0,  458,  458,  458,  460,    0,  460,    0,  460,
+        0,  460,  460,    0,    0,  460,  464,  464,  464,  464,
+
+      464,  464,  464,  464,    0,    0,    0,  460,  460,  460,
+      461,    0,  461,  461,  461,  461,  461,  461,  461,  461,
+        0,    0,    0,    0,  466,  464,  466,  466,  466,  466,
+      466,  466,  466,  466,  485,  485,  485,  485,  485,  485,
+      485,  461,  462,    0,  462,  462,  462,  462,  462,  462,
+      462,  462,  467,    0,  467,  467,  467,  467,  467,  467,
+      467,  467,  468,    0,  468,  468,  468,  468,  468,  468,
+      468,  468,    0,  462,  463,    0,  463,  463,  463,  463,
+      463,  463,  463,  463,  473,  473,  473,  473,  473,  473,
+      473,  473,  479,  479,  479,  479,  479,  479,  479,  479,
+
+        0,    0,    0,    0,    0,  463,  475,    0,  475,  475,
+      475,  475,  475,  475,  475,  475,  475,  478,    0,  478,
+      478,  478,  478,  478,  478,  478,  478,    0,    0,    0,
+        0,  478,  478,  478,  478,  478,  481,    0,  481,  481,
+      481,  481,  481,  481,  481,  481,    0,    0,    0,    0,
+      478,  478,  478,  478,  478,  478,  483,  483,  483,  483,
+      483,  483,  483,  483,  483,  484,  484,  484,  484,  484,
+      484,  484,  484,  484,  490,  490,  490,  490,  490,  490,
+      490,  490,    0,  494,    0,  494,  494,  494,  494,  494,
+      494,  495,  495,  495,  495,  495,  495,  495,  495,    0,
+
+        0,    0,    0,  490,  492,    0,  492,  492,  492,  492,
+      492,  492,  492,  492,  494,  497,    0,  497,  497,  497,
+      497,  497,  497,  497,  497,  498,    0,  498,  498,  498,
+      498,  498,  498,  498,  498,  492,  493,    0,  493,  493,
+      493,  493,  493,  493,  493,  493,  499,    0,  499,  499,
+      499,  499,  499,  499,  505,    0,  505,  505,  505,  505,
+      505,  505,  505,  505,    0,    0,    0,  493,  508,    0,
+      508,  508,  508,  508,  508,  508,  508,  508,  511,  511,
+      511,  511,  511,  511,  511,  511,  512,  512,  512,  512,
+      512,  512,  512,  512,    0,    0,    0,    0,    0,  508,
+
+      509,    0,  509,  509,  509,  509,  509,  509,  509,  509,
+      513,  513,  513,  513,  513,  513,  513,  513,  517,  517,
+      517,  517,  517,  517,  517,  517,    0,    0,    0,    0,
+        0,  509,  510,    0,  510,  510,  510,  510,  510,  510,
+      510,  510,    0,    0,    0,    0,  521,  517,  521,  521,
+      521,  521,  521,  521,  523,  523,  523,  523,  523,  523,
+      523,  523,    0,  510,  519,    0,  519,  519,  519,  519,
+      519,  519,  519,  519,    0,    0,    0,  521,  524,  524,
+      524,  524,  524,  524,  524,  524,  527,  527,  527,  527,
+      527,  527,  527,  527,    0,  519,  520,    0,  520,  520,
+
+      520,  520,  520,  520,  520,  520,  528,  528,  528,  528,
+      528,  528,  528,  528,    0,  527,  529,  529,  529,  529,
+      529,  529,  529,  529,    0,    0,    0,  520,  532,  532,
+      532,  532,  532,  532,    0,  528,  531,  531,  531,  531,
+      531,  531,  531,  531,    0,  529,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,  532,    0,    0,
+        0,    0,    0,    0,    0,  531,  534,  534,  534,  534,
+      534,  534,  534,  534,  534,  534,  534,  534,  534,  535,
+      535,  535,  535,  535,  535,  535,  535,  535,  535,  535,
+      535,  535,  536,  536,  536,  536,  536,  536,  536,  536,
+
+      536,  536,  536,  536,  536,  537,  537,  537,  537,  537,
+      537,  537,  537,  537,  537,  537,  537,  537,  538,    0,
+        0,    0,  538,    0,  538,  538,  538,    0,  538,  538,
+      538,  539,  539,  539,  539,  539,  539,  539,  539,  539,
+      539,  539,  539,  539,  540,    0,    0,    0,  540,    0,
+      540,  540,  540,    0,  540,  540,  540,  541,    0,    0,
+        0,  541,    0,  541,  541,  541,    0,  541,  541,  541,
+      542,    0,    0,  542,  542,    0,  542,  542,  542,    0,
+      542,  542,  542,  543,  543,    0,    0,  543,  544,    0,
+        0,  544,  544,    0,  544,  544,  544,    0,  544,  544,
+
+      544,  545,    0,    0,  545,  545,  545,  545,  545,  545,
+        0,    0,  545,  545,  546,  546,  547,    0,    0,  547,
+        0,    0,  547,  547,  547,  547,  547,  547,  547,  548,
+      548,  548,  548,  548,  548,  548,  548,  548,  548,  548,
+      548,  548,  549,  549,    0,  549,    0,  549,  549,  549,
+      549,  549,  549,  549,  549,  550,  550,  550,  550,  550,
+      550,  550,  550,  550,  550,  550,  550,  550,  551,    0,
+        0,  551,  551,    0,  551,  551,  551,    0,  551,  551,
+      551,  552,  552,    0,    0,  552,  553,  553,  553,    0,
+        0,  553,  554,    0,    0,  554,  554,    0,  554,  554,
+
+      554,    0,  554,  554,  554,  555,  555,    0,    0,  555,
+      556,  556,  556,    0,    0,  556,  557,  557,    0,    0,
+      557,  558,  558,    0,    0,  558,  559,  559,    0,    0,
+      559,  560,  560,  560,    0,    0,  560,  561,  561,    0,
+        0,  561,  562,  562,    0,    0,  562,  563,  563,    0,
+        0,  563,  564,  564,  564,    0,    0,  564,  565,  565,
+      565,  565,    0,    0,  565,  566,  566,    0,    0,  566,
+      567,  567,    0,    0,  567,  568,  568,    0,    0,  568,
+      569,  569,  569,    0,    0,  569,  570,  570,  570,  570,
+        0,    0,  570,  571,  571,    0,    0,  571,  572,  572,
+
+        0,    0,  572,  573,  573,  573,    0,    0,  573,  574,
+      574,  574,  574,    0,    0,  574,  575,  575,    0,    0,
+      575,  576,    0,  576,  576,    0,    0,  576,  577,  577,
+      577,    0,    0,  577,  578,  578,  578,  578,    0,    0,
+      578,  579,  579,    0,    0,  579,  580,    0,  580,  580,
+        0,    0,  580,  581,  581,  581,    0,    0,  581,  582,
+      582,  582,    0,    0,    0,  582,  583,    0,    0,    0,
+      583,    0,  583,  583,  583,    0,  583,  583,  583,  584,
+        0,    0,    0,  584,    0,  584,  584,  584,    0,  584,
+      584,  584,  585,  585,    0,    0,  585,  586,    0,  586,
+
+      586,    0,    0,  586,  587,  587,    0,    0,    0,  587,
+      588,  588,  588,  588,  588,  588,  588,  588,  588,  588,
+      588,  588,  588,  589,  589,    0,    0,  589,  590,    0,
+      590,  590,    0,    0,  590,  591,  591,    0,    0,  591,
+      592,    0,  592,    0,    0,    0,  592,  593,    0,    0,
+        0,  593,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+
+      533,  533,  533,  533,  533,  533,  533,  533,  533,  533,
+      533,  533,  533,  533,  533
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "toke.l"
+#define INITIAL 0
+#line 2 "toke.l"
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 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.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
+# include <malloc.h>
+#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
+#include <ctype.h>
+#include "sudo.h"
+#include "parse.h"
+#include <gram.h>
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: toke.c,v 1.27 2008/11/24 00:42:20 millert Exp $";
+#endif /* lint */
+
+extern YYSTYPE yylval;
+int sudolineno = 1;
+char *sudoers;
+static int sawspace = 0;
+static int arg_len = 0;
+static int arg_size = 0;
+
+static int append              __P((char *, int));
+static int _fill               __P((char *, int, int));
+static int fill_cmnd           __P((char *, int));
+static int fill_args           __P((char *, int, int));
+static int switch_buffer       __P((char *));
+static int ipv6_valid          __P((const char *s));
+static char *parse_include     __P((char *));
+extern void yyerror            __P((const char *));
+
+#define fill(a, b)             _fill(a, b, 0)
+
+#define        push_include(_p)        (switch_buffer((_p)))
+#define        pop_include()           (switch_buffer(NULL))
+
+/* realloc() to size + COMMANDARGINC to make room for command args */
+#define COMMANDARGINC  64
+
+#ifdef TRACELEXER
+#define LEXTRACE(msg)  fputs(msg, stderr)
+#else
+#define LEXTRACE(msg)
+#endif
+#define YY_NO_UNPUT 1
+#define GOTDEFS 1
+
+#define GOTCMND 2
+
+#define STARTDEFS 3
+
+#define INDEFS 4
+
+#define INSTR 5
+
+#line 1413 "lex.yy.c"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if defined(YY_STACK_USED) && YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#ifdef __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+       if ( yy_current_buffer->yy_is_interactive ) \
+               { \
+               int c = '*', n; \
+               for ( n = 0; n < max_size && \
+                            (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+                       buf[n] = (char) c; \
+               if ( c == '\n' ) \
+                       buf[n++] = (char) c; \
+               if ( c == EOF && ferror( yyin ) ) \
+                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
+               result = n; \
+               } \
+       else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+                 && ferror( yyin ) ) \
+               YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+       if ( yyleng > 0 ) \
+               yy_current_buffer->yy_at_bol = \
+                               (yytext[yyleng - 1] == '\n'); \
+       YY_USER_ACTION
+
+YY_DECL
+       {
+       register yy_state_type yy_current_state;
+       register char *yy_cp, *yy_bp;
+       register int yy_act;
+
+#line 113 "toke.l"
+
+#line 1569 "lex.yy.c"
+
+       if ( yy_init )
+               {
+               yy_init = 0;
+
+#ifdef YY_USER_INIT
+               YY_USER_INIT;
+#endif
+
+               if ( ! yy_start )
+                       yy_start = 1;   /* first start state */
+
+               if ( ! yyin )
+                       yyin = stdin;
+
+               if ( ! yyout )
+                       yyout = stdout;
+
+               if ( ! yy_current_buffer )
+                       yy_current_buffer =
+                               yy_create_buffer( yyin, YY_BUF_SIZE );
+
+               yy_load_buffer_state();
+               }
+
+       while ( 1 )             /* loops until end-of-file is reached */
+               {
+               yy_cp = yy_c_buf_p;
+
+               /* Support of yytext. */
+               *yy_cp = yy_hold_char;
+
+               /* yy_bp points to the position in yy_ch_buf of the start of
+                * the current run.
+                */
+               yy_bp = yy_cp;
+
+               yy_current_state = yy_start;
+               yy_current_state += YY_AT_BOL();
+yy_match:
+               do
+                       {
+                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+                       if ( yy_accept[yy_current_state] )
+                               {
+                               yy_last_accepting_state = yy_current_state;
+                               yy_last_accepting_cpos = yy_cp;
+                               }
+                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                               {
+                               yy_current_state = (int) yy_def[yy_current_state];
+                               if ( yy_current_state >= 534 )
+                                       yy_c = yy_meta[(unsigned int) yy_c];
+                               }
+                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+                       ++yy_cp;
+                       }
+               while ( yy_base[yy_current_state] != 3353 );
+
+yy_find_action:
+               yy_act = yy_accept[yy_current_state];
+               if ( yy_act == 0 )
+                       { /* have to back up */
+                       yy_cp = yy_last_accepting_cpos;
+                       yy_current_state = yy_last_accepting_state;
+                       yy_act = yy_accept[yy_current_state];
+                       }
+
+               YY_DO_BEFORE_ACTION;
+
+
+do_action:     /* This label is used only to access EOF actions. */
+
+
+               switch ( yy_act )
+       { /* beginning of action switch */
+                       case 0: /* must back up */
+                       /* undo the effects of YY_DO_BEFORE_ACTION */
+                       *yy_cp = yy_hold_char;
+                       yy_cp = yy_last_accepting_cpos;
+                       yy_current_state = yy_last_accepting_state;
+                       goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 114 "toke.l"
+BEGIN STARTDEFS;
+       YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 116 "toke.l"
+{
+                           BEGIN INDEFS;
+                           LEXTRACE("DEFVAR ");
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           return(DEFVAR);
+                       }
+       YY_BREAK
+
+case 3:
+YY_RULE_SETUP
+#line 125 "toke.l"
+{
+                           BEGIN STARTDEFS;
+                           LEXTRACE(", ");
+                           return(',');
+                       }                       /* return ',' */
+       YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 131 "toke.l"
+{
+                           LEXTRACE("= ");
+                           return('=');
+                       }                       /* return '=' */
+       YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 136 "toke.l"
+{
+                           LEXTRACE("+= ");
+                           return('+');
+                       }                       /* return '+' */
+       YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 141 "toke.l"
+{
+                           LEXTRACE("-= ");
+                           return('-');
+                       }                       /* return '-' */
+       YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 146 "toke.l"
+{
+                           LEXTRACE("BEGINSTR ");
+                           yylval.string = NULL;
+                           BEGIN INSTR;
+                       }
+       YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 152 "toke.l"
+{
+                           LEXTRACE("WORD(2) ");
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           return(WORD);
+                       }
+       YY_BREAK
+
+
+case 9:
+YY_RULE_SETUP
+#line 161 "toke.l"
+{
+                           /* Line continuation char followed by newline. */
+                           ++sudolineno;
+                           LEXTRACE("\n");
+                       }
+       YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 167 "toke.l"
+{
+                           LEXTRACE("ENDSTR ");
+                           BEGIN INDEFS;
+                           return(WORD);
+                       }
+       YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 173 "toke.l"
+{
+                           LEXTRACE("BACKSLASH ");
+                           if (!append(yytext, yyleng))
+                               yyterminate();
+                       }
+       YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 179 "toke.l"
+{
+                           LEXTRACE("STRBODY ");
+                           if (!append(yytext, yyleng))
+                               yyterminate();
+                       }
+       YY_BREAK
+
+
+case 13:
+YY_RULE_SETUP
+#line 187 "toke.l"
+{
+                           /* quoted fnmatch glob char, pass verbatim */
+                           LEXTRACE("QUOTEDCHAR ");
+                           if (!fill_args(yytext, 2, sawspace))
+                               yyterminate();
+                           sawspace = FALSE;
+                       }
+       YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 195 "toke.l"
+{
+                           /* quoted sudoers special char, strip backslash */
+                           LEXTRACE("QUOTEDCHAR ");
+                           if (!fill_args(yytext + 1, 1, sawspace))
+                               yyterminate();
+                           sawspace = FALSE;
+                       }
+       YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 203 "toke.l"
+{
+                           BEGIN INITIAL;
+                           yyless(0);
+                           return(COMMAND);
+                       }                       /* end of command line args */
+       YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 209 "toke.l"
+{
+                           LEXTRACE("ARG ");
+                           if (!fill_args(yytext, yyleng, sawspace))
+                               yyterminate();
+                           sawspace = FALSE;
+                       }                       /* a command line arg */
+       YY_BREAK
+
+case 17:
+YY_RULE_SETUP
+#line 217 "toke.l"
+{
+                           char *path;
+
+                           if ((path = parse_include(yytext)) == NULL)
+                               yyterminate();
+
+                           LEXTRACE("INCLUDE\n");
+
+                           /* Push current buffer and switch to include file */
+                           if (!push_include(path))
+                               yyterminate();
+                       }
+       YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 230 "toke.l"
+{
+                           int n;
+                           for (n = 0; isblank((unsigned char)yytext[n]); n++)
+                               continue;
+                           n += 8;
+                           BEGIN GOTDEFS;
+                           switch (yytext[n++]) {
+                               case ':':
+                                   yyless(n);
+                                   LEXTRACE("DEFAULTS_USER ");
+                                   return(DEFAULTS_USER);
+                               case '>':
+                                   yyless(n);
+                                   LEXTRACE("DEFAULTS_RUNAS ");
+                                   return(DEFAULTS_RUNAS);
+                               case '@':
+                                   yyless(n);
+                                   LEXTRACE("DEFAULTS_HOST ");
+                                   return(DEFAULTS_HOST);
+                               case '!':
+                                   yyless(n);
+                                   LEXTRACE("DEFAULTS_CMND ");
+                                   return(DEFAULTS_CMND);
+                               default:
+                                   LEXTRACE("DEFAULTS ");
+                                   return(DEFAULTS);
+                           }
+                       }
+       YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 259 "toke.l"
+{
+                           int n;
+                           for (n = 0; isblank((unsigned char)yytext[n]); n++)
+                               continue;
+                           switch (yytext[n]) {
+                               case 'H':
+                                   LEXTRACE("HOSTALIAS ");
+                                   return(HOSTALIAS);
+                               case 'C':
+                                   LEXTRACE("CMNDALIAS ");
+                                   return(CMNDALIAS);
+                               case 'U':
+                                   LEXTRACE("USERALIAS ");
+                                   return(USERALIAS);
+                               case 'R':
+                                   LEXTRACE("RUNASALIAS ");
+                                   return(RUNASALIAS);
+                           }
+                       }
+       YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 279 "toke.l"
+{
+                               /* cmnd does not require passwd for this user */
+                               LEXTRACE("NOPASSWD ");
+                               return(NOPASSWD);
+                       }
+       YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 285 "toke.l"
+{
+                               /* cmnd requires passwd for this user */
+                               LEXTRACE("PASSWD ");
+                               return(PASSWD);
+                       }
+       YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 291 "toke.l"
+{
+                               LEXTRACE("NOEXEC ");
+                               return(NOEXEC);
+                       }
+       YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 296 "toke.l"
+{
+                               LEXTRACE("EXEC ");
+                               return(EXEC);
+                       }
+       YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 301 "toke.l"
+{
+                               LEXTRACE("SETENV ");
+                               return(SETENV);
+                       }
+       YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 306 "toke.l"
+{
+                               LEXTRACE("NOSETENV ");
+                               return(NOSETENV);
+                       }
+       YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 311 "toke.l"
+{
+                           /* netgroup */
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NETGROUP ");
+                           return(NETGROUP);
+                       }
+       YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 319 "toke.l"
+{
+                           /* UN*X group */
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("USERGROUP ");
+                           return(USERGROUP);
+                       }
+       YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 327 "toke.l"
+{
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NTWKADDR ");
+                           return(NTWKADDR);
+                       }
+       YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 334 "toke.l"
+{
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NTWKADDR ");
+                           return(NTWKADDR);
+                       }
+       YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 341 "toke.l"
+{
+                           if (!ipv6_valid(yytext)) {
+                               LEXTRACE("ERROR ");
+                               return(ERROR);
+                           }
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NTWKADDR ");
+                           return(NTWKADDR);
+                       }
+       YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 352 "toke.l"
+{
+                           if (!ipv6_valid(yytext)) {
+                               LEXTRACE("ERROR ");
+                               return(ERROR);
+                           }
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NTWKADDR ");
+                           return(NTWKADDR);
+                       }
+       YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 363 "toke.l"
+{
+                           if (strcmp(yytext, "ALL") == 0) {
+                               LEXTRACE("ALL ");
+                               return(ALL);
+                           }
+#ifdef HAVE_SELINUX
+                           /* XXX - restrict type/role to initial state */
+                           if (strcmp(yytext, "TYPE") == 0) {
+                               LEXTRACE("TYPE ");
+                               return(TYPE);
+                           }
+                           if (strcmp(yytext, "ROLE") == 0) {
+                               LEXTRACE("ROLE ");
+                               return(ROLE);
+                           }
+#endif /* HAVE_SELINUX */
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("ALIAS ");
+                           return(ALIAS);
+                       }
+       YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 385 "toke.l"
+{
+                           /* no command args allowed for Defaults!/path */
+                           if (!fill_cmnd(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("COMMAND ");
+                           return(COMMAND);
+                       }
+       YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 393 "toke.l"
+{
+                           BEGIN GOTCMND;
+                           LEXTRACE("COMMAND ");
+                           if (!fill_cmnd(yytext, yyleng))
+                               yyterminate();
+                       }                       /* sudo -e */
+       YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 400 "toke.l"
+{
+                           /* directories can't have args... */
+                           if (yytext[yyleng - 1] == '/') {
+                               LEXTRACE("COMMAND ");
+                               if (!fill_cmnd(yytext, yyleng))
+                                   yyterminate();
+                               return(COMMAND);
+                           } else {
+                               BEGIN GOTCMND;
+                               LEXTRACE("COMMAND ");
+                               if (!fill_cmnd(yytext, yyleng))
+                                   yyterminate();
+                           }
+                       }                       /* a pathname */
+       YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 415 "toke.l"
+{
+                           /* a word */
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("WORD(4) ");
+                           return(WORD);
+                       }
+       YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 423 "toke.l"
+{
+                           LEXTRACE("( ");
+                           return ('(');
+                       }
+       YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 428 "toke.l"
+{
+                           LEXTRACE(") ");
+                           return(')');
+                       }
+       YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 433 "toke.l"
+{
+                           LEXTRACE(", ");
+                           return(',');
+                       }                       /* return ',' */
+       YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 438 "toke.l"
+{
+                           LEXTRACE("= ");
+                           return('=');
+                       }                       /* return '=' */
+       YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 443 "toke.l"
+{
+                           LEXTRACE(": ");
+                           return(':');
+                       }                       /* return ':' */
+       YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 448 "toke.l"
+{
+                           if (yyleng % 2 == 1)
+                               return('!');    /* return '!' */
+                       }
+       YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 453 "toke.l"
+{
+                           BEGIN INITIAL;
+                           ++sudolineno;
+                           LEXTRACE("\n");
+                           return(COMMENT);
+                       }                       /* return newline */
+       YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 460 "toke.l"
+{                      /* throw away space/tabs */
+                           sawspace = TRUE;    /* but remember for fill_args */
+                       }
+       YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 464 "toke.l"
+{
+                           sawspace = TRUE;    /* remember for fill_args */
+                           ++sudolineno;
+                           LEXTRACE("\n\t");
+                       }                       /* throw away EOL after \ */
+       YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 470 "toke.l"
+{
+                           BEGIN INITIAL;
+                           ++sudolineno;
+                           LEXTRACE("\n");
+                           return(COMMENT);
+                       }                       /* return comments */
+       YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 477 "toke.l"
+{
+                           LEXTRACE("ERROR ");
+                           return(ERROR);
+                       }       /* parse error */
+       YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(GOTDEFS):
+case YY_STATE_EOF(GOTCMND):
+case YY_STATE_EOF(STARTDEFS):
+case YY_STATE_EOF(INDEFS):
+case YY_STATE_EOF(INSTR):
+#line 482 "toke.l"
+{
+                           if (YY_START != INITIAL) {
+                               BEGIN INITIAL;
+                               LEXTRACE("ERROR ");
+                               return(ERROR);
+                           }
+                           if (!pop_include())
+                               yyterminate();
+                       }
+       YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 492 "toke.l"
+ECHO;
+       YY_BREAK
+#line 2184 "lex.yy.c"
+
+       case YY_END_OF_BUFFER:
+               {
+               /* Amount of text matched not including the EOB char. */
+               int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+               /* Undo the effects of YY_DO_BEFORE_ACTION. */
+               *yy_cp = yy_hold_char;
+               YY_RESTORE_YY_MORE_OFFSET
+
+               if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+                       {
+                       /* We're scanning a new file or input source.  It's
+                        * possible that this happened because the user
+                        * just pointed yyin at a new source and called
+                        * yylex().  If so, then we have to assure
+                        * consistency between yy_current_buffer and our
+                        * globals.  Here is the right place to do so, because
+                        * this is the first action (other than possibly a
+                        * back-up) that will match for the new input source.
+                        */
+                       yy_n_chars = yy_current_buffer->yy_n_chars;
+                       yy_current_buffer->yy_input_file = yyin;
+                       yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+                       }
+
+               /* Note that here we test for yy_c_buf_p "<=" to the position
+                * of the first EOB in the buffer, since yy_c_buf_p will
+                * already have been incremented past the NUL character
+                * (since all states make transitions on EOB to the
+                * end-of-buffer state).  Contrast this with the test
+                * in input().
+                */
+               if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+                       { /* This was really a NUL. */
+                       yy_state_type yy_next_state;
+
+                       yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+                       yy_current_state = yy_get_previous_state();
+
+                       /* Okay, we're now positioned to make the NUL
+                        * transition.  We couldn't have
+                        * yy_get_previous_state() go ahead and do it
+                        * for us because it doesn't know how to deal
+                        * with the possibility of jamming (and we don't
+                        * want to build jamming into it because then it
+                        * will run more slowly).
+                        */
+
+                       yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+                       yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+                       if ( yy_next_state )
+                               {
+                               /* Consume the NUL. */
+                               yy_cp = ++yy_c_buf_p;
+                               yy_current_state = yy_next_state;
+                               goto yy_match;
+                               }
+
+                       else
+                               {
+                               yy_cp = yy_c_buf_p;
+                               goto yy_find_action;
+                               }
+                       }
+
+               else switch ( yy_get_next_buffer() )
+                       {
+                       case EOB_ACT_END_OF_FILE:
+                               {
+                               yy_did_buffer_switch_on_eof = 0;
+
+                               if ( yywrap() )
+                                       {
+                                       /* Note: because we've taken care in
+                                        * yy_get_next_buffer() to have set up
+                                        * yytext, we can now set up
+                                        * yy_c_buf_p so that if some total
+                                        * hoser (like flex itself) wants to
+                                        * call the scanner after we return the
+                                        * YY_NULL, it'll still work - another
+                                        * YY_NULL will get returned.
+                                        */
+                                       yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+                                       yy_act = YY_STATE_EOF(YY_START);
+                                       goto do_action;
+                                       }
+
+                               else
+                                       {
+                                       if ( ! yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+                                       }
+                               break;
+                               }
+
+                       case EOB_ACT_CONTINUE_SCAN:
+                               yy_c_buf_p =
+                                       yytext_ptr + yy_amount_of_matched_text;
+
+                               yy_current_state = yy_get_previous_state();
+
+                               yy_cp = yy_c_buf_p;
+                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               goto yy_match;
+
+                       case EOB_ACT_LAST_MATCH:
+                               yy_c_buf_p =
+                               &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+                               yy_current_state = yy_get_previous_state();
+
+                               yy_cp = yy_c_buf_p;
+                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               goto yy_find_action;
+                       }
+               break;
+               }
+
+       default:
+               YY_FATAL_ERROR(
+                       "fatal flex scanner internal error--no action found" );
+       } /* end of action switch */
+               } /* end of scanning one token */
+       } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *     EOB_ACT_LAST_MATCH -
+ *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *     EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+       {
+       register char *dest = yy_current_buffer->yy_ch_buf;
+       register char *source = yytext_ptr;
+       register int number_to_move, i;
+       int ret_val;
+
+       if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+               YY_FATAL_ERROR(
+               "fatal flex scanner internal error--end of buffer missed" );
+
+       if ( yy_current_buffer->yy_fill_buffer == 0 )
+               { /* Don't try to fill the buffer, so this is an EOF. */
+               if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+                       {
+                       /* We matched a single character, the EOB, so
+                        * treat this as a final EOF.
+                        */
+                       return EOB_ACT_END_OF_FILE;
+                       }
+
+               else
+                       {
+                       /* We matched some text prior to the EOB, first
+                        * process it.
+                        */
+                       return EOB_ACT_LAST_MATCH;
+                       }
+               }
+
+       /* Try to read more data. */
+
+       /* First move last chars to start of buffer. */
+       number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+       for ( i = 0; i < number_to_move; ++i )
+               *(dest++) = *(source++);
+
+       if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+               /* don't do the read, it's not guaranteed to return an EOF,
+                * just force an EOF
+                */
+               yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+       else
+               {
+               int num_to_read =
+                       yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+               while ( num_to_read <= 0 )
+                       { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+                       YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+                       /* just a shorter name for the current buffer */
+                       YY_BUFFER_STATE b = yy_current_buffer;
+
+                       int yy_c_buf_p_offset =
+                               (int) (yy_c_buf_p - b->yy_ch_buf);
+
+                       if ( b->yy_is_our_buffer )
+                               {
+                               int new_size = b->yy_buf_size * 2;
+
+                               if ( new_size <= 0 )
+                                       b->yy_buf_size += b->yy_buf_size / 8;
+                               else
+                                       b->yy_buf_size *= 2;
+
+                               b->yy_ch_buf = (char *)
+                                       /* Include room in for 2 EOB chars. */
+                                       yy_flex_realloc( (void *) b->yy_ch_buf,
+                                                        b->yy_buf_size + 2 );
+                               }
+                       else
+                               /* Can't grow it, we don't own it. */
+                               b->yy_ch_buf = 0;
+
+                       if ( ! b->yy_ch_buf )
+                               YY_FATAL_ERROR(
+                               "fatal error - scanner input buffer overflow" );
+
+                       yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+                       num_to_read = yy_current_buffer->yy_buf_size -
+                                               number_to_move - 1;
+#endif
+                       }
+
+               if ( num_to_read > YY_READ_BUF_SIZE )
+                       num_to_read = YY_READ_BUF_SIZE;
+
+               /* Read in more data. */
+               YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+                       yy_n_chars, num_to_read );
+
+               yy_current_buffer->yy_n_chars = yy_n_chars;
+               }
+
+       if ( yy_n_chars == 0 )
+               {
+               if ( number_to_move == YY_MORE_ADJ )
+                       {
+                       ret_val = EOB_ACT_END_OF_FILE;
+                       yyrestart( yyin );
+                       }
+
+               else
+                       {
+                       ret_val = EOB_ACT_LAST_MATCH;
+                       yy_current_buffer->yy_buffer_status =
+                               YY_BUFFER_EOF_PENDING;
+                       }
+               }
+
+       else
+               ret_val = EOB_ACT_CONTINUE_SCAN;
+
+       yy_n_chars += number_to_move;
+       yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+       yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+       yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+       return ret_val;
+       }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+       {
+       register yy_state_type yy_current_state;
+       register char *yy_cp;
+
+       yy_current_state = yy_start;
+       yy_current_state += YY_AT_BOL();
+
+       for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+               {
+               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+               if ( yy_accept[yy_current_state] )
+                       {
+                       yy_last_accepting_state = yy_current_state;
+                       yy_last_accepting_cpos = yy_cp;
+                       }
+               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                       {
+                       yy_current_state = (int) yy_def[yy_current_state];
+                       if ( yy_current_state >= 534 )
+                               yy_c = yy_meta[(unsigned int) yy_c];
+                       }
+               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+               }
+
+       return yy_current_state;
+       }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *     next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+       {
+       register int yy_is_jam;
+       register char *yy_cp = yy_c_buf_p;
+
+       register YY_CHAR yy_c = 1;
+       if ( yy_accept[yy_current_state] )
+               {
+               yy_last_accepting_state = yy_current_state;
+               yy_last_accepting_cpos = yy_cp;
+               }
+       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+               {
+               yy_current_state = (int) yy_def[yy_current_state];
+               if ( yy_current_state >= 534 )
+                       yy_c = yy_meta[(unsigned int) yy_c];
+               }
+       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+       yy_is_jam = (yy_current_state == 533);
+
+       return yy_is_jam ? 0 : yy_current_state;
+       }
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+       {
+       register char *yy_cp = yy_c_buf_p;
+
+       /* undo effects of setting up yytext */
+       *yy_cp = yy_hold_char;
+
+       if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+               { /* need to shift things up to make room */
+               /* +2 for EOB chars. */
+               register int number_to_move = yy_n_chars + 2;
+               register char *dest = &yy_current_buffer->yy_ch_buf[
+                                       yy_current_buffer->yy_buf_size + 2];
+               register char *source =
+                               &yy_current_buffer->yy_ch_buf[number_to_move];
+
+               while ( source > yy_current_buffer->yy_ch_buf )
+                       *--dest = *--source;
+
+               yy_cp += (int) (dest - source);
+               yy_bp += (int) (dest - source);
+               yy_current_buffer->yy_n_chars =
+                       yy_n_chars = yy_current_buffer->yy_buf_size;
+
+               if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
+               }
+
+       *--yy_cp = (char) c;
+
+
+       yytext_ptr = yy_bp;
+       yy_hold_char = *yy_cp;
+       yy_c_buf_p = yy_cp;
+       }
+#endif /* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+       {
+       int c;
+
+       *yy_c_buf_p = yy_hold_char;
+
+       if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+               {
+               /* yy_c_buf_p now points to the character we want to return.
+                * If this occurs *before* the EOB characters, then it's a
+                * valid NUL; if not, then we've hit the end of the buffer.
+                */
+               if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+                       /* This was really a NUL. */
+                       *yy_c_buf_p = '\0';
+
+               else
+                       { /* need more input */
+                       int offset = yy_c_buf_p - yytext_ptr;
+                       ++yy_c_buf_p;
+
+                       switch ( yy_get_next_buffer() )
+                               {
+                               case EOB_ACT_LAST_MATCH:
+                                       /* This happens because yy_g_n_b()
+                                        * sees that we've accumulated a
+                                        * token and flags that we need to
+                                        * try matching the token before
+                                        * proceeding.  But for input(),
+                                        * there's no matching to consider.
+                                        * So convert the EOB_ACT_LAST_MATCH
+                                        * to EOB_ACT_END_OF_FILE.
+                                        */
+
+                                       /* Reset buffer status. */
+                                       yyrestart( yyin );
+
+                                       /* fall through */
+
+                               case EOB_ACT_END_OF_FILE:
+                                       {
+                                       if ( yywrap() )
+                                               return EOF;
+
+                                       if ( ! yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+#ifdef __cplusplus
+                                       return yyinput();
+#else
+                                       return input();
+#endif
+                                       }
+
+                               case EOB_ACT_CONTINUE_SCAN:
+                                       yy_c_buf_p = yytext_ptr + offset;
+                                       break;
+                               }
+                       }
+               }
+
+       c = *(unsigned char *) yy_c_buf_p;      /* cast for 8-bit char's */
+       *yy_c_buf_p = '\0';     /* preserve yytext */
+       yy_hold_char = *++yy_c_buf_p;
+
+       yy_current_buffer->yy_at_bol = (c == '\n');
+
+       return c;
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+       {
+       if ( ! yy_current_buffer )
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+       yy_init_buffer( yy_current_buffer, input_file );
+       yy_load_buffer_state();
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+       {
+       if ( yy_current_buffer == new_buffer )
+               return;
+
+       if ( yy_current_buffer )
+               {
+               /* Flush out information for old buffer. */
+               *yy_c_buf_p = yy_hold_char;
+               yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+               yy_current_buffer->yy_n_chars = yy_n_chars;
+               }
+
+       yy_current_buffer = new_buffer;
+       yy_load_buffer_state();
+
+       /* We don't actually know whether we did this switch during
+        * EOF (yywrap()) processing, but the only time this flag
+        * is looked at is after yywrap() is called, so it's safe
+        * to go ahead and always set it.
+        */
+       yy_did_buffer_switch_on_eof = 1;
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+       {
+       yy_n_chars = yy_current_buffer->yy_n_chars;
+       yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+       yyin = yy_current_buffer->yy_input_file;
+       yy_hold_char = *yy_c_buf_p;
+       }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+       {
+       YY_BUFFER_STATE b;
+
+       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_buf_size = size;
+
+       /* yy_ch_buf has to be 2 characters longer than the size given because
+        * we need to put in 2 end-of-buffer characters.
+        */
+       b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+       if ( ! b->yy_ch_buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_is_our_buffer = 1;
+
+       yy_init_buffer( b, file );
+
+       return b;
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+       {
+       if ( ! b )
+               return;
+
+       if ( b == yy_current_buffer )
+               yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+       if ( b->yy_is_our_buffer )
+               yy_flex_free( (void *) b->yy_ch_buf );
+
+       yy_flex_free( (void *) b );
+       }
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+#include <unistd.h>
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+       {
+       int oerrno = errno;
+
+       yy_flush_buffer( b );
+
+       b->yy_input_file = file;
+       b->yy_fill_buffer = 1;
+
+#if defined(YY_ALWAYS_INTERACTIVE) && YY_ALWAYS_INTERACTIVE
+       b->yy_is_interactive = 1;
+#else
+#if defined(YY_NEVER_INTERACTIVE) && YY_NEVER_INTERACTIVE
+       b->yy_is_interactive = 0;
+#else
+       b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+       errno = oerrno;
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+       {
+       if ( ! b )
+               return;
+
+       b->yy_n_chars = 0;
+
+       /* We always need two end-of-buffer characters.  The first causes
+        * a transition to the end-of-buffer state.  The second causes
+        * a jam in that state.
+        */
+       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+       b->yy_buf_pos = &b->yy_ch_buf[0];
+
+       b->yy_at_bol = 1;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       if ( b == yy_current_buffer )
+               yy_load_buffer_state();
+       }
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+       {
+       YY_BUFFER_STATE b;
+
+       if ( size < 2 ||
+            base[size-2] != YY_END_OF_BUFFER_CHAR ||
+            base[size-1] != YY_END_OF_BUFFER_CHAR )
+               /* They forgot to leave room for the EOB's. */
+               return 0;
+
+       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+       b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
+       b->yy_buf_pos = b->yy_ch_buf = base;
+       b->yy_is_our_buffer = 0;
+       b->yy_input_file = 0;
+       b->yy_n_chars = b->yy_buf_size;
+       b->yy_is_interactive = 0;
+       b->yy_at_bol = 1;
+       b->yy_fill_buffer = 0;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       yy_switch_to_buffer( b );
+
+       return b;
+       }
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+       {
+       int len;
+       for ( len = 0; yy_str[len]; ++len )
+               ;
+
+       return yy_scan_bytes( yy_str, len );
+       }
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+       {
+       YY_BUFFER_STATE b;
+       char *buf;
+       yy_size_t n;
+       int i;
+
+       /* Get memory for full buffer, including space for trailing EOB's. */
+       n = len + 2;
+       buf = (char *) yy_flex_alloc( n );
+       if ( ! buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+       for ( i = 0; i < len; ++i )
+               buf[i] = bytes[i];
+
+       buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+       b = yy_scan_buffer( buf, n );
+       if ( ! b )
+               YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+       /* It's okay to grow etc. this buffer, and we should throw it
+        * away when we're done.
+        */
+       b->yy_is_our_buffer = 1;
+
+       return b;
+       }
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+       {
+       if ( yy_start_stack_ptr >= yy_start_stack_depth )
+               {
+               yy_size_t new_size;
+
+               yy_start_stack_depth += YY_START_STACK_INCR;
+               new_size = yy_start_stack_depth * sizeof( int );
+
+               if ( ! yy_start_stack )
+                       yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+               else
+                       yy_start_stack = (int *) yy_flex_realloc(
+                                       (void *) yy_start_stack, new_size );
+
+               if ( ! yy_start_stack )
+                       YY_FATAL_ERROR(
+                       "out of memory expanding start-condition stack" );
+               }
+
+       yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+       BEGIN(new_state);
+       }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+       {
+       if ( --yy_start_stack_ptr < 0 )
+               YY_FATAL_ERROR( "start-condition stack underflow" );
+
+       BEGIN(yy_start_stack[yy_start_stack_ptr]);
+       }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+       {
+       return yy_start_stack[yy_start_stack_ptr - 1];
+       }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+       {
+       (void) fprintf( stderr, "%s\n", msg );
+       exit( YY_EXIT_FAILURE );
+       }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+               yytext[yyleng] = yy_hold_char; \
+               yy_c_buf_p = yytext + n; \
+               yy_hold_char = *yy_c_buf_p; \
+               *yy_c_buf_p = '\0'; \
+               yyleng = n; \
+               } \
+       while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+       {
+       register int i;
+       for ( i = 0; i < n; ++i )
+               s1[i] = s2[i];
+       }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+       {
+       register int n;
+       for ( n = 0; s[n]; ++n )
+               ;
+
+       return n;
+       }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+       {
+       return (void *) malloc( size );
+       }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+       {
+       /* The cast to (char *) in the following accommodates both
+        * implementations that use char* generic pointers, and those
+        * that use void* generic pointers.  It works with the latter
+        * because both ANSI C and C++ allow castless assignment from
+        * any pointer type to void*, and deal with argument conversions
+        * as though doing an assignment.
+        */
+       return (void *) realloc( (char *) ptr, size );
+       }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+       {
+       free( ptr );
+       }
+
+#if defined(YY_MAIN) && YY_MAIN
+int main()
+       {
+       yylex();
+       return 0;
+       }
+#endif
+#line 492 "toke.l"
+
+static int
+_fill(src, len, olen)
+    char *src;
+    int len, olen;
+{
+    int i, j;
+    char *dst;
+
+    dst = olen ? realloc(yylval.string, olen + len + 1) : malloc(len + 1);
+    if (dst == NULL) {
+       yyerror("unable to allocate memory");
+       return(FALSE);
+    }
+    yylval.string = dst;
+
+    /* Copy the string and collapse any escaped characters. */
+    dst += olen;
+    for (i = 0, j = 0; i < len; i++, j++) {
+       if (src[i] == '\\' && i != len - 1)
+           dst[j] = src[++i];
+       else
+           dst[j] = src[i];
+    }
+    dst[j] = '\0';
+    return(TRUE);
+}
+
+static int
+append(src, len)
+    char *src;
+    int len;
+{
+    int olen = 0;
+
+    if (yylval.string != NULL)
+       olen = strlen(yylval.string);
+
+    return(_fill(src, len, olen));
+}
+
+#define SPECIAL(c) \
+    ((c) == ',' || (c) == ':' || (c) == '=' || (c) == ' ' || (c) == '\t' || (c) == '#')
+
+static int
+fill_cmnd(src, len)
+    char *src;
+    int len;
+{
+    char *dst;
+    int i;
+
+    arg_len = arg_size = 0;
+
+    dst = yylval.command.cmnd = (char *) malloc(len + 1);
+    if (yylval.command.cmnd == NULL) {
+       yyerror("unable to allocate memory");
+       return(FALSE);
+    }
+
+    /* Copy the string and collapse any escaped sudo-specific characters. */
+    for (i = 0; i < len; i++) {
+       if (src[i] == '\\' && i != len - 1 && SPECIAL(src[i + 1]))
+           *dst++ = src[++i];
+       else
+           *dst++ = src[i];
+    }
+    *dst = '\0';
+
+    yylval.command.args = NULL;
+    return(TRUE);
+}
+
+static int
+fill_args(s, len, addspace)
+    char *s;
+    int len;
+    int addspace;
+{
+    int new_len;
+    char *p;
+
+    if (yylval.command.args == NULL) {
+       addspace = 0;
+       new_len = len;
+    } else
+       new_len = arg_len + len + addspace;
+
+    if (new_len >= arg_size) {
+       /* Allocate more space than we need for subsequent args */
+       while (new_len >= (arg_size += COMMANDARGINC))
+           ;
+
+       p = yylval.command.args ?
+           (char *) realloc(yylval.command.args, arg_size) :
+           (char *) malloc(arg_size);
+       if (p == NULL) {
+           efree(yylval.command.args);
+           yyerror("unable to allocate memory");
+           return(FALSE);
+       } else
+           yylval.command.args = p;
+    }
+
+    /* Efficiently append the arg (with a leading space if needed). */
+    p = yylval.command.args + arg_len;
+    if (addspace)
+       *p++ = ' ';
+    if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len) {
+       yyerror("fill_args: buffer overflow");  /* paranoia */
+       return(FALSE);
+    }
+    arg_len = new_len;
+    return(TRUE);
+}
+
+struct sudoers_state {
+    YY_BUFFER_STATE bs;
+    char *path;
+    int lineno;
+};
+
+#define MAX_SUDOERS_DEPTH      128
+#define SUDOERS_STACK_INCREMENT        16
+
+static int
+switch_buffer(path)
+    char *path;
+{
+    static size_t stacksize, depth;
+    static struct sudoers_state *state;
+    static int keepopen;
+    FILE *fp;
+
+    if (path != NULL) {
+       /* push current state */
+       if (depth >= stacksize) {
+           if (depth > MAX_SUDOERS_DEPTH) {
+               yyerror("too many levels of includes");
+               return(FALSE);
+           }
+           stacksize += SUDOERS_STACK_INCREMENT;
+           state = (struct sudoers_state *) realloc(state,
+               sizeof(state) * stacksize);
+           if (state == NULL) {
+               yyerror("unable to allocate memory");
+               return(FALSE);
+           }
+       }
+       if ((fp = open_sudoers(path, &keepopen)) == NULL) {
+           yyerror(path);
+           return(FALSE);
+       }
+       state[depth].bs = YY_CURRENT_BUFFER;
+       state[depth].path = sudoers;
+       state[depth].lineno = sudolineno;
+       depth++;
+       sudolineno = 1;
+       sudoers = path;
+       yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
+    } else {
+       /* pop */
+       if (depth == 0)
+           return(FALSE);
+       depth--;
+       if (!keepopen)
+           fclose(YY_CURRENT_BUFFER->yy_input_file);
+       yy_delete_buffer(YY_CURRENT_BUFFER);
+       yy_switch_to_buffer(state[depth].bs);
+       efree(sudoers);
+       sudoers = state[depth].path;
+       sudolineno = state[depth].lineno;
+       keepopen = FALSE;
+    }
+    return(TRUE);
+}
+
+static char *
+parse_include(base)
+    char *base;
+{
+    char *cp, *ep, *path;
+    int len;
+
+    /* Pull out path from #include line. */
+    cp = base + sizeof("#include");
+    while (isblank((unsigned char) *cp))
+       cp++;
+    ep = cp;
+    while (*ep != '\0' && !isspace((unsigned char) *ep))
+       ep++;
+
+    /* Make a copy of path and return it. */
+    len = (int)(ep - cp);
+    if ((path = malloc(len + 1)) == NULL)
+       yyerror("unable to allocate memory");
+    memcpy(path, cp, len);
+    path[len] = '\0';
+
+    /* Push any excess characters (e.g. comment, newline) back to the lexer */
+    if (*ep != '\0')
+       yyless((int)(ep - base));
+
+    return(path);
+}
+
+/*
+ * Check to make sure an IPv6 address does not contain multiple instances
+ * of the string "::".  Assumes strlen(s) >= 1.
+ * Returns TRUE if address is valid else FALSE.
+ */
+static int
+ipv6_valid(s)
+    const char *s;
+{
+    int nmatch = 0;
+
+    for (; *s != '\0'; s++) {
+       if (s[0] == ':' && s[1] == ':') {
+           if (++nmatch > 1)
+               break;
+       }
+       if (s[0] == '/')
+           nmatch = 0;                 /* reset if we hit netmask */
+    }
+
+    return (nmatch <= 1);
+}
diff --git a/toke.l b/toke.l
new file mode 100644 (file)
index 0000000..a38da3a
--- /dev/null
+++ b/toke.l
@@ -0,0 +1,719 @@
+%{
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 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.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
+# include <malloc.h>
+#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
+#include <ctype.h>
+#include "sudo.h"
+#include "parse.h"
+#include <gram.h>
+
+#ifndef lint
+__unused static const char rcsid[] = "$Sudo: toke.l,v 1.27 2008/11/24 00:41:36 millert Exp $";
+#endif /* lint */
+
+extern YYSTYPE yylval;
+int sudolineno = 1;
+char *sudoers;
+static int sawspace = 0;
+static int arg_len = 0;
+static int arg_size = 0;
+
+static int append              __P((char *, int));
+static int _fill               __P((char *, int, int));
+static int fill_cmnd           __P((char *, int));
+static int fill_args           __P((char *, int, int));
+static int switch_buffer       __P((char *));
+static int ipv6_valid          __P((const char *s));
+static char *parse_include     __P((char *));
+extern void yyerror            __P((const char *));
+
+#define fill(a, b)             _fill(a, b, 0)
+
+#define        push_include(_p)        (switch_buffer((_p)))
+#define        pop_include()           (switch_buffer(NULL))
+
+/* realloc() to size + COMMANDARGINC to make room for command args */
+#define COMMANDARGINC  64
+
+#ifdef TRACELEXER
+#define LEXTRACE(msg)  fputs(msg, stderr)
+#else
+#define LEXTRACE(msg)
+#endif
+%}
+
+HEX16                  [0-9A-Fa-f]{1,4}
+OCTET                  (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5])
+IPV4ADDR               {OCTET}(\.{OCTET}){3}
+IPV6ADDR               ({HEX16}?:){2,7}{HEX16}?|({HEX16}?:){2,6}:{IPV4ADDR}
+
+HOSTNAME               [[:alnum:]_-]+
+WORD                   ([^#>!=:,\(\) \t\n\\]|\\[^\n])+
+ID                     #-?[0-9]+
+PATH                   \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+
+ENVAR                  ([^#!=, \t\n\\\"]|\\[^\n])([^#=, \t\n\\\"]|\\[^\n])*
+DEFVAR                 [a-z_]+
+
+%option nounput
+%option noyywrap
+
+%s     GOTDEFS
+%x     GOTCMND
+%x     STARTDEFS
+%x     INDEFS
+%x     INSTR
+
+%%
+<GOTDEFS>[[:blank:]]+  BEGIN STARTDEFS;
+
+<STARTDEFS>{DEFVAR}    {
+                           BEGIN INDEFS;
+                           LEXTRACE("DEFVAR ");
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           return(DEFVAR);
+                       }
+
+<INDEFS>{
+    ,                  {
+                           BEGIN STARTDEFS;
+                           LEXTRACE(", ");
+                           return(',');
+                       }                       /* return ',' */
+
+    =                  {
+                           LEXTRACE("= ");
+                           return('=');
+                       }                       /* return '=' */
+
+    \+=                        {
+                           LEXTRACE("+= ");
+                           return('+');
+                       }                       /* return '+' */
+
+    -=                 {
+                           LEXTRACE("-= ");
+                           return('-');
+                       }                       /* return '-' */
+
+    \"                 {
+                           LEXTRACE("BEGINSTR ");
+                           yylval.string = NULL;
+                           BEGIN INSTR;
+                       }
+
+    {ENVAR}            {
+                           LEXTRACE("WORD(2) ");
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           return(WORD);
+                       }
+}
+
+<INSTR>{
+    \\[[:blank:]]*\n[[:blank:]]*       {
+                           /* Line continuation char followed by newline. */
+                           ++sudolineno;
+                           LEXTRACE("\n");
+                       }
+
+    \"                 {
+                           LEXTRACE("ENDSTR ");
+                           BEGIN INDEFS;
+                           return(WORD);
+                       }
+
+    \\                 {
+                           LEXTRACE("BACKSLASH ");
+                           if (!append(yytext, yyleng))
+                               yyterminate();
+                       }
+
+    ([^\"\n\\]|\\\")+  {
+                           LEXTRACE("STRBODY ");
+                           if (!append(yytext, yyleng))
+                               yyterminate();
+                       }
+}
+
+<GOTCMND>{
+    \\[\*\?\[\]\!]     {
+                           /* quoted fnmatch glob char, pass verbatim */
+                           LEXTRACE("QUOTEDCHAR ");
+                           if (!fill_args(yytext, 2, sawspace))
+                               yyterminate();
+                           sawspace = FALSE;
+                       }
+
+    \\[:\\,= \t#]      {
+                           /* quoted sudoers special char, strip backslash */
+                           LEXTRACE("QUOTEDCHAR ");
+                           if (!fill_args(yytext + 1, 1, sawspace))
+                               yyterminate();
+                           sawspace = FALSE;
+                       }
+
+    [#:\,=\n]          {
+                           BEGIN INITIAL;
+                           yyless(0);
+                           return(COMMAND);
+                       }                       /* end of command line args */
+
+    [^\\:, \t\n]+      {
+                           LEXTRACE("ARG ");
+                           if (!fill_args(yytext, yyleng, sawspace))
+                               yyterminate();
+                           sawspace = FALSE;
+                       }                       /* a command line arg */
+}
+
+<INITIAL>^#include[[:blank:]]+\/.*\n {
+                           char *path;
+
+                           if ((path = parse_include(yytext)) == NULL)
+                               yyterminate();
+
+                           LEXTRACE("INCLUDE\n");
+
+                           /* Push current buffer and switch to include file */
+                           if (!push_include(path))
+                               yyterminate();
+                       }
+
+<INITIAL>^[[:blank:]]*Defaults([:@>\!]{WORD})? {
+                           int n;
+                           for (n = 0; isblank((unsigned char)yytext[n]); n++)
+                               continue;
+                           n += 8;
+                           BEGIN GOTDEFS;
+                           switch (yytext[n++]) {
+                               case ':':
+                                   yyless(n);
+                                   LEXTRACE("DEFAULTS_USER ");
+                                   return(DEFAULTS_USER);
+                               case '>':
+                                   yyless(n);
+                                   LEXTRACE("DEFAULTS_RUNAS ");
+                                   return(DEFAULTS_RUNAS);
+                               case '@':
+                                   yyless(n);
+                                   LEXTRACE("DEFAULTS_HOST ");
+                                   return(DEFAULTS_HOST);
+                               case '!':
+                                   yyless(n);
+                                   LEXTRACE("DEFAULTS_CMND ");
+                                   return(DEFAULTS_CMND);
+                               default:
+                                   LEXTRACE("DEFAULTS ");
+                                   return(DEFAULTS);
+                           }
+                       }
+
+<INITIAL>^[[:blank:]]*(Host|Cmnd|User|Runas)_Alias     {
+                           int n;
+                           for (n = 0; isblank((unsigned char)yytext[n]); n++)
+                               continue;
+                           switch (yytext[n]) {
+                               case 'H':
+                                   LEXTRACE("HOSTALIAS ");
+                                   return(HOSTALIAS);
+                               case 'C':
+                                   LEXTRACE("CMNDALIAS ");
+                                   return(CMNDALIAS);
+                               case 'U':
+                                   LEXTRACE("USERALIAS ");
+                                   return(USERALIAS);
+                               case 'R':
+                                   LEXTRACE("RUNASALIAS ");
+                                   return(RUNASALIAS);
+                           }
+                       }
+
+NOPASSWD[[:blank:]]*:  {
+                               /* cmnd does not require passwd for this user */
+                               LEXTRACE("NOPASSWD ");
+                               return(NOPASSWD);
+                       }
+
+PASSWD[[:blank:]]*:    {
+                               /* cmnd requires passwd for this user */
+                               LEXTRACE("PASSWD ");
+                               return(PASSWD);
+                       }
+
+NOEXEC[[:blank:]]*:    {
+                               LEXTRACE("NOEXEC ");
+                               return(NOEXEC);
+                       }
+
+EXEC[[:blank:]]*:      {
+                               LEXTRACE("EXEC ");
+                               return(EXEC);
+                       }
+
+SETENV[[:blank:]]*:    {
+                               LEXTRACE("SETENV ");
+                               return(SETENV);
+                       }
+
+NOSETENV[[:blank:]]*:  {
+                               LEXTRACE("NOSETENV ");
+                               return(NOSETENV);
+                       }
+
+\+{WORD}               {
+                           /* netgroup */
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NETGROUP ");
+                           return(NETGROUP);
+                       }
+
+\%{WORD}               {
+                           /* UN*X group */
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("USERGROUP ");
+                           return(USERGROUP);
+                       }
+
+{IPV4ADDR}(\/{IPV4ADDR})? {
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NTWKADDR ");
+                           return(NTWKADDR);
+                       }
+
+{IPV4ADDR}\/([12][0-9]*|3[0-2]*) {
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NTWKADDR ");
+                           return(NTWKADDR);
+                       }
+
+{IPV6ADDR}(\/{IPV6ADDR})? {
+                           if (!ipv6_valid(yytext)) {
+                               LEXTRACE("ERROR ");
+                               return(ERROR);
+                           }
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NTWKADDR ");
+                           return(NTWKADDR);
+                       }
+
+{IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) {
+                           if (!ipv6_valid(yytext)) {
+                               LEXTRACE("ERROR ");
+                               return(ERROR);
+                           }
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NTWKADDR ");
+                           return(NTWKADDR);
+                       }
+
+[[:upper:]][[:upper:][:digit:]_]* {
+                           if (strcmp(yytext, "ALL") == 0) {
+                               LEXTRACE("ALL ");
+                               return(ALL);
+                           }
+#ifdef HAVE_SELINUX
+                           /* XXX - restrict type/role to initial state */
+                           if (strcmp(yytext, "TYPE") == 0) {
+                               LEXTRACE("TYPE ");
+                               return(TYPE);
+                           }
+                           if (strcmp(yytext, "ROLE") == 0) {
+                               LEXTRACE("ROLE ");
+                               return(ROLE);
+                           }
+#endif /* HAVE_SELINUX */
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("ALIAS ");
+                           return(ALIAS);
+                       }
+
+<GOTDEFS>({PATH}|sudoedit) {
+                           /* no command args allowed for Defaults!/path */
+                           if (!fill_cmnd(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("COMMAND ");
+                           return(COMMAND);
+                       }
+
+sudoedit               {
+                           BEGIN GOTCMND;
+                           LEXTRACE("COMMAND ");
+                           if (!fill_cmnd(yytext, yyleng))
+                               yyterminate();
+                       }                       /* sudo -e */
+
+{PATH}                 {
+                           /* directories can't have args... */
+                           if (yytext[yyleng - 1] == '/') {
+                               LEXTRACE("COMMAND ");
+                               if (!fill_cmnd(yytext, yyleng))
+                                   yyterminate();
+                               return(COMMAND);
+                           } else {
+                               BEGIN GOTCMND;
+                               LEXTRACE("COMMAND ");
+                               if (!fill_cmnd(yytext, yyleng))
+                                   yyterminate();
+                           }
+                       }                       /* a pathname */
+
+<INITIAL,GOTDEFS>({ID}|{WORD}) {
+                           /* a word */
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("WORD(4) ");
+                           return(WORD);
+                       }
+
+\(                     {
+                           LEXTRACE("( ");
+                           return ('(');
+                       }
+
+\)                     {
+                           LEXTRACE(") ");
+                           return(')');
+                       }
+
+,                      {
+                           LEXTRACE(", ");
+                           return(',');
+                       }                       /* return ',' */
+
+=                      {
+                           LEXTRACE("= ");
+                           return('=');
+                       }                       /* return '=' */
+
+:                      {
+                           LEXTRACE(": ");
+                           return(':');
+                       }                       /* return ':' */
+
+<*>!+                  {
+                           if (yyleng % 2 == 1)
+                               return('!');    /* return '!' */
+                       }
+
+<*>\n                  {
+                           BEGIN INITIAL;
+                           ++sudolineno;
+                           LEXTRACE("\n");
+                           return(COMMENT);
+                       }                       /* return newline */
+
+<*>[[:blank:]]+                {                       /* throw away space/tabs */
+                           sawspace = TRUE;    /* but remember for fill_args */
+                       }
+
+<*>\\[[:blank:]]*\n    {
+                           sawspace = TRUE;    /* remember for fill_args */
+                           ++sudolineno;
+                           LEXTRACE("\n\t");
+                       }                       /* throw away EOL after \ */
+
+<INITIAL,STARTDEFS,INDEFS>#([^\n0-9-].*)?\n    {
+                           BEGIN INITIAL;
+                           ++sudolineno;
+                           LEXTRACE("\n");
+                           return(COMMENT);
+                       }                       /* return comments */
+
+<*>.                   {
+                           LEXTRACE("ERROR ");
+                           return(ERROR);
+                       }       /* parse error */
+
+<*><<EOF>>             {
+                           if (YY_START != INITIAL) {
+                               BEGIN INITIAL;
+                               LEXTRACE("ERROR ");
+                               return(ERROR);
+                           }
+                           if (!pop_include())
+                               yyterminate();
+                       }
+
+%%
+static int
+_fill(src, len, olen)
+    char *src;
+    int len, olen;
+{
+    int i, j;
+    char *dst;
+
+    dst = olen ? realloc(yylval.string, olen + len + 1) : malloc(len + 1);
+    if (dst == NULL) {
+       yyerror("unable to allocate memory");
+       return(FALSE);
+    }
+    yylval.string = dst;
+
+    /* Copy the string and collapse any escaped characters. */
+    dst += olen;
+    for (i = 0, j = 0; i < len; i++, j++) {
+       if (src[i] == '\\' && i != len - 1)
+           dst[j] = src[++i];
+       else
+           dst[j] = src[i];
+    }
+    dst[j] = '\0';
+    return(TRUE);
+}
+
+static int
+append(src, len)
+    char *src;
+    int len;
+{
+    int olen = 0;
+
+    if (yylval.string != NULL)
+       olen = strlen(yylval.string);
+
+    return(_fill(src, len, olen));
+}
+
+#define SPECIAL(c) \
+    ((c) == ',' || (c) == ':' || (c) == '=' || (c) == ' ' || (c) == '\t' || (c) == '#')
+
+static int
+fill_cmnd(src, len)
+    char *src;
+    int len;
+{
+    char *dst;
+    int i;
+
+    arg_len = arg_size = 0;
+
+    dst = yylval.command.cmnd = (char *) malloc(len + 1);
+    if (yylval.command.cmnd == NULL) {
+       yyerror("unable to allocate memory");
+       return(FALSE);
+    }
+
+    /* Copy the string and collapse any escaped sudo-specific characters. */
+    for (i = 0; i < len; i++) {
+       if (src[i] == '\\' && i != len - 1 && SPECIAL(src[i + 1]))
+           *dst++ = src[++i];
+       else
+           *dst++ = src[i];
+    }
+    *dst = '\0';
+
+    yylval.command.args = NULL;
+    return(TRUE);
+}
+
+static int
+fill_args(s, len, addspace)
+    char *s;
+    int len;
+    int addspace;
+{
+    int new_len;
+    char *p;
+
+    if (yylval.command.args == NULL) {
+       addspace = 0;
+       new_len = len;
+    } else
+       new_len = arg_len + len + addspace;
+
+    if (new_len >= arg_size) {
+       /* Allocate more space than we need for subsequent args */
+       while (new_len >= (arg_size += COMMANDARGINC))
+           ;
+
+       p = yylval.command.args ?
+           (char *) realloc(yylval.command.args, arg_size) :
+           (char *) malloc(arg_size);
+       if (p == NULL) {
+           efree(yylval.command.args);
+           yyerror("unable to allocate memory");
+           return(FALSE);
+       } else
+           yylval.command.args = p;
+    }
+
+    /* Efficiently append the arg (with a leading space if needed). */
+    p = yylval.command.args + arg_len;
+    if (addspace)
+       *p++ = ' ';
+    if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len) {
+       yyerror("fill_args: buffer overflow");  /* paranoia */
+       return(FALSE);
+    }
+    arg_len = new_len;
+    return(TRUE);
+}
+
+struct sudoers_state {
+    YY_BUFFER_STATE bs;
+    char *path;
+    int lineno;
+};
+
+#define MAX_SUDOERS_DEPTH      128
+#define SUDOERS_STACK_INCREMENT        16
+
+static int
+switch_buffer(path)
+    char *path;
+{
+    static size_t stacksize, depth;
+    static struct sudoers_state *state;
+    static int keepopen;
+    FILE *fp;
+
+    if (path != NULL) {
+       /* push current state */
+       if (depth >= stacksize) {
+           if (depth > MAX_SUDOERS_DEPTH) {
+               yyerror("too many levels of includes");
+               return(FALSE);
+           }
+           stacksize += SUDOERS_STACK_INCREMENT;
+           state = (struct sudoers_state *) realloc(state,
+               sizeof(state) * stacksize);
+           if (state == NULL) {
+               yyerror("unable to allocate memory");
+               return(FALSE);
+           }
+       }
+       if ((fp = open_sudoers(path, &keepopen)) == NULL) {
+           yyerror(path);
+           return(FALSE);
+       }
+       state[depth].bs = YY_CURRENT_BUFFER;
+       state[depth].path = sudoers;
+       state[depth].lineno = sudolineno;
+       depth++;
+       sudolineno = 1;
+       sudoers = path;
+       yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
+    } else {
+       /* pop */
+       if (depth == 0)
+           return(FALSE);
+       depth--;
+       if (!keepopen)
+           fclose(YY_CURRENT_BUFFER->yy_input_file);
+       yy_delete_buffer(YY_CURRENT_BUFFER);
+       yy_switch_to_buffer(state[depth].bs);
+       efree(sudoers);
+       sudoers = state[depth].path;
+       sudolineno = state[depth].lineno;
+       keepopen = FALSE;
+    }
+    return(TRUE);
+}
+
+static char *
+parse_include(base)
+    char *base;
+{
+    char *cp, *ep, *path;
+    int len;
+
+    /* Pull out path from #include line. */
+    cp = base + sizeof("#include");
+    while (isblank((unsigned char) *cp))
+       cp++;
+    ep = cp;
+    while (*ep != '\0' && !isspace((unsigned char) *ep))
+       ep++;
+
+    /* Make a copy of path and return it. */
+    len = (int)(ep - cp);
+    if ((path = malloc(len + 1)) == NULL)
+       yyerror("unable to allocate memory");
+    memcpy(path, cp, len);
+    path[len] = '\0';
+
+    /* Push any excess characters (e.g. comment, newline) back to the lexer */
+    if (*ep != '\0')
+       yyless((int)(ep - base));
+
+    return(path);
+}
+
+/*
+ * Check to make sure an IPv6 address does not contain multiple instances
+ * of the string "::".  Assumes strlen(s) >= 1.
+ * Returns TRUE if address is valid else FALSE.
+ */
+static int
+ipv6_valid(s)
+    const char *s;
+{
+    int nmatch = 0;
+
+    for (; *s != '\0'; s++) {
+       if (s[0] == ':' && s[1] == ':') {
+           if (++nmatch > 1)
+               break;
+       }
+       if (s[0] == '/')
+           nmatch = 0;                 /* reset if we hit netmask */
+    }
+
+    return (nmatch <= 1);
+}
diff --git a/tsgetgrpw.c b/tsgetgrpw.c
new file mode 100644 (file)
index 0000000..7f35269
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2005,2008 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Trivial replacements for the libc get{gr,pw}{uid,nam}() routines
+ * for use by testsudoers in the sudo test harness.
+ * We need our own since many platforms don't provide set{pw,gr}file().
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
+#  include <memory.h>
+# endif
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#include <limits.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "sudo.h"
+
+#ifndef LINE_MAX
+# define LINE_MAX 2048
+#endif
+
+#undef GRMEM_MAX
+#define GRMEM_MAX 200
+
+static FILE *pwf;
+static const char *pwfile = "/etc/passwd";
+static int pw_stayopen;
+
+static FILE *grf;
+static const char *grfile = "/etc/group";
+static int gr_stayopen;
+
+void ts_setgrfile __P((const char *));
+void ts_setgrent __P((void));
+void ts_endgrent __P((void));
+struct group *ts_getgrent __P((void));
+struct group *ts_getgrnam __P((const char *));
+struct group *ts_getgrgid __P((gid_t));
+
+void ts_setpwfile __P((const char *));
+void ts_setpwent __P((void));
+void ts_endpwent __P((void));
+struct passwd *ts_getpwent __P((void));
+struct passwd *ts_getpwnam __P((const char *));
+struct passwd *ts_getpwuid __P((uid_t));
+
+void
+ts_setpwfile(file)
+    const char *file;
+{
+    pwfile = file;
+    if (pwf != NULL)
+       ts_endpwent();
+}
+
+void
+ts_setpwent()
+{
+    if (pwf == NULL)
+       pwf = fopen(pwfile, "r");
+    else
+       rewind(pwf);
+    pw_stayopen = 1;
+}
+
+void
+ts_endpwent()
+{
+    if (pwf != NULL) {
+       fclose(pwf);
+       pwf = NULL;
+    }
+    pw_stayopen = 0;
+}
+
+struct passwd *
+ts_getpwent()
+{
+    static struct passwd pw;
+    static char pwbuf[LINE_MAX];
+    size_t len;
+    char *cp, *colon;
+
+    if ((colon = fgets(pwbuf, sizeof(pwbuf), pwf)) == NULL)
+       return(NULL);
+
+    zero_bytes(&pw, sizeof(pw));
+    if ((colon = strchr(cp = colon, ':')) == NULL)
+       return(NULL);
+    *colon++ = '\0';
+    pw.pw_name = cp;
+    if ((colon = strchr(cp = colon, ':')) == NULL)
+       return(NULL);
+    *colon++ = '\0';
+    pw.pw_passwd = cp;
+    if ((colon = strchr(cp = colon, ':')) == NULL)
+       return(NULL);
+    *colon++ = '\0';
+    pw.pw_uid = atoi(cp);
+    if ((colon = strchr(cp = colon, ':')) == NULL)
+       return(NULL);
+    *colon++ = '\0';
+    pw.pw_gid = atoi(cp);
+    if ((colon = strchr(cp = colon, ':')) == NULL)
+       return(NULL);
+    *colon++ = '\0';
+    pw.pw_gecos = cp;
+    if ((colon = strchr(cp = colon, ':')) == NULL)
+       return(NULL);
+    *colon++ = '\0';
+    pw.pw_dir = cp;
+    pw.pw_shell = colon;
+    len = strlen(colon);
+    if (len > 0 && colon[len - 1] == '\n')
+       colon[len - 1] = '\0';
+    return(&pw);
+}
+
+struct passwd *
+ts_getpwnam(name)
+    const char *name;
+{
+    struct passwd *pw;
+
+    if (pwf != NULL)
+       rewind(pwf);
+    else if ((pwf = fopen(pwfile, "r")) == NULL)
+       return(NULL);
+    while ((pw = ts_getpwent()) != NULL) {
+       if (strcmp(pw->pw_name, name) == 0)
+           break;
+    }
+    if (!pw_stayopen) {
+       fclose(pwf);
+       pwf = NULL;
+    }
+    return(pw);
+}
+
+struct passwd *
+ts_getpwuid(uid)
+    uid_t uid;
+{
+    struct passwd *pw;
+
+    if (pwf != NULL)
+       rewind(pwf);
+    else if ((pwf = fopen(pwfile, "r")) == NULL)
+       return(NULL);
+    while ((pw = ts_getpwent()) != NULL) {
+       if (pw->pw_uid == uid)
+           break;
+    }
+    if (!pw_stayopen) {
+       fclose(pwf);
+       pwf = NULL;
+    }
+    return(pw);
+}
+
+void
+ts_setgrfile(file)
+    const char *file;
+{
+    grfile = file;
+    if (grf != NULL)
+       ts_endgrent();
+}
+
+void
+ts_setgrent()
+{
+    if (grf == NULL)
+       grf = fopen(grfile, "r");
+    else
+       rewind(grf);
+    gr_stayopen = 1;
+}
+
+void
+ts_endgrent()
+{
+    if (grf != NULL) {
+       fclose(grf);
+       grf = NULL;
+    }
+    gr_stayopen = 0;
+}
+
+struct group *
+ts_getgrent()
+{
+    static struct group gr;
+    static char grbuf[LINE_MAX], *gr_mem[GRMEM_MAX+1];
+    size_t len;
+    char *cp, *colon;
+    int n;
+
+    if ((colon = fgets(grbuf, sizeof(grbuf), grf)) == NULL)
+       return(NULL);
+
+    zero_bytes(&gr, sizeof(gr));
+    if ((colon = strchr(cp = colon, ':')) == NULL)
+       return(NULL);
+    *colon++ = '\0';
+    gr.gr_name = cp;
+    if ((colon = strchr(cp = colon, ':')) == NULL)
+       return(NULL);
+    *colon++ = '\0';
+    gr.gr_passwd = cp;
+    if ((colon = strchr(cp = colon, ':')) == NULL)
+       return(NULL);
+    *colon++ = '\0';
+    gr.gr_gid = atoi(cp);
+    len = strlen(colon);
+    if (len > 0 && colon[len - 1] == '\n')
+       colon[len - 1] = '\0';
+    if (*colon != '\0') {
+       gr.gr_mem = gr_mem;
+       cp = strtok(colon, ",");
+       for (n = 0; cp != NULL && n < GRMEM_MAX; n++) {
+           gr.gr_mem[n] = cp;
+           cp = strtok(NULL, ",");
+       }
+       gr.gr_mem[n++] = NULL;
+    } else
+       gr.gr_mem = NULL;
+    return(&gr);
+}
+
+struct group *
+ts_getgrnam(name)
+    const char *name;
+{
+    struct group *gr;
+
+    if (grf != NULL)
+       rewind(grf);
+    else if ((grf = fopen(grfile, "r")) == NULL)
+       return(NULL);
+    while ((gr = ts_getgrent()) != NULL) {
+       if (strcmp(gr->gr_name, name) == 0)
+           break;
+    }
+    if (!gr_stayopen) {
+       fclose(grf);
+       grf = NULL;
+    }
+    return(gr);
+}
+
+struct group *
+ts_getgrgid(gid)
+    gid_t gid;
+{
+    struct group *gr;
+
+    if (grf != NULL)
+       rewind(grf);
+    else if ((grf = fopen(grfile, "r")) == NULL)
+       return(NULL);
+    while ((gr = ts_getgrent()) != NULL) {
+       if (gr->gr_gid == gid)
+           break;
+    }
+    if (!gr_stayopen) {
+       fclose(grf);
+       grf = NULL;
+    }
+    return(gr);
+}
index ae163cd592e68b56750f679adf08471cb0ee62de..6d260c4c8b14c8236bc05c5bfe258d76d8a411a8 100644 (file)
--- a/utimes.c
+++ b/utimes.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2004-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -20,7 +20,7 @@
 #include <sys/time.h>
 #include <stdio.h>
 #if TIME_WITH_SYS_TIME
-#include <time.h>
+# include <time.h>
 #endif
 
 #ifdef HAVE_UTIME_H
@@ -32,7 +32,7 @@
 #include <compat.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: utimes.c,v 1.8.2.3 2007/06/12 00:56:43 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: utimes.c,v 1.10 2008/11/09 14:13:12 millert Exp $";
 #endif /* lint */
 
 #ifndef HAVE_UTIMES
index c9459cc1957d3b2bc428f4a676ce91393866db36..fa354e09f4e89f87cd33a43acdddf5b3c4289b14 100644 (file)
--- a/version.h
+++ b/version.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1996, 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1996, 1998-2005, 2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * Agency (DARPA) and Air Force Research Laboratory, Air Force
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  *
- * $Sudo: version.h,v 1.66.2.20 2008/06/22 20:29:03 millert Exp $
+ * $Sudo: version.h,v 1.71 2008/11/09 14:13:12 millert Exp $
  */
 
 #ifndef _SUDO_VERSION_H
 #define _SUDO_VERSION_H
 
-static const char version[] = "1.6.9p17";
+static const char version[] = "1.7.0";
 
 #endif /* _SUDO_VERSION_H */
index 4fdcd8f46a3718e7ed255a5c9ad5e0c7f46b0c39..81b57185395c428ef107f351504466969ff1ac2f 100644 (file)
--- a/visudo.c
+++ b/visudo.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 1996, 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1996, 1998-2005, 2007-2008
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -33,6 +34,7 @@
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/stat.h>
+#include <sys/socket.h>
 #include <sys/time.h>
 #ifndef __TANDEM
 # include <sys/file.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_ERR_H
-# include <err.h>
-#else
-# include "emul/err.h"
-#endif /* HAVE_ERR_H */
 #include <ctype.h>
 #include <pwd.h>
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
+#include <grp.h>
 #include <signal.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#ifdef __STDC__
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
 #ifndef HAVE_TIMESPEC
 # include <emul/timespec.h>
 #endif
 
 #include "sudo.h"
+#include "interfaces.h"
+#include "parse.h"
+#include <gram.h>
 #include "version.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: visudo.c,v 1.166.2.11 2008/06/21 00:47:52 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: visudo.c,v 1.223 2008/11/22 15:12:26 millert Exp $";
 #endif /* lint */
 
 struct sudoersfile {
     char *path;
-    char *tpath;
     int fd;
-    off_t orig_size;
-    struct timespec orig_mtim;
+    char *tpath;
+    int tfd;
+    int modified;
+    struct sudoersfile *next;
 };
 
 /*
  * Function prototypes
  */
-static void usage              __P((void)) __attribute__((__noreturn__));
-static char whatnow            __P((void));
-static RETSIGTYPE Exit         __P((int));
-static void edit_sudoers       __P((struct sudoersfile *, char *, char *, int));
-static void visudo             __P((struct sudoersfile *, char *, char *));
-static void setup_signals      __P((void));
-static void install_sudoers    __P((struct sudoersfile *, int));
-static int check_syntax                __P(());
-static int run_command         __P((char *, char **));
+static RETSIGTYPE quit         __P((int));
 static char *get_args          __P((char *));
 static char *get_editor                __P((char **));
-static FILE *open_sudoers      __P((struct sudoersfile *));
-
-int command_matches            __P((char *, char *));
-int addr_matches               __P((char *));
-int hostname_matches           __P((char *, char *, char *));
-int netgr_matches              __P((char *, char *, char *, char *));
-int usergr_matches             __P((char *, char *, struct passwd *));
-int userpw_matches             __P((char *, char *, struct passwd *));
-void init_parser               __P((void));
-void yyerror                   __P((char *));
-void yyrestart                 __P((FILE *));
+static char whatnow            __P((void));
+static int check_aliases       __P((int));
+static int check_syntax                __P((char *, int, int));
+static int edit_sudoers                __P((struct sudoersfile *, char *, char *, int));
+static int install_sudoers     __P((struct sudoersfile *, int));
+static int print_unused                __P((void *, void *));
+static int reparse_sudoers     __P((char *, char *, int, int));
+static int run_command         __P((char *, char **));
+static void setup_signals      __P((void));
+static void usage              __P((void)) __attribute__((__noreturn__));
+
+extern void yyerror            __P((const char *));
+extern void yyrestart          __P((FILE *));
 
 /*
  * External globals exported by the parser
  */
 extern FILE *yyin;
-extern int errorlineno;
-extern int pedantic;
-extern int quiet;
-
+extern char *sudoers, *errorfile;
+extern int errorlineno, parse_error;
 /* For getopt(3) */
 extern char *optarg;
 extern int optind;
@@ -130,26 +132,28 @@ extern int optind;
 /*
  * Globals
  */
+int Argc;
 char **Argv;
+int num_interfaces;
+struct interface *interfaces;
 struct sudo_user sudo_user;
-int Argc, parse_error = FALSE;
-static struct sudoersfile sudoers;
+struct passwd *list_pw;
+static struct sudoerslist {
+    struct sudoersfile *first, *last;
+} sudoerslist;
 
 int
 main(argc, argv)
     int argc;
     char **argv;
 {
-    char *args, *editor;
-    int ch, checkonly, n, oldperms;
-
-    /* Initialize sudoers struct. */
-    sudoers.path = _PATH_SUDOERS;
-    sudoers.tpath = _PATH_SUDOERS_TMP;
-    sudoers.fd = -1;
-
-    /* Warn about aliases that are used before being defined. */
-    pedantic = 1;
+    struct sudoersfile *sp;
+    char *args, *editor, *sudoers_path;
+    int ch, checkonly, quiet, strict, oldperms;
+#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
+    extern char *malloc_options;
+    malloc_options = "AFGJPR";
+#endif
 
     Argv = argv;
     if ((Argc = argc) < 1)
@@ -158,7 +162,8 @@ main(argc, argv)
     /*
      * Arg handling.
      */
-    checkonly = oldperms = FALSE;
+    checkonly = oldperms = quiet = strict = FALSE;
+    sudoers_path = _PATH_SUDOERS;
     while ((ch = getopt(argc, argv, "Vcf:sq")) != -1) {
        switch (ch) {
            case 'V':
@@ -167,13 +172,12 @@ main(argc, argv)
            case 'c':
                checkonly++;            /* check mode */
                break;
-           case 'f':                   /* sudoers file path */
-               sudoers.path = optarg;
-               easprintf(&sudoers.tpath, "%s.tmp", optarg);
+           case 'f':
+               sudoers_path = optarg;  /* sudoers file path */
                oldperms = TRUE;
                break;
            case 's':
-               pedantic++;             /* strict mode */
+               strict++;               /* strict mode */
                break;
            case 'q':
                quiet++;                /* quiet mode */
@@ -187,59 +191,115 @@ main(argc, argv)
     if (argc)
        usage();
 
+    sudo_setpwent();
+    sudo_setgrent();
+
     /* Mock up a fake sudo_user struct. */
     user_host = user_shost = user_cmnd = "";
-    if ((sudo_user.pw = getpwuid(getuid())) == NULL)
-       errx(1, "you don't exist in the passwd database");
+    if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL)
+       errorx(1, "you don't exist in the passwd database");
 
     /* Setup defaults data structures. */
     init_defaults();
 
     if (checkonly)
-       exit(check_syntax());
+       exit(check_syntax(sudoers_path, quiet, strict));
 
     /*
-     * Open and parse the existing sudoers file(s) in quiet mode to highlight
-     * any existing errors and to pull in editor and env_editor conf values.
-     */  
-    if ((yyin = open_sudoers(&sudoers)) == NULL)
-       err(1, "%s", sudoers.path);
-    n = quiet;
-    quiet = 1;
-    init_parser();
+     * Parse the existing sudoers file(s) in quiet mode to highlight any
+     * existing errors and to pull in editor and env_editor conf values.
+     */
+    if ((yyin = open_sudoers(sudoers_path, NULL)) == NULL)
+       error(1, "%s", sudoers_path);
+    init_parser(sudoers_path, 0);
     yyparse();
-    parse_error = FALSE;
-    quiet = n;
+    (void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER);
 
-    /* Edit sudoers, check for parse errors and re-edit on failure. */
     editor = get_editor(&args);
-    visudo(&sudoers, editor, args);
 
-    /* Install the new sudoers file. */
-    install_sudoers(&sudoers, oldperms);
+    /* Install signal handlers to clean up temp files if we are killed. */
+    setup_signals();
+
+    /* Edit the sudoers file(s) */
+    tq_foreach_fwd(&sudoerslist, sp) {
+       if (sp != tq_first(&sudoerslist)) {
+           printf("press return to edit %s: ", sp->path);
+           while ((ch = getchar()) != EOF && ch != '\n')
+                   continue;
+       }
+       edit_sudoers(sp, editor, args, -1);
+    }
+
+    /* Check edited files for a parse error and re-edit any that fail. */
+    reparse_sudoers(editor, args, strict, quiet);
+
+    /* Install the sudoers temp files. */
+    tq_foreach_fwd(&sudoerslist, sp) {
+       if (!sp->modified)
+           (void) unlink(sp->tpath);
+       else
+           (void) install_sudoers(sp, oldperms);
+    }
 
     exit(0);
 }
 
 /*
- * Edit the sudoers file.
+ * Edit each sudoers file.
  * Returns TRUE on success, else FALSE.
  */
-static void
+static int
 edit_sudoers(sp, editor, args, lineno)
     struct sudoersfile *sp;
     char *editor, *args;
     int lineno;
 {
+    int tfd;                           /* sudoers temp file descriptor */
+    int modified;                      /* was the file modified? */
     int ac;                            /* argument count */
     char **av;                         /* argument vector for run_command */
     char *cp;                          /* scratch char pointer */
+    char buf[PATH_MAX*2];              /* buffer used for copying files */
     char linestr[64];                  /* string version of lineno */
     struct timespec ts1, ts2;          /* time before and after edit */
+    struct timespec orig_mtim;         /* starting mtime of sudoers file */
+    off_t orig_size;                   /* starting size of sudoers file */
+    ssize_t nread;                     /* number of bytes read */
     struct stat sb;                    /* stat buffer */
 
-    /* Make timestamp on temp file match original. */
-    (void) touch(-1, sp->tpath, &sp->orig_mtim);
+#ifdef HAVE_FSTAT
+    if (fstat(sp->fd, &sb) == -1)
+#else
+    if (stat(sp->path, &sb) == -1)
+#endif
+       error(1, "can't stat %s", sp->path);
+    orig_size = sb.st_size;
+    orig_mtim.tv_sec = mtim_getsec(sb);
+    orig_mtim.tv_nsec = mtim_getnsec(sb);
+
+    /* Create the temp file if needed and set timestamp. */
+    if (sp->tpath == NULL) {
+       easprintf(&sp->tpath, "%s.tmp", sp->path);
+       tfd = open(sp->tpath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+       if (tfd < 0)
+           error(1, "%s", sp->tpath);
+
+       /* Copy sp->path -> sp->tpath and reset the mtime. */
+       if (orig_size != 0) {
+           (void) lseek(sp->fd, (off_t)0, SEEK_SET);
+           while ((nread = read(sp->fd, buf, sizeof(buf))) > 0)
+               if (write(tfd, buf, nread) != nread)
+                   error(1, "write error");
+
+           /* Add missing newline at EOF if needed. */
+           if (nread > 0 && buf[nread - 1] != '\n') {
+               buf[0] = '\n';
+               write(tfd, buf, 1);
+           }
+       }
+       (void) close(tfd);
+    }
+    (void) touch(-1, sp->tpath, &orig_mtim);
 
     /* Find the length of the argument vector */
     ac = 3 + (lineno > 0);
@@ -288,24 +348,26 @@ edit_sudoers(sp, editor, args, lineno)
         * Sanity checks.
         */
        if (stat(sp->tpath, &sb) < 0) {
-           warnx("cannot stat temporary file (%s), %s unchanged",
+           warningx("cannot stat temporary file (%s), %s unchanged",
                sp->tpath, sp->path);
-           Exit(-1);
+           return(FALSE);
        }
-       if (sb.st_size == 0) {
-           warnx("zero length temporary file (%s), %s unchanged",
+       if (sb.st_size == 0 && orig_size != 0) {
+           warningx("zero length temporary file (%s), %s unchanged",
                sp->tpath, sp->path);
-           Exit(-1);
+           sp->modified = TRUE;
+           return(FALSE);
        }
     } else {
-       warnx("editor (%s) failed, %s unchanged", editor, sp->path);
-       Exit(-1);
+       warningx("editor (%s) failed, %s unchanged", editor, sp->path);
+       return(FALSE);
     }
 
-    /* Check to see if the user changed the file. */
-    if (sp->orig_size == sb.st_size &&
-       sp->orig_mtim.tv_sec == mtim_getsec(sb) &&
-       sp->orig_mtim.tv_nsec == mtim_getnsec(sb)) {
+    /* Set modified bit if use changed the file. */
+    modified = TRUE;
+    if (orig_size == sb.st_size &&
+       orig_mtim.tv_sec == mtim_getsec(sb) &&
+       orig_mtim.tv_nsec == mtim_getnsec(sb)) {
        /*
         * If mtime and size match but the user spent no measurable
         * time in the editor we can't tell if the file was changed.
@@ -315,55 +377,59 @@ edit_sudoers(sp, editor, args, lineno)
 #else
        timespecsub(&ts1, &ts2, &ts2);
 #endif
-       if (timespecisset(&ts2)) {
-           warnx("%s unchanged", sp->tpath);
-           Exit(0);
-       }
+       if (timespecisset(&ts2))
+           modified = FALSE;
     }
+
+    /*
+     * If modified in this edit session, mark as modified.
+     */
+    if (modified)
+       sp->modified = modified;
+    else
+       warningx("%s unchanged", sp->tpath);
+
+    return(TRUE);
 }
 
 /*
  * Parse sudoers after editing and re-edit any ones that caused a parse error.
  * Returns TRUE on success, else FALSE.
  */
-static void
-visudo(sp, editor, args)
-    struct sudoersfile *sp;
+static int
+reparse_sudoers(editor, args, strict, quiet)
     char *editor, *args;
+    int strict, quiet;
 {
+    struct sudoersfile *sp, *last;
+    FILE *fp;
     int ch;
 
     /*
-     * Parse the edited sudoers file and do sanity checking
+     * Parse the edited sudoers files and do sanity checking
      */
     do {
-       edit_sudoers(sp, editor, args, errorlineno);
-
-       yyin = fopen(sp->tpath, "r+");
-       if (yyin == NULL) {
-           warnx("can't re-open temporary file (%s), %s unchanged.",
+       sp = tq_first(&sudoerslist);
+       last = tq_last(&sudoerslist);
+       fp = fopen(sp->tpath, "r+");
+       if (fp == NULL)
+           errorx(1, "can't re-open temporary file (%s), %s unchanged.",
                sp->tpath, sp->path);
-           Exit(-1);
-       }
-
-       /* Add missing newline at EOF if needed. */
-       if (fseek(yyin, -1, SEEK_END) == 0 && (ch = fgetc(yyin)) != '\n')
-           fputc('\n', yyin);
-       rewind(yyin);
 
        /* Clean slate for each parse */
-       user_runas = NULL;
        init_defaults();
-       init_parser();
+       init_parser(sp->path, quiet);
 
        /* Parse the sudoers temp file */
-       yyrestart(yyin);
+       yyrestart(fp);
        if (yyparse() && parse_error != TRUE) {
-           warnx("unabled to parse temporary file (%s), unknown error",
+           warningx("unabled to parse temporary file (%s), unknown error",
                sp->tpath);
            parse_error = TRUE;
        }
        fclose(yyin);
+       if (check_aliases(strict) != 0)
+           parse_error = TRUE;
 
        /*
         * Got an error, prompt the user for what to do now
@@ -372,18 +438,40 @@ visudo(sp, editor, args)
            switch (whatnow()) {
                case 'Q' :      parse_error = FALSE;    /* ignore parse error */
                                break;
-               case 'x' :      Exit(0);
+               case 'x' :      cleanup(0);
+                               exit(0);
                                break;
            }
        }
+       if (parse_error) {
+           /* Edit file with the parse error */
+           tq_foreach_fwd(&sudoerslist, sp) {
+               if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) {
+                   edit_sudoers(sp, editor, args, errorlineno);
+                   break;
+               }
+           }
+           if (sp == NULL)
+               errorx(1, "internal error, can't find %s in list!", sudoers);
+       }
+
+       /* If any new #include directives were added, edit them too. */
+       for (sp = last->next; sp != NULL; sp = sp->next) {
+           printf("press return to edit %s: ", sp->path);
+           while ((ch = getchar()) != EOF && ch != '\n')
+                   continue;
+           edit_sudoers(sp, editor, args, errorlineno);
+       }
     } while (parse_error);
+
+    return(TRUE);
 }
 
 /*
  * Set the owner and mode on a sudoers temp file and
  * move it into place.  Returns TRUE on success, else FALSE.
  */
-static void
+static int
 install_sudoers(sp, oldperms)
     struct sudoersfile *sp;
     int oldperms;
@@ -401,18 +489,19 @@ install_sudoers(sp, oldperms)
 #else
        if (stat(sp->path, &sb) == -1)
 #endif
-           err(1, "can't stat %s", sp->path);
+           error(1, "can't stat %s", sp->path);
        (void) chown(sp->tpath, sb.st_uid, sb.st_gid);
        (void) chmod(sp->tpath, sb.st_mode & 0777);
     } else {
        if (chown(sp->tpath, SUDOERS_UID, SUDOERS_GID) != 0) {
-           warn("unable to set (uid, gid) of %s to (%d, %d)",
+           warning("unable to set (uid, gid) of %s to (%d, %d)",
                sp->tpath, SUDOERS_UID, SUDOERS_GID);
-           Exit(-1);
+           return(FALSE);
        }
        if (chmod(sp->tpath, SUDOERS_MODE) != 0) {
-           warn("unable to change mode of %s to 0%o", sp->tpath, SUDOERS_MODE);
-           Exit(-1);
+           warning("unable to change mode of %s to 0%o", sp->tpath,
+               SUDOERS_MODE);
+           return(FALSE);
        }
     }
 
@@ -421,10 +510,13 @@ install_sudoers(sp, oldperms)
      * rename(2)'d to sp->path.  If the rename(2) fails we try using
      * mv(1) in case sp->tpath and sp->path are on different file systems.
      */
-    if (rename(sp->tpath, sp->path) != 0) {
+    if (rename(sp->tpath, sp->path) == 0) {
+       efree(sp->tpath);
+       sp->tpath = NULL;
+    } else {
        if (errno == EXDEV) {
            char *av[4];
-           warnx("%s and %s not on the same file system, using mv to rename",
+           warningx("%s and %s not on the same file system, using mv to rename",
              sp->tpath, sp->path);
 
            /* Build up argument vector for the command */
@@ -438,98 +530,64 @@ install_sudoers(sp, oldperms)
 
            /* And run it... */
            if (run_command(_PATH_MV, av)) {
-               warnx("command failed: '%s %s %s', %s unchanged",
+               warningx("command failed: '%s %s %s', %s unchanged",
                    _PATH_MV, sp->tpath, sp->path, sp->path);
-               Exit(-1);
+               (void) unlink(sp->tpath);
+               efree(sp->tpath);
+               sp->tpath = NULL;
+               return(FALSE);
            }
+           efree(sp->tpath);
+           sp->tpath = NULL;
        } else {
-           warn("error renaming %s, %s unchanged", sp->tpath, sp->path);
-           Exit(-1);
+           warning("error renaming %s, %s unchanged", sp->tpath, sp->path);
+           (void) unlink(sp->tpath);
+           return(FALSE);
        }
     }
-}
-
-/*
- * Dummy *_matches routines.
- * These exist to allow us to use the same parser as sudo(8).
- */
-int
-command_matches(path, sudoers_args)
-    char *path;
-    char *sudoers_args;
-{
-    return(TRUE);
-}
-
-int
-addr_matches(n)
-    char *n;
-{
     return(TRUE);
 }
 
-int
-hostname_matches(s, l, p)
-    char *s, *l, *p;
-{
-    return(TRUE);
-}
-
-int
-usergr_matches(g, u, pw)
-    char *g, *u;
-    struct passwd *pw;
+/* STUB */
+void
+set_fqdn()
 {
-    return(TRUE);
+    return;
 }
 
-int
-userpw_matches(s, u, pw)
-    char *s, *u;
-    struct passwd *pw;
+/* STUB */
+void
+init_envtables()
 {
-    return(TRUE);
+    return;
 }
 
+/* STUB */
 int
-netgr_matches(n, h, sh, u)
-    char *n, *h, *sh, *u;
+user_is_exempt()
 {
-    return(TRUE);
+    return(FALSE);
 }
 
+/* STUB */
 void
-set_fqdn()
+sudo_setspent()
 {
     return;
 }
 
-int
-set_runaspw(user)
-    char *user;
-{
-    extern int sudolineno, used_runas;
-
-    if (used_runas) {
-       (void) fprintf(stderr,
-           "%s: runas_default set after old value is in use near line %d\n",
-           pedantic > 1 ? "Error" : "Warning", sudolineno);
-       if (pedantic > 1)
-           yyerror(NULL);
-    }
-    return(TRUE);
-}
-
-int
-user_is_exempt()
+/* STUB */
+void
+sudo_endspent()
 {
-    return(TRUE);
+    return;
 }
 
-void
-init_envtables()
+char *
+sudo_getepw(pw)
+    const struct passwd *pw;
 {
-    return;
+    return (pw->pw_passwd);
 }
 
 /*
@@ -575,9 +633,10 @@ setup_signals()
        /*
         * Setup signal handlers to cleanup nicely.
         */
+       zero_bytes(&sa, sizeof(sa));
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = SA_RESTART;
-       sa.sa_handler = Exit;
+       sa.sa_handler = quit;
        (void) sigaction(SIGTERM, &sa, NULL);
        (void) sigaction(SIGHUP, &sa, NULL);
        (void) sigaction(SIGINT, &sa, NULL);
@@ -594,14 +653,14 @@ run_command(path, argv)
 
     switch (pid = fork()) {
        case -1:
-           warn("unable to run %s", path);
-           Exit(-1);
+           error(1, "unable to run %s", path);
            break;      /* NOTREACHED */
        case 0:
-           endpwent();
+           sudo_endpwent();
+           sudo_endgrent();
            closefrom(STDERR_FILENO + 1);
            execv(path, argv);
-           warn("unable to run %s", path);
+           warning("unable to run %s", path);
            _exit(127);
            break;      /* NOTREACHED */
     }
@@ -620,86 +679,111 @@ run_command(path, argv)
 }
 
 static int
-check_syntax()
+check_syntax(sudoers_path, quiet, strict)
+    char *sudoers_path;
+    int quiet;
+    int strict;
 {
+    struct stat sb;
+    int error;
 
-    if ((yyin = fopen(sudoers.path, "r")) == NULL) {
+    if ((yyin = fopen(sudoers_path, "r")) == NULL) {
        if (!quiet)
-           warn("unable to open %s", sudoers.path);
+           warning("unable to open %s", sudoers_path);
        exit(1);
     }
-    init_parser();
+    init_parser(sudoers_path, quiet);
     if (yyparse() && parse_error != TRUE) {
        if (!quiet)
-           warnx("failed to parse %s file, unknown error", sudoers.path);
+           warningx("failed to parse %s file, unknown error", sudoers_path);
        parse_error = TRUE;
     }
-    if (!quiet){
+    error = parse_error;
+    if (!quiet) {
        if (parse_error)
-           (void) printf("parse error in %s near line %d\n", sudoers.path,
+           (void) printf("parse error in %s near line %d\n", sudoers_path,
                errorlineno);
        else
-           (void) printf("%s file parsed OK\n", sudoers.path);
+           (void) printf("%s: parsed OK\n", sudoers_path);
     }
-
-    return(parse_error == TRUE);
-}
-
-static FILE *
-open_sudoers(sp)
-    struct sudoersfile *sp;
-{
-    struct stat sb;
-    ssize_t nread;
-    FILE *fp;
-    char buf[PATH_MAX*2];
-    int tfd;
-
-    /* Open and lock sudoers. */
-    sp->fd = open(sp->path, O_RDWR | O_CREAT, SUDOERS_MODE);
-    if (sp->fd == -1)
-       err(1, "%s", sp->path);
-    if (!lock_file(sp->fd, SUDO_TLOCK))
-       errx(1, "%s busy, try again later", sp->path);
-    if ((fp = fdopen(sp->fd, "r")) == NULL)
-       err(1, "%s", sp->path);
-
-    /* Stash sudoers size and mtime. */
+    /* Check mode and owner in strict mode. */
 #ifdef HAVE_FSTAT
-    if (fstat(sp->fd, &sb) == -1)
+    if (strict && fstat(fileno(yyin), &sb) == 0)
 #else
-    if (stat(sp->path, &sb) == -1)
+    if (strict && stat(sudoers_path, &sb) == 0)
 #endif
-       err(1, "can't stat %s", sp->path);
-    sp->orig_size = sb.st_size;
-    sp->orig_mtim.tv_sec = mtim_getsec(sb);
-    sp->orig_mtim.tv_nsec = mtim_getnsec(sb);
-
-    /* Create the temp file. */
-    tfd = open(sp->tpath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
-    if (tfd < 0)
-       err(1, "%s", sp->tpath);
+    {
+       if (sb.st_uid != SUDOERS_UID || sb.st_gid != SUDOERS_GID) {
+           error = TRUE;
+           if (!quiet) {
+               fprintf(stderr, "%s: wrong owner (uid, gid) should be (%d, %d)\n",
+                   sudoers_path, SUDOERS_UID, SUDOERS_GID);
+               }
+       }
+       if ((sb.st_mode & 07777) != SUDOERS_MODE) {
+           error = TRUE;
+           if (!quiet) {
+               fprintf(stderr, "%s: bad permissions, should be mode 0%o\n",
+                   sudoers_path, SUDOERS_MODE);
+           }
+       }
+    }
 
-    /* Install signal handlers to clean up temp file if we are killed. */
-    setup_signals();
+    return(error);
+}
 
-    /* Copy sp->path -> sp->tpath. */
-    if (sp->orig_size != 0) {
-       while ((nread = read(sp->fd, buf, sizeof(buf))) > 0)
-           if (write(tfd, buf, nread) != nread) {
-               warn("write error");
-               Exit(-1);
-           }
+/*
+ * Used to open (and lock) the initial sudoers file and to also open
+ * any subsequent files #included via a callback from the parser.
+ */
+FILE *
+open_sudoers(path, keepopen)
+    const char *path;
+    int *keepopen;
+{
+    struct sudoersfile *entry;
+    FILE *fp;
 
-       /* Add missing newline at EOF if needed. */
-       if (nread > 0 && buf[nread - 1] != '\n') {
-           buf[0] = '\n';
-           write(tfd, buf, 1);
+    /* Check for existing entry */
+    tq_foreach_fwd(&sudoerslist, entry) {
+       if (strcmp(path, entry->path) == 0)
+           break;
+    }
+    if (entry == NULL) {
+       entry = emalloc(sizeof(*entry));
+       entry->path = estrdup(path);
+       entry->modified = 0;
+       entry->next = NULL;
+       entry->fd = open(entry->path, O_RDWR | O_CREAT, SUDOERS_MODE);
+       entry->tpath = NULL;
+       if (entry->fd == -1) {
+           warning("%s", entry->path);
+           efree(entry);
+           return(NULL);
+       }
+       if (!lock_file(entry->fd, SUDO_TLOCK))
+           errorx(1, "%s busy, try again later", entry->path);
+       if ((fp = fdopen(entry->fd, "r")) == NULL)
+           error(1, "%s", entry->path);
+       /* XXX - macro here? */
+       if (sudoerslist.last == NULL)
+           sudoerslist.first = sudoerslist.last = entry;
+       else {
+           sudoerslist.last->next = entry;
+           sudoerslist.last = entry;
+       }
+       if (keepopen != NULL)
+           *keepopen = TRUE;
+    } else {
+       /* Already exists, open .tmp version if there is one. */
+       if (entry->tpath != NULL) {
+           if ((fp = fopen(entry->tpath, "r")) == NULL)
+               error(1, "%s", entry->tpath);
+       } else {
+           if ((fp = fdopen(entry->fd, "r")) == NULL)
+               error(1, "%s", entry->path);
        }
     }
-    (void) close(tfd);
-    rewind(fp);
-
     return(fp);
 }
 
@@ -727,8 +811,7 @@ get_editor(args)
        } else {
            if (def_env_editor) {
                /* If we are honoring $EDITOR this is a fatal error. */
-               warnx("specified editor (%s) doesn't exist!", UserEditor);
-               Exit(-1);
+               errorx(1, "specified editor (%s) doesn't exist!", UserEditor);
            } else {
                /* Otherwise, just ignore $EDITOR. */
                UserEditor = NULL;
@@ -751,8 +834,7 @@ get_editor(args)
 
        if (stat(UserEditor, &user_editor_sb) != 0) {
            /* Should never happen since we already checked above. */
-           warn("unable to stat editor (%s)", UserEditor);
-           Exit(-1);
+           error(1, "unable to stat editor (%s)", UserEditor);
        }
        EditorPath = estrdup(def_editor);
        Editor = strtok(EditorPath, ":");
@@ -799,10 +881,8 @@ get_editor(args)
        } while ((Editor = strtok(NULL, ":")));
 
        /* Bleah, none of the editors existed! */
-       if (Editor == NULL || *Editor == '\0') {
-           warnx("no editor found (editor path = %s)", def_editor);
-           Exit(-1);
-       }
+       if (Editor == NULL || *Editor == '\0')
+           errorx(1, "no editor found (editor path = %s)", def_editor);
     }
     *args = EditorArgs;
     return(Editor);
@@ -829,24 +909,165 @@ get_args(cmnd)
 }
 
 /*
- * Unlink the sudoers temp file (if it exists) and exit.
- * Used in place of a normal exit() and as a signal handler.
- * A positive parameter indicates we were called as a signal handler.
+ * Iterate through the sudoers datastructures looking for undefined
+ * aliases or unused aliases.
  */
-static RETSIGTYPE
-Exit(sig)
-    int sig;
+static int
+check_aliases(strict)
+    int strict;
 {
-#define        emsg     " exiting due to signal.\n"
+    struct cmndspec *cs;
+    struct member *m, *binding;
+    struct privilege *priv;
+    struct userspec *us;
+    struct defaults *d;
+    int atype, error = 0;
+
+    /* Forward check. */
+    tq_foreach_fwd(&userspecs, us) {
+       tq_foreach_fwd(&us->users, m) {
+           if (m->type == ALIAS) {
+               alias_seqno++;
+               if (find_alias(m->name, USERALIAS) == NULL) {
+                   warningx("%s: User_Alias `%s' referenced but not defined",
+                       strict ? "Error" : "Warning", m->name);
+                   error++;
+               }
+           }
+       }
+       tq_foreach_fwd(&us->privileges, priv) {
+           tq_foreach_fwd(&priv->hostlist, m) {
+               if (m->type == ALIAS) {
+                   alias_seqno++;
+                   if (find_alias(m->name, HOSTALIAS) == NULL) {
+                       warningx("%s: Host_Alias `%s' referenced but not defined",
+                           strict ? "Error" : "Warning", m->name);
+                       error++;
+                   }
+               }
+           }
+           tq_foreach_fwd(&priv->cmndlist, cs) {
+               tq_foreach_fwd(&cs->runasuserlist, m) {
+                   if (m->type == ALIAS) {
+                       alias_seqno++;
+                       if (find_alias(m->name, RUNASALIAS) == NULL) {
+                           warningx("%s: Runas_Alias `%s' referenced but not defined",
+                               strict ? "Error" : "Warning", m->name);
+                           error++;
+                       }
+                   }
+               }
+               if ((m = cs->cmnd)->type == ALIAS) {
+                   alias_seqno++;
+                   if (find_alias(m->name, CMNDALIAS) == NULL) {
+                       warningx("%s: Cmnd_Alias `%s' referenced but not defined",
+                           strict ? "Error" : "Warning", m->name);
+                       error++;
+                   }
+               }
+           }
+       }
+    }
 
-    (void) unlink(sudoers.tpath);
+    /* Reverse check (destructive) */
+    tq_foreach_fwd(&userspecs, us) {
+       tq_foreach_fwd(&us->users, m) {
+           if (m->type == ALIAS)
+               (void) alias_remove(m->name, USERALIAS);
+       }
+       tq_foreach_fwd(&us->privileges, priv) {
+           tq_foreach_fwd(&priv->hostlist, m) {
+               if (m->type == ALIAS)
+                   (void) alias_remove(m->name, HOSTALIAS);
+           }
+           tq_foreach_fwd(&priv->cmndlist, cs) {
+               tq_foreach_fwd(&cs->runasuserlist, m) {
+                   if (m->type == ALIAS)
+                       (void) alias_remove(m->name, RUNASALIAS);
+               }
+               if ((m = cs->cmnd)->type == ALIAS)
+                   (void) alias_remove(m->name, CMNDALIAS);
+           }
+       }
+    }
+    tq_foreach_fwd(&defaults, d) {
+       switch (d->type) {
+           case DEFAULTS_HOST:
+               atype = HOSTALIAS;
+               break;
+           case DEFAULTS_USER:
+               atype = USERALIAS;
+               break;
+           case DEFAULTS_RUNAS:
+               atype = RUNASALIAS;
+               break;
+           case DEFAULTS_CMND:
+               atype = CMNDALIAS;
+               break;
+           default:
+               continue; /* not an alias */
+       }
+       tq_foreach_fwd(&d->binding, binding) {
+           for (m = binding; m != NULL; m = m->next) {
+               if (m->type == ALIAS)
+                   (void) alias_remove(m->name, atype);
+           }
+       }
+    }
+
+    /* If all aliases were referenced we will have an empty tree. */
+    if (no_aliases())
+       return(0);
+    alias_apply(print_unused, strict ? "Error" : "Warning");
+    return (strict ? 1 : 0);
+}
+
+static int
+print_unused(v1, v2)
+    void *v1;
+    void *v2;
+{
+    struct alias *a = (struct alias *)v1;
+    char *prefix = (char *)v2;
+
+    warningx("%s: unused %s_Alias %s", prefix,
+       a->type == HOSTALIAS ? "Host" : a->type == CMNDALIAS ? "Cmnd" :
+       a->type == USERALIAS ? "User" : a->type == RUNASALIAS ? "Runas" :
+       "Unknown", a->name);
+    return(0);
+}
 
-    if (sig > 0) {
-       write(STDERR_FILENO, getprogname(), strlen(getprogname()));
-       write(STDERR_FILENO, emsg, sizeof(emsg) - 1);
-       _exit(sig);
+/*
+ * Unlink any sudoers temp files that remain.
+ */
+void
+cleanup(gotsignal)
+    int gotsignal;
+{
+    struct sudoersfile *sp;
+
+    tq_foreach_fwd(&sudoerslist, sp) {
+       if (sp->tpath != NULL)
+           (void) unlink(sp->tpath);
     }
-    exit(-sig);
+    if (!gotsignal) {
+       sudo_endpwent();
+       sudo_endgrent();
+    }
+}
+
+/*
+ * Unlink sudoers temp files (if any) and exit.
+ */
+static RETSIGTYPE
+quit(signo)
+    int signo;
+{
+    cleanup(signo);
+#define        emsg     " exiting due to signal.\n"
+    write(STDERR_FILENO, getprogname(), strlen(getprogname()));
+    write(STDERR_FILENO, emsg, sizeof(emsg) - 1);
+    _exit(signo);
 }
 
 static void
index 7eed3c7bd0fd533448d95700df0053673f2f963d..74be714137619a02b331fa7eddbfc8b1df8d813f 100644 (file)
@@ -11,96 +11,91 @@ S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS
        v\bvi\bis\bsu\bud\bdo\bo [-\b-c\bc] [-\b-q\bq] [-\b-s\bs] [-\b-V\bV] [-\b-f\bf _\bs_\bu_\bd_\bo_\be_\br_\bs]
 
 D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
-       v\bvi\bis\bsu\bud\bdo\bo edits the _\bs_\bu_\bd_\bo_\be_\br_\bs file in a safe fashion, analogous
-       to _\bv_\bi_\bp_\bw(1m).  v\bvi\bis\bsu\bud\bdo\bo locks the _\bs_\bu_\bd_\bo_\be_\br_\bs file against multi­
-       ple simultaneous edits, provides basic sanity checks, and
-       checks for parse errors.  If the _\bs_\bu_\bd_\bo_\be_\br_\bs file is currently
-       being edited you will receive a message to try again
-       later.
-
-       There is a hard-coded list of editors that v\bvi\bis\bsu\bud\bdo\bo will use
-       set at compile-time that may be overridden via the _\be_\bd_\bi_\bt_\bo_\br
-       _\bs_\bu_\bd_\bo_\be_\br_\bs Default variable.  This list defaults to the path
-       to _\bv_\bi(1) on your system, as determined by the _\bc_\bo_\bn_\bf_\bi_\bg_\bu_\br_\be
-       script.  Normally, v\bvi\bis\bsu\bud\bdo\bo does not honor the VISUAL or
-       EDITOR environment variables unless they contain an editor
-       in the aforementioned editors list.  However, if v\bvi\bis\bsu\bud\bdo\bo is
-       configured with the _\b-_\b-_\bw_\bi_\bt_\bh_\b-_\be_\bn_\bv_\be_\bd_\bi_\bt_\bo_\br flag or the _\be_\bn_\bv_\b__\be_\bd_\bi_\b­
-       _\bt_\bo_\br Default variable is set in _\bs_\bu_\bd_\bo_\be_\br_\bs, v\bvi\bis\bsu\bud\bdo\bo will use
-       any the editor defines by VISUAL or EDITOR.  Note that
-       this can be a security hole since it allows the user to
-       execute any program they wish simply by setting VISUAL or
-       EDITOR.
-
-       v\bvi\bis\bsu\bud\bdo\bo parses the _\bs_\bu_\bd_\bo_\be_\br_\bs file after the edit and will not
-       save the changes if there is a syntax error.  Upon finding
-       an error, v\bvi\bis\bsu\bud\bdo\bo will print a message stating the line
-       number(s) where the error occurred and the user will
-       receive the "What now?" prompt.  At this point the user
-       may enter "e" to re-edit the _\bs_\bu_\bd_\bo_\be_\br_\bs file, "x" to exit
-       without saving the changes, or "Q" to quit and save
-       changes.  The "Q" option should be used with extreme care
-       because if v\bvi\bis\bsu\bud\bdo\bo believes there to be a parse error, so
-       will s\bsu\bud\bdo\bo and no one will be able to s\bsu\bud\bdo\bo again until the
-       error is fixed.  If "e" is typed to edit the  _\bs_\bu_\bd_\bo_\be_\br_\bs file
-       after a parse error has been detected, the cursor will be
-       placed on the line where the error occurred (if the editor
-       supports this feature).
+       v\bvi\bis\bsu\bud\bdo\bo edits the _\bs_\bu_\bd_\bo_\be_\br_\bs file in a safe fashion, analogous to _\bv_\bi_\bp_\bw(1m).
+       v\bvi\bis\bsu\bud\bdo\bo locks the _\bs_\bu_\bd_\bo_\be_\br_\bs file against multiple simultaneous edits,
+       provides basic sanity checks, and checks for parse errors.  If the
+       _\bs_\bu_\bd_\bo_\be_\br_\bs file is currently being edited you will receive a message to
+       try again later.
+
+       There is a hard-coded list of editors that v\bvi\bis\bsu\bud\bdo\bo will use set at
+       compile-time that may be overridden via the _\be_\bd_\bi_\bt_\bo_\br _\bs_\bu_\bd_\bo_\be_\br_\bs Default
+       variable.  This list defaults to the path to _\bv_\bi(1) on your system, as
+       determined by the _\bc_\bo_\bn_\bf_\bi_\bg_\bu_\br_\be script.  Normally, v\bvi\bis\bsu\bud\bdo\bo does not honor
+       the VISUAL or EDITOR environment variables unless they contain an
+       editor in the aforementioned editors list.  However, if v\bvi\bis\bsu\bud\bdo\bo is
+       configured with the _\b-_\b-_\bw_\bi_\bt_\bh_\b-_\be_\bn_\bv_\be_\bd_\bi_\bt_\bo_\br option or the _\be_\bn_\bv_\b__\be_\bd_\bi_\bt_\bo_\br Default
+       variable is set in _\bs_\bu_\bd_\bo_\be_\br_\bs, v\bvi\bis\bsu\bud\bdo\bo will use any the editor defines by
+       VISUAL or EDITOR.  Note that this can be a security hole since it
+       allows the user to execute any program they wish simply by setting
+       VISUAL or EDITOR.
+
+       v\bvi\bis\bsu\bud\bdo\bo parses the _\bs_\bu_\bd_\bo_\be_\br_\bs file after the edit and will not save the
+       changes if there is a syntax error.  Upon finding an error, v\bvi\bis\bsu\bud\bdo\bo will
+       print a message stating the line number(s) where the error occurred and
+       the user will receive the "What now?" prompt.  At this point the user
+       may enter "e" to re-edit the _\bs_\bu_\bd_\bo_\be_\br_\bs file, "x" to exit without saving
+       the changes, or "Q" to quit and save changes.  The "Q" option should be
+       used with extreme care because if v\bvi\bis\bsu\bud\bdo\bo believes there to be a parse
+       error, so will s\bsu\bud\bdo\bo and no one will be able to s\bsu\bud\bdo\bo again until the
+       error is fixed.  If "e" is typed to edit the  _\bs_\bu_\bd_\bo_\be_\br_\bs file after a
+       parse error has been detected, the cursor will be placed on the line
+       where the error occurred (if the editor supports this feature).
 
 O\bOP\bPT\bTI\bIO\bON\bNS\bS
        v\bvi\bis\bsu\bud\bdo\bo accepts the following command line options:
 
-       -c  Enable c\bch\bhe\bec\bck\bk-\b-o\bon\bnl\bly\by mode.  The existing _\bs_\bu_\bd_\bo_\be_\br_\bs file
-           will be checked for syntax and a message will be
-           printed to the standard output detailing the status of
-           _\bs_\bu_\bd_\bo_\be_\br_\bs.  If the syntax check completes successfully,
-           v\bvi\bis\bsu\bud\bdo\bo will exit with a value of 0.  If a syntax error
-           is encountered, v\bvi\bis\bsu\bud\bdo\bo will exit with a value of 1.
+       -c          Enable c\bch\bhe\bec\bck\bk-\b-o\bon\bnl\bly\by mode.  The existing _\bs_\bu_\bd_\bo_\be_\br_\bs file will be
+                   checked for syntax and a message will be printed to the
+                   standard output detailing the status of _\bs_\bu_\bd_\bo_\be_\br_\bs.  If the
+                   syntax check completes successfully, v\bvi\bis\bsu\bud\bdo\bo will exit with
+                   a value of 0.  If a syntax error is encountered, v\bvi\bis\bsu\bud\bdo\bo
+                   will exit with a value of 1.
 
-       -f  Specify and alternate _\bs_\bu_\bd_\bo_\be_\br_\bs file location.  With
+       -f _\bs_\bu_\bd_\bo_\be_\br_\bs  Specify and alternate _\bs_\bu_\bd_\bo_\be_\br_\bs file location.  With this
+                   option v\bvi\bis\bsu\bud\bdo\bo will edit (or check) the _\bs_\bu_\bd_\bo_\be_\br_\bs file of your
+                   choice, instead of the default, _\b@_\bs_\by_\bs_\bc_\bo_\bn_\bf_\bd_\bi_\br_\b@_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs.  The
+                   lock file used is the specified _\bs_\bu_\bd_\bo_\be_\br_\bs file with ".tmp"
+                   appended to it.
 
+       -q          Enable q\bqu\bui\bie\bet\bt mode.  In this mode details about syntax
 
 
-1.6.9p17                   Jun 21, 2008                         1
 
+1.7.0                   November 15, 2008                       1
 
 
 
 
-VISUDO(1m)             MAINTENANCE COMMANDS            VISUDO(1m)
 
+VISUDO(1m)             MAINTENANCE COMMANDS            VISUDO(1m)
 
-           this option v\bvi\bis\bsu\bud\bdo\bo will edit (or check) the _\bs_\bu_\bd_\bo_\be_\br_\bs
-           file of your choice, instead of the default,
-           _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs.  The lock file used is the specified
-           _\bs_\bu_\bd_\bo_\be_\br_\bs file with ".tmp" appended to it.
 
-       -q  Enable q\bqu\bui\bie\bet\bt mode.  In this mode details about syntax
-           errors are not printed.  This option is only useful
-           when combined with the -\b-c\bc flag.
+                   errors are not printed.  This option is only useful when
+                   combined with the -\b-c\bc option.
 
-       -s  Enable s\bst\btr\bri\bic\bct\bt checking of the _\bs_\bu_\bd_\bo_\be_\br_\bs file.  If an
-           alias is used before it is defined, v\bvi\bis\bsu\bud\bdo\bo will con­
-           sider this a parse error.  Note that it is not possi­
-           ble to differentiate between an alias and a hostname
-           or username that consists solely of uppercase letters,
-           digits, and the underscore ('_') character.
+       -s          Enable s\bst\btr\bri\bic\bct\bt checking of the _\bs_\bu_\bd_\bo_\be_\br_\bs file.  If an alias is
+                   used before it is defined, v\bvi\bis\bsu\bud\bdo\bo will consider this a
+                   parse error.  Note that it is not possible to differentiate
+                   between an alias and a hostname or username that consists
+                   solely of uppercase letters, digits, and the underscore
+                   ('_') character.
 
-       -V  The -\b-V\bV (version) option causes v\bvi\bis\bsu\bud\bdo\bo to print its
-           version number and exit.
+       -V          The -\b-V\bV (version) option causes v\bvi\bis\bsu\bud\bdo\bo to print its version
+                   number and exit.
 
 E\bEN\bNV\bVI\bIR\bRO\bON\bNM\bME\bEN\bNT\bT
-       The following environment variables are used only if
-       v\bvi\bis\bsu\bud\bdo\bo was configured with the _\b-_\b-_\bw_\bi_\bt_\bh_\b-_\be_\bn_\bv_\b-_\be_\bd_\bi_\bt_\bo_\br option:
+       The following environment variables may be consulted depending on the
+       value of the _\be_\bd_\bi_\bt_\bo_\br and _\be_\bn_\bv_\b__\be_\bd_\bi_\bt_\bo_\br _\bs_\bu_\bd_\bo_\be_\br_\bs variables:
 
        VISUAL          Invoked by visudo as the editor to use
 
        EDITOR          Used by visudo if VISUAL is not set
 
 F\bFI\bIL\bLE\bES\bS
-       _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs            List of who can run what
+       _\b@_\bs_\by_\bs_\bc_\bo_\bn_\bf_\bd_\bi_\br_\b@_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs    List of who can run what
 
-       _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bt_\bm_\bp        Lock file for visudo
+       _\b@_\bs_\by_\bs_\bc_\bo_\bn_\bf_\bd_\bi_\br_\b@_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bt_\bm_\bp
+                               Lock file for visudo
 
 D\bDI\bIA\bAG\bGN\bNO\bOS\bST\bTI\bIC\bCS\bS
        sudoers file busy, try again later.
@@ -112,45 +107,38 @@ D\bDI\bIA\bAG\bGN\bNO\bOS\bST\bTI\bIC\bCS\bS
        Can't find you in the passwd database
            Your userid does not appear in the system passwd file.
 
-       Warning: undeclared Alias referenced near ...
-           Either you are using a {User,Runas,Host,Cmnd}_Alias
-           before defining it or you have a user or hostname
-           listed that consists solely of uppercase letters, dig­
-           its, and the underscore ('_') character.  If the lat­
-           ter, you can ignore the warnings (s\bsu\bud\bdo\bo will not com­
-           plain).  In -\b-s\bs (strict) mode these are errors, not
-           warnings.
+       Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined
+           Either you are trying to use an undeclare
+           {User,Runas,Host,Cmnd}_Alias or you have a user or hostname listed
+           that consists solely of uppercase letters, digits, and the
+           underscore ('_') character.  In the latter case, you can ignore the
+           warnings (s\bsu\bud\bdo\bo will not complain).  In -\b-s\bs (strict) mode these are
+           errors, not warnings.
 
-       Warning: runas_default set after old value is in use ...
-           You have a _\br_\bu_\bn_\ba_\bs_\b__\bd_\be_\bf_\ba_\bu_\bl_\bt Defaults setting listed in
-           the _\bs_\bu_\bd_\bo_\be_\br_\bs file after its value has already been
+       Warning: unused {User,Runas,Host,Cmnd}_Alias
+           The specified {User,Runas,Host,Cmnd}_Alias was defined but never
+           used.  You may wish to comment out or remove the unused alias.  In
+           -\b-s\bs (strict) mode this is an error, not a warning.
 
+S\bSE\bEE\bE A\bAL\bLS\bSO\bO
+       _\bv_\bi(1), _\bs_\bu_\bd_\bo_\be_\br_\bs(4), _\bs_\bu_\bd_\bo(1m), _\bv_\bi_\bp_\bw(8)
 
 
-1.6.9p17                   Jun 21, 2008                         2
 
 
 
+1.7.0                   November 15, 2008                       2
 
 
-VISUDO(1m)             MAINTENANCE COMMANDS            VISUDO(1m)
 
 
-           used.  This means that entries prior to the
-           _\br_\bu_\bn_\ba_\bs_\b__\bd_\be_\bf_\ba_\bu_\bl_\bt setting will match based on the default
-           value of _\br_\bu_\bn_\ba_\bs_\b__\bd_\be_\bf_\ba_\bu_\bl_\bt (root) whereas entries a\baf\bft\bte\ber\br
-           the _\br_\bu_\bn_\ba_\bs_\b__\bd_\be_\bf_\ba_\bu_\bl_\bt setting will match based on the new
-           value.  This is usually unintentional and in most
-           cases the <runas_default> setting should be placed
-           before any Runas_Alias or User specifications.  In -\b-s\bs
-           (strict) mode this is an error, not a warning.
 
-S\bSE\bEE\bE A\bAL\bLS\bSO\bO
-       _\bv_\bi(1), _\bs_\bu_\bd_\bo_\be_\br_\bs(4), _\bs_\bu_\bd_\bo(1m), _\bv_\bi_\bp_\bw(8)
+VISUDO(1m)             MAINTENANCE COMMANDS            VISUDO(1m)
+
 
 A\bAU\bUT\bTH\bHO\bOR\bR
-       Many people have worked on _\bs_\bu_\bd_\bo over the years; this ver­
-       sion of v\bvi\bis\bsu\bud\bdo\bwas written by:
+       Many people have worked on _\bs_\bu_\bd_\bo over the years; this version of v\bvi\bis\bsu\bud\bdo\bo
+       was written by:
 
         Todd Miller
 
@@ -158,26 +146,38 @@ A\bAU\bUT\bTH\bHO\bOR\bR
        http://www.sudo.ws/sudo/history.html for more details.
 
 C\bCA\bAV\bVE\bEA\bAT\bTS\bS
-       There is no easy way to prevent a user from gaining a root
-       shell if the editor used by v\bvi\bis\bsu\bud\bdo\bo allows shell escapes.
+       There is no easy way to prevent a user from gaining a root shell if the
+       editor used by v\bvi\bis\bsu\bud\bdo\bo allows shell escapes.
 
 B\bBU\bUG\bGS\bS
-       If you feel you have found a bug in v\bvi\bis\bsu\bud\bdo\bo, please submit
-       a bug report at http://www.sudo.ws/sudo/bugs/
+       If you feel you have found a bug in v\bvi\bis\bsu\bud\bdo\bo, please submit a bug report
+       at http://www.sudo.ws/sudo/bugs/
 
 S\bSU\bUP\bPP\bPO\bOR\bRT\bT
-       Limited free support is available via the sudo-users mail­
-       ing list, see http://www.sudo.ws/mail­
-       man/listinfo/sudo-users to subscribe or search the
-       archives.
+       Limited free support is available via the sudo-users mailing list, see
+       http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search
+       the archives.
 
 D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
-       v\bvi\bis\bsu\bud\bdo\bo 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.  See the LICENSE file distributed
-       with s\bsu\bud\bdo\bo or http://www.sudo.ws/sudo/license.html for com­
-       plete details.
+       v\bvi\bis\bsu\bud\bdo\bo 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.
+       See the LICENSE file distributed with s\bsu\bud\bdo\bo or
+       http://www.sudo.ws/sudo/license.html for complete details.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
 
 
@@ -193,6 +193,6 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
 
 
 
-1.6.9p17                   Jun 21, 2008                         3
+1.7.0                   November 15, 2008                       3
 
 
index 87ca8ab76bf0b56dc79bf511dd43d510efc48982..7aa576b4ceaae7bdf2ac6dfe8e3f91302dbf2439 100644 (file)
@@ -1,4 +1,5 @@
-.\" Copyright (c) 1996,1998-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
+.\" Copyright (c) 1996,1998-2005, 2007-2008
+.\"    Todd C. Miller <Todd.Miller@courtesan.com>
 .\" 
 .\" Permission to use, copy, modify, and distribute this software for any
 .\" purpose with or without fee is hereby granted, provided that the above
@@ -17,8 +18,8 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\" 
-.\" $Sudo: visudo.man.in,v 1.20.2.22 2008/06/22 20:29:03 millert Exp $
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
+.\" $Sudo: visudo.man.in,v 1.32 2008/11/15 18:34:26 millert Exp $
+.\" Automatically generated by Pod::Man 2.16 (Pod::Simple 3.05)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
 ..
 .\" Set up some character translations and predefined strings.  \*(-- will
 .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote.  | will give a
-.\" real vertical bar.  \*(C+ will give a nicer C++.  Capital omega is used to
-.\" do unbreakable dashes and therefore won't be available.  \*(C` and \*(C'
-.\" expand to `' in nroff, nothing in troff, for use with C<>.
-.tr \(*W-|\(bv\*(Tr
+.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
+.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
 .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
 .ie n \{\
 .    ds -- \(*W-
 .    ds R" ''
 'br\}
 .\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\"
 .\" If the F register is turned on, we'll generate index entries on stderr for
 .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
-.if \nF \{\
+.ie \nF \{\
 .    de IX
 .    tm Index:\\$1\t\\n%\t"\\$2"
 ..
 .    nr % 0
 .    rr F
 .\}
-.\"
-.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
+.el \{\
+.    de IX
+..
+.\}
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
 .\" ========================================================================
 .\"
 .IX Title "VISUDO @mansectsu@"
-.TH VISUDO @mansectsu@ "Jun 21, 2008" "1.6.9p17" "MAINTENANCE COMMANDS"
+.TH VISUDO @mansectsu@ "November 15, 2008" "1.7.0" "MAINTENANCE COMMANDS"
+.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
 .SH "NAME"
 visudo \- edit the sudoers file
 .SH "SYNOPSIS"
@@ -170,7 +178,7 @@ your system, as determined by the \fIconfigure\fR script.  Normally,
 \&\fBvisudo\fR does not honor the \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR environment
 variables unless they contain an editor in the aforementioned editors
 list.  However, if \fBvisudo\fR is configured with the \fI\-\-with\-enveditor\fR
-flag or the \fIenv_editor\fR \f(CW\*(C`Default\*(C'\fR variable is set in \fIsudoers\fR,
+option or the \fIenv_editor\fR \f(CW\*(C`Default\*(C'\fR variable is set in \fIsudoers\fR,
 \&\fBvisudo\fR will use any the editor defines by \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR.
 Note that this can be a security hole since it allows the user to
 execute any program they wish simply by setting \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR.
@@ -191,7 +199,7 @@ error occurred (if the editor supports this feature).
 .SH "OPTIONS"
 .IX Header "OPTIONS"
 \&\fBvisudo\fR accepts the following command line options:
-.IP "\-c" 4
+.IP "\-c" 12
 .IX Item "-c"
 Enable \fBcheck-only\fR mode.  The existing \fIsudoers\fR file will be
 checked for syntax and a message will be printed to the
@@ -199,32 +207,32 @@ standard output detailing the status of \fIsudoers\fR.
 If the syntax check completes successfully, \fBvisudo\fR will
 exit with a value of 0.  If a syntax error is encountered,
 \&\fBvisudo\fR will exit with a value of 1.
-.IP "\-f" 4
-.IX Item "-f"
+.IP "\-f \fIsudoers\fR" 12
+.IX Item "-f sudoers"
 Specify and alternate \fIsudoers\fR file location.  With this option
 \&\fBvisudo\fR will edit (or check) the \fIsudoers\fR file of your choice,
-instead of the default, \fI@sysconfdir@/sudoers\fR.  The lock file used
+instead of the default, \fI\f(CI@sysconfdir\fI@/sudoers\fR.  The lock file used
 is the specified \fIsudoers\fR file with \*(L".tmp\*(R" appended to it.
-.IP "\-q" 4
+.IP "\-q" 12
 .IX Item "-q"
 Enable \fBquiet\fR mode.  In this mode details about syntax errors
 are not printed.  This option is only useful when combined with
-the \fB\-c\fR flag.
-.IP "\-s" 4
+the \fB\-c\fR option.
+.IP "\-s" 12
 .IX Item "-s"
 Enable \fBstrict\fR checking of the \fIsudoers\fR file.  If an alias is
 used before it is defined, \fBvisudo\fR will consider this a parse
 error.  Note that it is not possible to differentiate between an
 alias and a hostname or username that consists solely of uppercase
 letters, digits, and the underscore ('_') character.
-.IP "\-V" 4
+.IP "\-V" 12
 .IX Item "-V"
 The \fB\-V\fR (version) option causes \fBvisudo\fR to print its version number
 and exit.
 .SH "ENVIRONMENT"
 .IX Header "ENVIRONMENT"
-The following environment variables are used only if \fBvisudo\fR
-was configured with the \fI\-\-with\-env\-editor\fR option:
+The following environment variables may be consulted depending on
+the value of the \fIeditor\fR and \fIenv_editor\fR \fIsudoers\fR variables:
 .ie n .IP "\*(C`VISUAL\*(C'" 16
 .el .IP "\f(CW\*(C`VISUAL\*(C'\fR" 16
 .IX Item "VISUAL"
@@ -235,10 +243,12 @@ Invoked by visudo as the editor to use
 Used by visudo if \s-1VISUAL\s0 is not set
 .SH "FILES"
 .IX Header "FILES"
-.IP "\fI@sysconfdir@/sudoers\fR" 24
+.ie n .IP "\fI\fI@sysconfdir\fI@/sudoers\fR" 24
+.el .IP "\fI\f(CI@sysconfdir\fI@/sudoers\fR" 24
 .IX Item "@sysconfdir@/sudoers"
 List of who can run what
-.IP "\fI@sysconfdir@/sudoers.tmp\fR" 24
+.ie n .IP "\fI\fI@sysconfdir\fI@/sudoers.tmp\fR" 24
+.el .IP "\fI\f(CI@sysconfdir\fI@/sudoers.tmp\fR" 24
 .IX Item "@sysconfdir@/sudoers.tmp"
 Lock file for visudo
 .SH "DIAGNOSTICS"
@@ -246,31 +256,25 @@ Lock file for visudo
 .IP "sudoers file busy, try again later." 4
 .IX Item "sudoers file busy, try again later."
 Someone else is currently editing the \fIsudoers\fR file.
-.IP "@sysconfdir@/sudoers.tmp: Permission denied" 4
+.ie n .IP "@sysconfdir@/sudoers.tmp: Permission denied" 4
+.el .IP "\f(CW@sysconfdir\fR@/sudoers.tmp: Permission denied" 4
 .IX Item "@sysconfdir@/sudoers.tmp: Permission denied"
 You didn't run \fBvisudo\fR as root.
 .IP "Can't find you in the passwd database" 4
 .IX Item "Can't find you in the passwd database"
 Your userid does not appear in the system passwd file.
-.IP "Warning: undeclared Alias referenced near ..." 4
-.IX Item "Warning: undeclared Alias referenced near ..."
-Either you are using a {User,Runas,Host,Cmnd}_Alias before
-defining it or you have a user or hostname listed that
-consists solely of uppercase letters, digits, and the
-underscore ('_') character.  If the latter, you can ignore
-the warnings (\fBsudo\fR will not complain).  In \fB\-s\fR (strict)
-mode these are errors, not warnings.
-.IP "Warning: runas_default set after old value is in use ..." 4
-.IX Item "Warning: runas_default set after old value is in use ..."
-You have a \fIrunas_default\fR Defaults setting listed in the \fIsudoers\fR
-file after its value has already been used.  This means that entries
-prior to the \fIrunas_default\fR setting will match based on the default
-value of \fIrunas_default\fR (\f(CW\*(C`@runas_default@\*(C'\fR) whereas entries
-\&\fBafter\fR the \fIrunas_default\fR setting will match based on the new
-value.  This is usually unintentional and in most cases the
-<runas_default> setting should be placed before any \f(CW\*(C`Runas_Alias\*(C'\fR
-or User specifications.  In \fB\-s\fR (strict) mode this is an error,
-not a warning.
+.IP "Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined" 4
+.IX Item "Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined"
+Either you are trying to use an undeclare {User,Runas,Host,Cmnd}_Alias
+or you have a user or hostname listed that consists solely of
+uppercase letters, digits, and the underscore ('_') character.  In
+the latter case, you can ignore the warnings (\fBsudo\fR will not
+complain).  In \fB\-s\fR (strict) mode these are errors, not warnings.
+.IP "Warning: unused {User,Runas,Host,Cmnd}_Alias" 4
+.IX Item "Warning: unused {User,Runas,Host,Cmnd}_Alias"
+The specified {User,Runas,Host,Cmnd}_Alias was defined but never
+used.  You may wish to comment out or remove the unused alias.  In
+\&\fB\-s\fR (strict) mode this is an error, not a warning.
 .SH "SEE ALSO"
 .IX Header "SEE ALSO"
 \&\fIvi\fR\|(1), \fIsudoers\fR\|(@mansectform@), \fIsudo\fR\|(@mansectsu@), \fIvipw\fR\|(8)
index d914fab45e7aff10b3d868408514fb7f361cc35a..63cb1131295622e755c69d7c67915f49f66dd4d1 100644 (file)
@@ -1,4 +1,5 @@
-Copyright (c) 1996,1998-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
+Copyright (c) 1996,1998-2005, 2007-2008
+       Todd C. Miller <Todd.Miller@courtesan.com>
 
 Permission to use, copy, modify, and distribute this software for any
 purpose with or without fee is hereby granted, provided that the above
@@ -17,7 +18,7 @@ Sponsored in part by the Defense Advanced Research Projects
 Agency (DARPA) and Air Force Research Laboratory, Air Force
 Materiel Command, USAF, under agreement number F39502-99-1-0512.
 
-$Sudo: visudo.pod,v 1.38.2.10 2008/02/19 15:45:12 millert Exp $
+$Sudo: visudo.pod,v 1.55 2008/11/15 18:34:01 millert Exp $
 =pod
 
 =head1 NAME
@@ -43,7 +44,7 @@ your system, as determined by the I<configure> script.  Normally,
 B<visudo> does not honor the C<VISUAL> or C<EDITOR> environment
 variables unless they contain an editor in the aforementioned editors
 list.  However, if B<visudo> is configured with the I<--with-enveditor>
-flag or the I<env_editor> C<Default> variable is set in I<sudoers>,
+option or the I<env_editor> C<Default> variable is set in I<sudoers>,
 B<visudo> will use any the editor defines by C<VISUAL> or C<EDITOR>.
 Note that this can be a security hole since it allows the user to
 execute any program they wish simply by setting C<VISUAL> or C<EDITOR>.
@@ -66,7 +67,7 @@ error occurred (if the editor supports this feature).
 
 B<visudo> accepts the following command line options:
 
-=over 4
+=over 12
 
 =item -c
 
@@ -77,7 +78,7 @@ If the syntax check completes successfully, B<visudo> will
 exit with a value of 0.  If a syntax error is encountered,
 B<visudo> will exit with a value of 1.
 
-=item -f
+=item -f I<sudoers>
 
 Specify and alternate I<sudoers> file location.  With this option
 B<visudo> will edit (or check) the I<sudoers> file of your choice,
@@ -88,7 +89,7 @@ is the specified I<sudoers> file with ".tmp" appended to it.
 
 Enable B<quiet> mode.  In this mode details about syntax errors
 are not printed.  This option is only useful when combined with
-the B<-c> flag.
+the B<-c> option.
 
 =item -s
 
@@ -107,8 +108,8 @@ and exit.
 
 =head1 ENVIRONMENT
 
-The following environment variables are used only if B<visudo>
-was configured with the I<--with-env-editor> option:
+The following environment variables may be consulted depending on
+the value of the I<editor> and I<env_editor> I<sudoers> variables:
 
 =over 16
 
@@ -152,26 +153,19 @@ You didn't run B<visudo> as root.
 
 Your userid does not appear in the system passwd file.
 
-=item Warning: undeclared Alias referenced near ...
-
-Either you are using a {User,Runas,Host,Cmnd}_Alias before
-defining it or you have a user or hostname listed that
-consists solely of uppercase letters, digits, and the
-underscore ('_') character.  If the latter, you can ignore
-the warnings (B<sudo> will not complain).  In B<-s> (strict)
-mode these are errors, not warnings.
-
-=item Warning: runas_default set after old value is in use ...
-
-You have a I<runas_default> Defaults setting listed in the I<sudoers>
-file after its value has already been used.  This means that entries
-prior to the I<runas_default> setting will match based on the default
-value of I<runas_default> (C<@runas_default@>) whereas entries
-B<after> the I<runas_default> setting will match based on the new
-value.  This is usually unintentional and in most cases the
-<runas_default> setting should be placed before any C<Runas_Alias>
-or User specifications.  In B<-s> (strict) mode this is an error,
-not a warning.
+=item Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined
+
+Either you are trying to use an undeclare {User,Runas,Host,Cmnd}_Alias
+or you have a user or hostname listed that consists solely of
+uppercase letters, digits, and the underscore ('_') character.  In
+the latter case, you can ignore the warnings (B<sudo> will not
+complain).  In B<-s> (strict) mode these are errors, not warnings.
+
+=item Warning: unused {User,Runas,Host,Cmnd}_Alias
+
+The specified {User,Runas,Host,Cmnd}_Alias was defined but never
+used.  You may wish to comment out or remove the unused alias.  In
+B<-s> (strict) mode this is an error, not a warning.
 
 =back
 
index f77c8cfb048d373d9e68821910d4aaabc3fbc52a..8ce2eb581bc9daf06619845548f841618c78d306 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2003-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -20,7 +20,7 @@
 #include <compat.h>
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: zero_bytes.c,v 1.2.2.2 2007/06/12 01:28:42 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: zero_bytes.c,v 1.7 2008/11/09 14:13:12 millert Exp $";
 #endif /* lint */
 
 /*
@@ -29,7 +29,7 @@ __unused static const char rcsid[] = "$Sudo: zero_bytes.c,v 1.2.2.2 2007/06/12 0
  */
 void
 zero_bytes(v, n)
-    volatile VOID *v;
+    volatile void *v;
     size_t n;
 {
     volatile char *p, *ep;