Imported Upstream version 1.8.1p2 upstream/1.8.1p2
authorBdale Garbee <bdale@gag.com>
Fri, 22 Jul 2011 12:53:40 +0000 (14:53 +0200)
committerBdale Garbee <bdale@gag.com>
Fri, 22 Jul 2011 12:53:40 +0000 (14:53 +0200)
399 files changed:
ChangeLog
HISTORY [deleted file]
INSTALL
LICENSE [deleted file]
MANIFEST [new file with mode: 0644]
Makefile.in
NEWS
PORTING [deleted file]
README
TROUBLESHOOTING [deleted file]
UPGRADE [deleted file]
aclocal.m4
aix.c [deleted file]
aixcrypt.exp [deleted file]
alias.c [deleted file]
alloc.c [deleted file]
alloc.h [deleted file]
audit.c [deleted file]
auth/API [deleted file]
auth/afs.c [deleted file]
auth/aix_auth.c [deleted file]
auth/bsdauth.c [deleted file]
auth/dce.c [deleted file]
auth/fwtk.c [deleted file]
auth/kerb4.c [deleted file]
auth/kerb5.c [deleted file]
auth/pam.c [deleted file]
auth/passwd.c [deleted file]
auth/rfc1938.c [deleted file]
auth/secureware.c [deleted file]
auth/securid.c [deleted file]
auth/securid5.c [deleted file]
auth/sia.c [deleted file]
auth/sudo_auth.c [deleted file]
auth/sudo_auth.h [deleted file]
boottime.c [deleted file]
bsm_audit.c [deleted file]
bsm_audit.h [deleted file]
check.c [deleted file]
closefrom.c [deleted file]
common/Makefile.in [new file with mode: 0644]
common/aix.c [new file with mode: 0644]
common/alloc.c [new file with mode: 0644]
common/atobool.c [new file with mode: 0644]
common/fileops.c [new file with mode: 0644]
common/fmt_string.c [new file with mode: 0644]
common/lbuf.c [new file with mode: 0644]
common/list.c [new file with mode: 0644]
common/term.c [new file with mode: 0644]
common/zero_bytes.c [new file with mode: 0644]
compat/Makefile.in [new file with mode: 0644]
compat/charclass.h [new file with mode: 0644]
compat/closefrom.c [new file with mode: 0644]
compat/dlfcn.h [new file with mode: 0644]
compat/dlopen.c [new file with mode: 0644]
compat/fnmatch.c [new file with mode: 0644]
compat/fnmatch.h [new file with mode: 0644]
compat/getcwd.c [new file with mode: 0644]
compat/getline.c [new file with mode: 0644]
compat/getprogname.c [new file with mode: 0644]
compat/glob.c [new file with mode: 0644]
compat/glob.h [new file with mode: 0644]
compat/isblank.c [new file with mode: 0644]
compat/memrchr.c [new file with mode: 0644]
compat/mksiglist.c [new file with mode: 0644]
compat/mksiglist.h [new file with mode: 0644]
compat/mktemp.c [new file with mode: 0644]
compat/nanosleep.c [new file with mode: 0644]
compat/regress/fnmatch/fnm_test.c [new file with mode: 0644]
compat/regress/fnmatch/fnm_test.in [new file with mode: 0644]
compat/regress/glob/files [new file with mode: 0644]
compat/regress/glob/globtest.c [new file with mode: 0644]
compat/regress/glob/globtest.in [new file with mode: 0644]
compat/setenv.c [new file with mode: 0644]
compat/siglist.in [new file with mode: 0644]
compat/snprintf.c [new file with mode: 0644]
compat/strlcat.c [new file with mode: 0644]
compat/strlcpy.c [new file with mode: 0644]
compat/strsignal.c [new file with mode: 0644]
compat/timespec.h [new file with mode: 0644]
compat/unsetenv.c [new file with mode: 0644]
compat/utime.h [new file with mode: 0644]
compat/utimes.c [new file with mode: 0644]
config.h.in
configure
configure.in
def_data.c [deleted file]
def_data.h [deleted file]
def_data.in [deleted file]
defaults.c [deleted file]
defaults.h [deleted file]
doc/HISTORY [new file with mode: 0644]
doc/LICENSE [new file with mode: 0644]
doc/Makefile.in [new file with mode: 0644]
doc/TROUBLESHOOTING [new file with mode: 0644]
doc/UPGRADE [new file with mode: 0644]
doc/history.pod [new file with mode: 0644]
doc/license.pod [new file with mode: 0644]
doc/sample.pam [new file with mode: 0644]
doc/sample.sudo.conf [new file with mode: 0644]
doc/sample.sudoers [new file with mode: 0644]
doc/sample.syslog.conf [new file with mode: 0644]
doc/schema.ActiveDirectory [new file with mode: 0644]
doc/schema.OpenLDAP [new file with mode: 0644]
doc/schema.iPlanet [new file with mode: 0644]
doc/sudo.cat [new file with mode: 0644]
doc/sudo.man.in [new file with mode: 0644]
doc/sudo.man.pl [new file with mode: 0644]
doc/sudo.pod [new file with mode: 0644]
doc/sudo_plugin.cat [new file with mode: 0644]
doc/sudo_plugin.man.in [new file with mode: 0644]
doc/sudo_plugin.pod [new file with mode: 0644]
doc/sudoers.cat [new file with mode: 0644]
doc/sudoers.ldap.cat [new file with mode: 0644]
doc/sudoers.ldap.man.in [new file with mode: 0644]
doc/sudoers.ldap.pod [new file with mode: 0644]
doc/sudoers.man.in [new file with mode: 0644]
doc/sudoers.man.pl [new file with mode: 0644]
doc/sudoers.pod [new file with mode: 0644]
doc/sudoreplay.cat [new file with mode: 0644]
doc/sudoreplay.man.in [new file with mode: 0644]
doc/sudoreplay.pod [new file with mode: 0644]
doc/visudo.cat [new file with mode: 0644]
doc/visudo.man.in [new file with mode: 0644]
doc/visudo.pod [new file with mode: 0644]
emul/charclass.h [deleted file]
emul/fnmatch.h [deleted file]
emul/glob.h [deleted file]
emul/timespec.h [deleted file]
emul/utime.h [deleted file]
env.c [deleted file]
error.c [deleted file]
error.h [deleted file]
exec.c [deleted file]
exec_pty.c [deleted file]
fileops.c [deleted file]
find_path.c [deleted file]
fnmatch.c [deleted file]
get_pty.c [deleted file]
getcwd.c [deleted file]
getdate.c [deleted file]
getdate.y [deleted file]
getline.c [deleted file]
getprogname.c [deleted file]
getspwuid.c [deleted file]
gettime.c [deleted file]
glob.c [deleted file]
goodpath.c [deleted file]
gram.c [deleted file]
gram.h [deleted file]
gram.y [deleted file]
include/Makefile.in [new file with mode: 0644]
include/alloc.h [new file with mode: 0644]
include/error.h [new file with mode: 0644]
include/fileops.h [new file with mode: 0644]
include/lbuf.h [new file with mode: 0644]
include/list.h [new file with mode: 0644]
include/missing.h [new file with mode: 0644]
include/sudo_plugin.h [new file with mode: 0644]
ins_2001.h [deleted file]
ins_classic.h [deleted file]
ins_csops.h [deleted file]
ins_goons.h [deleted file]
insults.h [deleted file]
interfaces.c [deleted file]
interfaces.h [deleted file]
iolog.c [deleted file]
isblank.c [deleted file]
lbuf.c [deleted file]
lbuf.h [deleted file]
ldap.c [deleted file]
linux_audit.c [deleted file]
linux_audit.h [deleted file]
list.c [deleted file]
list.h [deleted file]
logging.c [deleted file]
logging.h [deleted file]
ltmain.sh [changed mode: 0644->0755]
m4/libtool.m4
m4/ltoptions.m4
m4/ltversion.m4
m4/lt~obsolete.m4
match.c [deleted file]
memrchr.c [deleted file]
missing.h [deleted file]
mkdefaults [deleted file]
mksiglist.c [deleted file]
mksiglist.h [deleted file]
mkstemps.c [deleted file]
nanosleep.c [deleted file]
nonunix.h [deleted file]
parse.c [deleted file]
parse.h [deleted file]
parse_args.c [deleted file]
pathnames.h.in
plugins/sample/Makefile.in [new file with mode: 0644]
plugins/sample/sample_plugin.c [new file with mode: 0644]
plugins/sample/sample_plugin.sym [new file with mode: 0644]
plugins/sample_group/Makefile.in [new file with mode: 0644]
plugins/sample_group/getgrent.c [new file with mode: 0644]
plugins/sample_group/plugin_test.c [new file with mode: 0644]
plugins/sample_group/sample_group.c [new file with mode: 0644]
plugins/sample_group/sample_group.sym [new file with mode: 0644]
plugins/sudoers/Makefile.in [new file with mode: 0644]
plugins/sudoers/aixcrypt.exp [new file with mode: 0644]
plugins/sudoers/alias.c [new file with mode: 0644]
plugins/sudoers/audit.c [new file with mode: 0644]
plugins/sudoers/auth/API [new file with mode: 0644]
plugins/sudoers/auth/afs.c [new file with mode: 0644]
plugins/sudoers/auth/aix_auth.c [new file with mode: 0644]
plugins/sudoers/auth/bsdauth.c [new file with mode: 0644]
plugins/sudoers/auth/dce.c [new file with mode: 0644]
plugins/sudoers/auth/fwtk.c [new file with mode: 0644]
plugins/sudoers/auth/kerb4.c [new file with mode: 0644]
plugins/sudoers/auth/kerb5.c [new file with mode: 0644]
plugins/sudoers/auth/pam.c [new file with mode: 0644]
plugins/sudoers/auth/passwd.c [new file with mode: 0644]
plugins/sudoers/auth/rfc1938.c [new file with mode: 0644]
plugins/sudoers/auth/secureware.c [new file with mode: 0644]
plugins/sudoers/auth/securid.c [new file with mode: 0644]
plugins/sudoers/auth/securid5.c [new file with mode: 0644]
plugins/sudoers/auth/sia.c [new file with mode: 0644]
plugins/sudoers/auth/sudo_auth.c [new file with mode: 0644]
plugins/sudoers/auth/sudo_auth.h [new file with mode: 0644]
plugins/sudoers/boottime.c [new file with mode: 0644]
plugins/sudoers/bsm_audit.c [new file with mode: 0644]
plugins/sudoers/bsm_audit.h [new file with mode: 0644]
plugins/sudoers/check.c [new file with mode: 0644]
plugins/sudoers/def_data.c [new file with mode: 0644]
plugins/sudoers/def_data.h [new file with mode: 0644]
plugins/sudoers/def_data.in [new file with mode: 0644]
plugins/sudoers/defaults.c [new file with mode: 0644]
plugins/sudoers/defaults.h [new file with mode: 0644]
plugins/sudoers/env.c [new file with mode: 0644]
plugins/sudoers/find_path.c [new file with mode: 0644]
plugins/sudoers/getdate.c [new file with mode: 0644]
plugins/sudoers/getdate.y [new file with mode: 0644]
plugins/sudoers/getspwuid.c [new file with mode: 0644]
plugins/sudoers/goodpath.c [new file with mode: 0644]
plugins/sudoers/gram.c [new file with mode: 0644]
plugins/sudoers/gram.h [new file with mode: 0644]
plugins/sudoers/gram.y [new file with mode: 0644]
plugins/sudoers/group_plugin.c [new file with mode: 0644]
plugins/sudoers/ins_2001.h [new file with mode: 0644]
plugins/sudoers/ins_classic.h [new file with mode: 0644]
plugins/sudoers/ins_csops.h [new file with mode: 0644]
plugins/sudoers/ins_goons.h [new file with mode: 0644]
plugins/sudoers/insults.h [new file with mode: 0644]
plugins/sudoers/interfaces.c [new file with mode: 0644]
plugins/sudoers/interfaces.h [new file with mode: 0644]
plugins/sudoers/iolog.c [new file with mode: 0644]
plugins/sudoers/iolog_path.c [new file with mode: 0644]
plugins/sudoers/ldap.c [new file with mode: 0644]
plugins/sudoers/linux_audit.c [new file with mode: 0644]
plugins/sudoers/linux_audit.h [new file with mode: 0644]
plugins/sudoers/logging.c [new file with mode: 0644]
plugins/sudoers/logging.h [new file with mode: 0644]
plugins/sudoers/match.c [new file with mode: 0644]
plugins/sudoers/mkdefaults [new file with mode: 0755]
plugins/sudoers/parse.c [new file with mode: 0644]
plugins/sudoers/parse.h [new file with mode: 0644]
plugins/sudoers/plugin_error.c [new file with mode: 0644]
plugins/sudoers/pwutil.c [new file with mode: 0644]
plugins/sudoers/redblack.c [new file with mode: 0644]
plugins/sudoers/redblack.h [new file with mode: 0644]
plugins/sudoers/regress/iolog_path/check_iolog_path.c [new file with mode: 0644]
plugins/sudoers/regress/iolog_path/data [new file with mode: 0644]
plugins/sudoers/regress/parser/check_fill.c [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test1.in [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test1.out.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test1.toke.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test2.in [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test2.out.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test2.toke.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test3.in [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test3.out.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test3.toke.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test4.in [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test4.out.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test4.toke.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test5.in [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test5.out.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test5.toke.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test6.in [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test6.out.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test6.toke.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test7.in [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test7.out.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test7.toke.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test8.in [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test8.out.ok [new file with mode: 0644]
plugins/sudoers/regress/sudoers/test8.toke.ok [new file with mode: 0644]
plugins/sudoers/regress/testsudoers/test1.out.ok [new file with mode: 0644]
plugins/sudoers/regress/testsudoers/test1.sh [new file with mode: 0755]
plugins/sudoers/set_perms.c [new file with mode: 0644]
plugins/sudoers/sudo_nss.c [new file with mode: 0644]
plugins/sudoers/sudo_nss.h [new file with mode: 0644]
plugins/sudoers/sudoers.c [new file with mode: 0644]
plugins/sudoers/sudoers.h [new file with mode: 0644]
plugins/sudoers/sudoers.in [new file with mode: 0644]
plugins/sudoers/sudoers.sym [new file with mode: 0644]
plugins/sudoers/sudoers2ldif [new file with mode: 0755]
plugins/sudoers/sudoers_version.h [new file with mode: 0644]
plugins/sudoers/sudoreplay.c [new file with mode: 0644]
plugins/sudoers/testsudoers.c [new file with mode: 0644]
plugins/sudoers/timestr.c [new file with mode: 0644]
plugins/sudoers/toke.c [new file with mode: 0644]
plugins/sudoers/toke.h [new file with mode: 0644]
plugins/sudoers/toke.l [new file with mode: 0644]
plugins/sudoers/toke_util.c [new file with mode: 0644]
plugins/sudoers/tsgetgrpw.c [new file with mode: 0644]
plugins/sudoers/tsgetgrpw.h [new file with mode: 0644]
plugins/sudoers/visudo.c [new file with mode: 0644]
pwutil.c [deleted file]
redblack.c [deleted file]
redblack.h [deleted file]
sample.pam [deleted file]
sample.sudoers [deleted file]
sample.syslog.conf [deleted file]
schema.ActiveDirectory [deleted file]
schema.OpenLDAP [deleted file]
schema.iPlanet [deleted file]
selinux.c [deleted file]
sesh.c [deleted file]
set_perms.c [deleted file]
setsid.c [deleted file]
sigaction.c [deleted file]
siglist.in [deleted file]
snprintf.c [deleted file]
src/Makefile.in [new file with mode: 0644]
src/conversation.c [new file with mode: 0644]
src/error.c [new file with mode: 0644]
src/exec.c [new file with mode: 0644]
src/exec_pty.c [new file with mode: 0644]
src/get_pty.c [new file with mode: 0644]
src/load_plugins.c [new file with mode: 0644]
src/net_ifs.c [new file with mode: 0644]
src/parse_args.c [new file with mode: 0644]
src/preload.c [new file with mode: 0644]
src/selinux.c [new file with mode: 0644]
src/sesh.c [new file with mode: 0644]
src/sudo.c [new file with mode: 0644]
src/sudo.h [new file with mode: 0644]
src/sudo_edit.c [new file with mode: 0644]
src/sudo_exec.h [new file with mode: 0644]
src/sudo_noexec.c [new file with mode: 0644]
src/sudo_plugin_int.h [new file with mode: 0644]
src/sudo_usage.h.in [new file with mode: 0644]
src/tgetpass.c [new file with mode: 0644]
src/ttysize.c [new file with mode: 0644]
src/utmp.c [new file with mode: 0644]
strcasecmp.c [deleted file]
strerror.c [deleted file]
strlcat.c [deleted file]
strlcpy.c [deleted file]
strsignal.c [deleted file]
sudo.c [deleted file]
sudo.cat [deleted file]
sudo.h [deleted file]
sudo.man.in [deleted file]
sudo.man.pl [deleted file]
sudo.pod [deleted file]
sudo.pp
sudo_edit.c [deleted file]
sudo_exec.h [deleted file]
sudo_noexec.c [deleted file]
sudo_nss.c [deleted file]
sudo_nss.h [deleted file]
sudo_usage.h.in [deleted file]
sudoers.cat [deleted file]
sudoers.in [deleted file]
sudoers.ldap.cat [deleted file]
sudoers.ldap.man.in [deleted file]
sudoers.ldap.pod [deleted file]
sudoers.man.in [deleted file]
sudoers.man.pl [deleted file]
sudoers.pod [deleted file]
sudoers2ldif [deleted file]
sudoreplay.c [deleted file]
sudoreplay.cat [deleted file]
sudoreplay.man.in [deleted file]
sudoreplay.pod [deleted file]
term.c [deleted file]
testsudoers.c [deleted file]
tgetpass.c [deleted file]
timestr.c [deleted file]
toke.c [deleted file]
toke.h [deleted file]
toke.l [deleted file]
toke_util.c [deleted file]
tsgetgrpw.c [deleted file]
utimes.c [deleted file]
vasgroups.c [deleted file]
visudo.c [deleted file]
visudo.cat [deleted file]
visudo.man.in [deleted file]
visudo.pod [deleted file]
zero_bytes.c [deleted file]
zlib/Makefile.in [new file with mode: 0644]

index 5efe57dfce809921f4ec34e60cffa2312f221074..5eaab26fc822c5cfb535778bdd4e5b73ea67903e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
+2011-05-04  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Don't let the fnmatch/glob macros expand the function prototype.
+       [d449e9a8f447] <1.8>
+
+2011-05-03  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Resolve namespace collisions on HP-UX ia64 and possibly others by
+       adding a rpl_ prefix to our fnmatch and glob replacements and
+       #defining rpl_foo to foo in the header files.
+       [d23889375b21] <1.8>
+
+2011-04-29  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Split ALL, ROLE and TYPE into their own actions. Since you can only
+       have #ifdefs inside of braces, ROLE and TYPE use a naughty goto in
+       the non-SELinux case. This is safe because the actions are in one
+       big switch() statement.
+       [0bd9b7e37ab1] <1.8>
+
+       * Fix regexp for matching a CIDR-style IPv4 netmask. From Marc Espie.
+       [8dec97b359e0] <1.8>
+
+       * askpass moved from sudoers to sudo.conf in sudo 1.8.0
+       [1001d87d82ed] <1.8>
+
+       * Remove obsolete warning about runas_default and ordering. Move
+       syslog facility and priority lists into the section where the
+       relevant options are described.
+       [1286b9624021] <1.8>
+
+2011-04-26  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Fix SIA support; we no longer have access to the real argc and argv
+       so allocate space for a fake one and use the argv passed to the
+       plugin with "sudo" for argv[0].
+       [7c11eeffb91c] <1.8>
+
+       * Remove useless realloc when trying to get the buffer size right.
+       [58128e7f4e28] <1.8>
+
+       * Be explicit when setting euid to 0 before call to setreuid(0, 0)
+       [95769a564ab8] <1.8>
+
+2011-04-18  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * NEWS:
+       sudo 1.8.1p1 updates
+       [de3d688b5bb1] <1.8>
+
+       * configure, configure.in:
+       Need to do checks for krb5_verify_user, krb5_init_secure_context and
+       krb5_get_init_creds_opt_alloc regardless of whether or
+       notkrb5-config is present.
+       [456c4a9cd5d6] <1.8>
+
+2011-04-15  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Work around weird AIX saved uid semantics on setuid() and
+       setreuid(). On AIX, setuid() will only set the saved uid if the euid
+       is already 0.
+       [5d0a69e9d181] <1.8>
+
 2011-04-14  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudo.pp:
-       update copyright year
-       [edf691539a65] [tip] <1.7>
+       * update copyright year
+       [fa8da6d55783] <1.8>
 
-       * toke.c, toke.l:
-       Treat a missing includedir like an empty one and do not return an
+       * Treat a missing includedir like an empty one and do not return an
        error.
-       [9c770ff2d0bc] <1.7>
+       [5fd9fe004728] <1.8>
 
 2011-04-12  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * pp:
-       Fix ARCH setting in cross-compile Solaris packages.
-       [057d743bd1a2] <1.7>
+       * Fix ARCH setting in cross-compile Solaris packages.
+       [8ce40940f6c9] <1.8>
 
-       * sudo.pp:
-       Fix aix version setting.
-       [1a2621321f5c] <1.7>
+       * Fix aix version setting.
+       [02a9e25d46ba] <1.8>
 
-       * ldap.c:
-       Remove extraneous parens in LDAP filter when sudoers_search_filter
+       * Remove extraneous parens in LDAP filter when sudoers_search_filter
        is enabled that causes a search error. From Matthew Thomas.
-       [7a5a2d021d32] <1.7>
+       [b67be9b51ec6] <1.8>
+
+2011-04-11  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Correct sizeof() to fix test failure.
+       [a11b89fd13f9] <1.8>
+
+       * "install" target should depend on "install-dirs". Fixes "make -j"
+       problem and closes bz #487. From Chris Coleman.
+       [06ab0558f848] <1.8>
 
 2011-04-09  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * .hgtags:
-       Added tag SUDO_1_7_6 for changeset fafbb7b0aea2
-       [6f5c74a8a6ac] <1.7>
+       Added tag SUDO_1_8_1 for changeset 0ed6281995f0
+       [543d41a163e9] <1.8>
 
-       * configure, configure.in, sudo.cat, sudo.man.in, sudoers.cat,
-       sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.man.in,
-       sudoreplay.cat, sudoreplay.man.in, visudo.cat, visudo.man.in:
-       regen for 1.7.6
-       [fafbb7b0aea2] [SUDO_1_7_6] <1.7>
+       * doc/sudo.cat, doc/sudo.man.in, doc/sudo_plugin.cat,
+       doc/sudo_plugin.man.in, doc/sudoers.cat, doc/sudoers.ldap.cat,
+       doc/sudoers.ldap.man.in, doc/sudoers.man.in, doc/sudoreplay.cat,
+       doc/sudoreplay.man.in, doc/visudo.cat, doc/visudo.man.in:
+       Regen man pages for 1.8.1
+       [0ed6281995f0] [SUDO_1_8_1] <1.8>
 
-       * sudo.cat, sudo.man.in:
-       regen man pages for 1.7.6
-       [94d851285f31] <1.7>
+2011-04-07  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Add HAVE_RFC1938_SKEYCHALLENGE
+       [c0d7eb39799d] <1.8>
 
 2011-04-06  Todd C. Miller  <Todd.Miller@courtesan.com>
 
+       * Mention plugin loading and libgcc changes
+       [b74929cba37c] <1.8>
+
+       * Load plugins after parsing arguments and potentially printing the
+       version. That way, an error loading or initializing a plugin
+       doesn't break "sudo -h" or "sudo -V".
+       [c1ecb5979cf0] <1.8>
+
+       * Makefile.in:
+       When using a sub-shell to invoke the sub-make, exec make instead of
+       running it inside the shell to avoid an extra process.
+       [9439f016c993] <1.8>
+
+       * Stop testing unspecified behavior in fnmatch Make glob test more
+       portable
+       [87a91d76fbff] <1.8>
+
+       * No need to add current dir to include path and having it breaks the
+       test programs that expect to get the system glob.h and fnmatch.h
+       [3ae7f9e7b710] <1.8>
+
+       * configure, configure.in:
+       Fix and document --with-plugindir; partially from Diego Elio Petteno
+       [0220a0c2606f] <1.8>
+
+       * Fix fnmatch and glob tests to not use hard-coded flag values in the
+       input file. Link test programs with libreplace so we get our
+       replacement verions as needed.
+       [66bab80241e0] <1.8>
+
+       * Makefile.in:
+       If make in a subdir fails, fail the target in the upper level
+       Makefile too. Adapted from a patch from Diego Elio Petteno
+       [bc35b7813507] <1.8>
+
+       * configure, configure.in:
+       Add check for NetBSD-style 4-argument skeychallenge() as Gentoo also
+       has this. Adapted from a patch from Diego Elio Petteno
+       [bb6228f484b9] <1.8>
+
+       * Make SUDOERS_LDFLAGS reference $(LDFLAGS) instead of using @LDFLAGS@
+       directly.
+       [47e6d5fadc6d] <1.8>
+
        * configure, configure.in:
        Fix warnings when -without-skey, --without-opie, --without-kerb4,
        --without-kerb5 or --without-SecurID were specified.
-       [83a99d369286] <1.7>
+       [1b75035dd129] <1.8>
+
+       * Add plugins/sudoers/sudoers_version.h
+       [1d470c6033ca] <1.8>
+
+       * configure, configure.in:
+       Back out the --with-libpath addition to SUDOERS_LDFLAGS since that
+       now include LDFLAGS in the sudoers Makefile.in. Add missing settng
+       of @LDFLAGS@ in plugin Makefile.in files.
+       [dd237f43aa12] <1.8>
 
 2011-04-05  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * NEWS:
-       Mention %#gid support in User_List and Runas_List
-       [8ff14765d7df] <1.7>
+       * Mention %#gid support in User_List and Runas_List
+       [37e259b9181b] <1.8>
 
-       * sudoers.pod:
-       Merge SETENV and NOSETENV description from 1.8
-       [dd44e79b53a0] <1.7>
+       * Keep track of sudoers grammar version and report it in the -V
+       output.
+       [0e0b891dd8a4] <1.8>
+
+       * Add multiple inclusion guard
+       [ec6884f51ea8] <1.8>
+
+       * configure, configure.in:
+       The --with-libpath option now adds to SUDOERS_LDFLAGS as well as
+       LDFLAGS. Remove old -static hack for HP-UX < 9. Add LTLDFLAGS and
+       set it to -Wc,-static-libgcc if not using GNU ld so we don't
+       have a dependency on the shared libgcc in sudoers.so.
+       [28d03f3eb0d2] <1.8>
+
+       * Fix typo; from Petr Uzel
+       [d19b9bd92bd3] <1.8>
 
 2011-04-01  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * testsudoers.c:
-       In dump-only mode, use "root" as the default username instead of
+       * In dump-only mode, use "root" as the default username instead of
        "nobody" as the latter may not be available on all systems.
-       [8082b8a1374c] <1.7>
+       [b304111616dd] <1.8>
 
 2011-03-31  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * testsudoers.c:
-       Fix setting of user_args
-       [0669612feeb1] <1.7>
+       * Remove NewArgv/NewArgc, they are no longer needed.
+       [c0a36a42a68c] <1.8>
 
-       * toke.c, toke.l:
-       Add '!' token to lex tracing
-       [7738d002a8d0] <1.7>
+       * Fix setting of user_args
+       [529e79ea95d1] <1.8>
 
-       * toke.c, toke.l:
-       Avoid using pre or post increment in a parameter to a ctype(3)
+       * Add '!' token to lex tracing
+       [aef295d428e7] <1.8>
+
+       * Use group bin in test, not wheel as most systems have the bin group
+       but the same is no longer true of wheel.
+       [350347f09c1a] <1.8>
+
+       * Avoid using pre or post increment in a parameter to a ctype(3)
        function as it might be a macro that causes the increment to happen
        more than once.
-       [2d23161e06dc] <1.7>
+       [8a94ebdd53b8] <1.8>
 
 2011-03-30  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudo.pp:
-       Strip off the beta or release candidate version when building AIX
+       * Strip off the beta or release candidate version when building AIX
        packages.
-       [246ebb79e64f] <1.7>
+       [00ad950764e2] <1.8>
 
-       * aix.c:
-       getuserattr(user, ...) will fall back to the "default" entry
+       * configure, configure.in:
+       We need to include OSDEFS in CFLAGS when doing the utmp/utmpx
+       structure checks for glibc which only has __e_termination visible
+       when _GNU_SOURCE is *not* defined.
+       [1d58420a4a4a] <1.8>
+
+       * getuserattr(user, ...) will fall back to the "default" entry
        automatically, there's no need to check "default" manually.
-       [dd233ca1092a] <1.7>
+       [cefffa82967d] <1.8>
+
+       * Document parser changes.
+       [5038238f60eb] <1.8>
 
 2011-03-29  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * UPGRADE:
-       Document parser changes.
-       [f767c045e6c0] <1.7>
+       * Makefile.in:
+       If there is an existing sudoers file, only install if it passes a
+       syntax check.
+       [b1e4c9c56fe0] <1.8>
 
-       * testsudoers.c:
-       Add runasgroup support to testsudoers
-       [23f060665d23] <1.7>
+       * Add runasgroup support to testsudoers
+       [30838590e9de] <1.8>
 
-       * testsudoers.c:
-       More useful exit codes:
+       * For "make check", keep going even if a test fails.
+       [d3a72f67227e] <1.8>
+
+       * More useful exit codes:
         * 0 - parsed OK and command matched.
         * 1 - parse error
         * 2 - command not matched
         * 3 - command denied
-       [bda610d9f6da] <1.7>
-
-       * Makefile.in:
-       If there is an existing sudoers file, only install if it passes a
-       syntax check.
-       [189eaeea562e] <1.7>
+       [59301e0769cd] <1.8>
 
-       * sudoers.pod:
-       Document %#gid, and %:#nonunix_gid syntax.
-       [59e7df4c91e4] <1.7>
+       * Document %#gid, and %:#nonunix_gid syntax.
+       [39ee15af58e9] <1.8>
 
-       * pwutil.c:
-       Add support to user_in_group() for treating group names that begin
+       * Add support to user_in_group() for treating group names that begin
        with a '#' as gids.
-       [3926017fbf95] <1.7>
+       [0eb19980cf5f] <1.8>
+
+       * configure, configure.in:
+       Add explicit check for struct utmpx.ut_exit.e_termination and struct
+       utmpx.ut_exit.__e_termination. HP-UX uses the latter. Only update
+       ut_exit if we detect one or the other.
+       [ab5b665fc04b] <1.8>
 
 2011-03-28  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * aclocal.m4:
-       Quote first argument to AC_DEFUN(); from Elan Ruusamae
-       [a245e4891bab] <1.7>
+       * Add back missing #include of config.h
+       [9c82bec81018] <1.8>
+
+       * Avoid a NULL deref on unrecognized escapes. Collapse %% -> % like
+       strftime() does.
+       [1ae630470f8a] <1.8>
+
+       * Quote first argument to AC_DEFUN(); from Elan Ruusamae
+       [c467e9e3b399] <1.8>
 
 2011-03-27  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * toke.c, toke.l:
-       Use bitwise AND instead of modulus to check for length being odd. A
-       newline in the middle of a string is an error unless a line
+       * add new sudoers tests
+       [05f2a0924acc] <1.8>
+
+       * Add test for a newline in the middle of a string when no line
        continuation character is used.
-       [37a7f1fc54b7] <1.7>
+       [24b79be5822b] <1.8>
 
-       * gram.c, toke.c:
-       Add missing include of config.h
-       [b13da7baee1e] <1.7>
+       * Use bitwise AND instead of modulus to check for length being odd. A
+       newline in the middle of a string is an error unless a line
+       continuation character is used.
+       [65c468599688] <1.8>
 
-       * gram.c, gram.y, toke.c, toke.l:
-       Move lexer globals initialization into init_lexer.
-       [b7c124212d05] <1.7>
+       * Move lexer globals initialization into init_lexer.
+       [07a1171a1853] <1.8>
 
-       * toke.c, toke.l:
-       Fix a potential crash when a non-regular file is present in an
+       * Fix a potential crash when a non-regular file is present in an
        includedir. Fixes bz #452
-       [f1209a710607] <1.7>
+       [5057cb9516e4] <1.8>
 
-       * pp:
-       On some Linux systems, "uname -p" contains detailed processor info
+       * On some Linux systems, "uname -p" contains detailed processor info
        so check "uname -m" first and then "uname -p" if needed. Recognize
        PLD Linux.
-       [83af85a391df] <1.7>
+       [56226c84a060] <1.8>
 
-       * toke.c, toke.l:
-       Make an empty group or netgroup a syntax error.
-       [e88aa7b31a43] <1.7>
+2011-03-25  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * toke.c, toke.l:
-       Allow a group ID in the User_Spec.
-       [3e58bc732e33] <1.7>
+       * Don't need all sudoers.h here.
+       [43b6ae5999c5] <1.8>
 
-       * toke.c, toke.l:
-       Return an error for the empty string when a word is expected. Allow
+       * Print sudo version early, in case policy plugin init fails.
+       [620f2d0ec4b1] <1.8>
+
+2011-03-24  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Update to match change in input.
+       [69540f84721d] <1.8>
+
+       * Make an empty group or netgroup a syntax error.
+       [4b85bddc494e] <1.8>
+
+       * An empty group or netgroup should be a syntax error.
+       [6ec796972eff] <1.8>
+
+       * Check that uids work in per-user and per-runas Defaults Check that
+       uids and gids work in a Command_Spec
+       [68cf62353420] <1.8>
+
+       * Test empty string in User_Alias and Command_Spec
+       [017d487c31be] <1.8>
+
+       * Allow a group ID in the User_Spec.
+       [37e0bf69c8d8] <1.8>
+
+       * Return an error for the empty string when a word is expected. Allow
        an ID for per-user or per-runas Defaults.
-       [83bb1a9c80ad] <1.7>
+       [4c9020779582] <1.8>
 
 2011-03-23  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * testsudoers.c:
-       Fix printing "User_Alias FOO = ALL"
-       [8e6e810e89ce] <1.7>
+       * Fix printing "User_Alias FOO = ALL"
+       [97c9fd7caeb7] <1.8>
 
 2011-03-22  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * parse_args.c:
-       Better error message about invalid -C argument
-       [fc14f8dc03d2] <1.7>
+       * Better error message about invalid -C argument
+       [2301e7a3835b] <1.8>
 
-       * NEWS:
-       fix typo
-       [f789649fdeaf] <1.7>
+       * fix typo
+       [c5acde62a309] <1.8>
 
-       * sudoers.pod:
-       Fix placement of equal size ('=') in user specification summary.
-       [51861d678ac1] <1.7>
+       * Fix placement of equal size ('=') in user specification summary.
+       [4d0ffef77ae4] <1.8>
 
 2011-03-21  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * toke.l:
-       If we match a rule anchored to the beginning of a line after parsing
+       * update to match sudoers regress
+       [0efb8dc9092a] <1.8>
+
+       * Restore ability to define TRACELEXER and have trace output go to
+       stderr.
+       [441c8b372217] <1.8>
+
+       * Restore old behavior of setting sawspace = TRUE for command line
+       args when a line continuation character is hit to avoid causing
+       problems for existing sudoers files.
+       [963ded6ce070] <1.8>
+
+       * Add test for line continuation and aliases
+       [5703d11a3c46] <1.8>
+
+       * Make test output line up nicely for parse vs. toke
+       [15321ce2d7d9] <1.8>
+
+       * plugins/sudoers/regress/testsudoers/test1.ok,
+       plugins/sudoers/regress/testsudoers/test2.out,
+       plugins/sudoers/regress/testsudoers/test2.sh,
+       plugins/sudoers/regress/testsudoers/test3.ok,
+       plugins/sudoers/regress/testsudoers/test3.sh,
+       plugins/sudoers/regress/visudo/test1.ok,
+       plugins/sudoers/regress/visudo/test1.sh:
+       Move parser tests to sudoers directory and test the tokenizer output
+       too.
+       [111c1ccda334] <1.8>
+
+       * If we match a rule anchored to the beginning of a line after parsing
        a line continuation character, return an ERROR token. It would be
        nicer to use REJECT instead but that substantially slows down the
        lexer.
-       [f31c6622aaf9] <1.7>
+       [67e54b14aa9d] <1.8>
 
-       * toke.c, toke.l:
-       Allow whitespace after the modifier in a Defaults entry. E.g.
+       * Move LEXTRACE macro to toke.h so we can use it in yyerror().
+       [e6e04037deed] <1.8>
+
+       * Make lex tracing settable at run-time in testsudoers via the -t
+       flag. Trace output goes to stderr. Will be used by regress tests
+       to check lexer.
+       [a973f43cc0c2] <1.8>
+
+       * Allow whitespace after the modifier in a Defaults entry. E.g.
        "Defaults: username set_home"
-       [57c09139d10c] <1.7>
+       [bf876c9fc5bb] <1.8>
 
 2011-03-18  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * mkpkg:
-       Don't set CC when cross-compiling. Use the Sun Studio C compiler on
-       Solaris if possible.
-       [b91feb0678c1] <1.7>
+       * Don't set CC when cross-compiling.
+       [d3c33dcb02f2] <1.8>
 
-       * NEWS:
-       Credit Matthew Thomas for the sudoers_search_filter changes.
-       [4b3f239e114d] <1.7>
+       * Credit Matthew Thomas for the sudoers_search_filter changes.
+       [2209b80664af] <1.8>
 
-       * NEWS:
-       Update for sudo 1.7.6 beta
-       [26cdd6578c23] <1.7>
+       * Add the .sym files to the MANIFEST
+       [bb452b28a009] <1.8>
+
+       * Update for sudo 1.8.1 beta
+       [700d42d80e00] <1.8>
 
-       * exec_pty.c:
-       Save the controlling tty process group before suspending in pty
+       * user_shell -> run_shell to avoid confusion with the user's SHELL
+       variable.
+       [451b96d5f97e] <1.8>
+
+       * Save the controlling tty process group before suspending in pty
        mode. Previously, we assumed that the child pgrp == child pid
        (which is usually, but not always, the case).
-       [670657004784] <1.7>
+       [b0841d861191] <1.8>
 
-       * ldap.c, sudoers.ldap.pod:
-       Add support for sudoers_search_filter setting in ldap.conf. This
+       * Add support for sudoers_search_filter setting in ldap.conf. This
        can be used to restrict the set of records returned by the LDAP
        query.
-       [c941bb5f68f2] <1.7>
+       [70c5f496e2b3] <1.8>
 
 2011-03-17  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * configure, configure.in:
        Remove the hack to disable -g in CFLAGS unless --with-devel
-       [933300bf3848] <1.7>
+       [9459839f50ba] <1.8>
 
-       * sudoers.pod:
-       The '@' character does not normally need to be quoted.
-       [7e96569aed54] <1.7>
+       * The '@' character does not normally need to be quoted.
+       [e66c4c64e514] <1.8>
 
-       * toke.c, toke.l:
-       We normaly transition from GOTDEFS to STARTDEFS on whitespace, but
+       * We normaly transition from GOTDEFS to STARTDEFS on whitespace, but
        if that whitespace is followed by a comma, we want to treat it as
        part of a list and not transition.
-       [6dd87c25c79c] <1.7>
+       [52ae2df9959d] <1.8>
 
-       * Makefile.in:
-       toke_util.c lives in $(srcdir) not $(devdir)
-       [b1b59d72f026] <1.7>
+       * Add check for whitespace when a User_List is used for a per-user
+       Defaults entry.
+       [44a4db95be86] <1.8>
 
-       * toke.c, toke.l:
-       Fix parsing of double-quoted names in Defaults and Aliases which was
-       broken in c2b486b12951.
-       [30b2fdbafdc2] <1.7>
+       * Expand quoted name checks to cover recent fixes.
+       [bd494b5c2bed] <1.8>
 
-2011-03-16  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * Fix parsing of double-quoted names in Defaults and Aliases which was
+       broken in 601d97ea8792.
+       [dfdd58c3eb3b] <1.8>
 
-       * NEWS:
-       Document major changes for sudo 1.7.6
-       [d474a2aeb411] <1.7>
+       * toke_util.c lives in $(srcdir) not $(devdir)
+       [94f8f024782e] <1.8>
+
+2011-03-16  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * configure, configure.in:
-       Update version to 1.7.6
-       [c1c80b99ed82] <1.7>
+       Update version to 1.8.1
+       [531a7d520f18] <1.8>
 
-       * match.c:
-       Be careful not to deref user_stat if it is NULL. This cannot
+       * Document major changes in 1.8.1 and add upgrade notes.
+       [116821646140] <1.8>
+
+       * Be careful not to deref user_stat if it is NULL. This cannot
        currently happen in sudo but might in other programs using the
        parser.
-       [0926b1653e20] <1.7>
+       [d72a9c7151c4] <1.8>
 
-       * mkpkg:
-       configure will not add -O2 to CFLAGS if it is already defined to add
+       * configure will not add -O2 to CFLAGS if it is already defined to add
        -O2 to the CFLAGS we pass in when PIE is being used.
-       [a4444e287bcb] <1.7>
+       [2c7fe82be93d] <1.8>
 
-       * sudoers.pod:
-       Warn about the dangers of log_input and mention iolog_dir in the
-       log_input and log_output descriptions.
-       [68c3615f7487] <1.7>
+       * Warn about the dangers of log_input and mention iolog_file and
+       iolog_dir in the log_input and log_output descriptions.
+       [edc6aa59aa45] <1.8>
 
-       * pp:
-       Back out 2b81d57de4a4 and sync with git version
-       [5a2443567b9c] <1.7>
+       * sync with git version
+       [b121cf739c77] <1.8>
+
+       * It seems that h comes after i
+       [99ad15015f05] <1.8>
 
-       * exec.c:
-       Save the controlling tty process group before suspending so we can
+       * Move log_input and log_output to their proper, sorted, location.
+       Document set_utmp and utmp_runas.
+       [216ce8b0ae1a] <1.8>
+
+       * Save the controlling tty process group before suspending so we can
        restore it when we resume. Fixes job control problems on Linux
        caused by the previous attemp to fix resuming a shell when I/O
        logging not enabled.
-       [3e4e26b79f59] <1.7>
+       [dfe038f733be] <1.8>
+
+       * Fix printing of the remainder after a newline. Fixes "sudo -l"
+       output corruption that could occur in some cases.
+       [ab2f0a629e0d] <1.8>
+
+       * Add support for ut_exit
+       [7039ec6a73fa] <1.8>
+
+       * Add support for controlling whether utmp is updated and which user
+       is listed in the entry.
+       [1b008ce71eab] <1.8>
+
+       * Fix typo; tupple vs. tuple
+       [67bb5c67ae3d] <1.8>
+
+       * For legacy utmp, strip the /dev/ prefix before trying to determine
+       slot since the ttys file does not include the /dev/ prefix.
+       [8f597114381d] <1.8>
+
+       * Add check for _PATH_UTMP
+       [fe7e2456f017] <1.8>
+
+       * Adapt check_iolog_path to sessid changes
+       [3016201869b6] <1.8>
+
+       * Redo utmp handling. If no getutent()/getutxent() is available,
+       assume a ttyslot-based utmp. If getttyent() is available, use that
+       directly instead of ttyslot() so we don't have to do the stdin dup2
+       dance.
+       [817490c7c20e] <1.8>
+
+       * Move utmp handling into utmp.c
+       [e4729d9259e9] <1.8>
+
+       * Update copyright years.
+       [1065afc00233] <1.8>
+
+2011-03-11  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Add "user_shell" boolean as a way to indicate to the plugin that the
+       -s flag was given.
+       [6e8bc49b7ea7] <1.8>
+
+       * Move sessid out of sudo_user.
+       [00d67d5ba894] <1.8>
+
+       * Log the TSID even if it is not a simple session ID.
+       [490cf0adae29] <1.8>
+
+       * Document noexec in sample.sudo.conf and add back noexec_file section
+       in sudoers with a note that it is deprecated.
+       [c7a2d8d0c563] <1.8>
+
+       * Fix running commands as non-root on systems where setreuid() changes
+       the saved uid based on the effective uid we are changing to.
+       [f3b27db56ba6] <1.8>
+
+2011-03-10  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Move noexec path into sudo.conf now that sudo itself handles noexec.
+       Currently can be configured in sudoers too but is now undocumented
+       and will be removed in a future release.
+       [9c5f64709994] <1.8>
+
+       * Document "Path noexec ..." in sudo.conf. No longer document
+       noexec_file in sudoers, it will be removed in a future release.
+       [959fa6b5217b] <1.8>
+
+       * Move noexec handling to sudo front-end where it is documented as
+       being.
+       [ef6cd4a40c61] <1.8>
 
-       * exec.c:
-       In handle_signals(), restart the read() on EINTR to make sure we
+       * Add support for disabling exec via solaris privileges. Includes
+       preparation for moving noexec support out of sudoers and into front
+       end as documented.
+       [d9c05ba9a24f] <1.8>
+
+       * Only export the symbols corresponding to the plugin structs.
+       [cb07af1d9b39] <1.8>
+
+       * Install plugins manually instead of using libtool. This works
+       around a problem on AIX where libtool will install a .a file
+       containing the .so file instead of the .so file itself.
+       [1ccf5af58c05] <1.8>
+
+       * Makefile.in:
+       Move check into its own rule since some versions of make will run
+       both targets as the default rule.
+       [7159f37eb552] <1.8>
+
+       * Update to libtool 2.2.10
+       [9e49773b32b7] <1.8>
+
+       * In handle_signals(), restart the read() on EINTR to make sure we
        keep up with the signal pipe. Don't return -1 on EAGAIN, it just
        means we have emptied the pipe.
-       [5bcfe5a061c2] <1.7>
+       [dc2926097b2d] <1.8>
 
-       * lbuf.c:
-       Fix printing of the remainder after a newline. Fixes "sudo -l"
-       output corruption that could occur in some cases.
-       [41e5595f0559] <1.7>
+       * Reorder functions to quiet a compiler warning.
+       [5201367e5db4] <1.8>
+
+       * Use the Sun Studio C compiler on Solaris if possible
+       [b8d43b423fb9] <1.8>
 
 2011-03-08  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * mkpkg:
-       Fix default setting of osversion variable.
-       [c67d9d3bfa2b] <1.7>
+       * Fix default setting of osversion variable.
+       [e12905851be5] <1.8>
+
+       * Make two login_class entris consistent.
+       [0671d7b204be] <1.8>
+
+       * Add support for adding a utmp entry when allocating a new pty.
+       Requires the BSD login(3) or SYSV/POSIX getutent()/getutxent().
+       Currently only creates a new entry if the existing tty has a utmp
+       entry.
+       [40ff30099e79] <1.8>
+
+       * Avoid pulling in headers we don't need on Linux For getutx?id(),
+       call setutx?ent() first and always call endutx?ent().
+       [b86f7a13aae9] <1.8>
+
+       * Add some more libs to SUDOERS_LIBS instead of relying on them to be
+       pulled in by SUDO_LIBS.
+       [bcbd16ec56c6] <1.8>
+
+       * Fix return value of "sudo -l command" when command is not allowed,
+       broken in [c7097ea22111]. The default return value is now TRUE and
+       a bad: label is used when permission is denied. Also fixed missing
+       permissions restoration on certain errors. On error()/errorx(), the
+       password and group files are now closed before returning.
+       [757c941a47b2] <1.8>
 
 2011-03-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * mkpkg:
-       Add --osversion flag to specify OS instead of running "pp
+       * Fix passing of login class back to sudo front end.
+       [5e649de6b7f5] <1.8>
+
+       * Add --osversion flag to specify OS instead of running "pp
        --probeonly"
-       [550104604d4b] <1.7>
+       [8a03943ac5e8] <1.8>
 
-       * sudo.pp:
-       Fix expr usage w/ GNU expr
-       [c2161988dec9] <1.7>
+       * Fix expr usage w/ GNU expr
+       [bdecfa1f54fc] <1.8>
+
+2011-03-06  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Fix exit value for validate and list mode.
+       [6f8b20199935] <1.8>
+
+       * Fix non-interactive mode with sudoers plugin.
+       [cf5aca4fcbcf] <1.8>
+
+2011-03-05  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * sudoreplay can now find IDs other than %{seq} and display the
+       session.
+       [60396b417633] <1.8>
+
+       * Add support for replaying sessions when iolog_file is set to
+       something other than %{seq}.
+       [1cd2baa74d56] <1.8>
+
+2011-03-04  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * If we are killed by a signal, display the name of the signal that
+       got us.
+       [1b38c4d42282] <1.8>
+
+       * Move libs used for authentication from SUDO_LIBS to SUDOERS_LIBS
+       where they belong.
+       [78e97a921104] <1.8>
+
+       * Fix bug in skey/opie check that could cause a shell warning.
+       [f20229a04f30] <1.8>
+
+       * No longer need sudo_getepw() stubs.
+       [795631ac7db0] <1.8>
+
+2011-03-03  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Fix exit value of "sudo -l command" in sudoers module.
+       [4a05d6019b3d] <1.8>
 
 2011-03-02  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudo.pp:
-       Don't use the beta or release candidate version as the rpm release.
-       [56f8c0b1eb46] <1.7>
+       * Use fgets() not fgetln() for portability.
+       [1f2050745096] <1.8>
+
+       * Don't use the beta or release candidate version as the rpm release.
+       [a5b049477646] <1.8>
 
 2011-02-25  Todd C. Miller  <Todd.Miller@courtesan.com>
 
+       * Makefile.in:
+       Adjust ChangeLog rule now that 1.8 is branched
+       [a994ac361e44] <1.8>
+
        * .hgtags:
-       Added tag SUDO_1_7_5 for changeset 9314212577c3
-       [75f9d661ea03] <1.7>
+       Added tag SUDO_1_8_0 for changeset f6530d56f6ae
+       [99a2b3801419] <1.8>
+
+2011-02-25  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * configure, configure.in:
-       version 1.7.5
-       [9314212577c3] [SUDO_1_7_5] <1.7>
+       version 1.8.0
+       [f6530d56f6ae] [SUDO_1_8_0]
 
-2011-02-21  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * NEWS:
+       update sudo 1.8 section
+       [f2ee2cf95d18]
+
+2011-02-23  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/regress/testsudoers/test2.sh:
+       fix test description
+       [cd5730fa9f09]
+
+       * plugins/sudoers/regress/testsudoers/test2.out,
+       plugins/sudoers/regress/testsudoers/test2.sh,
+       plugins/sudoers/regress/visudo/test2.out,
+       plugins/sudoers/regress/visudo/test2.sh:
+       convert test2 to use testsudoers
+       [b5ec3f0b69f1]
+
+       * include/sudo_plugin.h, src/sudo_plugin_int.h:
+       Move struct generic_plugin to sudo_plugin_int.h
+       [6f7bc629329c]
+
+       * plugins/sudoers/gram.c, plugins/sudoers/gram.y,
+       plugins/sudoers/parse.c, plugins/sudoers/parse.h,
+       plugins/sudoers/set_perms.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h:
+       Allow sudoers file name, mode, uid and gid to be specified in the
+       settings list. The sudo front end does not currently set these but
+       may in the future.
+       [22f38a0fda2a]
 
-       * configure, configure.in, sudo.cat, sudo.man.in, sudoers.cat,
-       sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.man.in,
-       sudoreplay.cat, sudoreplay.man.in, visudo.cat, visudo.man.in:
-       1.7.5rc1
-       [216ab95b5de0] <1.7>
+2011-02-21  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * parse_args.c, sudo.c, sudo.pod, sudo_usage.h.in, sudoreplay.c,
-       sudoreplay.pod, visudo.c, visudo.pod:
+       * configure, configure.in, doc/sudo.cat, doc/sudo.man.in,
+       doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudoers.cat,
+       doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in, doc/sudoers.man.in,
+       doc/sudoreplay.cat, doc/sudoreplay.man.in, doc/visudo.cat,
+       doc/visudo.man.in:
+       1.8.0rc1
+       [5d4588b9c057]
+
+       * doc/sudo.pod, doc/sudoreplay.pod, doc/visudo.pod,
+       plugins/sudoers/sudoreplay.c, plugins/sudoers/visudo.c,
+       src/parse_args.c, src/sudo.h:
        add help text to sudo, visudo and sudoreplay for the -h option
-       [141d348c660b] <1.7>
+       [52e7378d8476]
 
 2011-02-19  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * snprintf.c:
+       * compat/snprintf.c:
        avoid using "howmany" for a parameter name since it is a select-
        related macro
-       [6b6c2d504103] <1.7>
+       [a14d565401a1]
 
-       * Makefile.in:
+       * doc/sudoers.pod:
+       mention group_plugin when describing nonunix_group
+       [e0d1d0034b17]
+
+       * doc/sudo_plugin.pod:
+       Add missing period at end of sentence
+       [6744d7e9056d]
+
+       * Makefile.in, doc/Makefile.in, include/Makefile.in,
+       plugins/sample/Makefile.in, plugins/sample_group/Makefile.in,
+       plugins/sudoers/Makefile.in, src/Makefile.in:
        add localstatedir; closes bug 471
-       [a4778228ae54] <1.7>
+       [7aefcab85088]
 
-       * config.h.in, configure, configure.in, exec.c, exec_pty.c,
-       sudoreplay.c:
+       * config.h.in, configure, configure.in, plugins/sudoers/sudoreplay.c,
+       src/exec.c, src/exec_pty.c:
        The howmany macro lives in sys/sysmacros.h on SVR5 systems Closes
        Bug 470
-       [be5dff63ff5d] <1.7>
+       [927ed6740f32]
+
+       * configure.in:
+       add missing AH_TEMPLATE for ENV_RESET
+       [16300010c986]
 
-       * exec.c:
+       * src/exec.c:
        SVR5 systems return non-zero for success on socketpair(), check for
        -1 instead. Closes Bug 469
-       [13ac9d0e0934] <1.7>
+       [4d276494bf8e]
 
-2011-02-17  Todd C. Miller  <Todd.Miller@courtesan.com>
+2011-02-16  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * auth/afs.c:
-       Move afs includes to be before sudo ones
-       [fbe0bdcf5798] <1.7>
+       * configure, configure.in:
+       1.8.0b5
+       [d611cd5d73d3]
 
-       * config.h.in, configure, configure.in:
-       No longer use vhangup
-       [9fce94512df9] <1.7>
+       * doc/sudo.cat, doc/sudo.man.in, doc/sudo_plugin.cat,
+       doc/sudo_plugin.man.in, doc/sudoers.cat, doc/sudoers.ldap.cat,
+       doc/sudoers.ldap.man.in, doc/sudoers.man.in, doc/sudoreplay.cat,
+       doc/sudoreplay.man.in, doc/visudo.cat, doc/visudo.man.in:
+       regen
+       [85e96eeaed82]
+
+       * doc/sudo.pod:
+       Document that a sudo.conf file with no Pligin lines uses the default
+       sudoers plugins.
+       [88bd52da977f]
+
+       * src/load_plugins.c:
+       If sudo.conf contains no Plugin lines, use the default sudoers
+       policy and I/O plugins.
+       [fd8f4cb811ab]
 
 2011-02-14  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudo_nss.c:
+       * plugins/sudoers/sudo_nss.c:
        Avoid printing empty "Runas and Command-specific defaults for user"
        line.
-       [3df2925f9982] <1.7>
+       [2dd330fe4f8b]
 
-       * lbuf.c:
+       * common/lbuf.c:
        Truncate the buffer at buf.len before printing in the non-wordwrap
        case.
-       [23a31b8d95b8] <1.7>
+       [901e9833f80d]
 
-       * lbuf.c:
+       * common/lbuf.c:
        Remove extra newline when the tty width is very small or unavailable
-       [32fa0b3ea47a] <1.7>
-
-2011-02-13  Todd C. Miller  <Todd.Miller@courtesan.com>
-
-       * configure, configure.in, sudo.cat, sudo.man.in, sudoers.cat,
-       sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.man.in,
-       sudoreplay.cat, sudoreplay.man.in, visudo.cat, visudo.man.in:
-       1.7.5b5
-       [0937b9bff020] <1.7>
-
-       * pp:
-       don't remap numeric uids/gids to names; if the user specified and id
-       instead of a name, they probably mean it
-       [2b81d57de4a4] <1.7>
+       [245c05506c0e]
 
 2011-02-11  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * alias.c:
+       * plugins/sudoers/alias.c:
        Remove unneeded variable.
-       [23329353f964] <1.7>
+       [2c086d30b796]
 
 2011-02-09  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * configure, configure.in:
        Prefer getutxid over getutid
-       [e89811f0e4da] <1.7>
+       [3f3322e9c93e]
 
-       * boottime.c:
+       * plugins/sudoers/boottime.c:
        Include utmp.h / utmpx.h before missing.h as apparently including it
        afterwards causes a compilation problem on GNU Hurd.
-       [d62781e31b27] <1.7>
+       [a528029ae962]
 
 2011-02-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * configure, configure.in, sudo.cat, sudo.man.in, sudoers.cat,
-       sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.man.in,
-       sudoreplay.cat, sudoreplay.man.in, visudo.cat, visudo.man.in:
-       1.7.5b4
-       [4b8a9632fe59] <1.7>
+       * plugins/sudoers/sudoreplay.c, plugins/sudoers/toke_util.c:
+       #include "foo.h", not <foo.h> for local includes.
+       [f65ec693998e]
 
-       * exec.c, missing.h, sudo.c, toke.h:
-       fix K&R compilation
-       [23ebea9c2183] <1.7>
+       * src/parse_args.c:
+       remove bogus XXX
+       [9136c17d53ce]
 
-       * mksiglist.c:
+       * compat/mksiglist.c:
        Fix typo
-       [1587615a186f] <1.7>
-
-       * Makefile.in, toke.h, toke.l, toke_util.c:
-       Split tokenizer utility functions out into toke_util.c
-       [88148d0b9338] <1.7>
+       [1a3bb7b455c9]
 
-       * alloc.c, bsm_audit.c, check.c, closefrom.c, sudo_nss.c, visudo.c:
-       Cosmetic changes to make diffing against trunk easier.
-       [95bdfcc29a22] <1.7>
-
-       * exec.c, exec_pty.c, mon_systrace.c, sudo.h, sudo_exec.h,
-       sudoreplay.c, tgetpass.c:
-       Use RETSIGTYPE for signal handlers.
-       [5ea1f34d1aab] <1.7>
-
-       * sudo_exec.h:
-       Use special values SIGCONT_FG and SIGCONT_BG instead of SIGUSR1 and
-       SIGUSR2 to indicate whether the child should be continued in the
-       foreground or background.
-       [9fec5a258d57] <1.7>
+       * compat/glob.c, plugins/sudoers/ldap.c, plugins/sudoers/logging.c,
+       plugins/sudoers/match.c:
+       return foo not return(foo)
+       [5c9e0647359a]
 
 2011-02-06  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * getspwuid.c:
-       Merge trunk version
-       [cd44ef67e57d] <1.7>
-
-       * exec_pty.c:
-       Use special values SIGCONT_FG and SIGCONT_BG instead of SIGUSR1 and
-       SIGUSR2 to indicate whether the child should be continued in the
-       foreground or background.
-       [6305babcf6bd] <1.7>
-
-       * exec.c:
-       If perform_io() fails, kill the child before exiting so it doesn't
-       complain about connection reset. We can get an I/O error if, for
-       example, and we get EIO reading from stdin.
-       [ca28e0a25698] <1.7>
+       * src/exec.c:
+       Remove duplicate FD_SET of signal_pipe[0]
+       [3096527d2215]
 
 2011-02-05  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * error.c, fileops.c, fnmatch.c, getcwd.c, getprogname.c, gettime.c,
-       glob.c, isblank.c, memrchr.c, mksiglist.c, mkstemps.c, nanosleep.c,
-       setsid.c, sigaction.c, snprintf.c, strcasecmp.c, strerror.c,
-       strlcat.c, strlcpy.c, strsignal.c, sudo_noexec.c, sudoreplay.c,
-       utimes.c, vasgroups.c, zero_bytes.c:
-       Make local includes consistent; use double quotes for local includes
-       [ec9d52fff4b3] <1.7>
+       * compat/mksiglist.c:
+       Use "missing.h" not <missing.h> in generated code.
+       [d8e09cffbe09]
 
 2011-02-04  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * error.c, getprogname.c, memrchr.c, sigaction.c, strcasecmp.c,
-       strerror.c, strlcat.c, strlcpy.c, strsignal.c, zero_bytes.c:
-       Must include config.h before any other headers.
-       [3c23ec625df0] <1.7>
-
        * aclocal.m4, configure:
        fix --with-iologdir=no
-       [ef60ca8b3789] <1.7>
+       [a89699cb5f5f]
 
        * aclocal.m4, configure:
        fix typo that broke --with-iologdir
-       [fca175fdfd81] <1.7>
+       [91b54eb22403]
 
 2011-02-03  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * NEWS:
-       sync for 1.7.5b3
-       [744e2e78ef5a] <1.7>
+       * configure, configure.in, doc/sudo.cat, doc/sudo.man.in,
+       doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudoers.cat,
+       doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in, doc/sudoers.man.in,
+       doc/sudoreplay.cat, doc/sudoreplay.man.in, doc/visudo.cat,
+       doc/visudo.man.in:
+       Bump version to 1.8.0b4
+       [e2b7f2cdc02e]
 
-       * configure, configure.in, sudo.cat, sudo.man.in, sudoers.cat,
-       sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.man.in,
-       sudoreplay.cat, sudoreplay.man.in, visudo.cat, visudo.man.in:
-       1.7.5b3
-       [7a24576e35ac] <1.7>
+       * NEWS:
+       sync
+       [decf5a0a8a33]
 
-       * sudoers.cat, sudoers.man.in, sudoers.pod:
+       * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod:
        Attempt to clarify how users and groups interact in Runas_Specs
-       [9e8c2fb328d0] <1.7>
+       [e6fb3a2dbd77]
 
-       * exec.c, exec_pty.c:
-       Do not handle SIGARLM specially, just pass it through.
-       [944978b640b5] <1.7>
+       * plugins/sudoers/regress/visudo/test2.out,
+       plugins/sudoers/regress/visudo/test2.sh:
+       Add test for quoted group that contains escaped double quotes
+       [44596c48c629]
 
-       * exec.c, exec_pty.c:
+       * src/exec.c, src/exec_pty.c:
        Pass SIGUSR1/SIGUSR2 through to the child.
-       [774506c977df] <1.7>
+       [c3108a827b01]
 
-       * exec.c:
-       Made tcsetpgrp() bits conditional on HAVE_TCSETPGRP
-       [386f69132ad4] <1.7>
+       * src/exec_pty.c, src/sudo_exec.h:
+       Use special values SIGCONT_FG and SIGCONT_BG instead of SIGUSR1 and
+       SIGUSR2 to indicate whether the child should be continued in the
+       foreground or background.
+       [35ca47cc6785]
 
-       * exec.c:
+       * src/exec.c:
        Use pid_t not int and check the return value of kill()
-       [5f15c3304a1d] <1.7>
+       [36ae7d37d7f9]
 
 2011-02-02  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * exec.c:
+       * src/exec_pty.c:
+       Remove obsolete comment
+       [baebef4919f6]
+
+       * src/exec.c:
        In non-pty mode before continuing the child, make it the foreground
        pgrp if possible. Fixes resuming a shell.
-       [dfaadefcc6c6] <1.7>
+       [fef5b1d02ddb]
 
-       * exec_pty.c:
+       * src/exec_pty.c:
        If we get a signal other than SIGCHLD in the monitor, pass it
        directly to the child.
-       [7e638105bfaf] <1.7>
+       [b3ecb28163a0]
 
-       * exec.c, exec_pty.c, sudo.h:
+       * src/exec.c, src/exec_pty.c, src/sudo.h:
        Save signal state before changing handlers and restore before we
        execute the command.
-       [83278957e630] <1.7>
+       [faf7475dc4bf]
 
 2011-02-01  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * toke.c, toke.l:
-       match quoted strings the same way whether in a Defaults line or as a
-       user/group/netgroup name. Fixes escaped double quotes in quoted
-       user/group/netgroup names.
-       [c2b486b12951] <1.7>
-
-       * iolog.c:
+       * plugins/sudoers/iolog.c:
        Use a char array to map a number to a base36 digit.
-       [d626ded3312d] <1.7>
+       [257576c51f8b]
 
-       * sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.ldap.pod:
+       * doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in, doc/sudoers.ldap.pod:
        Be clear about what versions of sudo support new LDAP attributes.
        Fix up some formatting of attribute names. Minor other tweaks.
-       [f7bd586ec755] <1.7>
+       [39f65df71f65]
 
 2011-01-31  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudoers2ldif:
-       Add sudoOrder attribute to each entry Parse LOG_{INPUT,OUTPUT} tags
-       [05a0d25b0f8d] <1.7>
+       * plugins/sudoers/toke.c, plugins/sudoers/toke.l:
+       match quoted strings the same way whether in a Defaults line or as a
+       user/group/netgroup name. Fixes escaped double quotes in quoted
+       user/group/netgroup names.
+       [601d97ea8792]
+
+       * plugins/sudoers/Makefile.in:
+       'make check' depends on visudo and testsudoers
+       [127c5a24df8f]
+
+       * plugins/sudoers/sudoers2ldif:
+       Add sudoOrder attribute to each entry Parse LOG_{INPUT,OUTPUT} tags
+       [9029163a58c3]
 
 2011-01-30  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * UPGRADE:
+       * doc/UPGRADE:
        Mention LDAP attribute compatibility status.
-       [adb74ad2331b] <1.7>
+       [2c3595aaec63]
 
 2011-01-28  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * README.LDAP:
        Mention phpQLAdmin
-       [5d80d6291142] <1.7>
+       [9304c9064fbe]
 
-       * INSTALL, NEWS, config.h.in, configure, configure.in, defaults.c,
-       sudoers.man.in, sudoers.pod:
+       * INSTALL, NEWS, config.h.in, configure, configure.in,
+       doc/sudoers.man.in, doc/sudoers.pod, plugins/sudoers/defaults.c:
        Add --disable-env-reset configure option.
-       [803ce2f4d85c] <1.7>
+       [8a753aa13a46]
 
-       * sudoers.cat, sudoers.man.in, sudoers.pod:
+       * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod:
        Document that sudoers_locale also affects logging and email.
-       [080dd4338374] <1.7>
+       [998d6ac11277]
 
-       * NEWS, config.h.in, configure, configure.in, logging.c:
+       * NEWS, config.h.in, configure, configure.in,
+       plugins/sudoers/logging.c:
        Do logging and email sending in the locale specified by the
        "sudoers_locale" setting ("C" by default). Email send by sudo
        includes MIME headers when the sudoers locale is not "C".
-       [592e5b2a3d10] <1.7>
+       [cb7e55408400]
+
+2011-01-27  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/check.c:
+       Fix indentation
+       [65ae7e92b9e4]
 
 2011-01-25  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * NEWS, sudo.c:
+       * NEWS, src/parse_args.c, src/sudo.c:
        Perform command escaping for "sudo -s" and "sudo -i" after
        validating sudoers so the sudoers entries don't need to have all the
        backslashes.
-       [7d39ea9924e4] <1.7>
+       [4e168c103f4b]
 
 2011-01-24  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * logging.c:
+       * plugins/sudoers/logging.c:
        Prepend "list " to the command logged when "sudo -l command" is used
        to make it clear that the command was listed, not run.
-       [9bcd40c1bfe9] <1.7>
+       [f392a6056cd6]
 
-       * parse.c:
+       * plugins/sudoers/parse.c:
        cosmetic change
-       [8ce3d60d910d] <1.7>
-
-       * aix.c, alias.c, alloc.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, bsm_audit.c, check.c,
-       defaults.c, env.c, exec.c, exec_pty.c, fileops.c, find_path.c,
-       fnmatch.c, get_pty.c, getcwd.c, getline.c, getprogname.c,
-       getspwuid.c, gettime.c, glob.c, goodpath.c, gram.c, gram.y, iolog.c,
-       isblank.c, lbuf.c, ldap.c, list.c, logging.c, match.c, memrchr.c,
-       mkstemps.c, mon_systrace.c, nanosleep.c, parse.c, parse_args.c,
-       pwutil.c, redblack.c, set_perms.c, sigaction.c, snprintf.c,
-       strerror.c, strlcat.c, strlcpy.c, strsignal.c, sudo.c,
-       sudo_noexec.c, sudo_nss.c, sudoreplay.c, term.c, testsudoers.c,
-       tgetpass.c, timestr.c, toke.c, toke.l, tsgetgrpw.c, utimes.c,
-       vasgroups.c, visudo.c:
+       [7c0951dbc2dd]
+
+       * common/aix.c, common/alloc.c, common/fileops.c, common/fmt_string.c,
+       common/list.c, common/term.c, compat/fnmatch.c, compat/getcwd.c,
+       compat/glob.c, compat/isblank.c, compat/memrchr.c, compat/mktemp.c,
+       compat/nanosleep.c, compat/regress/glob/globtest.c,
+       compat/snprintf.c, compat/strlcat.c, compat/strlcpy.c,
+       compat/strsignal.c, compat/utimes.c, plugins/sample/sample_plugin.c,
+       plugins/sample_group/getgrent.c, plugins/sample_group/plugin_test.c,
+       plugins/sudoers/alias.c, plugins/sudoers/auth/afs.c,
+       plugins/sudoers/auth/aix_auth.c, plugins/sudoers/auth/bsdauth.c,
+       plugins/sudoers/auth/dce.c, plugins/sudoers/auth/fwtk.c,
+       plugins/sudoers/auth/kerb4.c, plugins/sudoers/auth/kerb5.c,
+       plugins/sudoers/auth/pam.c, plugins/sudoers/auth/passwd.c,
+       plugins/sudoers/auth/rfc1938.c, plugins/sudoers/auth/secureware.c,
+       plugins/sudoers/auth/securid.c, plugins/sudoers/auth/securid5.c,
+       plugins/sudoers/auth/sia.c, plugins/sudoers/bsm_audit.c,
+       plugins/sudoers/check.c, plugins/sudoers/defaults.c,
+       plugins/sudoers/find_path.c, plugins/sudoers/goodpath.c,
+       plugins/sudoers/gram.c, plugins/sudoers/gram.y,
+       plugins/sudoers/iolog.c, plugins/sudoers/ldap.c,
+       plugins/sudoers/match.c, plugins/sudoers/mon_systrace.c,
+       plugins/sudoers/parse.c, plugins/sudoers/pwutil.c,
+       plugins/sudoers/redblack.c, plugins/sudoers/set_perms.c,
+       plugins/sudoers/sudo_nss.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c,
+       plugins/sudoers/timestr.c, plugins/sudoers/toke.c,
+       plugins/sudoers/toke.l, plugins/sudoers/toke_util.c,
+       plugins/sudoers/tsgetgrpw.c, plugins/sudoers/visudo.c,
+       src/exec_pty.c, src/get_pty.c, src/load_plugins.c, src/parse_args.c,
+       src/sudo_noexec.c, src/tgetpass.c:
        standardize on "return foo;" rather than "return(foo);" or "return
        (foo);"
-       [e05dd17dcec4] <1.7>
-
-       * NEWS:
-       sync
-       [bedc1e1bc7f8] <1.7>
+       [32d76c5aaf8c]
 
-       * sudo.c:
+       * plugins/sudoers/sudoers.c:
        Do not reject sudoers file just because it is root-writable.
-       [26634f322b04] <1.7>
+       [0febc579185b]
 
 2011-01-21  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * NEWS:
        sync
-       [c69b7537a020] <1.7>
-
-       * defaults.c:
-       When setting default iolog_dir, dynamically allocate the string.
-       [7ad2c0cbe865] <1.7>
+       [1ab03f8278ff]
 
-       * sudo_nss.c:
+       * plugins/sudoers/sudo_nss.c:
        For "sudo -U user -l" if user is not authorized on the host, say so.
-       [9eb5673f2f22] <1.7>
+       [289afe6dd15c]
 
-       * ldap.c:
+       * plugins/sudoers/ldap.c:
        In sudo_ldap_lookup(), always do the initial sudoers check as the
        invoking user. If we are listing another user's privs we will do a
        separate lookup using list_pw later.
-       [9b3ab41de717] <1.7>
+       [e52bc15de76d]
 
 2011-01-20  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudoreplay.c:
-       change an error() to errorx()
-       [5a0409f6c52b] <1.7>
-
-       * sudoers.ldap.man.in, sudoers.ldap.pod:
+       * MANIFEST:
+       add parser fill tests
+       [4f65140d3515]
+
+       * compat/regress/glob/globtest.c, compat/regress/glob/globtest.in:
+       Don't test features not supported by the bundled glob()
+       [8ec7ace11949]
+
+       * Makefile.in, aclocal.m4, common/Makefile.in, common/term.c,
+       compat/Makefile.in, configure.in, doc/LICENSE, doc/Makefile.in,
+       doc/sudo_plugin.man.in, doc/sudo_plugin.pod,
+       doc/sudoers.ldap.man.in, doc/sudoers.ldap.pod, doc/sudoers.man.in,
+       doc/sudoers.pod, include/Makefile.in, plugins/sample/Makefile.in,
+       plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in,
+       plugins/sudoers/check.c, plugins/sudoers/defaults.c,
+       plugins/sudoers/gram.c, plugins/sudoers/gram.y,
+       plugins/sudoers/iolog.c, plugins/sudoers/iolog_path.c,
+       plugins/sudoers/ldap.c, plugins/sudoers/match.c,
+       plugins/sudoers/pwutil.c, plugins/sudoers/sudo_nss.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h,
+       plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c,
+       plugins/sudoers/toke.c, plugins/sudoers/toke.l,
+       plugins/sudoers/toke_util.c, src/Makefile.in, zlib/Makefile.in:
        Update copyright year to 2011
-       [8959c05dc270] <1.7>
+       [ac1b45cb1809]
 
-       * LICENSE, Makefile.in, aclocal.m4, check.c, configure.in, ldap.c,
-       match.c, pwutil.c, sudo_nss.c, sudoers.man.in, sudoers.pod, term.c:
-       Update copyright year to 2011
-       [6367fb76120e] <1.7>
+       * plugins/sudoers/sudo_nss.c:
+       When listing, use separate lbufs for the defaults and the privileges
+       and only print something if the number of privileges is non-zero.
+       Fixes extraneous Defaults output for "sudo -U unauthorized_user -l".
+       [d0854d39f8ef]
 
-       * ldap.c:
+       * plugins/sudoers/ldap.c:
        Stash pointer to user group vector in LDAP handle and only reuse the
        query if it has not changed. We always allocate a new buffer when
        we reset the group vector so a simple pointer check is sufficient.
-       [c129d1acf7d6] <1.7>
+       [88861d4eba69]
 
-       * sudo_nss.c:
-       When listing, use separate lbufs for the defaults and the privileges
-       and only print something if the number of privileges is non-zero.
-       Fixes extraneous Defaults output for "sudo -U unauthorized_user -l".
-       [66aaa54f2865] <1.7>
-
-       * sudo_nss.c:
+       * plugins/sudoers/sudo_nss.c:
        Check initgroups() return value.
-       [973a67304e3b] <1.7>
+       [3bdaf58408a7]
+
+       * plugins/sudoers/Makefile.in,
+       plugins/sudoers/regress/parser/check_fill.c:
+       Add tests for the fill functions in toke_util.c
+       [bca587ab4956]
 
 2011-01-19  Todd C. Miller  <Todd.Miller@courtesan.com>
 
+       * plugins/sudoers/regress/iolog_path/check_iolog_path.c:
+       fix copyright year
+       [e2038cdaf055]
+
        * NEWS:
        sync
-       [deb822cce3dd] <1.7>
+       [56ca5d5eaebe]
 
 2011-01-18  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * term.c:
-       Clear, don't set, OPOST in c_oflag as was intended in e26055d17b72.
-       [eacd774c37c0] <1.7>
-
-2011-01-15  Todd C. Miller  <Todd.Miller@courtesan.com>
-
-       * sudo.c:
-       delref list_pw before exit
-       [0df5a53f3484] <1.7>
+       * common/term.c:
+       Clear, don't set, OPOST in c_oflag as was intended in 506ad5ae9b4e.
+       [b91f266624ec]
 
 2011-01-14  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * mkpkg, sudo.pp:
        Add Requires line for audit-libs >= 1.4 for RHEL5+
-       [a1b544018f5b] <1.7>
+       [6c02f976171b]
 
        * pp:
        sync with git version
-       [eb187023bb73] <1.7>
+       [d301c32d5865]
 
 2011-01-13  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudoers.cat, sudoers.man.in, sudoers.pod:
+       * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod:
        fix typo
-       [075e92a756a1] <1.7>
+       [39353f92976f]
 
 2011-01-12  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * NEWS:
        Update for sudo 1.7.4p5
-       [11cb87598478] <1.7>
+       [b444da76901f]
 
-       * schema.OpenLDAP, schema.iPlanet:
+       * doc/schema.OpenLDAP, doc/schema.iPlanet:
        Add sudoNotBefore and sudoNotAfter attributes as optional attributes
        to the sudoRole object class. From Andreas Mueller
-       [73357eb1b269] <1.7>
+       [dacfad7e7a95]
 
 2011-01-11  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * NEWS:
        Mention "sudo -g group" password check fix.
-       [8299a2d939e8] <1.7>
+       [1eb8fb14e53b]
 
-       * check.c:
+       * plugins/sudoers/sudoers.c:
+       Fix "sudo -g" support in the sudoers module.
+       [07d1b0ce530e]
+
+       * plugins/sudoers/check.c:
        If the user is running sudo as himself but as a different group we
        need to prompt for a password.
-       [fe8a94f96542] <1.7>
+       [caf1fcc9a117]
 
 2011-01-10  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * NEWS, config.h.in, configure, configure.in, ldap.c,
-       sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.ldap.pod:
+       * NEWS, config.h.in, configure, configure.in, doc/sudoers.ldap.cat,
+       doc/sudoers.ldap.man.in, doc/sudoers.ldap.pod,
+       plugins/sudoers/ldap.c:
        Add support for TIMEOUT in ldap.conf, mapping to the OpenLDAP
        LDAP_OPT_TIMEOUT. There is no corresponding option for mozilla-
        derived LDAP SDKs but we can pass the timeout parameter to
        ldap_search_ext_s() or ldap_search_st() when possible.
-       [8f9303326db7] <1.7>
+       [5537049991f7]
 
-       * sudoers.cat, sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.man.in:
+       * doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in:
        regen
-       [d56ad7169e67] <1.7>
+       [5b361c3c4324]
 
-       * NEWS, ldap.c, sudoers.ldap.pod:
+       * NEWS, doc/sudoers.ldap.pod, plugins/sudoers/ldap.c:
        Add NETWORK_TIMEOUT as an alias for BIND_TIMELIMIT for compatibility
        with OpenLDAP ldap.conf files.
-       [85e33e42c008] <1.7>
+       [e97843bd16fb]
 
-       * pwutil.c:
+       * plugins/sudoers/pwutil.c:
        If user has no supplementary groups, fall back on checking the group
-       file explicitly.
-       [c536ddb16bb6] <1.7>
+       file expliticly.
+       [5223ad4eb690]
+
+2011-01-08  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/toke.h, plugins/sudoers/toke_util.c:
+       constify
+       [6e132a4cca61]
+
+       * plugins/sudoers/toke.c, plugins/sudoers/toke.h,
+       plugins/sudoers/toke.l:
+       Move fill macro to toke.h
+       [623d430798cf]
+
+       * MANIFEST, plugins/sudoers/Makefile.in, plugins/sudoers/toke.c,
+       plugins/sudoers/toke.h, plugins/sudoers/toke.l,
+       plugins/sudoers/toke_util.c:
+       Split tokenizer utility functions out into toke_util.c
+       [89a97bd51618]
+
+       * plugins/sudoers/gram.c, plugins/sudoers/gram.y,
+       plugins/sudoers/toke.c, plugins/sudoers/toke.l:
+       ANSIfy
+       [ca0eba1dfaa9]
+
+2011-01-07  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * MANIFEST:
+       sync
+       [a43f94064bb3]
+
+       * plugins/sudoers/Makefile.in:
+       Add visudo tests to check target
+       [8c82fb4ed40f]
+
+       * compat/Makefile.in, compat/regress/fnmatch/fnm_test.c,
+       compat/regress/fnmatch/fnm_test.in, compat/regress/glob/files,
+       compat/regress/glob/globtest.c, compat/regress/glob/globtest.in:
+       Add my regress tests for fnmatch() and glob() from OpenBSD.
+       [6e8c1f211723]
+
+       * plugins/sudoers/regress/testsudoers/test1.sh,
+       plugins/sudoers/regress/visudo/test1.ok,
+       plugins/sudoers/regress/visudo/test1.sh:
+       Add regress test for command tags using visudo -c
+       [18b0ef207c0f]
+
+       * plugins/sudoers/Makefile.in,
+       plugins/sudoers/regress/testsudoers/test1.ok,
+       plugins/sudoers/regress/testsudoers/test1.sh:
+       Add support for regress tests using testsudoers
+       [1fa94bd2671b]
+
+       * plugins/sudoers/testsudoers.c:
+       Need to set user_name explicitly due to internal changes made when
+       converting sudoers to a plugin.
+       [1fa54e86a364]
+
+2011-01-06  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * MANIFEST, Makefile.in, common/Makefile.in, compat/Makefile.in,
+       doc/Makefile.in, include/Makefile.in, plugins/sample/Makefile.in,
+       plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in,
+       plugins/sudoers/regress/iolog_path/check_iolog_path.c,
+       plugins/sudoers/regress/iolog_path/data, src/Makefile.in,
+       zlib/Makefile.in:
+       Add regression tests for iolog_path()
+       [afa4b416e559]
+
+       * Makefile.in, common/Makefile.in, compat/Makefile.in,
+       doc/Makefile.in, include/Makefile.in, plugins/sample/Makefile.in,
+       plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in,
+       src/Makefile.in, zlib/Makefile.in:
+       Add support for "make Makefile" to regenerate Makefile from
+       Makefile.in
+       [98bd2dda3294]
+
+       * plugins/sudoers/iolog_path.c:
+       Quiest a bogus compiler warning.
+       [5ff932a7ad67]
+
+2011-01-05  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/iolog_path.c:
+       Protect call to setlocale() with HAVE_SETLOCALE
+       [2c29ee3ccc81]
 
 2011-01-04  Todd C. Miller  <Todd.Miller@courtesan.com>
 
+       * MANIFEST:
+       mkstemps.c was renamed mktemp.c
+       [ae299c3b1827]
+
        * NEWS:
-       update
-       [9f6e0ec3142a] <1.7>
+       Update from 1.7 branch
+       [20817d79717b]
 
        * Makefile.in:
        Use "mv -f" when regenerating ChangeLog
-       [b322b5995e7f] <1.7>
+       [c163635206c6]
 
-       * match.c:
+       * plugins/sudoers/match.c:
        Fix NULL dereference with "sudo -g group" when the sudoers rule has
        no runas user or group listed. Fixes RedHat bug Bug 667103.
-       [c51e2be737b2] <1.7>
+       [41a6a1243d9e]
+
+2011-01-03  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Correct the default sudo.conf example
+       [4e791698cad1]
+
+2010-12-31  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/iolog_path.c:
+       Reset slashp if we allocate a new buffer for strftime()
+       [e491daa4203b]
+
+       * plugins/sudoers/iolog_path.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h:
+       Add extra out parameter to expand_iolog_path() to allow the caller
+       to split the path into dir and file components if needed.
+       [88346bc5ae39]
+
+2010-12-30  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/iolog.c:
+       mkdir_iopath() returns size_t now that it uses strlcpy() and not
+       snprintf()
+       [3c4c64d265eb]
+
+       * plugins/sudoers/iolog.c, plugins/sudoers/iolog_path.c:
+       Trim leading slashes from iolog_file and trailing slashes from
+       iolog_dir
+       [a803b51f8948]
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod,
+       plugins/sudoers/iolog.c, plugins/sudoers/iolog_path.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h:
+       Pass a single I/O log file name in command_details instead of
+       separate dir + file parameters.
+       [d672a3e46e80]
+
+       * plugins/sudoers/sudoreplay.c:
+       change an error() to errorx()
+       [8013dcfdd69d]
+
+       * plugins/sudoers/iolog.c:
+       Add missing cwd line to I/O log info file that got dropped when
+       iolog_deserialize_info() was added
+       [7cf84f208423]
+
+2010-12-29  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/iolog.c:
+       Avoid relying on globals filled in by the sudoers policy module for
+       the sudoers I/O log module. The I/O log open function now pulls the
+       bits it needs out of user_info and command_info.
+       [c02f6951b0cc]
+
+       * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h:
+       If no iolog file is specified by the policy plugin, use io_nextid()
+       to determine the next file in the sequence.
+       [faa1130b1020]
+
+2010-12-28  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Document iolog_compress in command_info
+       [58895c7d12f5]
+
+       * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c:
+       Add support for the iolog_compress variable in command_info.
+       [36f13a2fd1c1]
+
+       * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c:
+       Add sigsetjmp() calls to all plugin entry points just to be safe.
+       [3fa482355bc4]
+
+       * src/sudo.c, src/sudo.h:
+       Don't need iolog variables in struct command_details, they are for
+       the I/O log plugins to handle.
+       [5111579ffd9d]
+
+2010-12-27  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod:
+       Document use of mkdtemp() for iolog path teplates
+       [5db6101408a9]
+
+       * doc/sudo.cat, doc/sudo.man.in, doc/sudo_plugin.cat,
+       doc/sudo_plugin.man.in, doc/sudoers.cat, doc/sudoers.ldap.cat,
+       doc/sudoers.ldap.man.in, doc/sudoers.man.in, doc/sudoreplay.cat,
+       doc/sudoreplay.man.in, doc/visudo.cat, doc/visudo.man.in:
+       regen
+       [1ee11fd6d4eb]
+
+       * doc/sudo_plugin.pod, doc/sudoers.pod:
+       Document iolog_file and supported escape sequences for sudoers.
+       Clarify that iolog_file can contain directories.
+       [da611dedcbdb]
+
+       * compat/Makefile.in, configure, configure.in:
+       Fix building of mkstemps/mkdtemp replacements.
+       [793a5e303122]
+
+       * compat/mkstemps.c, compat/mktemp.c, config.h.in, configure,
+       configure.in, include/missing.h:
+       Provide mkdtemp() for systems without it.
+       [b0527dfa965c]
+
+       * plugins/sudoers/iolog_path.c:
+       Fix typo
+       [277f6c514cba]
+
+       * plugins/sudoers/iolog.c:
+       Only use mkdtemp() if the path ends in at least 6 Xs since otherwise
+       glibc mkdtemp() returns EINVAL.
+       [2e7323b05579]
+
+       * plugins/sudoers/Makefile.in, plugins/sudoers/def_data.c,
+       plugins/sudoers/def_data.h, plugins/sudoers/def_data.in,
+       plugins/sudoers/defaults.c, plugins/sudoers/iolog.c,
+       plugins/sudoers/iolog_path.c, plugins/sudoers/plugin_error.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h:
+       Allow sudoers to specify the iolog file in addition to the iolog
+       dir. Add escape sequence support to iolog file and dir: sequence
+       number, user, group, runas_user, runas_group, hostname and
+       command in addition to any escape sequence recognized by
+       strftime(3).
+       [75cd32ee0435]
+
+       * plugins/sudoers/iolog.c:
+       Add missing sigsetjmp() call in I/O plugin open function. Fixes a
+       crash when the I/O plugin calls error(), errorx() or log_error().
+       [1a6718bd817d]
 
 2010-12-21  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * term.c:
+       * doc/sudo_plugin.pod, plugins/sudoers/iolog.c,
+       plugins/sudoers/sudoers.c:
+       Give the policy module fine-grained control over what the I/O plugin
+       logs.
+       [d29784fd2a66]
+
+       * common/term.c:
        Clear OPOST from c_oflag like we used to. Fixes screen-based
        editors such as vi.
-       [e26055d17b72] <1.7>
+       [506ad5ae9b4e]
 
-       * sudoers.pod:
+       * doc/sudoers.pod:
        Clarify umask option description. From Reuben Thomas.
-       [fb8bdcb54feb] <1.7>
+       [1294ac84222b]
 
-2010-12-18  Todd C. Miller  <Todd.Miller@courtesan.com>
+2010-12-20  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * ldap.c, sudoers.ldap.pod:
+       * doc/sudoers.ldap.pod, plugins/sudoers/ldap.c:
        Pick last match in LDAP sudoers too
-       [607801b83e25] <1.7>
+       [fbfd8e85703b]
+
+       * doc/sudo_plugin.pod:
+       Document iolog_file, iolog_dir and use_pty
+       [26120a59c20e]
+
+       * plugins/sample/sample_plugin.c, plugins/sudoers/iolog.c,
+       plugins/sudoers/sudoers.c:
+       Adapt plugins to version I/O logging ABI 1.1
+       [880dd64bc1e8]
+
+       * src/exec.c, src/sudo.h:
+       Add use_pty command_info flag for policies to indicate that a pty
+       should be allocated even if no I/O logging is performed.
+       [e7b167f8a6e5]
+
+       * src/sudo.c:
+       Add remaining plugin convenience functions
+       [ffeaf96da031]
+
+       * include/sudo_plugin.h, src/sudo.c, src/sudo.h,
+       src/sudo_plugin_int.h:
+       Change I/O log API to pass in command info to the I/O log open
+       function. Add iolog_file and iolog_dir parameters to command info.
+       This allows the policy plugin to specify the I/O log pathname. Add
+       convenience functions for calling plugin functions that handle ABI
+       backwards compatibility.
+       [9b81dce76ce5]
+
+       * compat/dlopen.c:
+       Remove useless cast
+       [7cecce969739]
+
+2010-12-17  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * configure, configure.in:
+       Bump version to 1.8.0b3
+       [1dc9f040aae0]
+
+2010-12-13  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * configure.in:
+       Remove extraneous newline
+       [71c94551eea5]
 
 2010-12-10  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * aclocal.m4, configure, configure.in, def_data.c, def_data.h,
-       def_data.in, defaults.c, iolog.c, sudoers.pod:
-       Make the iolog dir configurable in sudoers
-       [2630b2dba1b5] <1.7>
+       * doc/sudoers.pod, plugins/sudoers/def_data.c,
+       plugins/sudoers/def_data.h, plugins/sudoers/def_data.in,
+       plugins/sudoers/defaults.c, plugins/sudoers/iolog.c:
+       Make I/O log dir configurable.
+       [99b576667a38]
+
+       * aclocal.m4, configure, configure.in, doc/sudoers.pod:
+       Rename io_logdir to iolog_dir
+       [0731662acc8d]
 
 2010-12-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * pp:
        Add missing '*' that prevented the generic ELF case from matching.
-       [b35bbb42736f] <1.7>
+       [be77ca26bfb2]
 
        * pp:
        If file(1) can't identify the ELF binary type, try readelf(1).
-       [8a73092d8898] <1.7>
+       [38a18d32a9e3]
 
 2010-11-30  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * auth/kerb4.c, check.c, env.c, pwutil.c, sudo.c:
+       * plugins/sudoers/auth/kerb4.c, plugins/sudoers/check.c,
+       plugins/sudoers/env.c, plugins/sudoers/pwutil.c,
+       plugins/sudoers/sudoers.c, src/sudo.c:
        Use %u to print uid/gid, not %lu and adjust casts to match.
-       [e4eb94705a54] <1.7>
-
-       * NEWS:
-       Update with latest changes
-       [2c4209b20e3d] <1.7>
+       [03c43b8749cf]
 
-       * sudoers.ldap.pod:
-       Clarify ordering of entries and attributes
-       [598748ec3804] <1.7>
+       * doc/sudoers.ldap.pod:
+       Clarify ordering of entries and attributes.
+       [924e2a6bb603]
 
-       * sudoers.ldap.pod:
+       * doc/sudoers.ldap.pod:
        Fix typo and editing goof.
-       [197a2fe65be5] <1.7>
+       [79dc7ccd85a8]
 
-       * ldap.c:
+       * doc/schema.ActiveDirectory, doc/schema.OpenLDAP, doc/schema.iPlanet,
+       doc/sudoers.ldap.pod:
+       Merge in ordered LDAP entry support from Andreas Mueller.
+       [ea5885989bad]
+
+       * plugins/sudoers/ldap.c:
        Make sure we don't dereference a NULL handle.
-       [b0026541de1e] <1.7>
+       [1a9f9ee15371]
 
 2010-11-24  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * pp:
        Add support for RHEL 6 file modes that include a trailing dot on
        files with an SELinux security context
-       [fcc1daaf4df0] <1.7>
+       [dc09be959547]
+
+2010-11-23  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/sudo.c:
+       exec_setup() does not need to setuid(0), the Ubuntu issue was in the
+       sudoers module.
+       [d6dd99fc6062]
+
+       * plugins/sudoers/sudoers.c:
+       create_admin_success_flag() should use restore_perms() rather than
+       set_perms() to restore the uid.
+       [eba7a91c1f57]
+
+       * src/sudo.c:
+       In exec_setup() call setuid(0) to make certain the subsequent uid
+       and gid changes will succeed. Fixes a problem on Ubuntu.
+       [c5d32abf0645]
+
+       * src/sudo_edit.c:
+       Error out if we cannot change to root's uid so we catch the failure
+       early.
+       [7a2e7f8f2c80]
 
 2010-11-22  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudoers.pod:
+       * doc/sudoers.pod:
        fix typo; from Michael T Hunter
-       [46e70e2063af] <1.7>
+       [a574a9d0db5b]
 
-       * match.c:
+       * plugins/sudoers/match.c:
        In sudoedit mode, assume command line arguments are paths and pass
        FNM_PATHNAME to fnmatch().
-       [6087ba0064ff] <1.7>
+       [ce0abff8ce9f]
 
 2010-11-20  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        Add workaround for an error in sys/types.h on HP-UX 11.23 when large
        file support is enabled. Defining _XOPEN_SOURCE_EXTENDED avoids the
        broken bits of the header file.
-       [12da5b3249a3] <1.7>
+       [e337217f097a]
 
        * aclocal.m4:
        Fix SUDO_MAILDIR usage of AC_LANG_PROGRAM
-       [c0105d26574a] <1.7>
-
-       * testsudoers.c, tsgetgrpw.c, tsgetgrpw.h:
-       Avoid conflicts with system definitions in grp.h and pwd.h
-       [a152522c9f13] <1.7>
+       [fbbcee28961f]
 
        * sudo.pp:
        For Tru64, strip off beta version.
-       [a16213ec9c27] <1.7>
+       [eeccd762df5e]
+
+       * MANIFEST, plugins/sudoers/testsudoers.c,
+       plugins/sudoers/tsgetgrpw.c, plugins/sudoers/tsgetgrpw.h:
+       Avoid conflicts with system definitions in grp.h and pwd.h
+       [b219ffe1da09]
 
        * zlib/gzguts.h:
        Include stdio.h after zlib.h, not before. We need the large file
        defines to come first.
-       [389ea592d6c2] <1.7>
+       [21d6df39790f]
+
+2010-11-19  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in:
+       regen
+       [3ff8750d0aac]
+
+       * Makefile.in:
+       Don't clean ChangeLog
+       [ab0d30d289d4]
+
+       * plugins/sudoers/testsudoers.c, plugins/sudoers/visudo.c:
+       Add prototype for cleanup()
+       [75626fd3769a]
+
+2010-11-18  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/group_plugin.c:
+       Avoid deferencing group_plugin if it is NULL in
+       group_plugin_query(). This should not happen.
+       [4f2933c8da7e]
+
+       * plugins/sudoers/group_plugin.c:
+       group plugin init function return TRUE when successful
+       [198024477030]
 
 2010-11-17  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * ldap.c:
+       * plugins/sudoers/ldap.c:
        Enlarge the array of entry wrappers int blocks of 100 entries to
        save on allocation time. From Andreas Mueller
-       [db8da143e803] <1.7>
+       [375c916bb03b]
 
-       * ldap.c:
+       * plugins/sudoers/ldap.c:
        Add back call to sudo_ldap_timefilter() in sudo_ldap_build_pass2()
        that was mistakenly dropped.
-       [f6f1103f9971] <1.7>
+       [1555f5bc132d]
 
 2010-11-16  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * TROUBLESHOOTING:
+       * doc/TROUBLESHOOTING:
        Mention that sudo needs "ar" to build.
-       [eef95d0abfbe] <1.7>
+       [65582ace2d09]
 
        * configure, configure.in:
        Fail with a more useful error if "ar" is not found.
-       [1ef3c8501bf5] <1.7>
+       [d1cb83719c17]
 
 2010-11-14  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * ldap.c:
-       Reorder things to avoid most of the extra prototypes.
-       [0541a55deb86] <1.7>
+       * plugins/sudoers/ldap.c:
+       Merge in ordered LDAP entry support from Andreas Mueller and add
+       local changes from the 1.7 branch.
+       [bca29e461618]
 
-       * ldap.c:
-       Inline sudo_ldap_result_get_entry(), it is always called in
-       situations where the bounds are already checked.
-       [fa65cf4eaf5e] <1.7>
+2010-11-12  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * ldap.c:
-       Add user_matches and host_matches to struct ldap_result and set them
-       in sudo_ldap_result_get() which is where the user and host checks
-       live. When iterating through the ordered results, take the first
-       match. Remove allowed flag from struct ldap_entry_wrapper, we just
-       use first match.
-       [9a008cd81685] <1.7>
-
-2010-11-13  Todd C. Miller  <Todd.Miller@courtesan.com>
-
-       * configure, configure.in, sudo.cat, sudo.man.in, sudoers.cat,
-       sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.man.in,
-       sudoreplay.cat, sudoreplay.man.in, visudo.cat, visudo.man.in:
-       Bump version and regen man pages
-       [918433185f26] <1.7>
-
-       * ldap.c, schema.ActiveDirectory, schema.OpenLDAP, schema.iPlanet,
-       sudoers.ldap.pod:
-       Merge in ordered LDAP entry support from Andreas Mueller.
-       [21b8071c2f28] <1.7>
+       * doc/schema.ActiveDirectory, doc/schema.OpenLDAP, doc/schema.iPlanet,
+       doc/sudoers.ldap.pod, plugins/sudoers/ldap.c:
+       Add timed entry support from Andreas Mueller.
+       [e18d1df46a8d]
 
-2010-11-11  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * plugins/sudoers/group_plugin.c:
+       Don't try to unload if group_plugin is NULL. Don't call dlclose() if
+       group_handle is NULL
+       [de2273da37d5]
 
-       * ldap.c, schema.ActiveDirectory, schema.OpenLDAP, schema.iPlanet,
-       sudoers.ldap.pod:
-       Add timed entry support from Andreas Mueller.
-       [10b121c46a1c] <1.7>
+       * plugins/sudoers/sudoers.h:
+       It is now plugin_cleanup(), not cleanup()
+       [da62a4e1a78c]
 
-       * ldap.c:
-       Use efree() not free() and remove malloc.h include since we never
-       directly call malloc() or free().
-       [f2184b2a0646] <1.7>
+       * plugins/sudoers/logging.c, plugins/sudoers/sudoers.c:
+       Call plugin_cleanup(), not cleanup()
+       [e800ad8b33ad]
 
-2010-11-10  Todd C. Miller  <Todd.Miller@courtesan.com>
+2010-11-11  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * Makefile.in, getdate.c, gram.c, toke.c:
-       Include config.h before any other includes to make sure we get the
-       right value for _FILE_OFFSET_BITS.
-       [5a8c12426942] <1.7>
+       * plugins/sudoers/ldap.c:
+       Use efree() not free() and remove malloc.h include since we never
+       directly call malloc() or free().
+       [107fffd134bb]
 
 2010-11-09  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudo.pp:
        set PSTAMP for Solaris and move the backend-specific bits to their
        own %if [xxx] %endif blocks in %set.
-       [0d93cb5d009a] <1.7>
+       [a94ebe8920c1]
 
        * pp:
        sync with git repo
-       [e052d78dde35] <1.7>
+       [75ff509696b4]
 
-2010-11-03  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * configure, configure.in:
+       Only substitute file zlib files when using the builtin zlib
+       [6c8145b2deb4]
+
+       * common/Makefile.in, compat/Makefile.in, plugins/sample/Makefile.in,
+       plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in,
+       src/Makefile.in, zlib/Makefile.in:
+       Give up on using VPATH to find sources as it is implemented
+       inconsistenly in different versions of make.
+       [60517c69aaee]
+
+       * plugins/sudoers/Makefile.in, plugins/sudoers/getdate.c,
+       plugins/sudoers/gram.c, plugins/sudoers/toke.c:
+       Include config.h before any other includes to make sure we get the
+       right value for _FILE_OFFSET_BITS.
+       [8fb007ca832e]
 
-       * Makefile.in:
-       remove zlib/zconf.h for distclean
-       [5cf14594d014] <1.7>
+       * MANIFEST:
+       Add zlib
+       [04a3e23dfaa9]
 
-       * 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 for 1.7.5
-       [29253a721cfd] <1.7>
+       * zlib/Makefile.in:
+       Add missing targets
+       [40e45a177168]
 
-       * configure:
-       regen
-       [5b09c0dd9279] <1.7>
+       * src/Makefile.in:
+       g/c unused $(GENERATED)
+       [c8758068c1bc]
 
-       * NEWS:
-       Update 1.7.5 entries.
-       [73a7b2c01db4] <1.7>
+2010-11-08  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-2010-11-02  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * plugins/sudoers/group_plugin.c:
+       Zero out group_plugin on unload just to be safe.
+       [0b10f4d101ca]
 
-       * Makefile.in:
-       Include zlib in the tar file.
-       [3b7900c3f2af] <1.7>
+       * plugins/sudoers/group_plugin.c:
+       Unload group plugin if its init function fails.
+       [6552cdac4b7c]
+
+       * src/sudo.c:
+       Only chdir to cwd if it is different from the current cwd or there
+       is a new root (chroot).
+       [b8203e875e84]
+
+       * configure, configure.in, doc/sudo.cat, doc/sudo.man.in,
+       doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudoers.ldap.cat,
+       doc/sudoers.ldap.man.in, doc/visudo.cat, doc/visudo.man.in:
+       Bump version to 1.8.0b2
+       [6dadeb75a878]
 
 2010-10-28  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * INSTALL:
        Better --enable-zlib description
-       [0ca9936a7271] <1.7>
+       [e0da54fa59a6]
 
        * mkpkg:
        Use system zlib on Linux Let configure decide on Solaris For all
        others, use builtin zlib
-       [58e1b4383b58] <1.7>
+       [3d52eddb523c]
+
+       * zlib/zconf.h.in:
+       Add large file support.
+       [bec01215270d]
+
+       * config.h.in:
+       Add large file support.
+       [244e95b034ec]
 
-       * LICENSE, Makefile.in, config.h.in, configure, configure.in,
-       license.pod, zlib/adler32.c, zlib/compress.c, zlib/crc32.c,
+       * Makefile.in, configure, configure.in, doc/LICENSE, doc/license.pod,
+       zlib/Makefile.in, zlib/adler32.c, zlib/compress.c, zlib/crc32.c,
        zlib/crc32.h, zlib/deflate.c, zlib/deflate.h, zlib/gzclose.c,
        zlib/gzguts.h, zlib/gzlib.c, zlib/gzread.c, zlib/gzwrite.c,
        zlib/infback.c, zlib/inffast.c, zlib/inffast.h, zlib/inffixed.h,
        zlib/trees.c, zlib/trees.h, zlib/uncompr.c, zlib/zconf.h.in,
        zlib/zlib.h, zlib/zutil.c, zlib/zutil.h:
        Add local copy of zlib for systems that lack it.
-       [060627a4a413] <1.7>
+       [7542ca465c5a]
+
+2010-10-15  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/exec.c:
+       If perform_io() fails, kill the child before exiting so it doesn't
+       complain about connection reset. We can get an I/O error if, for
+       example, and we get EIO reading from stdin.
+       [e59a05fa729f]
 
 2010-10-12  Todd C. Miller  <Todd.Miller@courtesan.com>
 
+       * plugins/sudoers/sudoers.c, src/sudo.c:
+       Fix complilation on systems with set_auth_parameters() Sprinkle
+       volatile to quiet warnings from gcc 2.8.0
+       [a34c2b924ba7]
+
+       * compat/dlfcn.h, compat/dlopen.c:
+       Avoid potential namespace issues with dlopen() emulation.
+       [aedfababd6ca]
+
+       * MANIFEST:
+       sync
+       [6afb97e6d308]
+
+       * plugins/sudoers/interfaces.c:
+       Use INADDR_NONE instead of casting -1 to in_addr_t (which may not
+       exist).
+       [ddfca5af1a36]
+
        * Makefile.in:
-       Don't overwrite ChangeLog if we can't run hg
-       [8cad8bfce9ee] <1.7>
+       Mark ChangeLog as PHONY Don't overwrite ChangeLog if we can't run hg
+       [e9d04bfa4505]
 
        * configure, configure.in:
-       HP-UX 10.20 libc has an incompatible getline()
-       [6ae1631c6993] <1.7>
+       HP-UX 10.20 libc has an incompatible getline
+       [2e7bc202e78d]
 
-       * visudo.c:
+       * plugins/sudoers/visudo.c:
        Quiet an HP-UX compiler warning.
-       [b8eb3006d68b] <1.7>
+       [55b9d587ac8c]
+
+       * configure, configure.in:
+       Check for vi even with --with-editor specified; the sample plugin
+       needs it.
+       [94dfc3643f76]
 
 2010-10-11  Todd C. Miller  <Todd.Miller@courtesan.com>
 
+       * compat/dlopen.c:
+       Fix remaining syntax errors.
+       [9d729b5b577e]
+
+       * src/Makefile.in:
+       sudo binary depends on the libtool-generated libs
+       [9e6148406adb]
+
+       * plugins/sudoers/group_plugin.c, src/load_plugins.c:
+       Use HAVE_DLOPEN instead of HAVE_DLFCN_H when determining whether to
+       include the local or system dlfcn.h
+       [68cfe4c1089b]
+
        * pp:
        Don't use run_as_superuser=false on HP-UX
-       [2a9ec2750082] <1.7>
+       [532242370b09]
+
+       * src/net_ifs.c:
+       Use memset() instead of zero_bytes() since we don't include
+       sudoers.h
+       [a187c18c2472]
+
+       * plugins/sudoers/interfaces.c:
+       Fix pasto; AF_INET not AF_INET6
+       [2d2e9d7dc6f9]
+
+       * compat/dlopen.c:
+       Actually call shl_load()
+       [ed8153b8a3cd]
 
        * pp:
        Update from git repo. Debian: version numbers now compliant with
        policy section 5.6.12 HP-UX: minimal changes needed to work on HP-UX
        10.20
-       [cfe38672e358] <1.7>
-
-       * configure, configure.in:
-       Go back to checking whether the compiler is ANSI C when detecting
-       the HP-UX bundled C compiler.
-       [563ef7333662] <1.7>
+       [ecf2692bceeb]
 
        * configure, configure.in:
-       Fix syntax error
-       [96048f77d772] <1.7>
+       Fix dlopen() detection for systems where dlopen() is in a separate
+       library.
+       [fa6b175582b6]
 
-       * auth/pam.c:
+       * plugins/sudoers/auth/pam.c:
        If pam_acct_mgmt() returns PAM_AUTH_ERR print a (hopefully) more
        useful message and return AUTH_FATAL so sudo does not keep trying to
        validate the user.
-       [fffa5e51ac47] <1.7>
+       [1be8857e5291]
 
-2010-10-07  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * src/preload.c:
+       sudo_preload_table is an array
+       [b7704e72a9da]
+
+       * compat/dlopen.c:
+       Quiet a compiler warning and fix sudo_preload_table external
+       definition.
+       [8234987664cc]
 
-       * exec_pty.c:
-       don't need ws_col here
-       [049b4ef9c9ce] <1.7>
+       * compat/dlfcn.h:
+       Fix multiple inclusion guard in dlfcn.h and fix dlerror() prototype.
+       [8bab6a4053cc]
 
-       * check.c:
+       * plugins/sudoers/group_plugin.c:
+       Make this compile correctly when no dlopen is available.
+       [57643879bd2b]
+
+2010-10-07  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/check.c:
        Having a timestamp file defined is no longer indicative of tty
        tickets being enabled. Check def_tty_tickets directly.
-       [6c3803c239d9] <1.7>
+       [efcc11ad157f]
 
-       * exec_pty.c, lbuf.c:
+       * src/exec_pty.c, src/sudo.h, src/ttysize.c:
        Fix TCGETWINSZ compat.
-       [62233ba46ec7] <1.7>
+       [da3a8b17cf7a]
 
 2010-10-02  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * exec_pty.c, lbuf.c:
+       * src/exec_pty.c, src/ttysize.c:
        Prefer newer TIOCGWINSZ ioctl to old TIOCGSIZE
-       [0813e3030b1a] <1.7>
+       [926492dd10a6]
 
 2010-10-01  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * set_perms.c:
-       Sync set_project() with trunk.
-       [646fd9bc0537] <1.7>
+       * plugins/sudoers/sudoers.c, src/sudo.c:
+       Move set_project() from sudoers module into sudo proper.
+       [beabafac03b4]
 
-       * ldap.c:
+       * configure, configure.in:
+       Fix typo and regenerate
+       [4a3caf4234f3]
+
+       * plugins/sudoers/ldap.c:
        When iterating over returned LDAP entries, keep looking at remaining
        matches even if we have a positive match. This catches negative
        matches that may exist in other entries and more closely match the
        sudoers file behavior.
-       [8dce1dedb967] <1.7>
+       [f47db6e609b0]
 
        * pp:
        Add support for multiple package instances on Solaris.
-       [5bcc048375db] <1.7>
-
-       * set_perms.c, sudo.c:
-       Move set_project() into runas_setup(). Fixes a NULL deref when
-       project support is enabled and sudo's -g flag is used without the
-       -u flag.
-       [6ffd892243ab] <1.7>
+       [7f2a8b942545]
 
-       * exec.c:
+       * src/exec.c:
        Add missing signal_pipe[0] to fdsr for the non-pty case.
-       [3398af88db51] <1.7>
+       [79d01e11b19c]
 
        * mkpkg:
        Add --with-project for Solaris
-       [25bd2aa83884] <1.7>
+       [ffa4c2bb93f7]
 
        * README:
        Need ar and ranlib too
-       [d09e632d0a93] <1.7>
+       [5c2f679172ef]
 
 2010-09-27  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * env.c:
+       * plugins/sudoers/env.c:
        Preserve ODMDIR environment variable by default on AIX.
-       [75266d18e4a7] <1.7>
+       [bd47cb1e804f]
+
+2010-09-26  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Makefile.in, compat/Makefile.in, compat/dlfcn.h, compat/dlopen.c,
+       config.h.in, configure, configure.in, plugins/sample/Makefile.in,
+       plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in,
+       plugins/sudoers/group_plugin.c, plugins/sudoers/plugin_error.c,
+       plugins/sudoers/sudoers.c, src/Makefile.in, src/load_plugins.c,
+       src/preload.c:
+       Add dlopen() emulation for systems without it. For HP-UX 10, emulate
+       using shl_load(). For others, link sudoers plugin statically and use
+       a lookup table to emulate dlsym().
+       [e92edfb3c642]
+
+2010-09-24  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * compat/fnmatch.c, compat/glob.c, compat/mksiglist.c,
+       compat/nanosleep.c, compat/utimes.c:
+       When including compat headers, use the compat dir as part of the
+       path so we are sure to get the correct header.
+       [6c2a45da6af5]
 
 2010-09-21  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * linux_audit.c:
+       * plugins/sudoers/linux_audit.c:
        Ignore ECONNREFUSED from audit_log_user_command() which will occur
        if auditd is not running.
-       [a686884684ca] <1.7>
+       [d314fe4c8d03]
 
 2010-09-17  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * pp:
        Sync with git version
-       [9a328aa25c53] <1.7>
+       [1c0357744222]
 
 2010-09-16  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * defaults.c, fileops.c:
+       * common/fileops.c, plugins/sudoers/defaults.c:
        Cast isblank argument to unsigned char.
-       [64b9f3bed954] <1.7>
+       [c822dbb3ca54]
 
 2010-09-14  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * INSTALL, config.h.in, configure, configure.in, defaults.c,
-       sudoers.cat, sudoers.man.in, sudoers.pod:
+       * INSTALL, config.h.in, configure, configure.in, doc/sudoers.cat,
+       doc/sudoers.man.in, doc/sudoers.pod, plugins/sudoers/defaults.c:
        Implement --with-umask-override configure flag.
-       [5065008079df] <1.7>
+       [863e3047df22]
 
-       * env.c:
+       * plugins/sudoers/env.c:
        Take MODE_LOGIN_SHELL into account when initially setting reset_home
        instead of special-casing it later.
-       [25e6b8419dea] <1.7>
+       [5d6b16480fd6]
 
-       * sudo.c:
+       * plugins/sudoers/sudoers.c:
        In login mode, make a copy of the runas user's pw_shell for
        NewArgv[0] because 1) we modify it and 2) it will runas_pw gets
        freed before exec.
-       [4a0851a7688a] <1.7>
+       [1d1ccb568dfa]
 
-       * env.c:
+       * plugins/sudoers/env.c:
        Reset HOME for "sudo -i" even if HOME was listed in env_keep.
-       [8dc31006a428] <1.7>
+       [c1c1c65a2d63]
 
-       * sudo.c:
+       * src/sudo.c:
        Use SIG_SETMASK when resetting signal mask instead of SIG_UNBLOCK.
-       [8751ef94b18d] <1.7>
+       [7443454e5f88]
 
-       * sudo.c:
+       * src/sudo.c:
        Reset signal mask at sudo startup time; we need to be able to rely
        on normal signal delivery to control the child process.
-       [c986a4b6a942] <1.7>
-
-       * sigaction.c:
-       Fix SIG_UNBLOCK emulation
-       [f14264f8a0da] <1.7>
+       [95800163ff94]
 
 2010-09-13  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        Use sed instead of expr to split a flag from its argument. Fixes a
        problem with expr interpreting its arguments as a flag when they
        start with a dash.
-       [16372da8a286] <1.7>
+       [736065e14301]
 
-       * lbuf.c:
-       Back out rev e165f67d3127
-       [e9b70079698d] <1.7>
+       * common/lbuf.c:
+       Do not need sys/time.h after all
+       [91f6f668ccda]
 
-       * lbuf.c:
-       Include sys/time.h for utimes() and struct timeval.
-       [e165f67d3127] <1.7>
+       * common/lbuf.c:
+       Include sys/time.h for utimes() and struct timeval. No longer need
+       ioctl.h or termios.h
+       [2d75273d3213]
 
-       * snprintf.c:
+       * compat/snprintf.c:
        Quiet bogus compiler warnings.
-       [176fceb8db3c] <1.7>
+       [fe252e1968f5]
 
-       * missing.h:
+       * include/missing.h:
        Declare innetgr() for HP-UX which is missing a declaration. Declare
        domainname() for HP-UX and Solaris which are missing a declaration.
-       [0b4c1296d4da] <1.7>
+       [b37c50751138]
 
-       * bsm_audit.c:
+       * plugins/sudoers/bsm_audit.c:
        Use __sun for consistency with the rest of the sources.
-       [8f0db6350b3a] <1.7>
+       [6b086b61ccb6]
 
-       * pwutil.c:
+       * plugins/sudoers/group_plugin.c:
+       Quiet a bogus compiler warning.
+       [ebc069842c4a]
+
+       * plugins/sudoers/pwutil.c:
        Don't try to delref a NULL group.
-       [57e94fc5df3e] <1.7>
+       [f6ff0838be21]
 
-       * alloc.c, lbuf.c:
+       * common/alloc.c, common/lbuf.c:
        Include memory.h on systems that need it.
-       [e43d8d8a0008] <1.7>
+       [4e676da81c6f]
 
 2010-09-11  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * exec.c:
+       * src/exec.c:
        Quiet gcc warnings on glibc systems that use warn_unused_result for
        write(2).
-       [f22696affc78] <1.7>
+       [0532da0b7cf7]
+
+       * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod:
+       sudo_plugin is in section 8; from Ted Percival
+       [b4506a0de87e]
+
+       * plugins/sudoers/Makefile.in:
+       testsudoers depends on libsudoers.la, not sudoreplay
+       [cdb1cc3bf06a]
 
 2010-09-10  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * NEWS, README, configure, configure.in:
-       Update for sudo 1.7.5
-       [62ed8c6cb7c2] <1.7>
+       * src/exec.c:
+       Read as many signals on the signal pipe as we can before returning.
+       [b181671da047]
 
-       * exec.c, exec_pty.c, list.c, list.h, sudo_exec.h:
+       * src/exec.c, src/exec_pty.c, src/sudo_exec.h:
        Instead of using a array to store received signals, open a pipe and
        have the signal handler write the signal number to one end and
        select() on the other end. This makes it possible to handle signals
        similar to I/O without race conditions.
-       [2d9dd09a9fce] <1.7>
-
-       * INSTALL:
-       --with-iologdir not --enable-iologdir
-       [457471aaeda6] <1.7>
+       [ee84d65c16b6]
 
 2010-09-09  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * visudo.c, visudo.pod:
+       * doc/visudo.pod, plugins/sudoers/visudo.c:
        Make "visudo -c -f -" check the standard input.
-       [8ed46ff3141a] <1.7>
+       [195a3d2a9a26]
 
-       * sudoers.pod:
+       * doc/sudoers.pod:
        set_home and always_set_home have an effect if HOME is present in
        the env_keep list.
-       [a2b26d62176d] <1.7>
+       [159d0b9dc5c8]
 
-       * env.c:
+       * plugins/sudoers/env.c:
        Make -H flag work when HOME is listed in env_keep. Also makes
        "set_home" and "always_set_home" override override HOME in env_keep.
-       [91d842b6adc6] <1.7>
+       [a3e5b966193f]
 
 2010-09-08  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * bsm_audit.c:
+       * plugins/sudoers/Makefile.in, plugins/sudoers/interfaces.c,
+       plugins/sudoers/interfaces.h, plugins/sudoers/match.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/testsudoers.c,
+       plugins/sudoers/visudo.c, src/net_ifs.c:
+       Convert sudoers plugin to use interface list passed in settings.
+       [87d9b5f4f586]
+
+       * doc/sudo_plugin.pod, src/Makefile.in, src/net_ifs.c,
+       src/parse_args.c, src/sudo.h:
+       Query local network interfaces in the main sudo driver and pass to
+       the plugin as "network_addrs" in the settings list.
+       [7f35bcfe77a7]
+
+       * plugins/sudoers/bsm_audit.c:
        Solaris BSM audit return EINVAL when auditing is not enabled,
        whereas OpenBSM returns ENOSYS.
-       [bb9c94a8fa7d] <1.7>
+       [411b980ec58b]
 
 2010-09-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * toke.c, toke.l:
-       Add missing LOG_INPUT/LOG_OUTPUT support in the lexer.
-       [0a5519756bf1] <1.7>
+       * compat/fnmatch.c:
+       missing.h should come before most local includes
+       [53921a7b8b5b]
 
-       * sudo.c:
-       Set NewArgv[0] to the name of the pseudo-command we are running.
-       Fixes a problem with "sudo -l" when auditing is enabled and the user
-       is not allowed to run any commands on the host. Adapted from a patch
-       from Daniel Kopecek.
-       [694ed1a75a4a] <1.7>
+       * plugins/sudoers/sudoreplay.c:
+       missing.h should come before most local includes
+       [e9abb0db1aac]
 
-       * sudo.c:
-       Update comment to reality.
-       [de302f39566b] <1.7>
+       * plugins/sudoers/sudoers.h:
+       Make local includes consistent; use double quotes for local includes
+       except for generated ones where we use angle brackets.
+       [09de4faa9547]
 
-       * missing.h:
-       Need stdio.h for FILE *, not just NULL.
-       [77cf303f5696] <1.7>
+       * plugins/sudoers/sudoers.c:
+       Always fill in NewArgv for audit code.
+       [7c3aca60519f]
+
+       * plugins/sudoers/toke.c, plugins/sudoers/toke.l:
+       Add missing LOG_INPUT/LOG_OUTPUT support in the lexer.
+       [007cf6560f92]
+
+       * common/alloc.c, common/atobool.c, common/fileops.c,
+       common/fmt_string.c, common/lbuf.c, common/list.c, common/term.c,
+       common/zero_bytes.c, compat/closefrom.c, compat/fnmatch.c,
+       compat/getcwd.c, compat/getgrouplist.c, compat/getline.c,
+       compat/getprogname.c, compat/glob.c, compat/isblank.c,
+       compat/memrchr.c, compat/mksiglist.c, compat/mkstemps.c,
+       compat/nanosleep.c, compat/setenv.c, compat/snprintf.c,
+       compat/strlcat.c, compat/strlcpy.c, compat/strsignal.c,
+       compat/unsetenv.c, compat/utimes.c, include/compat.h,
+       plugins/sample/sample_plugin.c, plugins/sample_group/getgrent.c,
+       plugins/sample_group/plugin_test.c,
+       plugins/sample_group/sample_group.c, plugins/sudoers/audit.c,
+       plugins/sudoers/auth/afs.c, plugins/sudoers/boottime.c,
+       plugins/sudoers/getdate.c, plugins/sudoers/getdate.y,
+       plugins/sudoers/linux_audit.c, plugins/sudoers/match.c,
+       plugins/sudoers/plugin_error.c, plugins/sudoers/sudoreplay.c,
+       plugins/sudoers/timestr.c, src/error.c, src/sesh.c, src/sudo.h,
+       src/sudo_noexec.c, src/ttysize.c:
+       Make local includes consistent; use double quotes for local includes
+       except for generated ones where we use angle brackets. Also g/c
+       unused compat.h.
+       [e57070dc8f04]
 
 2010-09-06  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * match.c:
+       * plugins/sudoers/match.c:
        When matching the runas user and runas group (-u and -g command line
        options), keep track of runas group and runas user matches
        separately. Only return a positive match if we have a match for
        both runas user and runas group (if specified).
-       [68d30216c13a] <1.7>
+       [815219e04cc8]
 
 2010-09-04  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * ldap.c, parse.c:
-       Do not return -1 on error from the display functions; the call
-       expects a return value >= 0.
-       [e50e6ae4d06d] <1.7>
+       * doc/sudoers.ldap.pod, plugins/sudoers/ldap.c:
+       Add support for multiple URI lines by joining the contents and
+       passing the result to ldap_initialize.
+       [a47cae3b72e8]
 
-       * ldap.c:
-       display_bound_defaults now returns a count so make the stub return
-       0, not 1.
-       [97293ced4908] <1.7>
+       * plugins/sudoers/ldap.c, plugins/sudoers/parse.c:
+       Do not return -1 on error from the display functions; the caller
+       expects a return value >= 0.
+       [101456a7dd00]
 
-       * fnmatch.c:
-       Add #include of sys/types.h for .c files that include missing.h to
-       be sure that size_t and ssize_t are defined.
-       [a4f3070d0a2b] <1.7>
+       * plugins/sudoers/sudoers.c:
+       Do not set both MODE_EDIT and MODE_RUN
+       [8faa36694d54]
 
 2010-09-03  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * get_pty.c:
-       It looks like AIX doesn't need to push STREAMS modules for ptys.
-       [62c281fcd4ad] <1.7>
+       * include/missing.h:
+       Move includes to the top of the file.
+       [a51436798e8c]
 
 2010-08-30  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * error.c, getprogname.c, isblank.c, missing.h, mksiglist.c,
-       sigaction.c, strerror.c, strsignal.c, sudo_noexec.c:
+       * plugins/sudoers/Makefile.in:
+       Add missing definition of timedir
+       [458a749c2c5e]
+
+       * compat/fnmatch.c, compat/getprogname.c, compat/isblank.c,
+       compat/mksiglist.c, compat/strsignal.c,
+       plugins/sudoers/plugin_error.c, src/error.c, src/sudo_noexec.c:
        Add #include of sys/types.h for .c files that include missing.h to
        be sure that size_t and ssize_t are defined.
-       [2ffbbb12f322] <1.7>
+       [08e3132dbf4f]
 
-       * Makefile.in:
+       * plugins/sudoers/Makefile.in:
        Install sudoers file from the build dir not hte src dir.
-       [a26afd8db531] <1.7>
+       [ca89e962dbf4]
 
 2010-08-26  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * set_perms.c:
+       * plugins/sudoers/set_perms.c:
        If runas_pw changes, reset the stashed runas aux group vector.
        Otherwise, if runas_default is set in a per-command Defaults
        statement, the command runs with root's aux group vector (i.e. the
        one that was used when locating the command).
-       [24a695707b67] <1.7>
+       [24f9107cedd2]
 
-       * Makefile.in:
+       * plugins/sudoers/Makefile.in:
        Add target to generate sudoers file Remove generated sudoers file as
        part of distclean
-       [448627fc35b6] <1.7>
+       [fb7422e90f03]
 
-2010-08-23  millert  <millert@rh4-x86.home.courtesan.com>
+2010-08-24  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * exec.c:
+       * src/exec.c:
        When not logging I/O install a handler for SIGCONT and deliver it to
        the command upon resume. Fixes bugzilla #431
-       [e84690aa67bd] <1.7>
+       [495dce52a5aa]
 
 2010-08-21  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudo.c, sudo.h:
-       g/c unused auth_pw global
-       [e30778d73c0b] <1.7>
+       * plugins/sudoers/sudoers.h:
+       g/c unused auth_pw extern definition
+       [40eb7477ba17]
 
-       * check.c, sudo.c:
+       * plugins/sudoers/check.c, plugins/sudoers/sudoers.c:
        Move get_auth() into check.c where it is actually used.
-       [3130e37787af] <1.7>
-
-       * sudo.c:
-       Don't need to fork and wait when compiled with --disable-pam-session
-       [2ae1bbe4437a] <1.7>
+       [e31db0ce3a61]
 
 2010-08-20  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * lbuf.c:
+       * common/lbuf.c:
        Convert a remaining puts() and putchar() to use the output function.
-       [d68c213feb0f] <1.7>
+       [d69e363a506b]
 
-2010-08-18  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * plugins/sudoers/plugin_error.c:
+       Plug memory leak
+       [68895469ea8d]
 
-       * Makefile.in:
-       Replace sudoers with sudoers.in in DISTFILES
-       [616509f85d6c] <1.7>
+2010-08-18  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * env.c:
+       * plugins/sudoers/env.c:
        Set dupcheck to TRUE when setting new HOME value if !env_reset but
        always_set_home is true. Prevents a duplicate HOME in the
-       environment (old value plus the new one) introduced in 9f97e4b43a4b.
-       [2672ae047984] <1.7>
+       environment (old value plus the new one) introduced in f421f8827340.
+       [9ca19183794f]
 
-       * configure, configure.in, sudoers, sudoers.in:
+       * configure, configure.in, plugins/sudoers/sudoers,
+       plugins/sudoers/sudoers.in:
        Substitute sysconfdir in the installed sudoers file to get the
        correct path for sudoers.d.
-       [ab14a68e546f] <1.7>
+       [86072b6cd55d]
 
 2010-08-17  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * boottime.c, get_pty.c:
-       Fix typos that prevented compilation on Irix; Friedrich Haubensak
-       [a3e6c5a66890] <1.7>
+       * src/get_pty.c:
+       Fix typo that prevented compilation on Irix; Friedrich Haubensak
+       [b48be51b65fc]
 
 2010-08-16  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * Makefile.in, aix.c, audit.c, boottime.c, compat.h, error.c,
-       fnmatch.c, getcwd.c, getdate.c, getdate.y, getline.c, getprogname.c,
-       gettime.c, glob.c, isblank.c, linux_audit.c, memrchr.c, missing.h,
-       mksiglist.c, nanosleep.c, sesh.c, setsid.c, sigaction.c, snprintf.c,
-       strcasecmp.c, strerror.c, strlcat.c, strlcpy.c, strsignal.c, sudo.h,
-       sudo_noexec.c, sudoreplay.c, timestr.c, utimes.c, vasgroups.c,
-       zero_bytes.c:
+       * MANIFEST, common/Makefile.in, common/aix.c, common/alloc.c,
+       common/atobool.c, common/fileops.c, common/fmt_string.c,
+       common/lbuf.c, common/list.c, common/term.c, common/zero_bytes.c,
+       compat/Makefile.in, compat/closefrom.c, compat/fnmatch.c,
+       compat/getcwd.c, compat/getgrouplist.c, compat/getline.c,
+       compat/getprogname.c, compat/glob.c, compat/isblank.c,
+       compat/memrchr.c, compat/mksiglist.c, compat/mkstemps.c,
+       compat/nanosleep.c, compat/setenv.c, compat/snprintf.c,
+       compat/strlcat.c, compat/strlcpy.c, compat/strsignal.c,
+       compat/unsetenv.c, compat/utimes.c, include/compat.h,
+       include/missing.h, plugins/sample/sample_plugin.c,
+       plugins/sample_group/getgrent.c,
+       plugins/sample_group/sample_group.c, plugins/sudoers/Makefile.in,
+       plugins/sudoers/audit.c, plugins/sudoers/boottime.c,
+       plugins/sudoers/getdate.c, plugins/sudoers/getdate.y,
+       plugins/sudoers/linux_audit.c, plugins/sudoers/plugin_error.c,
+       plugins/sudoers/sudoers.h, plugins/sudoers/sudoreplay.c,
+       plugins/sudoers/timestr.c, src/Makefile.in, src/error.c, src/sesh.c,
+       src/sudo.h, src/sudo_noexec.c, src/ttysize.c:
        Merge compat.h and missing.h into missing.h
-       [905905c7a8f0] <1.7>
+       [572909ae9716]
 
 2010-08-14  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * auth/pam.c:
+       * plugins/sudoers/auth/pam.c:
        If the user hits ^C while a password is being read, error out before
        reading any further passwords in the pam conversation function.
        Otherwise, if multiple PAM auth methods are required, the user will
        have to hit ^C for each one.
-       [c8f6bc58fd86] <1.7>
+       [23782631748c]
 
-2010-08-09  Todd C. Miller  <Todd.Miller@courtesan.com>
+2010-08-12  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * exec.c:
-       Fix waitpid() loop termination condition.
-       [97719b3259f2] <1.7>
+       * plugins/sudoers/check.c:
+       Update comment
+       [a5296cb3a20a]
 
-       * exec_pty.c:
-       Use sudo_waitpid() instead of bare waitpid()
-       [624a40269189] <1.7>
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Document sudo_conv_t function and sudo_printf_t return values.
+       [745c0017814c]
+
+       * src/conversation.c:
+       Make _sudo_printf return the number of characters printed on success
+       like printf(3).
+       [8eeefe8d7e77]
+
+2010-08-10  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/sudoers.c:
+       sudoers.h includes sudo_plugin.h for us
+       [cabe68e07807]
+
+       * common/Makefile.in, common/gettime.c, compat/mkstemps.c,
+       plugins/sudoers/sudoers.h, plugins/sudoers/visudo.c, src/sudo.h,
+       src/sudo_edit.c:
+       Use gettimeofday() directly instead of via the gettime() wrapper.
+       [7490426c99ae]
+
+       * common/gettime.c, compat/snprintf.c, compat/strcasecmp.c,
+       compat/strerror.c, config.h.in, configure, configure.in,
+       include/compat.h, include/missing.h, plugins/sudoers/logging.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/visudo.c, src/sudo.c:
+       Remove some obsolete configure tests, ancient Unix systems are no
+       longer supported.
+       [2be6218c3a36]
 
 2010-08-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudo.pp:
-       Set pp_kit_version and strip off patchlevel
-       [814c87778567] <1.7>
+       Set pp_kit_version and strip off patch level
+       [aacfda1b676d]
 
        * sudo.pp:
        Better handling of versions with a patchlevel. For rpm and deb, use
        the patchlevel+1 as the release. For AIX, use the patchlevel as the
        4th version number. For the rest, just leave the patchlevel in the
        version string.
-       [d18ef30f0a72] <1.7>
+       [638bd35f2346]
 
 2010-08-06  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * auth/sudo_auth.c:
+       * plugins/sudoers/auth/sudo_auth.c:
        For non-standalone auth methods, stop reading the password if the
        user enters ^C at the prompt.
-       [59d2b1328d1e] <1.7>
-
-       * configure, configure.in:
-       Don't print getspwuid as an auth method.
-       [d35cf4628d9a] <1.7>
+       [82c2911bb264]
 
-       * Makefile.in, auth/passwd.c, auth/secureware.c, auth/sudo_auth.c,
-       auth/sudo_auth.h, configure, configure.in, pwutil.c:
+       * configure, configure.in, plugins/sudoers/Makefile.in,
+       plugins/sudoers/auth/passwd.c, plugins/sudoers/auth/secureware.c,
+       plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/auth/sudo_auth.h,
+       plugins/sudoers/pwutil.c:
        No need to look up shadow password unless we are doing password-
        style authentication. This moves the shadow password lookup to the
        auth functions that need it.
-       [10a85eebbf4c] <1.7>
+       [ba9e3eba2b72]
 
-       * check.c:
+       * plugins/sudoers/sudoers.c:
+       Retain final passwd/group refs until the policy close() function.
+       Note that this doesn't get called in all cases so putting this in a
+       cleanup function is probably better.
+       [bbe214cb4119]
+
+       * plugins/sudoers/check.c:
+       Fix mismerge
+       [395115f89dd6]
+
+       * plugins/sudoers/check.c:
        When removing/resetting the timestamp file ignore the tty ticket
        contents.
-       [8b285f601ec0] <1.7>
-
-2010-08-05  Todd C. Miller  <Todd.Miller@courtesan.com>
+       [b709f5667a0b]
 
-       * sudo.c:
+       * plugins/sudoers/sudoers.c:
        delref sudo_user.pw, runas_pw and runas_gr immediately before we
-       exec.
-       [220be2de2f31] <1.7>
-
-       * sudo.c:
-       Move calls to sudo_endgrent() and sudo_endpwent() to be after
-       set_perms(), which may do passwd or group lookups.
-       [883f0db94fd4] <1.7>
+       return.
+       [4d67d15dfd3b]
 
 2010-08-04  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * check.c:
-       Make sure we don't try to delref NULL.
-       [19bc5a47db06] <1.7>
-
-       * pwutil.c:
-       Add missing delref in user_in_group()
-       [fafb278f47a6] <1.7>
-
-       * sudo.c:
-       delref the old runas group in set_runasgr()
-       [0a7dd113cb1f] <1.7>
-
-       * match.c:
-       Repair usergr_matches() return value broken in last checkin.
-       [460b7b6ca2ce] <1.7>
-
-       * check.c, get_pty.c, glob.c, ldap.c, match.c, pwutil.c, sudo.c,
-       sudo.h:
+       * plugins/sudoers/check.c, plugins/sudoers/ldap.c,
+       plugins/sudoers/match.c, plugins/sudoers/pwutil.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h:
        Reference count cached passwd and group structs. The cache holds
        one reference itself and another is added by sudo_getgr{gid,nam} and
        sudo_getpw{uid,nam}. The final ref on the runas and user passwd and
        group structs are persistent for now.
-       [e414c67e11fd] <1.7>
+       [e544685523c3]
 
-       * UPGRADE:
-       Fix typo
-       [0f443aa22e96] <1.7>
+       * doc/UPGRADE:
+       fix typo
+       [e32f2d35e6c9]
 
 2010-08-03  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * check.c:
+       * plugins/sudoers/check.c:
        Do not produce a warning for "sudo -k" if the ticket file does not
        exist.
-       [eeaaa73d7f5b] <1.7>
+       [1598f6061b75]
 
-       * pwutil.c:
+       * plugins/sudoers/pwutil.c:
        Instead of caching struct passwd and struct group in the red-black
        tree, store a struct cache_item which includes both the key and
        datum. This allows us to user the actual name that was looked up as
        like set_perms() and the logging functions. Fixing this would
        require making a copy of the structs for user and runas or adding a
        reference count (better).
-       [2c1d8ec4fa5f] <1.7>
+       [225d4a22f60e]
 
-       * check.c, exec_pty.c, get_pty.c, logging.c, sudoreplay.c, tgetpass.c,
-       visudo.c:
+       * plugins/sudoers/Makefile.in:
+       Fix path to mkinstalldirs
+       [b4968379b12d]
+
+       * plugins/sudoers/check.c, plugins/sudoers/logging.c,
+       plugins/sudoers/sudoreplay.c, plugins/sudoers/visudo.c,
+       src/exec_pty.c, src/get_pty.c, src/tgetpass.c:
        Quiet gcc warnings on glibc systems that use warn_unused_result for
        write(2) and others.
-       [5faf88695c66] <1.7>
+       [c99f138960e0]
 
 2010-08-02  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * toke.c, toke.l:
+       * plugins/sudoers/toke.c, plugins/sudoers/toke.l:
        Add %option noinput
-       [8a5e05d6f71f] <1.7>
+       [72b9cd49b4f1]
 
-       * aclocal.m4, configure:
-       Add cross-compile defaults for remaining AC_TRY_RUN usage.
-       [fb88d22eabc6] <1.7>
+       * aclocal.m4, configure, configure.in:
+       Add cross-compile defaults for remaining AC_TRY_RUN usage. Also add
+       back getgroups() check since AC_FUNC_GETGROUPS defaults to "no" when
+       cross-compiling.
+       [e385c176d0ee]
 
 2010-07-31  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * aclocal.m4, config.h.in, configure, configure.in, snprintf.c:
+       * aclocal.m4, compat/snprintf.c, config.h.in, configure, configure.in:
        Use AC_CHECK_MEMBER in SUDO_SOCK_SA_LEN Use AC_TYPE_LONG_LONG_INT
        and AC_CHECK_SIZEOF([long int]) instead of rolling our own.
-       [5e7cc557a46e] <1.7>
-
-2010-07-30  Todd C. Miller  <Todd.Miller@courtesan.com>
-
-       * .hgtags:
-       Added tag SUDO_1_7_4 for changeset 2920a3b9d568
-       [e929004d5102] <1.7>
-
-       * pp:
-       Debian: Remove dots from decoded release number AIX: looser matching
-       of file command output for AIX 5.1
-       [2920a3b9d568] [SUDO_1_7_4] <1.7>
-
-       * .hgtags:
-       Added tag SUDO_1_7_4 for changeset 0d844aa34c1d
-       [cf65ddcec602] <1.7>
+       [cf3e60d9c440]
 
 2010-07-29  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * exec_pty.c:
-       exec_monitor is static
-       [0d844aa34c1d] <1.7>
-
        * pp:
        Update to latest version
-       [7b8a00defbd6] <1.7>
+       [32f93be33961]
 
 2010-07-28  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudo.pp:
        Let pp determine pp_aix_version itself.
-       [c5ee7944af03] <1.7>
+       [7cf0245d84ed]
 
-       * INSTALL, config.h.in, configure, configure.in, mkpkg, sudo.c:
+       * INSTALL, config.h.in, configure, configure.in, mkpkg,
+       plugins/sudoers/sudoers.c:
        Add support for Ubuntu admin flag file and enable it when building
        Ubuntu packages.
-       [2d97501cda0c] <1.7>
+       [00e27cff2dfb]
 
-       * sudo.pp, sudoers:
+       * plugins/sudoers/sudoers, sudo.pp:
        Add commented out SuSE-like targetpw settings
-       [f4ad331ace46] <1.7>
+       [4605d47b7413]
 
        * configure, configure.in:
-       Only try to use +DAportable for non-GCC on hppa Check the value of
-       $pic_flag insteaf of whether the compiler is ANSI C when detecting
-       the HP-UX bundled C compiler.
-       [654da0091c16] <1.7>
+       Only try to use +DAportable for non-GCC on hppa
+       [75d0f284ccf7]
 
        * configure, configure.in:
        Prevent configure from adding the -g flag unless in devel mode
-       [e3c11f228c56] <1.7>
+       [b1fd3f8d45c0]
 
 2010-07-27  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudo.pp:
        Go back to sudo-flavor to match existing packages and only use an
        underscore for those that need it.
-       [1f78ecf3b990] <1.7>
+       [d737069d1e1c]
 
        * sudo.pp:
        Use sudo_$flavor instead of sudo-$flavor since that causes the least
        amount of trouble for the various package managers.
-       [7e1e07115788] <1.7>
+       [71f547af35fc]
 
        * mkpkg:
        Fix handling of the ldap flavor Remove destdir unless --debug was
        specified Make distclean before running configure if there is a
        Makefile present
-       [2bde3925346d] <1.7>
+       [6316f08de7d3]
 
-       * configure, configure.in:
-       Back out version change in 5baf2187a138
-       [bbc3a81afbba] <1.7>
+       * sudo.pp:
+       Add back include file.
+       [195627bf68b8]
 
        * mkpkg:
        Pass extra args on to configure on HP-UX, if we don't have the HP C
        compiler, disable zlib to prevent gcc from finding it in
        /usr/local/lib.
-       [87201c7f1116] <1.7>
+       [473efa0e2bac]
 
-       * configure, configure.in, mkpkg:
+       * mkpkg:
        Use the HP ANSI C compiler on HP-UX if possible
-       [5baf2187a138] <1.7>
+       [fb249b6b175d]
 
-       * sudoreplay.c:
+       * plugins/sudoers/sudoreplay.c:
        Some getline() implementations (FreeBSD 8.0) do not ignore the
        length pointer when the line pointer is NULL as they should.
-       [8652300785ed] <1.7>
+       [2410a1a3543c]
 
-       * sudoreplay.c:
+       * plugins/sudoers/sudoreplay.c:
        Don't need to check for *cp being non-zero, isdigit() will do that.
-       [107301a99b6a] <1.7>
+       [7df11ea8a487]
 
-       * sudoreplay.c:
+       * plugins/sudoers/sudoreplay.c:
        Add setlocale() so the command line arguments that use floating
        point work in different locales. Since sudo now logs the timing
        data in the C locale we must Parse the seconds in the timing file
        manually instead of using strtod(). Furthermore, sudo 1.7.3 logged
        the number of seconds with the user's locale so if the decimal point
        is not '.' try using the locale-specific version.
-       [2b8ed181e37c] <1.7>
+       [4d385765f23b]
 
-       * exec.c:
+       * src/exec.c:
        Do I/O logging in the C locale so the floating point numbers in the
        timing file are not locale-dependent.
-       [18abbca14078] <1.7>
+       [5961cec044ec]
 
-       * sudoreplay.c:
+       * plugins/sudoers/sudoreplay.c:
        Use errorx() not error() for thingsthat don't set errno.
-       [a2e7c6793d26] <1.7>
+       [0fe5e692af84]
 
 2010-07-26  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudo.pp:
-       Add Tru64 kit support
-       [40e2d21aa17f] <1.7>
-
        * pp:
        Better support for 1.2.3 style versions in Tru64 kits
-       [f7133199a711] <1.7>
+       [997c549bb777]
+
+       * sudo.pp:
+       Add Tru64 kit support
+       [e273a954f981]
 
        * pp:
        Remove apparently unnecessary use of sudo
-       [a667a69eeab0] <1.7>
+       [be8840d85125]
 
-       * Makefile.in:
+       * Makefile.in, plugins/sudoers/Makefile.in:
        Create timedir as part of install-dirs target.
-       [a2e394d694dd] <1.7>
+       [c736bc2fb14f]
 
-       * exec_pty.c:
+       * src/exec_pty.c:
        Handle ENXIO from read/write which can occur when reading/writing a
-       pty that has gone away. Fixes bugzilla 422
-       [142f4c2efa17] <1.7>
+       pty that has gone away.
+       [fa2e8059879f]
 
-       * pwutil.c:
+       * plugins/sudoers/pwutil.c:
        sudo_pwdup() was not expanding an empty pw_shell to _PATH_BSHELL
-       [82e5e46bf458] <1.7>
+       [3a045475d5ee]
 
        * mkpkg:
        platform is a pp flag not a variable
-       [9d0ab9b9bf0c] <1.7>
+       [12eba39a47c1]
 
        * Makefile.in, mkpkg, sudo.pp:
        Add simple arg parsing for mkpkg so we can set debug, flavor or
        platform.
-       [8142ab01ccd9] <1.7>
+       [ada839fe252d]
 
        * pp:
        Make rpm backend work on AIX 5.x
-       [2467a79d0b4d] <1.7>
+       [549a76d11393]
 
 2010-07-25  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudoers:
+       * plugins/sudoers/sudoers:
        Add commented out Defaults entry for log_output
-       [b3fe97e59ae0] <1.7>
+       [7e67d7588900]
 
 2010-07-23  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * Makefile.in:
+       * doc/Makefile.in:
+       Remove sudo docdir completely
+       [dce8e82878ef]
+
+       * doc/sample.sudo.conf:
+       Add sample sudo.conf
+       [aafdba3fc411]
+
+2010-07-22  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/Makefile.in:
+       Add PACKAGE_TARNAME for docdir
+       [930c92b8f8f0]
+
+2010-07-23  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/Makefile.in:
+       Pass install-sh -b~ here too.
+       [c3f5eb446c38]
+
+       * plugins/sample/Makefile.in, plugins/sample_group/Makefile.in,
+       plugins/sudoers/Makefile.in, src/Makefile.in:
        Install binary files with -b~ to make a backup. Fixes "text file
        busy" error on HP-UX during install.
-       [3563e3e0163a] <1.7>
+       [81f306f54f8c]
 
        * install-sh:
        "mv -f" on HP-UX doesn't unlink the destination first so add an
        explicit rm before moving the temporary into place.
-       [3994af813c88] <1.7>
+       [fb719a79582d]
 
        * configure, configure.in:
        Some more ${foo} -> $(foo) conversion for consistent Makefiles.
-       [c214d50c32ec] <1.7>
+       [0aa098770074]
+
+       * doc/Makefile.in, plugins/sudoers/Makefile.in:
+       Install sudoers2ldif in the doc dir
+       [33ac3b53d7f5]
 
 2010-07-22  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * pathnames.h.in:
        Add missing include of maillock.h for Solaris
-       [343f04b7a581] <1.7>
+       [5a58883be23a]
 
-       * NEWS, TROUBLESHOOTING, UPGRADE, configure, configure.in,
-       sample.syslog.conf, sudoers.cat:
+       * NEWS, configure, configure.in, doc/TROUBLESHOOTING, doc/UPGRADE,
+       doc/sample.syslog.conf, doc/sudoers.cat:
        Change the default syslog facility from local2 to authpriv (or auth
        if the operating system doesn't support authpriv).
-       [949f39cf4a59] <1.7>
+       [3b70ba514f49]
 
-       * Makefile.in, configure, configure.in, sudo.pp:
+       * Makefile.in, sudo.pp:
        Install sudoers as /etc/sudoers on RPM and debian systems where the
        package manager will not replace a user-modified configuration file.
        This fixes upgrades from the vendor sudo packages.
-       [74c7ff01e880] <1.7>
+       [d886b6d60b5b]
 
        * pp:
        RPM: use %config(noreplace) instead of %config for volatile This
        results in the new file being installed with a .rpmnew suffix
        instead of the file being replaced and the old one renamed with a
        .rpmsave suffix.
-       [166133a4fb9e] <1.7>
+       [58be2119f8e8]
 
 2010-07-21  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * boottime.c, mkstemps.c:
-       Include time.h for struct timeval.
-       [50446e0b8398] <1.7>
+       * compat/mkstemps.c, plugins/sudoers/boottime.c:
+       Include time.h for struct timeval
+       [ddf8b04f0276]
 
-       * exec_pty.c:
+       * src/exec_pty.c:
        The return value of strsignal() may be const and should be treated
        as const regardless.
-       [c035b17b50e3] <1.7>
+       [620074ae1e77]
 
-       * sudoers.cat, sudoers.man.in, sudoers.pod:
+       * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod:
        Mention that 127.0.0.1 will not match, nor will localhost unless
        that is the actual host name.
-       [e9977ec7ac4f] <1.7>
-
-       * Makefile.in:
-       fix typo
-       [f216d653404d] <1.7>
+       [8b574122eb8f]
 
-       * Makefile.in, NEWS, README, UPGRADE, WHATSNEW:
+       * MANIFEST, NEWS, README, WHATSNEW, doc/Makefile.in, doc/UPGRADE:
        Rename WHATSNEW -> NEWS
-       [f3ce0a462ca0] <1.7>
+       [d1a2c8c47d89]
 
        * pp:
        Updated pp with latest patches
-       [cded68af5ba0] <1.7>
+       [98e16b9b8f62]
 
-       * WHATSNEW, exec.c, exec_pty.c, set_perms.c, sudo.c, sudo.h:
-       If pam is in use, wait until the process has finished before calling
-       pam_close_session().
-       [fb3d7de50a05] <1.7>
-
-       * sudoers.cat, sudoers.man.in:
-       regen sudoers manual
-       [7498a058eeb1] <1.7>
+       * WHATSNEW:
+       Sync with 1.7.4
+       [65ac4dafeef7]
 
-       * UPGRADE, sudoers, sudoers.pod:
+       * doc/UPGRADE, doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod,
+       plugins/sudoers/sudoers:
        Add commented out line to add HOME to env_keep and add a warning to
        the note about the HOME change in UPGRADE.
-       [0f7e08f09b9f] <1.7>
+       [0d6a775bb6c8]
 
 2010-07-20  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudoreplay.c:
+       * plugins/sudoers/sudoreplay.c:
        Add LINE_MAX define for those without it.
-       [6248dd44573c] <1.7>
+       [446d9dbe7859]
 
-       * WHATSNEW:
-       Mention that tty_tickets is now the default.
-       [4cf26eaee5ba] <1.7>
-
-       * INSTALL, UPGRADE, config.h.in, configure, configure.in, defaults.c,
-       sudoers.cat, sudoers.man.in, sudoers.pod:
+       * INSTALL, WHATSNEW, config.h.in, configure, configure.in,
+       doc/UPGRADE, doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod,
+       plugins/sudoers/defaults.c:
        The tty_tickets option is now on by default.
-       [73dd2b82a3a9] <1.7>
+       [a01c48206d80]
 
        * WHATSNEW:
        Mention that AIX authdb support has been fixed.
-       [9331829dc276] <1.7>
+       [87bd7f4eba6a]
 
-       * aix.c:
+       * common/aix.c:
        setauthdb() only sets the "old" registry if it was set by a previous
        call to setauthdb(). To restore the original value, passing NULL
        (or an empty string) to setauthdb() is sufficient.
-       [d956fd763521] <1.7>
+       [470da190a254]
 
 2010-07-19  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudoers.cat, sudoers.man.in, sudoers.pod:
-       Mention new handling of HOME in always_set_home and set_home
-       descriptions.
-       [a69c9bed3164] <1.7>
-
-       * sudo.cat, sudo.man.in, sudo.pod:
-       fix typo
-       [9b90bb3e9187] <1.7>
-
-       * UPGRADE, WHATSNEW, env.c, sudo.cat, sudo.man.in, sudo.pod:
+       * WHATSNEW, doc/UPGRADE, doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod,
+       doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod,
+       plugins/sudoers/env.c:
        Reset HOME when env_reset is enabled unless it is in env_keep
-       [18223dfd1ac3] <1.7>
+       [f421f8827340]
 
-       * sudoers.cat, sudoers.man.in, sudoers.pod:
+       * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod:
        The default for set_logname has been "true" for some time now.
-       [9f97e4b43a4b] <1.7>
-
-       * sudoers.cat, sudoers.man.in, sudoers.pod:
-       Document that MAIL it set in env_reset mode.
-       [dcf9ad98079e] <1.7>
+       [f489da5674c3]
 
-       * boottime.c:
+       * plugins/sudoers/boottime.c:
        Add missing include of time.h
-       [57bee414982d] <1.7>
+       [624d7014932f]
 
-       * defaults.c, sudo.c:
-       Check return value of setdefs() but don't stop setting defaults if
-       we hit an unknown one.
-       [a42cb2d6b7ed] <1.7>
-
-       * logging.c:
+       * plugins/sudoers/logging.c:
        Fix check for dup2() return value.
-       [916cd7fdeba7] <1.7>
+       [140ea2d50d20]
 
-       * visudo.c:
-       Treat an unknown defaults entry as a parse error.
-       [1f94675835d9] <1.7>
+       * plugins/sudoers/env.c:
+       Add PYTHONUSERBASE to initial_badenv_table
+       [3149aae5b12c]
 
-       * env.c:
-       Check KEPT_MAIL not DID_MAIL when determining whether to set MAIL in
-       -i and env_reset mode.
-       [aa6657ccfe01] <1.7>
+       * plugins/sudoers/visudo.c:
+       Treat an unknown defaults entry as a parse error.
+       [b3ebad73efb2]
 
-       * env.c:
-       Add PYTHONUSERBASE to initial_badenv_table
-       [93058374f0d9] <1.7>
+       * plugins/sudoers/defaults.c, plugins/sudoers/sudoers.c:
+       Check return value of setdefs() but don't stop setting defaults if
+       we hit an unknown one.
+       [945e752239ab]
 
-       * WHATSNEW, aclocal.m4, config.h.in, configure, configure.in, env.c,
-       pathnames.h.in, sudo.cat, sudo.man.in, sudo.pod:
+       * WHATSNEW, aclocal.m4, config.h.in, configure, configure.in,
+       doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod, doc/sudoers.cat,
+       doc/sudoers.man.in, doc/sudoers.pod, pathnames.h.in,
+       plugins/sudoers/env.c:
        If env_reset is enabled, set the MAIL environment variable based on
        the target user unless MAIL is explicitly preserved in sudoers.
-       [d903c904dcd4] <1.7>
+       [a1b03e2e0e96]
 
 2010-07-17  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * pp:
        decode debian code names
-       [2df0ecbc23b4] <1.7>
+       [8741280d9960]
 
        * WHATSNEW:
        fix typo
-       [b66a95fa1869] <1.7>
+       [a8a19451110b]
 
 2010-07-16  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * WHATSNEW:
-       Add entry about SuSE bash script fix.
-       [04af78fa281c] <1.7>
+       Merge with 1.7.4
+       [9348fa7e15b8]
 
-       * sudo.c:
+       * src/sudo.c:
        Restore RLIMIT_NPROC after the uid switch if it appears that
        runas_setup() did not do it for us. Fixes a bash script problem on
        SuSE with RLIMIT_NPROC set to RLIM_INFINITY.
-       [bb14802d48b1] <1.7>
+       [786fb272e5fd]
 
 2010-07-15  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * mkpkg, pp, sudo.pp:
        Restore the dot removal in the os version reported by polypkg. Adapt
        mkpkg and sudo.pp to the change.
-       [83c7870130fe] <1.7>
+       [dcafdd53b88f]
 
 2010-07-16  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * WHATSNEW:
-       Mention polypkg
-       [c5f6e40bbb58] <1.7>
-
-       * README, WHATSNEW:
-       Update for sudo 1.7.4
-       [0c688f1f8160] <1.7>
-
        * INSTALL:
        document --with-pam-login
-       [33ca3f6308ae] <1.7>
+       [ea93e4c6873c]
 
-       * sudoers.cat, sudoers.man.in, sudoers.pod:
+       * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod:
        The tag is NOSETENV, not UNSETENV. From Petr Uzel.
-       [95f37e63ca15] <1.7>
+       [2ac90d8de36e]
 
 2010-07-15  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudo.pp:
        Include flavor in solaris package name
-       [b6d56ccf367e] <1.7>
+       [e605f6364c9f]
 
        * mkpkg:
        Older shells don't support IFS= so set explictly to space, tab,
        newline.
-       [336925525e17] <1.7>
+       [7773960bc8a0]
 
        * mkpkg:
        Use '=' not '==' in test
-       [98c692271cfd] <1.7>
+       [c99d42bc48e6]
 
        * mkpkg:
        Fix typo that prevented debian from matching
-       [af4deec35e37] <1.7>
+       [84421078fcb7]
 
        * mkpkg:
        Add missing prefix setting for debian
-       [d0c1941cb6ec] <1.7>
-
-       * sudo.pp:
-       Use tab indents to reduce the chance of problem with <<- Uncomment
-       some env_keep lines for RHEL, SLES and Debian to more closely match
-       the vendor sudoers files.
-       [74ba26566cdc] <1.7>
+       [6466f23de4aa]
 
        * sudo.pp:
-       Fix indentation Fix the debian %set section, pp does not set
-       pp_deb_distro Uncomment %sudo line in sudoers for debian Add pam.d
-       to %files for debian Remove the /etc/sudo-ldap.conf symlink on
+       Use tab indents to reduce the chance of problem with <<- Fix the
+       debian %set section, pp does not set pp_deb_distro Uncomment %sudo
+       line in sudoers for debian Uncomment some env_keep lines for RHEL,
+       SLES and debian to more closely match the vendor sudoers files.
+       Add /etc/pam.d to %files Remove the /etc/sudo-ldap.conf symlink on
        debian for ldap flavor
-       [f15ff41b5afd] <1.7>
+       [c5b49feb1a0c]
 
-       * sudoers:
+       * plugins/sudoers/sudoers:
        Add commented out env_keep entries, sample Aliases and a %sudo line
        for debian.
-       [8264e4ed42dc] <1.7>
+       [387719e52d0f]
 
        * configure, configure.in:
-       Remove check for egrep; configure has its own
-       [27b3d85ebf4f] <1.7>
+       Move zlib check later on in the script to avoid a strange shell
+       problem on SLES11.
+       [1a3153bb1291]
 
        * configure.in:
-       Use enable_zlib instead of enableval for consistency
-       [4a15cfd43d3e] <1.7>
+       Remove check for egrep; configure has its own
+       [a3b9d98cb5d2]
 
 2010-07-14  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * mkpkg:
        Enable zlib for linux distros
-       [fcab91448bb0] <1.7>
+       [8fa51a1405a4]
 
        * mkpkg:
        Add ldap flavor to default build
-       [e35a577c8994] <1.7>
+       [97644f5a555f]
 
        * mkpkg, sudo.pp:
        Simplify rpm linux distro settings
-       [f30547765636] <1.7>
+       [b9dcf10cdf20]
 
-       * UPGRADE, aclocal.m4, configure, configure.in, sudo.cat, sudo.man.in,
-       sudoers.cat:
+       * aclocal.m4, configure, configure.in, doc/UPGRADE, doc/sudoers.cat:
        Move time stamp files from /var/run/sudo to /var/{db,lib,adm}/sudo.
-       [8c9440423d98] <1.7>
+       [2c549c1acde9]
 
-       * Makefile.in, mkpkg, sudo.pp:
+       * Makefile.in:
+       Fix ChangeLog creation from build dir
+       [3d0c7904f173]
+
+       * plugins/sudoers/sudoers.c:
+       Handle getcwd() failure.
+       [aef7bef87394]
+
+       * doc/Makefile.in, mkpkg, sudo.pp:
        Add ldap "flavor" for debian, controlled by the SUDO_FLAVOR
        environment variable.
-       [9f418defc08a] <1.7>
+       [be6ed611b7a8]
 
        * sudo.pp:
        Create sudo group on debian
-       [4b0cc7b8b0b5] <1.7>
+       [6ed6c032042e]
 
        * mkpkg, sudo.pp:
        Add debian 4/5/6 and use the dot when doing version matches
-       [d5184f0a1efc] <1.7>
-
-       * sudoers.cat, sudoers.man.in, sudoers.pod:
-       Remove spurious "and"; from debian
-       [8b9f2a5937bc] <1.7>
+       [6bcb664d1f4f]
 
        * aclocal.m4, configure:
        Use a loop when searching for mv, sendmail and sh
-       [a1c7d19721a4] <1.7>
+       [d5e9369f8d13]
 
-       * aclocal.m4, configure, configure.in, sudoers.cat, sudoers.man.in,
-       sudoers.pod, visudo.cat, visudo.man.in, visudo.pod:
+       * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod:
+       Remove spurious "and"; from debian
+       [a21e6f7c5b99]
+
+       * aclocal.m4, configure, configure.in, doc/sudoers.cat,
+       doc/sudoers.man.in, doc/sudoers.pod, doc/visudo.cat,
+       doc/visudo.man.in, doc/visudo.pod:
        Substitute the value of EDITOR into the sudoers and visudo manuals.
-       [f00dc9343f94] <1.7>
+       [cd79e587dd7f]
 
 2010-07-13  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * mkpkg, pp, sudo.pp:
-       Initial debian 4.0 support
-       [6d73c000723f] <1.7>
+       Initial support for debian 4.0
+       [ac6707915fa8]
 
        * mkpkg:
        Some platforms need -fPIE instead of -fpie
-       [8533a29633e8] <1.7>
-
-       * Makefile.in:
-       Add packaging bits to DISTFILES
-       [dea9f374f28b] <1.7>
+       [fd6be19e5bc2]
 
-       * auth/pam.c:
+       * plugins/sudoers/auth/pam.c:
        Only set PAM_RHOST for Solaris, where it is needed to avoid a bug.
        On Linux it causes a DNS lookup via libaudit.
-       [22e04d2f5f0f] <1.7>
+       [1e10105ade5b]
+
+       * MANIFEST:
+       Update MANIFEST to match packaging changes
+       [ef86ee557b5b]
 
        * sudo.psf:
        We now use pp to generate HP-UX packages
-       [6c9f8ae6bc11] <1.7>
-
-2010-07-12  Todd C. Miller  <Todd.Miller@courtesan.com>
+       [f7aa8da7844e]
 
-       * auth/pam.c:
-       Fix indentation
-       [e52e9e6338d5] <1.7>
-
-       * INSTALL, Makefile.in:
-       isntall-man -> install-doc
-       [02cc8198ea7a] <1.7>
+       * INSTALL.binary, plugins/sudoers/Makefile.binary.in:
+       Remove vestiges of old binary package bits.
+       [afffd005452f]
 
-       * configure, configure.in, sudo.cat, sudo.man.in, sudoers.cat,
-       sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.man.in,
-       sudoreplay.cat, sudoreplay.man.in, visudo.cat, visudo.man.in:
-       Bump version to 1.7.4
-       [df6ce4ea908a] <1.7>
-
-       * INSTALL.binary, Makefile.binary.in, Makefile.in:
-       Remove remaining bits of the old binary package
-       [8d4f82c23c22] <1.7>
-
-       * sudo.pp:
-       Use http://rc.quest.com/topics/polypkg/ for packaging
-       [d71793085629] <1.7>
+       * INSTALL, Makefile.in, common/Makefile.in, compat/Makefile.in,
+       doc/Makefile.in, include/Makefile.in, plugins/sample/Makefile.in,
+       plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in,
+       src/Makefile.in:
+       install-man -> install-doc
+       [99b5fa05567c]
 
-       * Makefile.in, mkpkg, pp:
+       * Makefile.in, doc/Makefile.in, include/Makefile.in, mkpkg,
+       plugins/sudoers/Makefile.in, pp, src/Makefile.in, sudo.pp:
        Use http://rc.quest.com/topics/polypkg/ for packaging
-       [675e505758c5] <1.7>
+       [5ca8eb75b223]
 
        * install-sh:
        Just ignore the -c option, it is the default Add support for -d
        option
-       [2adfb3a63231] <1.7>
+       [a8b6b0a131e8]
 
-       * env.c, logging.c, pathnames.h.in:
+2010-07-12  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * pathnames.h.in, plugins/sudoers/env.c, plugins/sudoers/logging.c:
        Use _PATH_STDPATH instead of _PATH_DEFPATH
-       [2c22d54a1f02] <1.7>
+       [137fa911908e]
 
-       * Makefile.in:
+       * plugins/sudoers/Makefile.in, src/Makefile.in:
        Do not strip binaries.
-       [bc84682b372c] <1.7>
+       [20166e287176]
 
        * INSTALL, configure, configure.in:
        Add --insults=disabled configure option to allow people to build in
        insult support but have the insults disabled unless explicitly
        enabled in sudoers.
-       [6d9f40db9cca] <1.7>
-
-2010-07-10  Todd C. Miller  <Todd.Miller@courtesan.com>
+       [523b8c552e90]
 
-       * env.c, sudoreplay.c:
-       Fix K&R compilation
-       [e44d3be7ab85] <1.7>
+       * compat/mkstemps.c:
+       Add prototype for gettime()
+       [275eee40473b]
 
-2010-07-09  Todd C. Miller  <Todd.Miller@courtesan.com>
-
-       * auth/pam.c, config.h.in, configure, configure.in, env.c, sudo.c,
-       sudo.h:
+       * config.h.in, configure, configure.in, plugins/sudoers/auth/pam.c,
+       plugins/sudoers/env.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h:
        Add support for a sudo-i pam.d file to be used for "sudo -i".
        Adapted from a RedHat patch.
-       [2984c3831d88] <1.7>
+       [06d34f16520b]
 
-       * Makefile.in:
-       Fix installation of sudo_noexec.so
-       [d1f7ca8331b6] <1.7>
+2010-07-09  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * include/missing.h:
+       Fix mkstemps() prototype
+       [2421841e815b]
 
-       * Makefile.in, config.h.in, configure, configure.in, missing.h,
-       mkstemp.c, mkstemps.c, sudo_edit.c:
+       * MANIFEST, compat/Makefile.in, compat/mkstemp.c, compat/mkstemps.c,
+       config.h.in, configure, configure.in, include/missing.h,
+       src/sudo_edit.c:
        Use mkstemps() instead of mkstemp() in sudoedit. This allows
        sudoedit to preserve the file extension (if any) which may be used
        by the editor (like emacs) to choose the editing mode.
-       [46399679d9ae] <1.7>
+       [d33172d2c086]
 
 2010-07-08  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * ldap.c, sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.ldap.pod:
+       * doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in, doc/sudoers.ldap.pod,
+       plugins/sudoers/ldap.c:
        TLS_CACERT is now an alias for TLS_CACERTFILE. OpenLDAP uses
        TLS_CACERT, not TLS_CACERTFILE in its ldap.conf. Other LDAP client
        code, such as nss_ldap, uses TLS_CACERTFILE. Also document why you
        should avoid disabling TLS_CHECKPEER is possible.
-       [1d626a5cf8c0] <1.7>
+       [196622436212]
 
 2010-07-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * toke.c, toke.l:
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Make sudo_plugin format a bit more like a man page
+       [048d596e32da]
+
+       * plugins/sudoers/toke.c, plugins/sudoers/toke.l:
        Add suport for negated user/host/command lists in a Defaults entry.
        E.g. Defaults:!baduser noexec
-       [24f07a805dce] <1.7>
+       [d41112cf0342]
+
+       * Makefile.in, common/Makefile.in, compat/Makefile.in,
+       doc/Makefile.in, include/Makefile.in, plugins/sample/Makefile.in,
+       plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in,
+       src/Makefile.in:
+       Add uninstall target
+       [fea66ebf136a]
+
+       * common/Makefile.in, compat/Makefile.in:
+       Remove unused AR, SED and RANLIB variables
+       [2ff9928bfdb3]
+
+       * Makefile.in:
+       Do not install sample plugins
+       [5443b87bd1c3]
+
+2010-07-06  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * MANIFEST, aclocal.m4, compat/setenv.c, compat/unsetenv.c, configure,
+       configure.in, plugins/sudoers/env.c:
+       Now that sudoers is a dynamically loaded module we cannot override
+       the libc environment functions because the symbols may already have
+       been resolved via libc. Remove getenv/putenv/setenv/unsetenv
+       replacements from sudoers and add replacements for setenv/unsetenv
+       for systems that lack them.
+       [3f2b43cb8851]
+
+       * configure, configure.in, plugins/sudoers/Makefile.in:
+       Link testsudoers with -ldl when needed
+       [f79606f9fcd7]
+
+       * plugins/sample_group/plugin_test.c:
+       Remove unused time.h and add limits.h for PATH_MAX
+       [3f5d0074d621]
+
+       * doc/sudoers.ldap.pod:
+       Fix typo.
+       [bc855fd57397]
+
+2010-07-05  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sample_group/plugin_test.c:
+       Do not depend on strlcpy/strlcat
+       [6e7e2b5af051]
+
+       * plugins/sample_group/plugin_test.c:
+       Standalone test driver for sudoers group plugin.
+       [eb1235fc3b8e]
+
+2010-07-02  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/group_plugin.c, src/load_plugins.c:
+       Use RTLD_LAZY instead of RTLD_NOW; was using RTLD_NOW as a debugging
+       aid.
+       [2a34e616229b]
+
+       * plugins/sample_group/sample_group.c:
+       Fix style nit in function declarations
+       [ab87c7c76bf9]
+
+       * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod:
+       Document group_plugin syntax.
+       [ed1faf72ddcb]
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Document the sudoers group plugin.
+       [f19a62dc8cfc]
+
+       * INSTALL, MANIFEST, Makefile.in, config.h.in, configure,
+       configure.in, doc/LICENSE, doc/license.pod, include/sudo_plugin.h,
+       plugins/sample_group/Makefile.in, plugins/sample_group/getgrent.c,
+       plugins/sample_group/sample_group.c, plugins/sudoers/Makefile.in,
+       plugins/sudoers/def_data.c, plugins/sudoers/def_data.h,
+       plugins/sudoers/def_data.in, plugins/sudoers/group_plugin.c,
+       plugins/sudoers/match.c, plugins/sudoers/nonunix.h,
+       plugins/sudoers/set_perms.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h, plugins/sudoers/testsudoers.c,
+       plugins/sudoers/vasgroups.c, plugins/sudoers/visudo.c, src/sudo.c:
+       Replace built-in non-unix group support with a sudoers group plugin.
+       Include a sample plugin that can read Unix-format group files.
+       [8fc58ce0b1a8]
+
+       * configure, configure.in, src/load_plugins.c:
+       Add a trailing slash to _PATH_SUDO_PLUGIN_DIR to simplify usage.
+       [5c491dddb8ef]
 
 2010-07-01  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudoers.ldap.pod:
-       fix typo.
-       [d5f2922cecf2] <1.7>
+       * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod, doc/sudoers.cat,
+       doc/sudoers.man.in, doc/sudoers.pod:
+       Move sudoers-specific bits out of sudo(8) and into sudoers(5)
+       [e8a5a5830cfe]
 
-2010-06-29  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * aclocal.m4, configure, configure.in:
+       Substitute @io_logdir@ for the sudoers I/O log directory.
+       [21a75ca7b0ab]
 
-       * .hgtags:
-       Added tag SUDO_1_7_3 for changeset 72fd1f510a08
-       [cc8b2277e17e] <1.7>
+2010-06-29  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * configure, configure.in, sudo.cat, sudo.man.in, sudoers.cat,
-       sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.man.in,
-       sudoreplay.cat, sudoreplay.man.in, visudo.cat, visudo.man.in:
-       Sudo 1.7.3 GA
-       [72fd1f510a08] [SUDO_1_7_3] <1.7>
+       * MANIFEST, common/Makefile.in, common/aix.c, common/alloc.c,
+       common/atobool.c, common/fileops.c, common/fmt_string.c,
+       common/lbuf.c, common/term.c, compat/fnmatch.c, compat/getcwd.c,
+       compat/getgrouplist.c, compat/getline.c, compat/glob.c,
+       compat/snprintf.c, config.h.in, configure, configure.in,
+       include/fileops.h, plugins/sample/sample_plugin.c,
+       plugins/sudoers/alias.c, plugins/sudoers/auth/afs.c,
+       plugins/sudoers/auth/aix_auth.c, plugins/sudoers/auth/bsdauth.c,
+       plugins/sudoers/auth/dce.c, plugins/sudoers/auth/fwtk.c,
+       plugins/sudoers/auth/kerb4.c, plugins/sudoers/auth/kerb5.c,
+       plugins/sudoers/auth/pam.c, plugins/sudoers/auth/passwd.c,
+       plugins/sudoers/auth/rfc1938.c, plugins/sudoers/auth/secureware.c,
+       plugins/sudoers/auth/securid.c, plugins/sudoers/auth/securid5.c,
+       plugins/sudoers/auth/sia.c, plugins/sudoers/auth/sudo_auth.c,
+       plugins/sudoers/boottime.c, plugins/sudoers/check.c,
+       plugins/sudoers/defaults.c, plugins/sudoers/env.c,
+       plugins/sudoers/find_path.c, plugins/sudoers/getdate.c,
+       plugins/sudoers/getdate.y, plugins/sudoers/getspwuid.c,
+       plugins/sudoers/goodpath.c, plugins/sudoers/gram.c,
+       plugins/sudoers/gram.y, plugins/sudoers/interfaces.c,
+       plugins/sudoers/iolog.c, plugins/sudoers/ldap.c,
+       plugins/sudoers/logging.c, plugins/sudoers/match.c,
+       plugins/sudoers/parse.c, plugins/sudoers/pwutil.c,
+       plugins/sudoers/set_perms.c, plugins/sudoers/sudo_nss.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h,
+       plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c,
+       plugins/sudoers/toke.c, plugins/sudoers/toke.l,
+       plugins/sudoers/tsgetgrpw.c, plugins/sudoers/visudo.c,
+       src/Makefile.in, src/aix.c, src/conversation.c, src/exec.c,
+       src/exec_pty.c, src/get_pty.c, src/load_plugins.c, src/parse_args.c,
+       src/sudo.c, src/sudo.h, src/sudo_edit.c, src/tgetpass.c:
+       Set usrinfo for AIX Set adminstrative domain for the process when
+       looking up user's password or group info and when preparing for
+       execve(). Include strings.h even if string.h exists since they may
+       define different things. Fixes warnings on AIX and others.
+       [cf8b93e872c9]
 
-       * alias.c, alloc.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, boottime.c, check.c,
-       defaults.c, env.c, exec.c, exec_pty.c, fileops.c, find_path.c,
-       fnmatch.c, get_pty.c, getcwd.c, getdate.c, getdate.y, getline.c,
-       getspwuid.c, glob.c, goodpath.c, gram.c, gram.y, interfaces.c,
-       iolog.c, lbuf.c, ldap.c, logging.c, match.c, parse.c, parse_args.c,
-       pwutil.c, set_perms.c, snprintf.c, sudo.c, sudo_edit.c, sudo_nss.c,
-       sudoreplay.c, term.c, testsudoers.c, tgetpass.c, toke.c, toke.l,
-       tsgetgrpw.c, visudo.c:
-       Include strings.h even if string.h exists since they may define
-       different things. Fixes warnings on AIX and others.
-       [7c6de7fb5dba] <1.7>
+       * Makefile.in:
+       Add a separate all target for AIX make which was using the entire
+       LHS (not just the first entry) of the first target as the implicit
+       target.
+       [a45b980a01ef]
 
-       * env.c:
+       * plugins/sudoers/env.c:
        Do not rely on env.env_len when unsetting a variable, just use the
        NULL terminator.
-       [faf088613ce5] <1.7>
+       [ca6eb239c829]
 
-       * env.c:
+       * plugins/sudoers/env.c:
        In unsetenv() check for NULL or empty name as per POSIX 1003.1-2008
-       [47f8dfcc7a48] <1.7>
-
-2010-06-28  Todd C. Miller  <Todd.Miller@courtesan.com>
-
-       * sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.ldap.pod:
-       Mention that multiple URI lines are merged into a single one.
-       [1dc0ac5929bf] <1.7>
-
-       * WHATSNEW:
-       Document AIX fixes
-       [be36e8a6dddd] <1.7>
-
-2010-06-26  Todd C. Miller  <Todd.Miller@courtesan.com>
-
-       * env.c, sudo.c, sudo.h:
-       For env_init() just use environ not the envp from main().
-       [d4f3e374caeb] <1.7>
+       [7046ba7caa4e]
 
 2010-06-25  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * configure, configure.in, sudo.cat, sudo.man.in, sudoers.cat,
-       sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.man.in,
-       sudoreplay.cat, sudoreplay.man.in, visudo.cat, visudo.man.in:
-       Update version to 1.7.3rc1
-       [fe43fe79070d] <1.7>
-
-       * TODO:
-       fqdn issue is resolved
-       [f35cb63eb74b] <1.7>
-
-       * env.c:
-       In unsetenv(), assign ep in the for loop instead of doing it
-       earlier. This version of the code does not change env.envp in
-       between when ep is assigned and when it is used but older versions
-       (e.g. 1.7.2) do.
-       [a4cd29c862c9] <1.7>
-
-       * aix.c:
-       Use S_REGISTRY instead of S_AUTHSYSTEM as the argument to
-       getuserattr() when fetching the administrative domain to be used by
-       setauthdb(). This was suggested by AIX support and is consistent
-       with what OpenSSH does.
-       [d3109706ec85] <1.7>
-
-       * vasgroups.c:
+       * plugins/sudoers/vasgroups.c:
        Use warningx() instead of log_error() since the latter is not
        available to visudo or testsudoers. This does mean that they don't
        end up in syslog.
-       [0174e89f983b] <1.7>
+       [152b7c50f426]
 
-       * sudo.c:
+       * plugins/sudoers/sudoers.c:
        Defer call to sudo_nonunix_groupcheck_cleanup() until after we have
        closed the sudoers sources. From Quest sudo.
-       [c1b33e3e0f9e] <1.7>
+       [c1cd573bab94]
 
-       * pwutil.c:
+       * plugins/sudoers/pwutil.c:
        Ignore case when matching user/group names in the cache. From Quest
        sudo.
-       [72df368a8a0e] <1.7>
+       [2aa4ecc7d7f5]
 
 2010-06-24  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * config.h.in, configure, configure.in, selinux.c:
+       * config.h.in, configure, configure.in, src/selinux.c:
        Add check for setkeycreatecon() when --with-selinux is specified.
-       [24144c52c0cc] <1.7>
+       [affae247b4e0]
 
        * configure, configure.in:
-       Bump version to 1.7.3b5 Error out if libaudit.h is missing or
-       ununable when --with-linux-audit was specified
-       [215c7653d9bc] <1.7>
-
-       * aix.c:
-       K&R function declaration for aix_setauthdb()
-       [82da12d222a6] <1.7>
-
-       * env.c, sudo.c, sudo.h:
-       If env_init() was called implicitly via getenv(), setenv() or
-       putenv() just use the specified envp instead of mallocing a new
-       copy. This prevents an infinite loop on OpenBSD which calls
-       getenv() from malloc() to get MALLOC_OPTIONS.
-       [8e82ce63f774] <1.7>
-
-       * ldap.c:
-       Add support for multiple URI lines by joining the contents and
-       passing the result to ldap_initialize.
-       [b4e10b2ffdb1] <1.7>
-
-2010-06-23  Todd C. Miller  <Todd.Miller@courtesan.com>
-
-       * pwutil.c, set_perms.c, sudo_nss.c:
-       Bracket initgroups with calls to aix_setauthdb() and
-       aix_restoreauthdb()
-       [363dbe449f1c] <1.7>
-
-       * aix.c:
-       Include compat.h before alloc.h to get __P
-       [819a2667ffd7] <1.7>
-
-       * auth/aix_auth.c:
-       Include usersec.h for authenticate() prototype
-       [2b8dd2b67131] <1.7>
+       Error out if libaudit.h is missing or ununable when --with-linux-
+       audit was specified
+       [d82e743fac04]
 
-       * aix.c:
-       Add missing includes Add missing trailing NUL in userinfo string
-       [8deaedf44943] <1.7>
+       * doc/HISTORY, doc/history.pod:
+       Add =head3 entries, mostly for the html version
+       [ee93112d0308]
 
 2010-06-22  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * HISTORY, history.pod:
-       Mention when LDAP was incorporated.
-       [4e6c8ec4f67c] <1.7>
+       * doc/HISTORY, doc/history.pod:
+       Mention when LDAP was incorporate.
+       [2923dc17f79c]
 
 2010-06-21  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * configure:
-       Define _LINUX_SOURCE_COMPAT on AIX for strsignal() prototype, it is
-       not covered by _ALL_SOURCE.
-       [3657f1b181b9] <1.7>
-
-       * pwutil.c:
-       Include usersec.h on AIX to get IDtouser() prototype.
-       [11483bbe15c7] <1.7>
-
-       * configure.in:
+       * configure, configure.in:
        Define _LINUX_SOURCE_COMPAT on AIX for strsignal() prototype, it is
        not covered by _ALL_SOURCE.
-       [fd48e6e2136b] <1.7>
+       [c92fd69809d0]
 
 2010-06-18  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * iolog.c:
+       * plugins/sudoers/iolog.c:
        Add a cast to quiet a compiler warning.
-       [51e9d419bd83] <1.7>
+       [a200e07ee1bc]
 
-       * boottime.c:
-       Use memset() instead of zero_bytes() since we don't include sudo.h
-       [f310b2123ba9] <1.7>
-
-       * Makefile.in:
-       getline.o is already in LIB_OBJS, do not need it in COMMON_OBJS
-       [c8750c2d75ab] <1.7>
-
-       * getdate.c, getdate.y:
+       * plugins/sudoers/getdate.c, plugins/sudoers/getdate.y:
        Quiet a compiler warning.
-       [9f231be15958] <1.7>
+       [c9acfc927cea]
 
-       * defaults.c, sudo.c:
+       * plugins/sudoers/defaults.c, plugins/sudoers/sudoers.c:
        Call set_fqdn() after sudoers has parsed instead of inline as a
        callback.
-       [26d413ddb6dd] <1.7>
+       [5f4e5d075f2d]
 
-       * WHATSNEW:
+       * WHATSNEW, plugins/sudoers/sudoers.c:
        Do not call set_fqdn() until sudoers parses (where is gets run as a
        callback).
-       [582453a993a1] <1.7>
-
-       * sudo.c:
-       Do not call set_fqdn() until sudoers parses (where is gets run as a
-       callback). Otherwise, if sudo is built --with-fqdn the fqdn will be
-       set even if !fqdn is set in sudoers.
-       [aa01e867d1bb] <1.7>
-
-       * configure, configure.in, sudo.cat, sudo.man.in, sudoers.cat,
-       sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.man.in,
-       sudoreplay.cat, sudoreplay.man.in, visudo.cat, visudo.man.in:
-       Bump version to 1.7.3b4
-       [c1c5a73766b6] <1.7>
+       [09040fca6d40]
 
        * WHATSNEW:
        mention the change in tty ticket behavior when there is no tty
-       [93ddde63e453] <1.7>
-
-       * TODO:
-       remove done items
-       [9601b2e8dcef] <1.7>
-
-       * aix.c:
-       Remove comment; NAME in usrinfo should be user name.
-       [eb46f1e8ea08] <1.7>
+       [575a1fd98f05]
 
-       * check.c:
+       * plugins/sudoers/check.c:
        Do not update tty ticket if there is no tty.
-       [e64e8c8f2286] <1.7>
-
-       * sudo.cat, sudo.man.in, sudo.pod:
-       No longer need to use -- with the -s flag
-       [e45c18dd79dc] <1.7>
+       [63f9c33ce6a7]
 
-       * Makefile.in:
-       Add missing $(srcdir) to sudo.man.in target
-       [2bd89f6ca9f3] <1.7>
+       * doc/LICENSE, doc/license.pod:
+       Update copyright year
+       [0722ab5d404b]
 
-       * Makefile.in:
+       * doc/Makefile.in:
        Do not rely on BSD make's $>
-       [cb328b82cb92] <1.7>
+       [936a86398bd9]
 
        * configure, configure.in:
        Set timedir to /var/db/sudo for darwin to match Apple sudo's
        location
-       [860c7f1b001f] <1.7>
+       [d5b9b03096f1]
 
 2010-06-16  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * Makefile.in, configure, configure.in:
-       Move aix.o from SUDO_OBJS to COMMON_OBJS
-       [f8a9bdf346c1] <1.7>
+       * plugins/sudoers/sudoers.h:
+       Add stub declarations for struct stat and struct timeval
+       [f6d90551a4fd]
 
-       * config.h.in, configure, configure.in, defaults.c, iolog.c,
-       sudoreplay.c:
+       * MANIFEST:
+       Remove compat/sigaction.c
+       [d0ed6d9a770e]
+
+       * config.h.in, configure, configure.in, plugins/sudoers/defaults.c,
+       plugins/sudoers/iolog.c, plugins/sudoers/sudoreplay.c:
        Check for zlib.h in addition to libz.
-       [fb77e44d5196] <1.7>
+       [6e191b4a6065]
 
-       * Makefile.in, exec.c, exec_pty.c, sudo.h, sudo_exec.h:
+       * MANIFEST, src/Makefile.in, src/exec.c, src/exec_pty.c, src/sudo.h,
+       src/sudo_exec.h:
        Move functions and symbols shared between exec.c and exec_pty.c into
        sudo_exec.h.
-       [e798d945424e] <1.7>
-
-       * sudo.h:
-       Add missing prototypes for aix_setauthdb and aix_restoreauthdb
-       [8bc2af6d4e17] <1.7>
+       [14ae63403544]
 
-       * Makefile.in:
+       * doc/Makefile.in:
        Comment out rules to build .man.in and .cat files unless --with-
        devel
-       [81d6726a19ab] <1.7>
+       [3cf7e5606a85]
 
-       * aix.c, pwutil.c, set_perms.c, sudo.h:
-       Fix AIX compilation problems.
-       [7d95f73eca42] <1.7>
-
-       * sudo.c:
-       Cast isalnum() arg to unsigned char.
-       [5fff9a81af00] <1.7>
-
-       * WHATSNEW:
-       Add Linux audit support.
-       [e59e0670ba79] <1.7>
+       * doc/Makefile.in:
+       Comment out rules to build .man.in and .cat files unless --with-
+       devel
+       [d30495b0e29e]
 
-       * sudo.c:
+       * src/parse_args.c:
        Quote any non-alphanumeric characters other than '_' or '-' when
        passing a command to be run via the shell for the -s and -i options.
-       [d35a3f4cb3c0] <1.7>
+       [d633f74fe2d9]
 
-       * sudo.c:
-       Add missing braces that broke -i mode.
-       [7fe124b078ec] <1.7>
+       * doc/Makefile.in:
+       Add back .man suffix
+       [6e63b60a2739]
 
-       * linux_audit.c:
-       Fix linux_audit_command() return value
-       [0c582476181c] <1.7>
+       * INSTALL, MANIFEST, WHATSNEW, config.h.in, configure, configure.in,
+       plugins/sudoers/Makefile.in, plugins/sudoers/audit.c,
+       plugins/sudoers/bsm_audit.c, plugins/sudoers/linux_audit.c,
+       plugins/sudoers/linux_audit.h, plugins/sudoers/logging.h,
+       src/selinux.c:
+       Add Linux audit support.
+       [5a2f445e0bd4]
 
 2010-06-15  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * Makefile.in, linux_audit.c, linux_audit.h:
-       Add Linux audit support.
-       [b207dc9960de] <1.7>
+       * plugins/sudoers/iolog.c:
+       Remove an XXX
+       [a170cbe651d1]
+
+       * doc/sudoreplay.cat, doc/sudoreplay.man.in, doc/sudoreplay.pod,
+       plugins/sudoers/sudoreplay.c:
+       Add -f (filter) option to sudoreplay to allow certain streams to be
+       replayed and others ignored.
+       [62e51b432ea1]
+
+       * src/load_plugins.c, src/parse_args.c, src/sudo.c, src/sudo.h,
+       src/tgetpass.c:
+       Fix -A flag when askpass is specified in sudo.conf or if sudo
+       doesn't need to read a password.
+       [2e401e4a00e3]
+
+       * src/exec.c, src/exec_pty.c, src/parse_args.c, src/sudo.c,
+       src/sudo.h, src/sudo_edit.c, src/tgetpass.c:
+       Clean up some XXXs
+       [689f0b002d3d]
+
+       * WHATSNEW, doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in,
+       doc/sudoers.ldap.pod, plugins/sudoers/ldap.c:
+       Add support for multiple sudoers_base entries in ldap.conf. From
+       Joachim Henke
+       [e3e4a3c2bd5b]
 
-2010-06-16  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * config.h.in, configure, configure.in, plugins/sudoers/logging.c,
+       src/exec_pty.c:
+       remove setsid check, we require a POSIX system
+       [cc73cb9e22c0]
 
-       * INSTALL, audit.c, bsm_audit.c, config.h.in, configure, configure.in,
-       logging.h, selinux.c:
-       Add Linux audit support.
-       [26ae31d7ff93] <1.7>
+       * plugins/sudoers/logging.c, src/exec_pty.c, src/selinux.c,
+       src/sudo.c, src/tgetpass.c:
+       Check for dup2() failure.
+       [5d46d66794f5]
 
-2010-06-15  Todd C. Miller  <Todd.Miller@courtesan.com>
-
-       * sudoreplay.c, sudoreplay.cat, sudoreplay.man.in, sudoreplay.pod:
-       Sync sudoreplay with trunk
-       [65b780cccfa5] <1.7>
-
-       * exec_pty.c:
-       Remove an XXX
-       [8304ac649241] <1.7>
-
-       * aix.c, configure, configure.in, pwutil.c, set_perms.c, sudo.h:
-       Set usrinfo for AIX Set adminstrative domain for the process when
-       looking up user's password info and when preparing for execve().
-       [52b48cbe97fd] <1.7>
-
-       * ldap.c, parse.c:
-       Better prefix determination now that we can't rely on len==0 to tell
-       the beginning on an entry.
-       [32f1875d9605] <1.7>
-
-       * WHATSNEW, ldap.c, sudoers.ldap.cat, sudoers.ldap.man.in,
-       sudoers.ldap.pod:
-       Add support for multiple sudoers_base entries in ldap.conf. From
-       Joachim Henke
-       [3c0b59fce7b4] <1.7>
-
-       * configure, configure.in:
-       Remove duplicate setsid check
-       [7712d6d52da1] <1.7>
-
-       * Makefile.in, config.h.in, configure, configure.in, exec_pty.c,
-       logging.c, missing.h, setsid.c:
-       Move setsid emulation into setsid.c
-       [f24743c9e4e9] <1.7>
-
-       * exec_pty.c, logging.c, selinux.c, sudo.c, tgetpass.c:
-       Check for dup2() failure.
-       [b1b6ba761b61] <1.7>
-
-       * config.h.in, configure, configure.in:
-       Remove dup2 check, it is not optional.
-       [cfbe5f3b5956] <1.7>
+       * config.h.in, configure, configure.in:
+       Remove dup2() check, it is not optional.
+       [5f1d56de4384]
 
 2010-06-14  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * WHATSNEW:
-       Add mbr_check_membership support and SELinux fixes
-       [af1936a7cf2f] <1.7>
+       sync with sudo 1.7.3
+       [88e5c0bd6d59]
 
-       * Makefile.in:
-       Sync SRCS and DISTFILES with reality
-       [0971b5dcb1be] <1.7>
+       * INSTALL:
+       SunOS does not ship with an ANSI compiler
+       [f13c85c67069]
 
        * INSTALL:
        Update OS specific notes. Delete some really ancient ones and move
        older ones to the end of the list.
-       [872dd8b437a8] <1.7>
+       [59ce592c4c52]
 
        * README:
-       Bump for sudo 1.7.3 Merge some changes from trunk
-       [a3088c75bf22] <1.7>
+       Sudo can be downloaded from the web site too Mention "OS dependent
+       notes" section in INSTALL
+       [191871538984]
 
-       * selinux.c, sudo.c:
+       * src/exec_pty.c, src/selinux.c:
        Call selinux_restore_tty() as part of cleanup() so it gets called
        from error()/errorx()
-       [0197c07d4c1e] <1.7>
+       [bb017da6b6da]
 
-       * compat.h:
-       No longer use SA_NOCLDSTOP
-       [73ca654cd3f8] <1.7>
+       * MANIFEST, doc/PORTING:
+       Remove obsolete porting guide
+       [321e35591344]
 
-       * interfaces.h, match.c:
+       * plugins/sudoers/interfaces.h, plugins/sudoers/match.c:
        Move union sudo_in_addr_un into interfaces.h
-       [c84bda7c332a] <1.7>
-
-       * pathnames.h.in:
+       [b2c8b19ee094]
+
+       * doc/Makefile.in:
+       Remove useless circular dependencies
+       [5682181b59cf]
+
+       * plugins/sudoers/auth/afs.c, plugins/sudoers/auth/aix_auth.c,
+       plugins/sudoers/auth/bsdauth.c, plugins/sudoers/auth/dce.c,
+       plugins/sudoers/auth/fwtk.c, plugins/sudoers/auth/kerb4.c,
+       plugins/sudoers/auth/kerb5.c, plugins/sudoers/auth/pam.c,
+       plugins/sudoers/auth/passwd.c, plugins/sudoers/auth/rfc1938.c,
+       plugins/sudoers/auth/secureware.c, plugins/sudoers/auth/securid.c,
+       plugins/sudoers/auth/securid5.c, plugins/sudoers/auth/sia.c:
+       Convert to ANSI C function declarations
+       [a4f76927d034]
+
+       * common/alloc.c, common/fileops.c, common/gettime.c, common/list.c,
+       common/zero_bytes.c, compat/charclass.h, compat/closefrom.c,
+       compat/fnmatch.c, compat/glob.c, compat/isblank.c, compat/memrchr.c,
+       compat/mkstemp.c, compat/nanosleep.c, compat/snprintf.c,
+       compat/strcasecmp.c, compat/strerror.c, compat/strlcat.c,
+       compat/strlcpy.c, compat/timespec.h, compat/utime.h,
+       compat/utimes.c, doc/HISTORY, doc/history.pod, doc/license.pod,
+       include/alloc.h, include/error.h, include/lbuf.h, include/list.h,
+       include/missing.h, pathnames.h.in, plugins/sudoers/alias.c,
+       plugins/sudoers/audit.c, plugins/sudoers/auth/sudo_auth.h,
+       plugins/sudoers/boottime.c, plugins/sudoers/bsm_audit.c,
+       plugins/sudoers/bsm_audit.h, plugins/sudoers/defaults.c,
+       plugins/sudoers/defaults.h, plugins/sudoers/find_path.c,
+       plugins/sudoers/getspwuid.c, plugins/sudoers/goodpath.c,
+       plugins/sudoers/gram.y, plugins/sudoers/interfaces.c,
+       plugins/sudoers/interfaces.h, plugins/sudoers/logging.c,
+       plugins/sudoers/logging.h, plugins/sudoers/match.c,
+       plugins/sudoers/parse.h, plugins/sudoers/plugin_error.c,
+       plugins/sudoers/pwutil.c, plugins/sudoers/redblack.c,
+       plugins/sudoers/redblack.h, plugins/sudoers/sudo_nss.h,
+       plugins/sudoers/sudoers.h, plugins/sudoers/sudoreplay.c,
+       plugins/sudoers/testsudoers.c, plugins/sudoers/timestr.c,
+       plugins/sudoers/toke.l, plugins/sudoers/visudo.c, src/aix.c,
+       src/conversation.c, src/error.c, src/load_plugins.c,
+       src/parse_args.c, src/sesh.c, src/sudo.h, src/sudo_noexec.c,
+       src/sudo_plugin_int.h, src/sudo_usage.h.in, src/tgetpass.c:
        Update copyright year
-       [94871f44206b] <1.7>
+       [26ac7991f7d8]
 
-       * HISTORY, LICENSE, aix.c, alias.c, alloc.h, boottime.c, bsm_audit.h,
-       compat.h, defaults.c, defaults.h, env.c, fileops.c, find_path.c,
-       gettime.c, gram.y, history.pod, lbuf.h, license.pod, logging.c,
-       match.c, missing.h, nanosleep.c, parse.h, set_perms.c,
-       sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.ldap.pod,
-       sudoreplay.c, term.c, tgetpass.c, toke.l, visudo.c, visudo.cat,
-       visudo.man.in, visudo.pod:
-       Update copyright year
-       [4cfb47c799b8] <1.7>
+       * doc/Makefile.in:
+       Fix commented DEVDOCS when not in devel mode.
+       [e0a97eaf3793]
 
-       * Makefile.in:
-       Remove varsub as part of clean
-       [61f04a21b0bb] <1.7>
-
-       * match.c:
+       * plugins/sudoers/match.c:
        Quiet a compiler warning.
-       [06d8cfe916c8] <1.7>
+       [b2a17ebd5d38]
 
-       * getdate.c, getdate.y:
+       * plugins/sudoers/getdate.c, plugins/sudoers/getdate.y:
        Quiet a compiler warning.
-       [473d2b7d44a1] <1.7>
+       [687843bc593d]
 
-       * ldap.c, sudo.h:
-       Make the remaining functions in ldap.c static
-       [ba555565b30a] <1.7>
+       * plugins/sudoers/ldap.c, plugins/sudoers/sudoers.h:
+       Make all functions in ldap.c static
+       [b2111e89eeba]
 
-       * ldap.c:
-       Make private functions static. Diff from Joachim Henke
-       [1603035b1863] <1.7>
-
-       * schema.ActiveDirectory:
+       * doc/schema.ActiveDirectory:
        Updates from Alain Roy to provide better examples for importing the
        schema and to fix problems caused by Windows validating attributes
        which have not yet been added before committing the changes.
-       [83f11ae00f19] <1.7>
+       [69f4c5ccaf89]
 
-2010-06-12  Todd C. Miller  <Todd.Miller@courtesan.com>
+2010-06-11  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * Makefile.in, configure, configure.in, sudo.cat, sudoers.cat:
-       Generate .cat files directly from .man.in instead of .man using
-       default values in configure.in
-       [0a92b41c5ce5] <1.7>
+       * configure, configure.in, doc/Makefile.in, doc/sudo.cat,
+       doc/sudo.man.in, doc/sudo_plugin.cat, doc/sudo_plugin.man.in,
+       doc/sudoers.cat, doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in,
+       doc/sudoers.man.in, doc/sudoreplay.cat, doc/sudoreplay.man.in,
+       doc/visudo.cat, doc/visudo.man.in:
+       Leave rules to build .man.in and .cat files uncommented but only
+       make them part of the "all" rule in devel mode. Generate .cat files
+       directly from .man.in instead of .man using default values in
+       configure.in
+       [c3054a44f6a5]
 
-2010-06-11  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * configure, configure.in:
+       Bump sudo version to 1.8.0b1
+       [8f79c85135e1]
 
-       * configure, configure.in, sudo.c, sudo_usage.h.in:
+       * configure, configure.in, src/sudo.c, src/sudo_usage.h.in:
        Print configure args with verbose version information.
-       [ca4a5fcf0af8] <1.7>
+       [1ce690660ed2]
 
-       * visudo.c:
+       * TODO, plugins/sudoers/visudo.c:
        Remove tfd from struct sudoersfile; it is not used. Add prev pointer
        to struct sudoersfile. Declare list of sudoersfile using TQ_DECLARE.
        Use tq_append to append sudoers entries to the tail queue.
-       [344c631d0d43] <1.7>
+       [1743f9a286e4]
 
 2010-06-10  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * WHATSNEW:
        Describe tty timestamp improvements
-       [136b0f832903] <1.7>
+       [e214e863a313]
 
-       * toke.c, toke.l:
+       * plugins/sudoers/toke.c, plugins/sudoers/toke.l:
        A comment character may not be part of a command line argument
        unless it is quoted with a backslash. Fixes parsing of:
        testuser ALL=NOPASSWD: /usr/bin/wl #comment foo bar closes bz #441
-       [2a0c82ffedde] <1.7>
-
-       * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in:
-       regen
-       [c9fddd23c7e1] <1.7>
+       [ea2e990f85ed]
 
-       * sudoers.pod:
+       * doc/sudoers.pod:
        Make this read a little bit better when passwd_timeout is 0.
-       [51644950823f] <1.7>
+       [39d362757f31]
 
-       * Makefile.in:
-       Use the --file argument to config.status instead of setting
-       CONFIG_FILES
-       [fc2b42c60b5d] <1.7>
-
-       * sudo.man.pl, sudo.pod:
+       * doc/sudo.man.in, doc/sudo.man.pl, doc/sudo.pod:
        Attempt to handle a default password prompt timeout of zero more
        gracefully.
-       [478b8e720993] <1.7>
+       [ea47d43acf5b]
 
-       * toke.c, toke.l:
+       * plugins/sudoers/toke.c, plugins/sudoers/toke.l:
        Do not override value of keepopen global, instead restore it to the
        value we pushed onto the stack when popping.
-       [dc370d57a668] <1.7>
+       [fe282e5a3402]
+
+       * plugins/sudoers/Makefile.in:
+       Add dependency for utility programs on libreplace and libcommon
+       [2339aba64928]
 
-       * exec.c, exec_pty.c, logging.c, mon_systrace.c, tgetpass.c:
-       Use SA_INTERRUPT in sa_flags
-       [3845c6637361] <1.7>
+       * compat/sigaction.c, config.h.in, configure.in, include/compat.h,
+       plugins/sudoers/logging.c, plugins/sudoers/mon_systrace.c,
+       src/exec.c, src/exec_pty.c, src/tgetpass.c:
+       Remove sigaction emulation Use SA_INTERRUPT in sa_flags
+       [7dd61f1bd8d2]
 
-       * getdate.c, getdate.y, ldap.c, sudoreplay.c:
+       * MANIFEST, config.h.in, configure, configure.in, include/missing.h:
+       We don't use getgrouplist() at the moment so there's no need to
+       provide a compat version.
+       [1597536fbada]
+
+       * TODO:
+       sync with reality
+       [9e1a874e7885]
+
+       * include/sudo_plugin.h, plugins/sudoers/auth/sudo_auth.c,
+       src/conversation.c, src/sudo.h, src/tgetpass.c:
+       Fix visiblepw sudoers option; the plugin API portion still needs
+       documenting
+       [60b6933ef5e0]
+
+       * src/sudo.c:
+       Print sudo version as well.
+       [987ed459b459]
+
+       * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c:
+       Use sudo_printf for I/O log version Clarify policy plugin version
+       string
+       [5a58b7e8c80b]
+
+       * plugins/sudoers/getdate.c, plugins/sudoers/getdate.y,
+       plugins/sudoers/ldap.c, plugins/sudoers/sudoreplay.c:
        Silence some compiler warnings
-       [112ac65afd0c] <1.7>
+       [afb1eba90915]
+
+       * src/load_plugins.c, src/tgetpass.c:
+       Store askpass path in a global instead of uses setenv() which many
+       systems lack.
+       [b440bcc0e660]
 
 2010-06-09  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * exec.c, exec_pty.c, sudo.c, sudo.h:
+       * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod, doc/sudo_plugin.cat,
+       doc/sudo_plugin.man.in, doc/sudo_plugin.pod,
+       plugins/sudoers/check.c, plugins/sudoers/def_data.c,
+       plugins/sudoers/def_data.h, plugins/sudoers/def_data.in,
+       plugins/sudoers/defaults.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h, src/load_plugins.c, src/parse_args.c,
+       src/tgetpass.c:
+       Move askpass path specification from sudoers to sudo.conf.
+       [5507ab867c26]
+
+       * src/exec.c, src/exec_pty.c, src/sudo.c, src/sudo.h:
+       Use a flag bit in struct command_details for selinux instead of a
+       separate field.
+       [c59ca4acded9]
+
+       * src/exec.c, src/exec_pty.c, src/sudo.c, src/sudo.h:
        Implement background mode. If I/O logging we use pipes instead of a
        pty.
-       [8d448eaf2aaa] <1.7>
+       [c07a4b356cbd]
 
-       * compat.h, exec.c, exec_pty.c, mksiglist.c, strsignal.c, tgetpass.c:
+       * compat/mksiglist.c, compat/strsignal.c, include/compat.h,
+       src/exec.c, src/exec_pty.c, src/tgetpass.c:
        Move compat definition of NSIG to compat.h
-       [cae72a4c9dec] <1.7>
+       [ab0385467f25]
 
-       * tgetpass.c:
-       Ignore SIGPIPE for "sudo -S"
-       [c6595c8527c4] <1.7>
+       * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod, doc/sudo_plugin.cat,
+       doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Mention plugins in the sudo manual and add some missing path
+       substitution in the sudo_plugin manual.
+       [570f831f47a3]
 
-       * tgetpass.c:
-       Properly handle TGP_ECHO again. Print a newline if the user
-       interrupted password input.
-       [15acbe4fb535] <1.7>
+       * src/Makefile.in:
+       Set _PATH_SUDO_CONF based on $(sysconfdir)
+       [fde51869cf07]
 
-       * exec_pty.c:
+       * common/lbuf.c, common/term.c, config.h.in, configure, configure.in,
+       src/exec.c, src/exec_pty.c, src/ttysize.c:
+       Require POSIX termios to build sudo
+       [9ec6b41f3f95]
+
+       * src/tgetpass.c:
+       Ignore SIGPIPE for "sudo -S"
+       [7ad27fde0c06]
+
+       * src/tgetpass.c:
+       Fix uninitialized variable in TGP_ECHO case and print a newline if
+       the user interrupted password input.
+       [ce19204d8dd4]
+
+       * src/tgetpass.c:
+       Make TGP_ECHO override TGP_MASK and don't try to restore the
+       terminal if we didn't modify it.
+       [a7e11abfe7e4]
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod,
+       include/sudo_plugin.h, plugins/sudoers/auth/sudo_auth.c,
+       src/conversation.c, src/sudo.h, src/tgetpass.c:
+       Add SUDO_CONV_PROMPT_MASK define which corresponds to the
+       "pwfeedback" sudoers option. Do not disable echo if TGP_ECHO is
+       set.
+       [e0550590cabe]
+
+       * src/exec_pty.c:
        Use POSIX tcgetpgrp() instead of BSD TIOCGPGRP ioctl
-       [dd041fc9554c] <1.7>
+       [762448182fe3]
 
 2010-06-08  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * exec.c, exec_pty.c, selinux.c, sudo.c, sudo.h:
-       Return an error from selinux_setup() instead of exiting. Call
-       selinux_setup() from exec_setup().
-       [b518225cafba] <1.7>
+       * src/exec.c, src/exec_pty.c, src/selinux.c, src/sudo.c, src/sudo.h:
+       Add selinux_enabled flag into struct command_details and set it in
+       command_info_to_details(). Return an error from selinux_setup()
+       instead of exiting. Call selinux_setup() from exec_setup().
+       [011bea23a5a0]
 
-       * compat.h:
-       Add definition of WCOREDUMP for systems without it. This is known
-       to work on AIX and SunOS 4, but may be incorrect on other systems
-       that lack WCOREDUMP.
-       [365e56db7cd5] <1.7>
+2010-06-09  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/exec_pty.c:
+       Remove commented out copy of old sudo_execve() function.
+       [9c5e21380472]
+
+2010-06-08  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * check.c, compat.h, config.h.in, configure, configure.in, iolog.c,
-       nanosleep.c, sudo_edit.c, visudo.c:
+       * plugins/sudoers/sudoers.c:
+       Fix setting selinux type on command line.
+       [814b20a0b3be]
+
+       * plugins/sudoers/iolog.c:
+       In sudoers_io_close(), skip NULL io_fds[] elements.
+       [4011ff7d4daf]
+
+       * include/compat.h:
+       No longer need NGROUPS_MAX define
+       [cae4c49d7077]
+
+       * compat/nanosleep.c, config.h.in, configure, configure.in,
+       include/compat.h, plugins/sudoers/check.c, plugins/sudoers/iolog.c,
+       plugins/sudoers/visudo.c, src/sudo_edit.c:
        Replace timerfoo macros with timevalfoo since the timer macros are
        known to be busted on some systems.
-       [4bb5228606c5] <1.7>
+       [4f97d79f2d41]
 
-       * toke.c, toke.l:
+       * src/exec_pty.c:
+       Remove duplicate call to selinux_setup().
+       [82bd52764e21]
+
+       * plugins/sudoers/auth/pam.c:
+       If pam_open_session() fails, pass its status to pam_end.
+       [1d8de4cf8ff3]
+
+       * plugins/sudoers/toke.c, plugins/sudoers/toke.l:
        If a file in a #includedir has improper permissions or owner just
        skip it. This prevents packages that incorrectly install a file
        into /etc/sudoers.d from breaking sudo so easily. Syntax errors in
        #includedir files still result in a parse error (for now).
-       [b7fb75eddb77] <1.7>
+       [ade99a4549a4]
 
-       * TODO, auth/pam.c, exec.c, exec_pty.c, set_perms.c, sudo.c, sudo.h:
-       Defer call to pam_close_session() until after the command finishes
-       if there is a monitor process.
-       [0a39c8e6a81b] <1.7>
-
-       * WHATSNEW, def_data.c, def_data.h, def_data.in, exec.c, sudoers.cat,
-       sudoers.man.in, sudoers.pod:
+       * WHATSNEW, doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod,
+       plugins/sudoers/def_data.c, plugins/sudoers/def_data.h,
+       plugins/sudoers/def_data.in, plugins/sudoers/iolog.c:
        Add use_pty sudoers option to force use of a pty even when not
        logging I/O.
-       [aea971f1456a] <1.7>
+       [b280a8972a79]
 
-       * env.c, sudo.c, sudo.h:
-       Instead of trying to keep the global environment in sync with our
-       private copy, provide our own getenv() that returns values from the
-       private environment and use env_get() to pass the environment in to
-       run_command().
-       [58c85c5695dc] <1.7>
+       * plugins/sudoers/env.c, plugins/sudoers/sudoers.h:
+       Make env_init() void as it never fails.
+       [d3890e55daa7]
 
-       * set_perms.c:
-       Fix typo
-       [0f677fcdde04] <1.7>
+       * plugins/sudoers/env.c:
+       No longer use _NSGetEnviron so don't need crt_externs.h
+       [9b4e0e139881]
 
-2010-06-07  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * plugins/sudoers/env.c:
+       Remove unused VNULL define
+       [a42cacb263e3]
 
-       * sudo.h:
-       Rename pty.c -> get_pty.c
-       [39137dcc4420] <1.7>
+2010-06-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * iolog.c:
+       * plugins/sudoers/iolog.c:
        Add #define for maximum session id
-       [2a487437f013] <1.7>
+       [9e18c17a28c2]
 
-       * Makefile.in, configure, configure.in, exec.c, exec_pty.c, iolog.c,
-       selinux.c, sudo.c, sudo.h, sudo_edit.c:
-       Split exec.c into exec.c and exec_pty.c Pass a flag in to
-       sudo_execve to indicate whether we need to wait for the command
-       to finish (fork + execve vs. execve).
-       [b197515585db] <1.7>
+       * MANIFEST, src/Makefile.in, src/exec.c, src/exec_pty.c, src/sudo.h:
+       Split exec.c into exec.c and exec_pty.c
+       [d52376327332]
 
-       * Makefile.in, configure, configure.in, get_pty.c, pty.c:
-       Rename pty.c -> get_pty.c
-       [c0e5270bb28a] <1.7>
+       * MANIFEST:
+       Sync with source file moves.
+       [4a62c6c9e846]
 
-       * aclocal.m4, configure, configure.in:
-       Fix --without-iologdir
-       [dcd6c5907b10] <1.7>
+       * src/Makefile.in, src/get_pty.c, src/pty.c:
+       Rename pty.c -> get_pty.c
+       [5696a12bd29b]
 
 2010-06-06  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * iolog.c:
+       * plugins/sudoers/iolog.c:
        Only use I/O input log file if def_log_input is set and output file
        if def_log_output is set.
-       [96cdd49be996] <1.7>
+       [d866992f1681]
 
-2010-06-05  Todd C. Miller  <Todd.Miller@courtesan.com>
+2010-06-04  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * parse_args.c, sudo.c:
-       Include sudo_usage.h after sudo.h now that it has function
-       prototypes to guarantee that __P is defined.
-       [c67b77f8d6b1] <1.7>
+       * compat/strsignal.c:
+       Update copyright year
+       [a96f2593fd4e]
 
-2010-06-04  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * src/pty.c:
+       uid -> ttyuid
+       [c3454d74ebcb]
 
-       * tgetpass.c:
-       Do signal setup after turning off echo, not before. If we are using
-       a tty but are not the foreground pgrp this will generate SIGTTOU so
-       we want the default action to be taken (suspend process). Use an
-       array for signals received instead of a single variable so we don't
-       lose any when there are multiple different signals.
-       [de356064ea01] <1.7>
+       * plugins/sudoers/sudoers.c:
+       For sudoedit, make a local copy of editor string si become part of
+       argv. If no editor environment variable, split def_editor on ':'
+       since it may be a colon-delimited path.
+       [2ee298506a6e]
 
-       * defaults.h, lbuf.h, sudo.h:
-       Reorg function prototypes a bit
-       [5c40f58bb28e] <1.7>
+       * src/sudo_edit.c:
+       Remove unneeded endpwent()/endgrent()
+       [623f6743d101]
 
-       * Makefile.in, parse_args.c, sudo.c, sudo.h, sudo_usage.h.in:
-       Move argument parsing into parse_args.c
-       [fad7b8737c12] <1.7>
+       * doc/Makefile.in:
+       Use value of nroff from configure
+       [b2ce649125ab]
 
-       * Makefile.in, config.h.in, configure, configure.in, missing.h,
-       mksiglist.c, mksiglist.h, siglist.in, strsignal.c:
-       Build our own sys_siglist for systems that lack it.
-       [3b5f671936dc] <1.7>
+       * src/exec.c:
+       Add missing const to I/O log action function
+       [d764a3955e04]
 
-       * exec.c, iolog.c, missing.h, sudo_edit.c:
-       K&R fixes
-       [dad62986f2fe] <1.7>
+       * plugins/sudoers/check.c:
+       Update copyright year and fix whitespace
+       [e648c35b16be]
 
-       * exec.c, pty.c, sudo.c, sudo.h, sudo_edit.c:
-       Log sudoedit sessions as well; adapted from trunk
-       [2c5d9695022b] <1.7>
+       * configure, configure.in:
+       Fix typo
+       [8e0bdfc47da4]
 
-       * configure:
-       regen
-       [9b319e89a6c4] <1.7>
-
-       * INSTALL, Makefile.in, WHATSNEW, aclocal.m4, configure, configure.in,
-       def_data.c, def_data.h, def_data.in, defaults.c, exec.c, gram.c,
-       gram.h, gram.y, iolog.c, parse.c, parse.h, pathnames.h.in, pty.c,
-       script.c, selinux.c, sudo.c, sudo.h, sudoers.cat, sudoers.man.in,
-       sudoers.pod, sudoreplay.c, sudoreplay.cat, sudoreplay.man.in,
-       sudoreplay.pod, term.c:
-       Merge I/O logging changes from trunk. Disabling I/O log support at
-       compile time does not currently work. Sudoedit is not yet hooked up
-       to I/O logging.
-       [968c2c74c69b] <1.7>
+       * plugins/sudoers/iolog.c:
+       Remove redundant tty signal blocking in log function.
+       [f17f575dabd4]
 
 2010-06-03  Todd C. Miller  <Todd.Miller@courtesan.com>
 
+       * plugins/sudoers/iolog.c:
+       Place static keyword where it belongs
+       [b01aec7c86b4]
+
+       * plugins/sudoers/logging.c:
+       Always use a printf format string for send_mail()
+       [13b1ada644c9]
+
+       * common/atobool.c, plugins/sudoers/ldap.c:
+       Extend atobool() so we can use it in the LDAP code.
+       [73f8e6807044]
+
+       * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod:
+       Sudo now stashes tty ctime for tty_tickets on Solaris too.
+       [e82df13ad3fd]
+
+       * plugins/sudoers/boottime.c:
+       Fix dummy version of get_boottime()
+       [01d69c06013b]
+
+2010-06-02  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/check.c:
+       Enable tty_is_devpts() support for Solaris with the "devices"
+       filesystem.
+       [237c6b25fa84]
+
+       * src/exec.c:
+       Unbreak the non-io logging case.
+       [4822b9f709fb]
+
+       * src/conversation.c, src/sudo.c, src/sudo_plugin_int.h:
+       Fix symbol name conflict with sudo_printf.
+       [0d44eab0a8f6]
+
+       * plugins/sudoers/auth/pam.c:
+       Fix OpenPAM detection for newer versions.
+       [1b2abed232d8]
+
+       * plugins/sudoers/vasgroups.c:
+       Sync with Quest sudo git repo
+       [f1d98b3cba02]
+
+       * aclocal.m4, configure, configure.in:
+       HP-UX ld uses +b instead or -R or -rpath Fix typo in libvas check
+       Add missing template for ENV_DEBUG Adapted from Quest sudo
+       [695dbd7b28f4]
+
+       * README.LDAP:
+       Fix typos; from Quest Sudo
+       [4eba9da33b8e]
+
+2010-06-01  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/Makefile.in:
+       Add back -I$(top_srcdir); we need it for including compat/foo.h
+       since we cannot rely on "foo.h" being found relative to the source
+       file when the cwd is different.
+       [bbf24695f325]
+
+       * src/exec.c:
+       Fix a bug where we could treat EAGAIN as a permanent error. Also set
+       cstat if perform_io() returns an error.
+       [200475c4326f]
+
+       * common/alloc.c, plugins/sudoers/boottime.c,
+       plugins/sudoers/sudoers.c:
+       Add casts to quiet compiler warnings.
+       [85eb1c336697]
+
+       * plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c,
+       plugins/sudoers/visudo.c:
+       Fix typo in ternary operator usage.
+       [6492ac1450e2]
+
+2010-05-30  Todd C. Miller  <Todd.Miller@courtesan.com>
+
        * INSTALL, configure, configure.in:
-       Add --enable-warnings configure option
-       [19cf967c36d1] <1.7>
+       Add --enable-warnings and fix typo in SUDO_IO_LOGDIR
+       [92121d693b30]
+
+       * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod,
+       doc/sudoreplay.cat, doc/sudoreplay.man.in, doc/sudoreplay.pod:
+       Update docs to match sudoers I/O logging changes
+       [18d651989e49]
+
+       * INSTALL, WHATSNEW, aclocal.m4, configure, configure.in,
+       pathnames.h.in, plugins/sudoers/def_data.c,
+       plugins/sudoers/def_data.h, plugins/sudoers/def_data.in,
+       plugins/sudoers/defaults.c, plugins/sudoers/gram.c,
+       plugins/sudoers/gram.h, plugins/sudoers/gram.y,
+       plugins/sudoers/iolog.c, plugins/sudoers/parse.c,
+       plugins/sudoers/parse.h, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoreplay.c:
+       Break sudoers transcript feature up into log_input and log_output.
+       [db3c1248d2ad]
+
+       * plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c,
+       plugins/sudoers/visudo.c:
+       Use setprogname() as needed.
+       [6beee63a4553]
+
+       * plugins/sudoers/iolog.c, plugins/sudoers/sudoreplay.c:
+       Adapt sudoreplay to iolog changes.
+       [581f52c05f0f]
+
+2010-05-29  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/iolog.c:
+       Log all input and output into separate files and store a number on
+       each timing file line to indicate which file the data is in.
+       [fb460c5273dd]
+
+       * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h:
+       Make sudoers_io functions static to iolog.c
+       [b2df3cc3eecb]
 
-       * check.c, lbuf.h, script.c, sudo.c, sudo_nss.c:
-       Fix K&R compilation issues on HP-UX.
-       [c01a547cdcf8] <1.7>
+2010-05-28  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * lbuf.c, lbuf.h, ldap.c, parse.c, sudo.c, sudo_nss.c:
-       Pass in output function to lbuf_init() instead of writing to stdout.
-       A side effect is that the usage info can now go to stderr as it
-       should. Add support for embedded newlines in lbuf and use that
-       instead of multiple calls to lbuf_print.
-       [596a427ff873] <1.7>
+       * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod, src/parse_args.c,
+       src/sudo_usage.h.in:
+       Completely remove the -L flag from the sudo front end.
+       [3d220030b720]
+
+       * plugins/sudoers/sudoreplay.c:
+       Fix EAGAIN handling when writing to stdout.
+       [4766d77cea49]
+
+       * plugins/sudoers/sudoers.c:
+       Eliminate unused variables
+       [83bd711e79c4]
+
+       * plugins/sudoers/sudoers.c, src/exec.c, src/sudo.c:
+       Re-enable cleanup functions in sudoers plugin and sudo driver for
+       error()/errorx().
+       [43093f937dd8]
+
+       * plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/defaults.c,
+       plugins/sudoers/interfaces.c, plugins/sudoers/iolog.c,
+       plugins/sudoers/parse.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/testsudoers.c, plugins/sudoers/visudo.c:
+       Use sudo_printf to display verbose version information.
+       [435cc9f8d4a2]
+
+       * common/Makefile.in, compat/Makefile.in, plugins/sample/Makefile.in,
+       plugins/sudoers/Makefile.in, src/Makefile.in:
+       Minor Makefile cleanup: fix a typo, change the removal order in the
+       clean targets, and remove a superfluous include path for the sudoers
+       plugin.
+       [6e3b2d6b4437]
+
+       * plugins/sudoers/env.c:
+       Handle duplicate variables in the environment. For unsetenv(), keep
+       looking even after remove the first instance. For sudo_putenv(),
+       check for and remove dupes after we replace an existing value.
+       [c1bbb88d0435]
+
+2010-05-27  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/Makefile.in:
+       Use explicit path to source file instead of $< for files that live
+       in devdir and top_srcdir.
+       [358ab7f6cc64]
+
+       * plugins/sudoers/Makefile.in:
+       Add explicit rules to compile gram.c and toke.c for HP-UX Pevent
+       ending LIBSUDOERS_OBJS with a backslash
+       [481a5c96d47e]
+
+       * plugins/sudoers/Makefile.in, src/Makefile.in:
+       Link libcommon before libreplace since libcommon may use functions
+       only present in libreplace.
+       [1847c496ff5b]
+
+       * common/Makefile.in:
+       Move code common to sudo and the sudoers plugin to a convenience
+       library, libcommon. Removes the need to make links in the sudoers
+       plugin dir and reduces re-compilation of duplicate object files.
+       [4c8986352937]
+
+       * Makefile.in, common/alloc.c, common/atobool.c, common/fileops.c,
+       common/fmt_string.c, common/gettime.c, common/lbuf.c, common/list.c,
+       common/term.c, common/zero_bytes.c, configure, configure.in,
+       plugins/sample/Makefile.in, plugins/sudoers/Makefile.in,
+       src/Makefile.in, src/alloc.c, src/atobool.c, src/fileops.c,
+       src/fmt_string.c, src/gettime.c, src/lbuf.c, src/list.c, src/term.c,
+       src/zero_bytes.c:
+       Move code common to sudo and the sudoers plugin to a convenience
+       library, libcommon. Removes the need to make links in the sudoers
+       plugin dir and reduces re-compilation of duplicate object files.
+       [1d1d98bd55b9]
+
+       * src/exec.c, src/sudo.c, src/sudo.h:
+       Rename script_execve to sudo_execve and rename script_foo in exec.c
+       [a35ec80de96a]
+
+       * MANIFEST, src/Makefile.in, src/exec.c, src/script.c:
+       rename script.c exec.c and fix up the MANIFEST file
+       [36bc3bff9578]
+
+       * src/script.c, src/sudo.c, src/sudo.h:
+       Rename script_setup() to pty_setup() and call from script_execve()
+       directly.
+       [899b0fb2a14d]
+
+       * configure, configure.in:
+       bump version to 1.8.0a2
+       [0b1c1ca9d4e5]
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Document init_session
+       [b5324785a406]
+
+       * plugins/sudoers/auth/API, plugins/sudoers/auth/sudo_auth.c,
+       plugins/sudoers/auth/sudo_auth.h:
+       Clean up the sudoers auth API a bit and update the docs.
+       [c40fd4cb6e68]
+
+       * include/sudo_plugin.h, plugins/sudoers/auth/pam.c,
+       plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h, src/script.c, src/sudo.c:
+       Add init_session function to struct policy_plugin that gets called
+       before the uid/gid/etc changes. A struct passwd pointer is passed
+       in,which may be NULL if the user does not exist in the passwd
+       database.The sudoers module uses init_session to open the pam
+       session as needed.
+       [d71723320ee8]
+
+2010-05-26  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/auth/pam.c, plugins/sudoers/auth/sudo_auth.c,
+       plugins/sudoers/auth/sudo_auth.h, plugins/sudoers/set_perms.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h:
+       Add open/close session to sudo auth, only used by PAM. This allows
+       us to open (and close) the PAM session from sudoers.
+       [2665e2920d0d]
+
+       * plugins/sudoers/Makefile.in:
+       Add explicit rule to build getdate.o for HP-UX make.
+       [7f049e989956]
+
+       * plugins/sudoers/Makefile.in:
+       Back out most of change 45e406ebdea2. Create dummy .l.c and .y.c
+       rules as an alternate way to prevent HP-UX make (and others) from
+       trying to rebuild the parser in non-dev mode.
+       [f84badad98c5]
+
+       * plugins/sudoers/sudoers.c:
+       Re-enable PATH_MAX check for command
+       [40d8a50da136]
+
+       * Makefile.in:
+       For distclean, clean the main directory last since the subdirs need
+       to be able to run libtool to clean things.
+       [8949a9861634]
+
+       * compat/Makefile.in:
+       Fix generation of mksiglist.h
+       [b7cdc9b36650]
+
+       * src/script.c:
+       Now that we defer sending cstat until the end of script_child() we
+       cannot reuse cstat when reading command status from parent.
+       [25c882643466]
 
-       * configure, configure.in, sudo.man.pl, sudoers.man.pl:
+2010-05-25  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * configure, configure.in, doc/sudo.man.in, doc/sudo.man.pl,
+       doc/sudoers.cat, doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in,
+       doc/sudoers.man.in, doc/sudoers.man.pl, doc/sudoreplay.cat,
+       doc/sudoreplay.man.in, doc/visudo.cat, doc/visudo.man.in:
        Use numeric registers to handle conditionals instead of trying to do
        it all with text processing.
-       [31570c372e0e] <1.7>
+       [478079c3fd4b]
 
-       * sudoers.pod:
+       * doc/sudoers.pod:
        Document per-command SELinux settings
-       [bbce5acad1be] <1.7>
+       [13840d566805]
 
-       * sudo.pod:
-       timestamp -> time stamp
-       [d7335ce6286f] <1.7>
+       * plugins/sudoers/sudoers.c:
+       Repair "sudo -l -U username"
+       [10a0dcdf2ddf]
 
-       * tsgetgrpw.c:
-       Set close on exec flag in private versions of setpwent() and
-       setgrent().
-       [954814bdbd56] <1.7>
+       * plugins/sudoers/sudoers.c:
+       Set selinux role and type in command details.
+       [8ae6d35a126d]
 
-       * logging.c:
-       Make send_mail() take a printf-style argument list
-       [0783ad585062] <1.7>
+       * src/script.c, src/selinux.c, src/sudo.h:
+       Rework SELinux support.
+       [83279cc94bf2]
 
-       * Makefile.binary.in, Makefile.in, aclocal.m4, acsite.m4,
-       config.guess, config.h.in, config.sub, configure, configure.in,
-       ltmain.sh, m4/libtool.m4, m4/ltoptions.m4, m4/ltsugar.m4,
-       m4/ltversion.m4, m4/lt~obsolete.m4:
-       Update to autoconf 2.65 and libtool 2.2.6b
-       [3544dd2f1a94] <1.7>
+2010-05-24  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * boottime.c:
-       Don't use TRUE/FALSE which may not be defined.
-       [8649bf22b3b2] <1.7>
+       * src/script.c, src/selinux.c, src/sudo.h:
+       Make SELinux support compile again. Needs more work to be complete.
+       [3d3addebcf82]
 
-       * sudo.cat, sudo.man.in, sudo.pod:
-       Document new tty_ticket behavior
-       [0663e0390338] <1.7>
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h,
+       src/parse_args.c, src/script.c, src/selinux.c, src/sudo.c,
+       src/sudo.h:
+       Bring back closefrom settings.
+       [b1c6257d4bbb]
+
+       * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h:
+       If running a command or sudoedit in transcript mode, call
+       io_nextid() before log_allowed() so the session id is logged.
+       [c42f3ae40150]
+
+       * configure, configure.in:
+       Use mandoc(1) if nroff(1) is not present.
+       [daad4bbd04af]
 
-       * find_path.c, sudo.c, sudo.h, visudo.c:
+       * doc/Makefile.in:
+       Use the --file argument to config.status instead of setting
+       CONFIG_FILES in the environment.
+       [c89411a8bf70]
+
+       * plugins/sudoers/Makefile.in:
+       We cannot conditionally update gram.h or the dependency ordering
+       gets messed up in devel mode.
+       [c938953231d9]
+
+2010-05-21  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Makefile.in, compat/Makefile.in, configure, configure.in,
+       doc/Makefile.in, include/Makefile.in, plugins/sample/Makefile.in,
+       plugins/sudoers/Makefile.in, src/Makefile.in:
+       Substitute @SHELL@ into Makefiles
+       [36aa6a095335]
+
+       * config.sub:
+       Fix typo
+       [16d294d26b58]
+
+       * config.guess, config.sub, configure, configure.in:
+       Update to autoconf 2.65
+       [4fa6ea8caea3]
+
+       * Makefile.in:
+       Fix libtool target (space vs. tabs)
+       [755cf3892618]
+
+       * config.h.in, plugins/sudoers/logging.h, plugins/sudoers/visudo.c:
+       Remove use of RETSIGTYPE; all modern systems have signal handlers
+       that return void.
+       [42b4e3aee668]
+
+       * Makefile.in, aclocal.m4, acsite.m4, configure, configure.in,
+       ltmain.sh, m4/libtool.m4, m4/ltoptions.m4, m4/ltsugar.m4,
+       m4/ltversion.m4, m4/lt~obsolete.m4, plugins/sample/Makefile.in,
+       plugins/sudoers/Makefile.in, src/Makefile.in:
+       Update to libtool-2.2.6b. I haven't made any local modifications
+       this time, which should be OK since we install sudo_noexec.so by
+       hand now.
+       [6f79ced593bb]
+
+       * compat/Makefile.in, plugins/sample/Makefile.in,
+       plugins/sudoers/Makefile.in, src/Makefile.in:
+       Use libtool to clean objects
+       [1581057d6472]
+
+       * include/Makefile.in:
+       Install sudo_plugin.h as part of "make install" and make other
+       install targets callable from the top-level Makefile
+       [aaaeb027d774]
+
+       * configure, configure.in:
+       regen with autoupdate to eliminate AC_TRY_LINK
+       [5d5541c230f5]
+
+       * Makefile.in, compat/Makefile.in, configure, configure.in,
+       doc/Makefile.in, plugins/sample/Makefile.in,
+       plugins/sudoers/Makefile.in, src/Makefile.in:
+       Install sudo_plugin.h as part of "make install" and make other
+       install targets callable from the top-level Makefile
+       [b258b8401b1c]
+
+       * plugins/sample/sample_plugin.c:
+       The sample plugin doesn't support being run with no args so return a
+       usage error in this case.
+       [473b3cf965be]
+
+       * plugins/sudoers/iolog.c:
+       Set close on exec flag for descriptors used for I/O logging so they
+       are not present in the command being run.
+       [2c7e8708df76]
+
+       * plugins/sudoers/tsgetgrpw.c:
+       Set close on exec flag in private versions of setpwent() and
+       setgrent().
+       [64fef78cb833]
+
+       * src/script.c:
+       Close the I/O pipes aftering dup2()ing them to std{in,out,err}.
+       Fixes extra fds being present in the command when it is part of a
+       pipeline.
+       [060451617713]
+
+       * plugins/sudoers/sudoers.c:
+       Set user_tty to "unknown" if there is no tty, like sudo 1.7 does (it
+       is used when logging). Note that user_ttypath will still be NULL if
+       there is no tty.
+       [31b69a6ecda7]
+
+       * src/script.c, src/sudo.h:
+       Cosmetic changes: add comments, remove orphaned prototype and
+       make a global static.
+       [f7851af0143e]
+
+2010-05-20  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/script.c:
+       Move check for maxfd == -1 to flush_output where it belongs.
+       [b826a95b4491]
+
+       * src/script.c:
+       Break out of select loop if all the fds we want to select on are -1.
+       [f5b387024238]
+
+       * src/sudo.c:
+       Avoid possible malloc(0) if plugin returns an empty groups list.
+       [9765a8fe5ce7]
+
+       * src/sudo.c:
+       Add debugging info when calling plugin close function
+       [95a273c7ff66]
+
+       * src/script.c:
+       Avoid closing stdin/stdout/stderr when we are piping output.
+       [330e76423caf]
+
+       * src/script.c:
+       When execve() of the command fails, it is possible to receive
+       SIGCHLD before we've read the error status from the pipe. Re-order
+       things such that we send the final status at the very end and prefer
+       error status over wait status.
+       [b0dcf825244f]
+
+2010-05-19  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/auth/sudo_auth.c:
+       Fix compilation for non PAM/BSD auth/AIX auth
+       [e382b39d2e4f]
+
+2010-05-18  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/script.c:
+       Additional checks to make sure we don't close /dev/tty by mistake.
+       When flushing, sleep in select as long as we have buffers that need
+       to be written out.
+       [8139cbd3dd54]
+
+       * src/script.c:
+       Now that we can use pipes for stdin/stdout/stderr there is no longer
+       a need to error out when there is no tty. We just need to make sure
+       we don't try to use the tty fd if it is -1.
+       [666621635d26]
+
+2010-05-17  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod,
+       include/sudo_plugin.h, plugins/sample/sample_plugin.c,
+       plugins/sudoers/iolog.c, plugins/sudoers/sudoers.h, src/sudo.c:
+       Add argc and argv to I/O logger open function.
+       [0d7faa007d27]
+
+       * doc/sudo_plugin.man.in, doc/sudo_plugin.pod, include/sudo_plugin.h,
+       plugins/sample/sample_plugin.c, plugins/sudoers/sudoers.c,
+       src/parse_args.c, src/sudo.c, src/sudo_edit.c:
+       Remove check_sudoedit function pointer in struct sudo_policy.
+       Instead, sudo will set sudoedit=true in the settings array. The
+       plugin should check for this and modify argv_out as appropriate in
+       check_policy.
+       [c0328e3276b8]
+
+2010-05-16  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sample/sample_plugin.c, src/sudo.c, src/sudo.h,
+       src/sudo_edit.c:
+       If plugin sets "sudoedit=true" in the command info, enable sudoedit
+       mode even if not invoked as sudoedit. This allows a plugin to
+       enable sudoedit when the user runs an editor.
+       [96d67b99e42e]
+
+2010-05-15  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/Makefile.in:
+       gram.h must not depend on gram.y if we want to avoid unnecessary
+       rebuilding of targets dependent on gram.h when gram.y changes.
+       [9db4b767fdca]
+
+       * plugins/sample/sample_plugin.c:
+       Refactor common bits of check_policy and check_edit
+       [ac4d366a04cf]
+
+       * plugins/sample/sample_plugin.c:
+       Add sudoedit support
+       [a1a6cc4c0cef]
+
+2010-05-14  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/Makefile.in:
+       Rely more on VPATH; fixes a dependency issue with the parser.
+       [45e406ebdea2]
+
+       * include/compat.h:
+       Fix typo introduced in last commit
+       [3ccb0f853d11]
+
+       * include/compat.h:
+       Emulate seteuid using setreuid() or setresuid() as needed. There are
+       still a few places that call seteuid() directly.
+       [36e8efa3a99d]
+
+       * src/parse_args.c, src/sudo_edit.c:
+       Attempt to fix building on systems that only have setuid.
+       [8e9ba4083318]
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Clarify sudoedit a tad.
+       [d39dfaa14ade]
+
+2010-05-13  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/sudo_edit.c:
+       Fix compilation on HP-UX
+       [f6e47843d139]
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Document sudoedit
+       [4cbf5196d993]
+
+       * plugins/sudoers/sudoers.c, src/sudo.c, src/sudo.h, src/sudo_edit.c:
+       Change how we handle the sudoedit argv. We now require that there
+       be a "--" in argv to separate the editor and any command line
+       arguments from the files to be edited.
+       [20623d549a3c]
+
+       * include/sudo_plugin.h, plugins/sample/sample_plugin.c,
+       plugins/sudoers/Makefile.in, plugins/sudoers/gettime.c,
+       plugins/sudoers/set_perms.c, plugins/sudoers/sudoers.c,
+       src/Makefile.in, src/gettime.c, src/parse_args.c, src/sudo.c,
+       src/sudo.h, src/sudo_edit.c:
+       Work in progress support for sudoedit. The actual interface used by
+       the plugin for sudoedit is likely to change.
+       [c31262a31997]
+
+       * plugins/sudoers/find_path.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h, plugins/sudoers/visudo.c:
        Make find_path() a little more generic by not checking def_foo
        variables inside it. Instead, pass in ignore_dot as a function
        argument.
-       [16c3f27cd9b9] <1.7>
+       [9c23101a094d]
 
-       * check.c:
-       Store info from stat(2)ing the tty in the tty ticket when tty
-       tickets are in use. If the tty lives on a devpts (Linux) or devices
-       (Solaris) filesystem, stash the ctime in the tty ticket file, as it
-       is not updated when the tty is written to. This helps us determine
-       when a tty has been reused without the user authenticating again
-       with sudo.
-       [f9aec9ab9054] <1.7>
-
-       * boottime.c, check.c, sudo.h:
-       get_boottime() now fills in a timeval struct
-       [dbd2003659c0] <1.7>
+       * plugins/sudoers/env.c:
+       Add version of getenv(3) that uses our own environ pointer.
+       [0e3783e63534]
 
-2010-06-02  Todd C. Miller  <Todd.Miller@courtesan.com>
+2010-05-12  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * check.c, compat.h, config.h.in, configure, configure.in, fileops.c,
-       gettime.c, sudo.h, sudo_edit.c, visudo.c:
-       Use timeval directly instead of converting to timespec when dealing
-       with file times and time of day.
-       [c85bf3e41839] <1.7>
+       * src/script.c:
+       Avoid a potential race condition if SIGCHLD is received immediately
+       before we call select().
+       [99adc5ea7f0a]
 
-       * auth/pam.c:
-       Fix OpenPAM detection for newer versions.
-       [67f29a0703d0] <1.7>
+       * plugins/sudoers/sudoers.c:
+       Call env_init() before we open the sudoers sources as those may call
+       our setenv() replacement.
+       [5f82601f5ab0]
 
-       * vasgroups.c:
-       Sync with Quest sudo git repo
-       [2680ad9762c2] <1.7>
+       * plugins/sudoers/env.c:
+       Initialize env_len in env_init()
+       [7ae02b3029b5]
 
-       * aclocal.m4, configure, configure.in:
-       HP-UX ld uses +b instead or -R or -rpath Fix typo in libvas check
-       libvas may need libdl for dlopen() Add missing template for
-       ENV_DEBUG Adapted from Quest sudo
-       [6c886eb9070a] <1.7>
+2010-05-11  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * README.LDAP:
-       Fix typos; from Quest Sudo
-       [cf258fc69f1a] <1.7>
+       * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod:
+       Document time stamp shortcomings under SECURITY NOTES Use "time
+       stamp" instead of timestamp.
+       [2b86120815b2]
 
-       * Makefile.in, configure.in:
-       Use value of SHELL from configure in Makefile
-       [08aaf12221d6] <1.7>
+       * doc/Makefile.in:
+       Make sed substitution of mansectsu and mansectform global.
+       [94588632dba0]
 
-2010-05-28  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * plugins/sudoers/check.c:
+       If the tty lives on a devpts filesystem, stash the ctime in the tty
+       ticket file, as it is not updated when the tty is written to. This
+       helps us determine when a tty has been reused without the user
+       authenticating again with sudo.
+       [0e62a31bceb0]
 
-       * env.c:
-       Handle duplicate variables in the environment. For unsetenv(), keep
-       looking even after remove the first instance. For sudo_putenv(),
-       check for and remove dupes after we replace an existing value.
-       [086c6397d8cd] <1.7>
+       * src/tgetpass.c:
+       Fix pasto in mulitple signal fix and use _NSIG not NSIG since that
+       is what our compat checks set.
+       [df50f0a040c9]
+
+       * configure, configure.in:
+       Add check for whether sudo need to link with -ldl to get dlopen().
+       This is a bit of a hack that will get reworked when libtool is
+       updated.
+       [63bdcf579533]
+
+       * plugins/sudoers/check.c:
+       Fix timestamp removal with -k/-K
+       [6b4639fef973]
+
+       * plugins/sudoers/Makefile.in:
+       audit.c is now private to the sudoers plugin
+       [1974f342ae0b]
+
+       * configure, configure.in:
+       Link with -lpthread on HP-UX since a plugin may be linked with
+       -lpthread and dlopen() will fail if the shared object has a
+       dependency on -lpthread but the main program is not linked with it.
+       [d42139391263]
+
+       * config.h.in, configure, configure.in, plugins/sudoers/set_perms.c:
+       Add separate test for getresuid() since HP-UX has setresuid() but no
+       getresuid().
+       [910fe727a374]
+
+       * doc/Makefile.in:
+       Remove errant backslash
+       [dd5464257c69]
+
+       * src/script.c:
+       Fix SIGPIPE handling. Now that we use may use pipes for
+       stdin/stdout we need to pass any SIGPIPE we receive to the running
+       command.
+       [3f6b1991f4fd]
+
+       * src/script.c:
+       Also start the command in the background if stdin is not a tty.
+       [d93bc33a3740]
+
+2010-05-10  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/sudoreplay.c, src/script.c, src/sudo.h, src/term.c:
+       No need to use pseudo-cbreak mode now that we use pipes when stdout
+       is not a tty. Instead, check whether stdin is a tty and if not,
+       delay setting the tty to raw mode until the command tries to access
+       it itself (and receives SIGTTIN or SIGTTOU).
+       [e68315cf8c6b]
+
+       * src/tgetpass.c:
+       Use an array for signals received instead of a single variable so we
+       don't lose any when there are multiple different signals.
+       [2ac726dac864]
+
+       * src/tgetpass.c:
+       Do signal setup after turning off echo, not before. If we are using
+       a tty but are not the foreground pgrp this will generate SIGTTOU so
+       we want the default action to be taken (suspend process).
+       [bebb6209c795]
+
+2010-05-07  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/script.c:
+       Flush the iobufs on suspend or child exit using the same logic as
+       the main event loop.
+       [c627feee1035]
+
+       * src/script.c:
+       Free memory after we are done with it.
+       [8db9b611b45a]
+
+2010-05-06  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * doc/HISTORY:
+       Quest now sponsors Sudo development
+       [6cc490083bc7]
+
+2010-05-05  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * doc/Makefile.in:
+       Install sudo_plugin man page.
+       [c253729790b2]
+
+       * src/script.c:
+       Go back to reseting io_buffer offset and length (and now also the
+       EOF handling) in the loop we do the FD_SET, not after we drain the
+       buffer after write() since we don't know what order reads and writes
+       will occur in.
+       [5f38bfa8497f]
+
+       * MANIFEST:
+       audit files moved to sudoers plugin directory
+       [b1ead182428e]
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Document plugin_printf and new logging functions.
+       [fe9430b60ab5]
+
+       * src/script.c:
+       Add support for logging stdin when it is not a tty. There is still a
+       bug where "cat | sudo cat" has problems because both cat and sudo
+       are trying to read from the tty.
+       [04c9c59fcfba]
+
+       * include/sudo_plugin.h, plugins/sample/sample_plugin.c,
+       plugins/sudoers/sudoers.c, src/script.c:
+       Add separate I/O logging functions for tty in/out and
+       stdin/stdout/stderr. NOTE: stdin logging does not currently work and
+       is disabled for now.
+       [a36dfd4ca935]
+
+2010-05-04  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * include/sudo_plugin.h, plugins/sample/sample_plugin.c,
+       plugins/sudoers/iolog.c, plugins/sudoers/ldap.c,
+       plugins/sudoers/logging.c, plugins/sudoers/plugin_error.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h,
+       src/conversation.c, src/sudo.c, src/sudo_plugin_int.h:
+       Add pointer to a printf like function to plugin open functon. This
+       can be used instead of the conversation function to display info and
+       error messages.
+       [98734eea8ef1]
+
+       * Makefile.in:
+       Stop if make in a subdir fails
+       [228bb3ad2dbc]
+
+       * src/script.c:
+       Only set user's tty to blocking mode when doing the final flush.
+       Flush pipes as well as pty master when the process is done.
+       [20ff67218666]
+
+2010-05-03  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/ldap.c:
+       Use print_error() when displaying ldap config info in debugging
+       mode.
+       [d142e0cacb22]
+
+       * compat/Makefile.in, compat/strdup.c, compat/strndup.c:
+       No longer need strdup() or strndup() replacements.
+       [df53697174ec]
+
+       * plugins/sudoers/logging.c, plugins/sudoers/plugin_error.c,
+       plugins/sudoers/sudoers.h:
+       Add print_error() function that uses the conversation function to
+       print a variable number of error strings and use it in log_error().
+       [b1fa2861b575]
+
+       * src/script.c, src/sudo.h, src/term.c:
+       Do not need the opost flag to term_copy() now that we use pipes for
+       stdout/stderr when they are not a tty.
+       [f42811f70a19]
+
+       * src/script.c:
+       Use pipes to the sudo process if stdout or stderr is not a tty.
+       Still needs some polishing and a decision as to whether it is
+       desirable to add additonal entry points for logging
+       stdout/stderr/stdin when they are not ttys. That would allow a
+       replay program to keep things separate and to know whether the
+       terminal needs to be in raw mode at replay time.
+       [1a945e0ab2da]
+
+2010-04-30  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/Makefile.in, plugins/sudoers/audit.c,
+       plugins/sudoers/bsm_audit.c, plugins/sudoers/bsm_audit.h,
+       src/audit.c, src/bsm_audit.c, src/bsm_audit.h:
+       Move audit sources into the sudoers plugin dir; the driver does not
+       use them.
+       [50ec36422cd0]
+
+       * compat/getline.c, compat/mksiglist.c, compat/nanosleep.c,
+       compat/strdup.c, compat/strndup.c, plugins/sample/sample_plugin.c,
+       plugins/sudoers/boottime.c, plugins/sudoers/getdate.c,
+       plugins/sudoers/match.c, plugins/sudoers/sudoreplay.c,
+       plugins/sudoers/timestr.c, plugins/sudoers/vasgroups.c, src/alloc.c,
+       src/atobool.c, src/audit.c, src/lbuf.c, src/list.c, src/sesh.c,
+       src/term.c, src/ttysize.c:
+       Use angle brackets when including headers that can only be found
+       when an -I flag is specified. The files in the compat dir could get
+       away with double quotes here but I've converted all the source files
+       to use angle brackets for consistency.
+       [9e30a8fc6d4b]
+
+       * plugins/sudoers/Makefile.in:
+       Add missing -I$(top_srcdir) to CPPFLAGS so includes in the compat
+       dir can be found when building outside the source tree.
+       [1150934b79dd]
+
+       * plugins/sudoers/Makefile.in:
+       Clean up links in distclean
+       [78595028be8b]
+
+       * plugins/sudoers/Makefile.in:
+       Hack around VPATH semantic differences by symlinking files we need
+       from ../../src into the current directory and build those. A better
+       fix would be to either make a .a or .la file with those files in it
+       or simply use a single, flat, Makefile instead of per-subdirs
+       Makefiles.
+       [892c332d3f05]
+
+       * plugins/sudoers/Makefile.in, src/Makefile.in, src/fmt_string.c:
+       fmt_string is used by the sudoers plugin too so do not include
+       sudo.h (which is not really needed here anyway)
+       [231c35e3941f]
+
+       * compat/Makefile.in, plugins/sample/Makefile.in,
+       plugins/sudoers/Makefile.in, src/Makefile.in:
+       Fix building with non-BSD versions of make such as GNU make.
+       Requires VPATH support, which should be in any non-neolithic make.
+       [dc174f135919]
+
+       * configure, configure.in, plugins/sudoers/Makefile.in,
+       plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/sudoers.c,
+       src/Makefile.in:
+       Re-enable bsm audit. Currently auditing is done within the sudoers
+       plugin itself. If possible, this should really be done in the main
+       driver but we don't presently have the needed data to do that. This
+       will be re-evaluated when Linux audit support is added.
+       [1d05a3236bfe]
+
+       * compat/Makefile.in, plugins/sample/Makefile.in,
+       plugins/sudoers/Makefile.in, src/Makefile.in:
+       Remove extraneous $srcdir and use more .c.lo and .c.o rules instead
+       of explicit rules in the dependency.
+       [88f80efd25f0]
+
+       * plugins/sudoers/visudo.c:
+       Fix mismerge; alias_remove_recursive() now returns int
+       [6257a4849641]
 
 2010-04-29  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * visudo.c:
+       * plugins/sudoers/visudo.c:
        Fix a crash when checking a sudoers file that has aliases that
        reference themselves. Based on a diff from David Wood.
-       [5efc702a3b35] <1.7>
+       [545d194484a7]
+
+       * src/script.c:
+       Print signal info after restoring the tty mode, not before.
+       [a68618e67435]
+
+       * src/script.c:
+       Defer call to alarm() until after we fork the child. Pass correct
+       pid to terminate_child() If the command exits due to signal, set
+       alive to false like we do when it exits normally. Add missing
+       check for errpipe[0] != -1 before using it in FD_ISSET
+       [22f0a1549391]
+
+2010-04-28  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/boottime.c:
+       Use 1/0 instead of TRUE/FALSE so we don't need sudoers.h
+       [0e627170c6e8]
+
+2010-04-27  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/Makefile.in:
+       Simplify dependencies by using .c.o and .c.lo rules.
+       [6abcaef5d1ac]
+
+       * configure, configure.in, plugins/sudoers/Makefile.in,
+       src/Makefile.in:
+       Substitute in @PROGS@ into src/Makefile to add sesh
+       [cc46d3b6208f]
+
+2010-04-26  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/sudoers.c:
+       Add back calls to log_denial() if sudoers does not allow the
+       command.
+       [9783316207f0]
+
+       * plugins/sudoers/sudoers.c:
+       Pass in correct pwflag for list and validate.
+       [973dd56d4b81]
+
+       * plugins/sudoers/env.c:
+       Add missing check for NULL in validate_env_vars
+       [1d6eb6957824]
+
+       * src/Makefile.in:
+       Add sudo_noexec.la to "all" target, otherwise it only gets built at
+       install time.
+       [644a9694d2ef]
+
+       * plugins/sudoers/sudoers.c:
+       Only set sudo_user.env_vars if the env_add list is empty.
+       [fccdf6f0e0e2]
+
+       * plugins/sudoers/sudoers.c:
+       Set sudo_user.env_vars so that environment variables specified on
+       the command line get logged correctly.
+       [9b51012c491e]
+
+       * plugins/sudoers/env.c, plugins/sudoers/logging.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h:
+       Re-enable environment files and setting environment variables on the
+       command line.
+       [5662d5645dbd]
+
+2010-04-24  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/check.c:
+       Fix typo in last commit (ifndef vs ifdef) Make sure we pass ctime()
+       a pointer to time_t as tv_sec in struct timeval may be long.
+       [4de0c46e788e]
+
+       * plugins/sudoers/check.c:
+       Don't stash ctime in on-disk tty ticket info for now; on many
+       (most?) systems the ctime is updated when the tty is written to.
+       Once I have a better idea of what systems do not update ctime on
+       ttys (and have a way to test for this) the ctime stash will be
+       conditionally re-enabled.
+       [a90eeec0f648]
+
+2010-04-23  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * MANIFEST, Makefile.in:
+       Add back "dist" target, this time using a MANIFEST file
+       [29277c05499f]
+
+       * Makefile.in:
+       Remove Makefile in distclean target
+       [83d695f4f450]
+
+       * Makefile.in, src/Makefile.in:
+       Update clean and cleandir targets
+       [ad7b2afeb9c1]
+
+       * include/fileops.h, plugins/sudoers/sudoers.h, src/fileops.c,
+       src/sudo.h:
+       Move fileops.c defines and prototypes to filesops.h
+       [4545e9b6892d]
+
+       * plugins/sudoers/check.c:
+       Lock the tty timestamp when writing. We shouldn't have to lock when
+       reading since the file is updated via a single write system call.
+       [0c7276f02696]
+
+2010-04-22  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/alias.c, plugins/sudoers/check.c,
+       plugins/sudoers/defaults.c, plugins/sudoers/find_path.c,
+       plugins/sudoers/getspwuid.c, plugins/sudoers/gettime.c,
+       plugins/sudoers/goodpath.c, plugins/sudoers/interfaces.c,
+       plugins/sudoers/iolog.c, plugins/sudoers/ldap.c,
+       plugins/sudoers/logging.c, plugins/sudoers/match.c,
+       plugins/sudoers/nonunix.h, plugins/sudoers/parse.c,
+       plugins/sudoers/pwutil.c, plugins/sudoers/redblack.c,
+       plugins/sudoers/sudo_nss.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c,
+       plugins/sudoers/timestr.c, plugins/sudoers/tsgetgrpw.c,
+       plugins/sudoers/vasgroups.c, plugins/sudoers/visudo.c:
+       Convert to ANSI C function declarations
+       [9c45def57cf7]
+
+       * plugins/sudoers/sudoers.h:
+       Remove extraneous bits and classify by source file.
+       [e8ea9f109ebb]
+
+       * include/compat.h:
+       Add timercmp macro for systems without it
+       [d3bf87b1d08e]
+
+       * plugins/sudoers/boottime.c, plugins/sudoers/check.c,
+       plugins/sudoers/sudoers.h:
+       get_boottime() now fills in a timeval struct
+       [3573c3f44e11]
+
+       * plugins/sudoers/check.c:
+       Store info from stat(2)ing the tty in the tty ticket when tty
+       tickets are in use. On most systems, this closes the loophole
+       whereby a user can log out of a tty, log back in and still have the
+       timestamp be valid.
+       [53380f9f5242]
+
+       * config.h.in, configure.in:
+       Add timespec2timeval and use it when getting ctime/mtime
+       [4cb7f7caec2c]
+
+2010-04-20  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/set_perms.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h,
+       plugins/sudoers/testsudoers.c:
+       Convert perm setting to push/pop model; still needs some work Use
+       the stashed runas groups instead of using getgrouplist() Reset perms
+       to the initial value on error
+       [09c072ebde8b]
+
+       * config.h.in, configure.in:
+       fix ctim_get and mtim_get macros
+       [58773dc1e360]
+
+       * config.h.in, configure, configure.in, include/compat.h,
+       plugins/sudoers/check.c, plugins/sudoers/gettime.c,
+       plugins/sudoers/sudoers.h, plugins/sudoers/visudo.c, src/fileops.c:
+       Use timeval directly instead of converting to timespec when dealing
+       with file times and time of day.
+       [a0ce1ae00a67]
+
+       * plugins/sudoers/Makefile.in:
+       Don't like sudoreplay with libsudoers.la due to a yacc symbol
+       conflict.
+       [f1a59cc63a15]
+
+2010-04-18  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * configure, configure.in:
+       Darwin >= 9.x has real setreuid(2)
+       [7ec942a64275]
+
+2010-04-17  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/env.c, plugins/sudoers/sudoers.h:
+       Ansify env.c
+       [f58551bad10a]
+
+       * plugins/sudoers/env.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h:
+       Remove remaining references to the environ pointer.
+       [96faa530816a]
+
+2010-04-16  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * config.h.in, configure, configure.in, plugins/sudoers/env.c:
+       Don't change the environ directly in the sudoers plugin
+       [6db48ed3f7e0]
 
 2010-04-15  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * alias.c:
+       * plugins/sudoers/sudoers.c:
+       Fix typo
+       [4aa452b07f8f]
+
+       * plugins/sudoers/alias.c:
        Fix use after free in error message when a duplicate alias exists.
-       [9eaac49bd22b] <1.7>
+       [ce1d2812ee34]
 
 2010-04-14  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * visudo.c:
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod,
+       src/parse_args.c:
+       Add a "noninteractive" boolean to the settings passed in to the
+       plugin's open function that is set when the user specifies the -n
+       flag.
+       [68f8d9d6d4d0]
+
+       * config.h.in, configure, configure.in, plugins/sudoers/env.c:
+       Add workaround for the lack of the environ pointer on Mac OS X in
+       dlopen()ed modules. Use of environ in the sudoers plugin should
+       ultimately be removed but this will do for the moment.
+       [80c61647434f]
+
+       * plugins/sudoers/visudo.c:
        Set errorfile to the sudoers path if we set parse_error manually.
        This prevents a NULL dereference in printf() when checking a sudoers
        file in strict mode when alias errors are present.
-       [b4eed2f0615d] <1.7>
+       [45e249ca99f7]
+
+       * plugins/sudoers/sudoers.c:
+       Main sudo no longer print "unable to execute" on exec failure so do
+       it here.
+       [50aaf62b43b5]
+
+2010-04-13  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/script.c:
+       Use a pipe to pass back errno to the parent if execve() fails. If we
+       get an error in script_child(), kill the command and exit.
+       [dc3bf870f91b]
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod,
+       src/parse_args.c, src/sudo.c:
+       Handle plugin's open function returning -2 (usage error).
+       [aadf900c1de8]
+
+       * src/script.c:
+       If execve() fails, leave it to the plugin to print an error string.
+       [e25748f2d5b9]
+
+       * src/script.c:
+       If execve fails in logging mode, pass the errno directly to the
+       grandparent on the backchannel and exit. The immediate parent will
+       get SIGCHLD and try to report that status but its parent will no
+       longer be listening. It would probably be cleaner to pass this over
+       a pipe in script_child().
+       [cb122acc81a8]
+
+       * plugins/sudoers/sudoers.c:
+       Don't override rval with results of check_user() unless it failed.
+       [46fb7e87ac7d]
 
 2010-04-12  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * TODO, sudoers.cat, sudoers.man.in, sudoers.pod:
+       * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod:
        Fix typo
-       [57198cae9cf5] <1.7>
+       [ccd0b693f3da]
+
+       * src/parse_args.c:
+       NULL-terminate env_add
+       [2c534368a0c3]
+
+2010-04-11  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/sudo.c:
+       Call the I/O log open function before the I/O version function.
+       [e88bf898990b]
+
+       * plugins/sudoers/iolog.c:
+       Remove io_conv and just use sudo_conv
+       [a280052468eb]
+
+       * plugins/sudoers/set_perms.c:
+       Fix set/restore perms for systems w/o setresuid
+       [4160517f6666]
+
+2010-04-10  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/check.c, plugins/sudoers/logging.c,
+       plugins/sudoers/parse.c, plugins/sudoers/set_perms.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h:
+       Primitive set/restore permissions. Will be replaced by a push/pop
+       model.
+       [aae102290866]
+
+       * src/script.c:
+       Only need to take action on SIGCHLD in parent if no I/O logger. If
+       there is an I/O logger we will receive ECONNRESET or EPIPE when we
+       try to read from the socketpair.
+       [e1e4560401f6]
 
 2010-04-09  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * find_path.c:
-       Qualify the command even if it is in the current working directory,
-       e.g. "./foo" instead of just returning "foo". This removes an
-       ambiguity between real commands and possible pseudo-commands in
-       command matching.
-       [fb4d571495fa] <1.7>
+       * compat/memrchr.c, doc/sudoers.cat, doc/sudoers.man.in,
+       doc/sudoers.pod, plugins/sudoers/find_path.c:
+       Merge fb4d571495fa from the 1.7 branch to trunk.
+       [c8fb424ad4d2]
+
+2010-04-08  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/script.c:
+       Don't set SA_RESTART when registering SIGALRM handler. Do set
+       SA_RESTART when registering SIGWINCH handler.
+       [173472b76525]
+
+       * doc/Makefile.in:
+       Add dev targets for *.man.in and *.cat that don't specfify the
+       $(srcdir) prefix.
+       [b62f425da2e4]
+
+       * src/script.c:
+       If log_input or log_output returns false, terminate the command.
+       [074f4c0c34a0]
+
+       * src/script.c:
+       Better signal handling. Instead of using a single variable to store
+       the received signal, use an array so we can't lose a signal when
+       multiple are sent. Fix process termination by SIGALRM in non-I/O
+       logger mode. Fix relaying terminal signals to the child in non-I/O
+       logger mode.
+       [7a4723aca99d]
+
+       * src/script.c:
+       Fix a race between when we get the child pid in the parent and when
+       the child process exits. The problem exhibited as a hang after a
+       short-lived process, e.g. "sudo id" when no IO logger was enabled.
+       [80bcc0aca70b]
 
 2010-04-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * sudoers.cat, sudoers.man.in, sudoers.pod:
+       * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod:
        Add a note about the security implications of the fast_glob option.
-       [84f8097553d9] <1.7>
+       [c37a92ab7c93]
 
-       * memrchr.c:
-       Remove duplicate includes
-       [3e8d90f4c30f] <1.7>
+2010-04-06  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * config.h.in, configure, configure.in:
+       Fix up some AC_DEFINE descriptions and regen config.h.in
+       [f4655adc0db3]
+
+2010-04-05  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * include/missing.h:
+       No longer check for strdup or strndup for LIBOBJ replacement.
+       [fdc764ee8109]
+
+       * src/script.c:
+       Avoid installing signal handlers that are io-logger specific. Fixes
+       job control when no io logger is enabled.
+       [0853dd0906d4]
+
+       * doc/Makefile.in:
+       Only regen man pages from pod when configured with --with-devel
+       [ab1995f8103d]
+
+2010-04-04  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Makefile, Makefile.in, configure, configure.in:
+       Top-level Makefile.in. Nothing is currently substituted but this is
+       needed for separate build dirs.
+       [e80873cbd201]
+
+       * compat/Makefile.in, doc/Makefile.in, plugins/sample/Makefile.in,
+       plugins/sudoers/Makefile.in, src/Makefile.in:
+       Fix out-of-tree builds
+       [59a35bef07b8]
+
+       * Merge
+       [386b848047e9]
+
+       * doc/Makefile.in:
+       We always install sudoreplay in 1.8
+       [ce52ba6617c9]
+
+2010-04-03  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * compat/siglist.in:
+       SIGPOLL is sometimes the same as SIGIO (like on HP-UX)
+       [6d69e1b05faf]
+
+2010-04-02  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * configure, configure.in:
+       No need to provide strdup() or strndup(), sudo uses estrdup() and
+       estrndup()
+       [57ec23b72958]
+
+2010-04-04  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c:
+       Free str after using it in the version method. Use sudo_conv, not
+       io_conv since we don't have the IO conversation function pointer in
+       the I/O version method anymore now that io_open is delayed.
+       [f2ed132adeb0]
+
+2010-04-02  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * compat/Makefile.in, compat/mksiglist.c, compat/mksiglist.h,
+       compat/siglist.in:
+       Add license to mksiglist.c and note that the bits from pdksh are
+       public domain
+       [d8121a2467e8]
+
+       * compat/Makefile.in:
+       Fix LIBOBJDIR vs. srcdir wrt the siglist bits
+       [164160148421]
+
+       * plugins/sudoers/Makefile.in:
+       Add sudoreplay testsudoers and visudo to clean target
+       [138a17e51c0c]
+
+       * compat/Makefile.in, compat/mksiglist.c, compat/mksiglist.h,
+       compat/siglist.in, compat/strsignal.c, configure, configure.in,
+       include/missing.h, src/script.c:
+       Create our own sys_siglist for systems without it for use by
+       strsignal()
+       [2e5da011ebc3]
+
+       * compat/Makefile.in:
+       Remove duplicate $(LIBOBJDIR)
+       [adf9abc9432f]
+
+2010-04-01  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/sudoers.c, src/sudo.c, src/sudo_edit.c:
+       Main sudo should not block signals; the plugin should do this in
+       check_policy.
+       [3f3736a7c5ed]
+
+2010-03-31  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/script.c:
+       Fix a sizeof(ptr) vs. sizeof(*ptr)
+       [aa1bcf5afcce]
+
+       * src/script.c:
+       Unlike most operating systems, HP-UX select() is not interrupted by
+       SIGCHLD when the signal is registered with SA_RESTART. If we clear
+       SA_RESTART when calling sigaction() for SIGCHLD we get the expected
+       behavior and the code in the select() loops already handles EINTR
+       correctly.
+       [9eba0115e35a]
+
+       * compat/getprogname.c:
+       progname should be const
+       [130228f062b7]
+
+       * plugins/sudoers/Makefile.in:
+       Move --tag=disable-static to when we link sudoers.la, not when we
+       install.
+       [ceb5e6c3b78b]
+
+       * src/load_plugins.c:
+       Load the sudoers I/O plugin by default too now that it is hooked up.
+       [ea38befd0742]
+
+2010-03-30  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/pty.c:
+       It looks like AIX doesn't need to push STREAMS modules for ptys.
+       [22da618ba0a1]
+
+2010-03-28  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/parse_args.c, src/sudo.c:
+       Delay calling the I/O plugin open function until the policy plugin
+       returns success.
+       [f3297c325b48]
+
+2010-03-27  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/Makefile.in, plugins/sudoers/iolog.c,
+       plugins/sudoers/set_perms.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h:
+       Add back io logging (transcript) support. Currently, the open
+       function runs too early and it is not possible to use the io module
+       independently of the policy module.
+       [9bd932f66226]
+
+       * plugins/sudoers/set_perms.c:
+       Comment out dead code; will be removed when set_perms is rewritten.
+       [af7a995284f8]
+
+2010-03-23  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/sudoers.c:
+       Fix off by one error when allocating user_groups.
+       [6281fcf9c3bb]
 
 2010-03-22  Todd C. Miller  <Todd.Miller@courtesan.com>
 
+       * configure, configure.in, plugins/sudoers/Makefile.in:
+       Add REPLAY_LIBS for sudoreplay and add -lrt to it on Solaris.
+       [fbce3e9eda3a]
+
+       * plugins/sudoers/sudoers.c:
+       Fix typo in preserve groups case
+       [1fd72024fb5a]
+
+       * plugins/sudoers/sudoers.c:
+       In command_info it is "runas_groups" not "groups".
+       [5c64dce4f285]
+
+       * src/sudo.c:
+       Fix iteration over runas_groups list.
+       [b3c45a0cd643]
+
+       * configure, configure.in, plugins/sudoers/env.c,
+       plugins/sudoers/match.c, src/script.c:
+       Merge 5177a284b9ff 549f8f7c2463 88f3181692fe from 1.7 branch.
+       [a8108a0776c2]
+
+       * compat/getgrouplist.c:
+       getgrouplist(3) for those without it
+       [4ab4d21e3b16]
+
+       * plugins/sudoers/sudoers.c:
+       Set preserve_groups or groups list in command_info
+       [1266119ad654]
+
+       * src/sudo.c:
+       Fix setting of groups list
+       [e75315e40bd4]
+
+       * config.h.in, configure, configure.in, include/compat.h,
+       include/missing.h:
+       Add checks for getgrset and getgrouplist and use replacement
+       getgrouplist if the system doesn't support it.
+       [a62b8ba50863]
+
+       * src/parse_args.c:
+       Pass in preserve_groups when the -P flag is specified as per the
+       design
+       [7420c5d15474]
+
+       * plugins/sudoers/sudoers.c:
+       Check preserve_groups and ignore_ticket args with atobool instead of
+       assuming they are true if present.
+       [71c905702697]
+
+2010-03-21  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/Makefile.in, plugins/sudoers/error.c,
+       plugins/sudoers/plugin_error.c:
+       Rename plugin-specific error.c to plugin_error.c Wire up visudo,
+       sudoreplay and testsudoers in the build
+       [9d581d5fa4d4]
+
+       * src/Makefile.in, src/term.c:
+       term.c does not needto include sudo.h
+       [f6683cdcd2dd]
+
+       * TODO, doc/sudo_plugin.cat, doc/sudo_plugin.man.in,
+       doc/sudo_plugin.pod:
+       Document the -2 return in the check_policy section too
+       [e9cb4c34bbcf]
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h,
+       src/parse_args.c, src/sudo.c, src/sudo.h:
+       Fix the -s and -i flags and add support for the "implied_shell"
+       option. If the user does not specify a command, sudo will now pass
+       in the path to the user's shell and set impied_shell=true. The
+       plugin can them either check the command normally or return -2 to
+       cause sudo to print a usage message and exit.
+       [bf889c38f229]
+
+2010-03-19  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * config.h.in, configure, configure.in, src/load_plugins.c:
+       Bring back SUDOERS_PLUGIN but add .dylib -> .so conversion for
+       Darwin where libraries end in .dylib but modules end in .so
+       [2c56aaa38e21]
+
+       * plugins/sudoers/parse.c:
+       Better prefix determination now that we can't rely on len==0 to tell
+       the beginning on an entry.
+       [622bf18179e9]
+
+       * plugins/sudoers/ldap.c:
+       display_bound_defaults() stub should return 0, not 1 since it is a
+       count, not a boolean.
+       [0327a6c3d55d]
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Document progname in settings
+       [42031d56a2e3]
+
+       * compat/getprogname.c, include/compat.h,
+       plugins/sample/sample_plugin.c, plugins/sudoers/sudoers.c,
+       src/parse_args.c, src/sudo.c:
+       Rewrite compat/getprogname.c and add setprogname(). The progname is
+       now passed to the plugin via the settings array.
+       [25d8663e6006]
+
+       * configure, configure.in, plugins/sudoers/Makefile.in:
+       Fix --with-ldap
+       [b64b633f426d]
+
+       * plugins/sudoers/sudo_nss.c:
+       Add missing whitespace for Runas and Command-specific defaults
+       [65f4ddf5545e]
+
+       * plugins/sudoers/ldap.c, plugins/sudoers/parse.c,
+       plugins/sudoers/sudo_nss.c:
+       Use embedded newlines in lbuf instead of multiple calls to
+       lbuf_print.
+       [eed3af9cc3e1]
+
+       * src/lbuf.c:
+       Add support for embedded newlines.
+       [e11f79b18deb]
+
+2010-03-18  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * compat/getprogname.c:
+       If system doesn't support getprogname or __programe and we are
+       building a shared object don't bother with Argc/Argv, just return
+       "sudo"
+       [aebde9062be7]
+
+       * config.h.in, configure, configure.in, src/load_plugins.c:
+       Hard-code sudoers.so instead of using SUDOERS_PLUGIN since libtool
+       appears to always install a shared object with the .so suffix.
+       [f9bbd0c0e9d3]
+
+       * compat/Makefile.in, configure, configure.in,
+       plugins/sample/Makefile.in, plugins/sudoers/Makefile.in,
+       src/Makefile.in:
+       Play more nicely with libtool and let it build libreplace (was
+       libmissing) for us.
+       [a4c6ebb2495c]
+
+       * include/missing.h:
+       Include stdarg.h for va_list rather than requiring all consumers of
+       missing.h to include stdarg.h themselves.
+       [37382df948de]
+
+       * include/lbuf.h, plugins/sudoers/auth/sudo_auth.c,
+       plugins/sudoers/check.c, plugins/sudoers/sudo_nss.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, src/lbuf.c,
+       src/parse_args.c:
+       Pass in output function to lbuf_init() instead of writing to stdout.
+       A side effect is that the usage info can now go to stderr as it
+       should.
+       [6d261261a072]
+
+2010-03-17  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * include/lbuf.h, plugins/sudoers/sudo_nss.c,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, src/lbuf.c,
+       src/parse_args.c, src/sudo.c:
+       Use number of tty columns that is passed in user_info instead of
+       getting it directly in the lbuf code.
+       [8a16635c2638]
+
+       * plugins/sudoers/alias.c, plugins/sudoers/auth/dce.c,
+       plugins/sudoers/auth/kerb5.c, plugins/sudoers/auth/pam.c,
+       plugins/sudoers/auth/sia.c, plugins/sudoers/auth/sudo_auth.h,
+       plugins/sudoers/check.c, plugins/sudoers/defaults.c,
+       plugins/sudoers/defaults.h, plugins/sudoers/env.c,
+       plugins/sudoers/getdate.c, plugins/sudoers/getdate.y,
+       plugins/sudoers/gram.c, plugins/sudoers/gram.y,
+       plugins/sudoers/interfaces.h, plugins/sudoers/logging.c,
+       plugins/sudoers/logging.h, plugins/sudoers/match.c,
+       plugins/sudoers/mon_systrace.h, plugins/sudoers/parse.c,
+       plugins/sudoers/parse.h, plugins/sudoers/pwutil.c,
+       plugins/sudoers/redblack.c, plugins/sudoers/redblack.h,
+       plugins/sudoers/set_perms.c, plugins/sudoers/sudo_nss.h,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h,
+       plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c,
+       plugins/sudoers/timestr.c, plugins/sudoers/toke.c,
+       plugins/sudoers/toke.l, plugins/sudoers/tsgetgrpw.c,
+       plugins/sudoers/visudo.c:
+       Kill __P in sudoers
+       [63601e6cb171]
+
+       * config.h.in, configure, configure.in, src/load_plugins.c:
+       Set the sudoers plugin name in configure so we get the extension
+       right.
+       [edad89924cd1]
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Document lines/cols in user_info
+       [a808872394f3]
+
+       * src/Makefile.in, src/sudo.c, src/sudo.h, src/ttysize.c:
+       Add tty size to user info
+       [23f3d27e77a7]
+
+       * src/script.c:
+       Use TIOCGSIZE/TIOCSSIZE instead of TIOCGWINSZ/TIOCSWINSZ
+       [a2208dd09051]
+
+2010-03-16  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/sudoers.c:
+       Kill dead code Add missing sigsetjmp in sudo_policy_invalidate Error
+       out if we fail to lookup the user's name that is passed in
+       [e4e3728ed482]
+
+       * plugins/sudoers/error.c:
+       Pass the error value back via siglongjmp.
+       [667b8ad575ce]
+
+       * plugins/sudoers/check.c:
+       Use conversation function for lecture.
+       [1ab4719f509b]
+
+       * plugins/sudoers/check.c:
+       Don't update ticket file if verify_user returns FALSE.
+       [2bbc46a39a2b]
+
+2010-03-15  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/sudoers.c, src/sudo.c:
+       Wire up invalidate and validate methods for sudoers
+       [c0630c7bca47]
+
+       * plugins/sudoers/check.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h:
+       Add support for -k flag with a command.
+       [edad239b098b]
+
+       * src/parse_args.c:
+       Allow -k to be specified with a command.
+       [43a45add9974]
+
+       * plugins/sudoers/sudoers.c:
+       Wire up policy_list
+       [27cc35699eca]
+
+       * plugins/sudoers/error.c:
+       Add newline at the end of message and space after the colon in
+       warning message
+       [5a591aa8e744]
+
+       * plugins/sudoers/auth/sudo_auth.c:
+       Add missing newline after pass password warning
+       [337dba3870a7]
+
+       * plugins/sudoers/sudoers.c:
+       Set user_groups and user_ngroups based on user_info
+       [61bee85128c8]
+
+       * plugins/sudoers/error.c:
+       Make this compile
+       [7041c441e1c8]
+
+       * plugins/sudoers/error.c, plugins/sudoers/sudoers.c:
+       Make _warning in error.c use the conversation function and remove
+       commented out warning/warningx in sudoers.c.
+       [7c9b09024b63]
+
+       * plugins/sudoers/logging.c:
+       Use siglongjmp() in log_error for fatal errors
+       [b50e26f1c73f]
+
+       * plugins/sample/Makefile.in, plugins/sudoers/Makefile.in:
+       Quiet a libtool warning
+       [b2331fb006bc]
+
+       * Makefile:
+       Build sudoers plugin
+       [5cdf06e66978]
+
+       * plugins/sudoers/gram.c, plugins/sudoers/gram.y:
+       Use warningx in yyerror() so the conversation function gets used
+       when built as part of sudoers.
+       [85f964215eef]
+
+2010-03-14  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sudoers/auth/pam.c:
+       Rename sudo_conv to conversation to avoid a namespace conflict.
+       [1ad359d36be9]
+
+       * plugins/sudoers/Makefile.in, plugins/sudoers/alias.c,
+       plugins/sudoers/auth/afs.c, plugins/sudoers/auth/aix_auth.c,
+       plugins/sudoers/auth/bsdauth.c, plugins/sudoers/auth/dce.c,
+       plugins/sudoers/auth/fwtk.c, plugins/sudoers/auth/kerb4.c,
+       plugins/sudoers/auth/kerb5.c, plugins/sudoers/auth/pam.c,
+       plugins/sudoers/auth/passwd.c, plugins/sudoers/auth/rfc1938.c,
+       plugins/sudoers/auth/secureware.c, plugins/sudoers/auth/securid.c,
+       plugins/sudoers/auth/securid5.c, plugins/sudoers/auth/sia.c,
+       plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/auth/sudo_auth.h,
+       plugins/sudoers/check.c, plugins/sudoers/defaults.c,
+       plugins/sudoers/env.c, plugins/sudoers/error.c,
+       plugins/sudoers/find_path.c, plugins/sudoers/getspwuid.c,
+       plugins/sudoers/goodpath.c, plugins/sudoers/gram.c,
+       plugins/sudoers/gram.y, plugins/sudoers/interfaces.c,
+       plugins/sudoers/ldap.c, plugins/sudoers/logging.c,
+       plugins/sudoers/match.c, plugins/sudoers/mon_systrace.c,
+       plugins/sudoers/parse.c, plugins/sudoers/pwutil.c,
+       plugins/sudoers/redblack.c, plugins/sudoers/set_perms.c,
+       plugins/sudoers/sudo_nss.c, plugins/sudoers/sudoers.c,
+       plugins/sudoers/sudoers.h, plugins/sudoers/testsudoers.c,
+       plugins/sudoers/toke.c, plugins/sudoers/tsgetgrpw.c,
+       plugins/sudoers/vasgroups.c, plugins/sudoers/visudo.c:
+       Initial bits of sudoers plugin; still needs work.
+       [af2a2c59a952]
+
+       * config.h.in:
+       Add HAVE_STRDUP and HAVE_STRNDUP
+       [50a3c0dd510f]
+
+       * compat/Makefile.in, configure, configure.in:
+       Build libmissing in two flavors (one PIC one non-PIC) and link with
+       the appropriate one.
+       [b62f411a4c18]
+
+       * Makefile, compat/fnmatch.c, compat/glob.c, compat/nanosleep.c,
+       compat/utimes.c, plugins/sample/Makefile.in, src/Makefile.in:
+       Build libmissing in two flavors (one PIC one non-PIC) and link with
+       the appropriate one.
+       [e1e04972b5fe]
+
+2010-03-13  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * include/missing.h:
+       Add strdup and strndup and fix strsignal
+       [c159babe2896]
+
+2010-03-12  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * compat/strdup.c, compat/strndup.c, configure, configure.in,
+       plugins/sample/Makefile.in, src/Makefile.in:
+       Add strdup and strndup to compat
+       [25c9fd399a4d]
+
+       * plugins/sample/sample_plugin.c:
+       Need to include compat.h before missing.h
+       [c94f7aad380f]
+
+       * compat/strsignal.c:
+       Must check HAVE_DECL_SYS_SIGLIST == 1 (not just if defined) since if
+       it doesn't exist configure will set it to 0.
+       [384580566389]
+
+       * compat/glob.c:
+       Fix botched ANSI C coversion of globexp2()
+       [4a344b8cbe49]
+
        * configure, configure.in:
-       Fix installation of sudoers.ldap in "make install" when --with-ldap
-       was specified without a directory. From Prof. Dr. Andreas Mueller
-       [5177a284b9ff] <1.7>
+       Remove redundant getgroups check
+       [0b16ec210c81]
+
+       * configure, configure.in, src/lbuf.c, src/script.c, src/term.c:
+       Require either termios or termio, no more sgtty.
+       [9b2fa2f17a1c]
+
+       * compat/strsignal.c, config.h.in, configure, configure.in:
+       Change the sys_siglist check to use AC_CHECK_DECLS and also check
+       for _sys_siglist and__sys_siglist
+       [2e078fed2408]
+
+2010-03-11  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * configure, configure.in, src/Makefile.in:
+       Change SUDO_LDFLAGS to SUDOERS_LDFLAGS and add SUDOERS_OBJS. We now
+       use SUDO_OBJS for the main driver as part of OBJS.
+       [9ae4a80a5ade]
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Mention in the conversation function section that a newline is not
+       implicit.
+       [04a233b6c491]
+
+       * include/compat.h:
+       Add definition of WCOREDUMP for systems without it. This is known
+       to work on AIX and SunOS 4, but may be incorrect on other systems
+       that lack WCOREDUMP.
+       [c85b3ce6b77d]
 
 2010-03-09  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * match.c:
-       When doing a glob match, short circuit if gl.gl_pathc is 0. From
-       Mark Kettenis.
-       [549f8f7c2463] <1.7>
+       * plugins/sample/sample_plugin.c, src/conversation.c:
+       conversation function no longer puts a newline at the end of info or
+       error messages.
+       [c534cae1ac4a]
 
-2010-03-08  Todd C. Miller  <Todd.Miller@courtesan.com>
+2010-03-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-       * script.c:
+       * src/script.c:
        Use parent process group id instead of parent process id when
        checking foreground status and suspending parent. Fixes an issue
        when running commands under /usr/bin/time and others.
-       [eac86126e335] <1.7>
+       [564f528c3bb7]
 
-       * env.c:
-       In setenv(), if the var is empty, return 1 and set errno to EINVAL
-       instead of returning EINVAL directly.
-       [d202091ec15e] <1.7>
+2010-03-06  Todd C. Miller  <Todd.Miller@courtesan.com>
 
-2010-02-22  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * aclocal.m4:
+       transcript option is now --with not --enable
+       [0646fac4cf93]
 
-       * match.c:
-       Check for pseudo-command by looking at the first character of the
-       command in sudoers instead of checking the user-supplied command for
-       a slash.
-       [88f3181692fe] <1.7>
+       * plugins/sample/sample_plugin.c:
+       Add support to -u and -g flags Check fmt_string retval Add timeout
+       for debugging purposes
+       [cfefa4fa60b5]
 
-2010-02-09  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * src/script.c, src/sudo.c:
+       Wire up SIGALRM handler Set close on exec flag for child side of the
+       socketpair Fix signal handling when not doing I/O logging
+       [379581ec7272]
 
-       * toke.l:
-       Avoid a duplicate fclose() of the sudoers file.
-       [164d39108dde] <1.7>
+       * src/sudo.c:
+       g/c unused SIGCHLD handler
+       [0afa03912dce]
 
-       * toke.l:
-       Fix size arg when realloc()ing include stack. From Daniel Kopecek
-       [8900bccef219] <1.7>
+       * src/fmt_string.c, src/parse_args.c, src/sudo.c:
+       Don't use emalloc() in fmt_string(); we want to be able to use it
+       from a plugin.
+       [ade64d368147]
+
+       * include/list.h:
+       tq_remove not list_remove
+       [0e0e1fd5c31c]
+
+       * configure, configure.in:
+       AUTH_OBJS should contain .lo files not .o files.
+       [c64c82c9d5a2]
+
+2010-03-05  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/parse_args.c:
+       Simplify conversion of command line args to name=value pairs.
+       [75ab127c6a94]
+
+       * plugins/sample/sample_plugin.c:
+       Handle NULL reply from conversation function
+       [6ce09b6cb204]
+
+       * compat/getline.c:
+       Don't depend on emalloc/erealloc
+       [73df09e2109f]
+
+       * plugins/sample/Makefile.in:
+       Use $(OBJS) instead of sample_plugin.lo
+       [2d995db9aa99]
 
-2010-02-06  Todd C. Miller  <Todd.Miller@courtesan.com>
+       * plugins/sample/sample_plugin.c:
+       runas_user is in settings not user_info
+       [7ee12068bc57]
+
+       * src/parse_args.c:
+       Fix a mismatch between sudo_settings and settings_pairs that causes
+       some settings to get the wrong values.
+       [b1bc6d81a65f]
+
+2010-03-04  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/Makefile.in, src/aix.c, src/alloc.c, src/atobool.c, src/error.c,
+       src/fileops.c, src/lbuf.c, src/list.c, src/pty.c, src/sesh.c,
+       src/sudo.c, src/sudo_edit.c, src/term.c, src/zero_bytes.c:
+       Convert to ANSI C
+       [d03b6e4a3b75]
+
+       * src/load_plugins.c:
+       Fix strlcpy() return value check.
+       [7cd66999a374]
+
+       * INSTALL, configure, configure.in:
+       No longer need to substitute in script.o and pty.o; I/O logging
+       support is always built.
+       [45250024c5dc]
 
-       * aix.c, config.h.in, configure, configure.in:
-       Use setrlimit64(), if available, instead of setrlimit() when setting
+2010-02-28  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/script.c:
+       Add fallback to /bin/sh when execve() fails with ENOEXEC.
+       [7684a15a1352]
+
+       * include/alloc.h, src/alloc.c:
+       Add estrndup()
+       [47621c83bed9]
+
+2010-02-27  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/script.c, src/sudo.c:
+       Refactor script_execve() a bit so that it can be used in non-script
+       mode. Needs more cleanup.
+       [f09e022d547c]
+
+       * src/sudo.c:
+       Ignore empty entries in command_info list
+       [1eea9a8de21c]
+
+       * include/list.h, src/list.c:
+       Add tq_remove
+       [40908a617cb2]
+
+       * src/conversation.c:
+       Pass timeout to tgetpass()
+       [9e66c918b771]
+
+       * Makefile:
+       Add ChangeLog target
+       [da4a39150838]
+
+       * README, WHATSNEW:
+       Bump version and update things slightly for sudo 1.8.0
+       [4b73cc45e2d4]
+
+       * configure, configure.in:
+       Sudo now requires an ANSI/ISO C compiler
+       [1e51f72e6964]
+
+       * src/alloc.c, src/audit.c, src/error.c, src/lbuf.c,
+       src/sudo_noexec.c:
+       Convert to ANSI C
+       [5cbd315dbde8]
+
+       * include/alloc.h, include/compat.h, include/error.h, include/lbuf.h,
+       include/list.h, include/missing.h:
+       Convert to ANSI C
+       [3f5016ff64f4]
+
+       * compat/charclass.h, compat/closefrom.c, compat/fnmatch.c,
+       compat/fnmatch.h, compat/getcwd.c, compat/getline.c,
+       compat/getprogname.c, compat/glob.c, compat/glob.h,
+       compat/isblank.c, compat/memrchr.c, compat/mkstemp.c,
+       compat/nanosleep.c, compat/sigaction.c, compat/snprintf.c,
+       compat/strcasecmp.c, compat/strerror.c, compat/strlcat.c,
+       compat/strlcpy.c, compat/strsignal.c, compat/utime.h,
+       compat/utimes.c:
+       Convert to ANSI C
+       [0d635c85461c]
+
+2010-02-24  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/sudo.c, src/tgetpass.c:
+       Make user_details extern so tgetpass can get at the uid and gid. Set
+       uid/gid to user before executing askpass program. Check environment
+       for SUDO_ASKPASS and use that if set. TODO: a way for the policy to
+       set the askpass program itself
+       [d33606396176]
+
+       * src/sudo.c:
+       No longer need sudo_usage.h in sudo.c
+       [063e2946c382]
+
+       * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod, doc/sudo_plugin.man.in,
+       doc/sudo_plugin.pod, src/Makefile.in, src/parse_args.c,
+       src/sudo_usage.h.in:
+       Document -D level command line flag which maps to the debug_level
+       setting.
+       [61f1e2ab3ac1]
+
+       * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Document debug_level in plugin doc. Still need to document the -D
+       flag in sudo itself.
+       [8c62daea3e9b]
+
+2010-02-21  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * plugins/sample/sample_plugin.c:
+       include missing,h for vasprintf
+       [92503de49b39]
+
+       * doc/Makefile.in, doc/plugin.pod, doc/sudo_plugin.cat,
+       doc/sudo_plugin.man.in, doc/sudo_plugin.pod:
+       Rename plugin.pod -> sudo_plugin.pod and wire into Makefile
+       [14cfb4775238]
+
+       * plugins/sample/sample_plugin.c:
+       Need to include limits.h
+       [bda7f74343d2]
+
+       * compat/glob.c:
+       No more sudo_getpw*
+       [232e52907634]
+
+       * plugins/sample/Makefile.in, src/Makefile.in:
+       Add missing compat bits
+       [4843dd000e08]
+
+       * compat/closefrom.c, compat/mkstemp.c, plugins/sample/Makefile.in:
+       compat files should not include sudo.h wire up compat in sample
+       plugin
+       [a175b8185e0f]
+
+       * Makefile, configure, configure.in, doc/Makefile.in, src/Makefile.in:
+       Fix up compat dependencies. Fix distclean target in doc/Makefile.in
+       [57e49bc20857]
+
+       * configure, configure.in:
+       Fix typo
+       [333655e3d5fe]
+
+       * plugins/sample/sample_plugin.c:
+       Log input and output to temp files for proof of concept.
+       [ae1dfc34f7d6]
+
+       * Makefile, configure, configure.in, doc/Makefile.in:
+       Add doc Makefile.in and wire it up
+       [6a310443c87d]
+
+       * src/script.c:
+       Handle SIGSTOP in addition to SIGTSTP. Fixes a problem with
+       suspending a shell with the "suspend" builtint.
+       [3d65f182819a]
+
+       * src/script.c:
+       In child, handle parent side of the pipe going away.
+       [a29c14d78cd9]
+
+       * src/script.c:
+       No longer need to check for explicit death of the child (process #2)
+       since if it dies we will get EPIPE from the socketpair. Fix a
+       sizeof() that was causing a spurious error. Convert SCRIPT_DEBUG to
+       sudo_debug.
+       [24c55dd4ff60]
+
+       * src/sudo.c:
+       Make sudo_debug do a single vfprintf() which will result in a single
+       write call on most systems. Avoids problems with interleaved debug
+       printf from different processes. Also remove an extraneous error
+       case since recv() can't return a short read and add some more XXX.
+       [b37a8533ef1e]
+
+2010-02-20  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * src/script.c:
+       Fix uninitialized variable.
+       [e012a0a30890]
+
+       * src/Makefile.in:
+       Fix sudo install target
+       [1417fa4b4ab9]
+
+       * src/parse_args.c, src/sudo.c, src/sudo.h:
+       Wire up debug_level
+       [144fab289c73]
+
+       * src/Makefile.in:
+       Fix dependencies
+       [5170940af2ce]
+
+       * configure, configure.in:
+       Fix setting of plugin dir
+       [144eda170a72]
+
+       * Makefile:
+       add clean targets
+       [d53f6f6f5c3a]
+
+       * src/atobool.c:
+       Add missing source for sudo front end
+       [42487de9c489]
+
+       * plugins/sample/Makefile.in, plugins/sample/sample_plugin.c:
+       Sample plugin demonstrating the sudo plugin API
+       [f1fd62d7644f]
+
+       * Makefile, configure, configure.in, install-sh, pathnames.h.in,
+       plugins/sudoers/install-sh, src/Makefile.in, src/conversation.c,
+       src/fileops.c, src/fmt_string.c, src/load_plugins.c,
+       src/parse_args.c, src/pty.c, src/script.c, src/sudo.c, src/sudo.h,
+       src/sudo_plugin_int.h, src/sudo_usage.h.in, src/tgetpass.c,
+       sudo_usage.h.in:
+       Modular sudo front-end which loads policy and I/O plugins that do
+       most the actual work. Currently relies on dynamic loading using
+       dlopen(). See doc/plugin.pod for the plugin API.
+       [924f6eb2fbba]
+
+       * doc/plugin.pod, include/sudo_plugin.h:
+       Sudo plugin API
+       [374ccbbd24ae]
+
+       * compat/fnmatch.c, compat/glob.c, compat/nanosleep.c,
+       compat/utimes.c, plugins/sudoers/check.c, plugins/sudoers/gettime.c,
+       plugins/sudoers/match.c, plugins/sudoers/sudoreplay.c,
+       plugins/sudoers/testsudoers.c, plugins/sudoers/visudo.c,
+       src/fileops.c, src/sudo_edit.c:
+       Replace emul/include.h with compat/include.h to match new source
+       tree layout.
+       [7eccd10449a1]
+
+       * src/lbuf.c:
+       Include missing.h for memrchr() proto
+       [03abd63a8a33]
+
+       * HISTORY, LICENSE, Makefile.binary.in, Makefile.in, PORTING,
+       TROUBLESHOOTING, UPGRADE, aix.c, aixcrypt.exp, alias.c, alloc.c,
+       alloc.h, audit.c, 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, boottime.c, bsm_audit.c, bsm_audit.h, check.c,
+       closefrom.c, compat.h, compat/charclass.h, compat/closefrom.c,
+       compat/fnmatch.c, compat/fnmatch.h, compat/getcwd.c,
+       compat/getline.c, compat/getprogname.c, compat/glob.c,
+       compat/glob.h, compat/isblank.c, compat/memrchr.c, compat/mkstemp.c,
+       compat/nanosleep.c, compat/sigaction.c, compat/snprintf.c,
+       compat/strcasecmp.c, compat/strerror.c, compat/strlcat.c,
+       compat/strlcpy.c, compat/strsignal.c, compat/timespec.h,
+       compat/utime.h, compat/utimes.c, def_data.c, def_data.h,
+       def_data.in, defaults.c, defaults.h, doc/HISTORY, doc/LICENSE,
+       doc/PORTING, doc/TROUBLESHOOTING, doc/UPGRADE, doc/history.pod,
+       doc/license.pod, doc/sample.pam, doc/sample.sudoers,
+       doc/sample.syslog.conf, doc/schema.ActiveDirectory,
+       doc/schema.OpenLDAP, doc/schema.iPlanet, doc/sudo.cat,
+       doc/sudo.man.in, doc/sudo.man.pl, doc/sudo.pod, doc/sudoers.cat,
+       doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in, doc/sudoers.ldap.pod,
+       doc/sudoers.man.in, doc/sudoers.man.pl, doc/sudoers.pod,
+       doc/sudoreplay.cat, doc/sudoreplay.man.in, doc/sudoreplay.pod,
+       doc/visudo.cat, doc/visudo.man.in, doc/visudo.pod, emul/charclass.h,
+       emul/fnmatch.h, emul/glob.h, emul/timespec.h, emul/utime.h, env.c,
+       error.c, error.h, fileops.c, find_path.c, fnmatch.c, getcwd.c,
+       getdate.c, getdate.y, getline.c, getprogname.c, getspwuid.c,
+       gettime.c, glob.c, goodpath.c, gram.c, gram.h, gram.y, history.pod,
+       include/alloc.h, include/compat.h, include/error.h, include/lbuf.h,
+       include/list.h, include/missing.h, ins_2001.h, ins_classic.h,
+       ins_csops.h, ins_goons.h, install-sh, insults.h, interfaces.c,
+       interfaces.h, isblank.c, lbuf.c, lbuf.h, ldap.c, license.pod,
+       list.c, list.h, logging.c, logging.h, match.c, memrchr.c, missing.h,
+       mkdefaults, mkstemp.c, mon_systrace.c, mon_systrace.h, nanosleep.c,
+       nonunix.h, parse.c, parse.h, plugins/sudoers/Makefile.binary.in,
+       plugins/sudoers/Makefile.in, plugins/sudoers/aixcrypt.exp,
+       plugins/sudoers/alias.c, plugins/sudoers/auth/API,
+       plugins/sudoers/auth/afs.c, plugins/sudoers/auth/aix_auth.c,
+       plugins/sudoers/auth/bsdauth.c, plugins/sudoers/auth/dce.c,
+       plugins/sudoers/auth/fwtk.c, plugins/sudoers/auth/kerb4.c,
+       plugins/sudoers/auth/kerb5.c, plugins/sudoers/auth/pam.c,
+       plugins/sudoers/auth/passwd.c, plugins/sudoers/auth/rfc1938.c,
+       plugins/sudoers/auth/secureware.c, plugins/sudoers/auth/securid.c,
+       plugins/sudoers/auth/securid5.c, plugins/sudoers/auth/sia.c,
+       plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/auth/sudo_auth.h,
+       plugins/sudoers/boottime.c, plugins/sudoers/check.c,
+       plugins/sudoers/def_data.c, plugins/sudoers/def_data.h,
+       plugins/sudoers/def_data.in, plugins/sudoers/defaults.c,
+       plugins/sudoers/defaults.h, plugins/sudoers/env.c,
+       plugins/sudoers/find_path.c, plugins/sudoers/getdate.c,
+       plugins/sudoers/getdate.y, plugins/sudoers/getspwuid.c,
+       plugins/sudoers/gettime.c, plugins/sudoers/goodpath.c,
+       plugins/sudoers/gram.c, plugins/sudoers/gram.h,
+       plugins/sudoers/gram.y, plugins/sudoers/ins_2001.h,
+       plugins/sudoers/ins_classic.h, plugins/sudoers/ins_csops.h,
+       plugins/sudoers/ins_goons.h, plugins/sudoers/install-sh,
+       plugins/sudoers/insults.h, plugins/sudoers/interfaces.c,
+       plugins/sudoers/interfaces.h, plugins/sudoers/ldap.c,
+       plugins/sudoers/logging.c, plugins/sudoers/logging.h,
+       plugins/sudoers/match.c, plugins/sudoers/mkdefaults,
+       plugins/sudoers/mon_systrace.c, plugins/sudoers/mon_systrace.h,
+       plugins/sudoers/nonunix.h, plugins/sudoers/parse.c,
+       plugins/sudoers/parse.h, plugins/sudoers/pwutil.c,
+       plugins/sudoers/redblack.c, plugins/sudoers/redblack.h,
+       plugins/sudoers/set_perms.c, plugins/sudoers/sudo_nss.c,
+       plugins/sudoers/sudo_nss.h, plugins/sudoers/sudoers,
+       plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h,
+       plugins/sudoers/sudoers2ldif, plugins/sudoers/sudoreplay.c,
+       plugins/sudoers/testsudoers.c, plugins/sudoers/timestr.c,
+       plugins/sudoers/toke.c, plugins/sudoers/toke.l,
+       plugins/sudoers/tsgetgrpw.c, plugins/sudoers/vasgroups.c,
+       plugins/sudoers/visudo.c, pty.c, pwutil.c, redblack.c, redblack.h,
+       sample.pam, sample.sudoers, sample.syslog.conf,
+       schema.ActiveDirectory, schema.OpenLDAP, schema.iPlanet, script.c,
+       selinux.c, sesh.c, set_perms.c, sigaction.c, snprintf.c, src/aix.c,
+       src/alloc.c, src/audit.c, src/bsm_audit.c, src/bsm_audit.h,
+       src/error.c, src/fileops.c, src/lbuf.c, src/list.c, src/pty.c,
+       src/script.c, src/selinux.c, src/sesh.c, src/sudo_edit.c,
+       src/sudo_noexec.c, src/term.c, src/tgetpass.c, src/zero_bytes.c,
+       strcasecmp.c, strerror.c, strlcat.c, strlcpy.c, strsignal.c, sudo.c,
+       sudo.cat, sudo.h, sudo.man.in, sudo.man.pl, sudo.pod, sudo_edit.c,
+       sudo_noexec.c, sudo_nss.c, sudo_nss.h, sudoers, sudoers.cat,
+       sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.ldap.pod,
+       sudoers.man.in, sudoers.man.pl, sudoers.pod, sudoers2ldif,
+       sudoreplay.c, sudoreplay.cat, sudoreplay.man.in, sudoreplay.pod,
+       term.c, testsudoers.c, tgetpass.c, timestr.c, toke.c, toke.l,
+       tsgetgrpw.c, utimes.c, vasgroups.c, visudo.c, visudo.cat,
+       visudo.man.in, visudo.pod, zero_bytes.c:
+       Rework source layout in preparation for modular sudo.
+       [7fc1978c6ad5]
+
+2010-02-13  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Avoid a duplicate fclose() of the sudoers file.
+       [5dba851088c1]
+
+       * Fix size arg when realloc()ing include stack. From Daniel Kopecek
+       [0a2935061e33]
+
+       * Use setrlimit64(), if available, instead of setrlimit() when setting
        AIX resource limits since rlim_t is 32bits.
-       [2cbb14d98fc1] <1.7>
+       [353db89bac61]
 
-       * logging.c:
-       Fix use after free when sending error messages. From Timo Juhani
+       * Fix use after free when sending error messages. From Timo Juhani
        Lindfors
-       [caf183fd9d94] <1.7>
-
-2010-01-18  Todd C. Miller  <Todd.Miller@courtesan.com>
+       [e50dbd902382]
 
        * ChangeLog, Makefile.in:
        Generate the ChangeLog as part of "make dist" instead of having it
        in the repo.
-       [836c31615859] <1.7>
-
-2010-01-17  Todd C. Miller  <Todd.Miller@courtesan.com>
-
-       * Makefile.in:
-       Generate correct ChangeLog for 1.7 branch.
-       [586dd90b8878] <1.7>
+       [251b70964673]
 
 2010-01-17  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        Remove CVS $Sudo$ tags.
        [de683a8b31f5]
 
+2010-01-18  convert-repo  <convert-repo>
+
+       * .hgtags:
+       update tags
+       [9b7aa44ae436]
+
 2009-12-26  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudo_usage.h.in:
diff --git a/HISTORY b/HISTORY
deleted file mode 100644 (file)
index 63c7f9f..0000000
--- a/HISTORY
+++ /dev/null
@@ -1,56 +0,0 @@
-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 had 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 2003, Nationwide Mutual Insurance Company contributed code written by
-Aaron Spangler to store the sudoers data in LDAP. These changes were
-incorporated into Sudo 1.6.8.
-
-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.
-
-In 2010, Quest Software began sponsoring Sudo development by hiring Todd to
-work on Sudo as part of his full-time job.
-
-sudo, in its current form, is maintained by:
-
-        Todd Miller <Todd.Miller@courtesan.com>
-
-Todd continues to enhance sudo and fix bugs.
-
diff --git a/INSTALL b/INSTALL
index d9568d3ff270afe68a776cb9e573731438bf9efb..b8156e64c7c0d5365af9be933c88fef6b580865c 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -1,4 +1,4 @@
-Installation instructions for Sudo 1.7
+Installation instructions for Sudo 1.8
 ======================================
 
 Sudo uses a `configure' script to probe the capabilities and type
@@ -30,13 +30,13 @@ For most systems and configurations it is possible simply to:
        have changed the paths via options to `configure'.
 
     5) Type `make' to compile sudo.  If you are building sudo
-       in a separate build tree (apart from the sudo source)
-       GNU make will probably be required.  If `configure' did
-       its job properly (and you have a supported configuration)
-       there won't be any problems.  If this doesn't work, take
-       a look at the files TROUBLESHOOTING and PORTING for tips
-       on what might have gone wrong.  Please mail us if you have a
-       fix or if you are unable to come up with a fix (address at EOF).
+       in a separate build tree (apart from the sudo source) GNU
+       make will probably be required.  If `configure' did its job
+       properly (and you have a supported configuration) there won't
+       be any problems.  If this doesn't work, take a look at the
+       TROUBLESHOOTING file for tips on what might have gone wrong.
+       Please mail us if you have a fix or if you are unable to
+       come up with a fix (address at EOF).
 
     6) Type `make install' (as root) to install sudo, visudo, the
        man pages, and a skeleton sudoers file.  Note that the install
@@ -134,6 +134,10 @@ Special features/options:
        `-l' will be prepended to it.  Multiple libraries may be
        specified as long as they are space separated.
 
+  --with-plugindir=PATH
+       Set the directory that sudo looks in to find the policy and I/O
+       logging plugins.  Defaults to the libexec dir used by configure.
+
   --with-efence
        Link with the "electric fence" debugging malloc.
 
@@ -141,13 +145,18 @@ Special features/options:
        Enable support for sudo BSM audit logs on systems that support
        it.  Currently only supported under FreeBSD and Mac OS X.
 
+  --with-csops
+       Add CSOps standard options.  You probably aren't interested in this.
+
+  --with-devel
+        Configure development options.  This will enable compiler warnings
+       and set the Makefile to be able to regenerate the sudoers parser
+       as well as the manual pages.
+
   --with-linux-audit
        Enable audit support for Linux systems.  Audits attempts
        to run a command as well as SELinux role changes.
 
-  --with-csops
-       Add CSOps standard options.  You probably aren't interested in this.
-
   --with-skey[=DIR]
        Enable S/Key OTP (One Time Password) support.  If specified,
        DIR should contain include and lib directories with skey.h
@@ -346,16 +355,6 @@ Special features/options:
        Enable support for role based access control (RBAC) on
        systems that support SELinux.
 
-  --with-libvas=[NAME]
-        Enable non-Unix group support using Quest Authentication
-        Services.  If NAME is specified, it should be the name of
-       the shared library providing QAS support (libvas.so by default).
-
-  --with-libvas-rpath=[PATH]
-       The path to search when loading libvas.so (or an alternate
-       name as specified by --with-libvas).  This option only has
-       an effect when --with-libvas is specified.
-
 The following options are also configurable at runtime:
 
   --with-long-otp-prompt
@@ -567,15 +566,11 @@ The following options are also configurable at runtime:
         prompt as an argument and print the received password to
         the standard output.
 
-  --without-iologdir
-       Disable sudo's I/O logging support.  This can be used to allow sudo
-       to be compiled on systems without pseudo-tty support.
-
   --with-iologdir[=DIR]
-       By default, sudo stores I/O log files in either /var/log/sudo-io,
-       /var/adm/sudo-sudo-io or /usr/log/sudo-io.  If DIR is
-       specified, I/O logs will be stored in the indicated directory
-       instead.
+        By default, sudo stores I/O log files in either /var/log/sudo-io,
+        /var/adm/sudo-io, or /usr/log/sudo-io.  If this option is
+        specified, I/O logs will be stored in the indicated directory
+        instead.
 
   --disable-authentication
        By default, sudo requires the user to authenticate via a
@@ -619,15 +614,14 @@ The following options are also configurable at runtime:
        the user that they are not allowed to run it, which can be confusing.
 
   --enable-zlib[=location]
-        Enable the use of the zlib compress library when storing
-        I/O log files.  If specified, location is the base directory
-        containing the zlib include and lib directories.  The special
-        values "system" and "builtin" can be used to indicate that
-        the system version of zlib should be used or that the version
-        of zlib shipped with sudo should be used instead.
-        If this option is not specified, configure will use the
-        system zlib if it is present and I/O logging support has
-        not been disabled.
+       Enable the use of the zlib compress library when storing
+       I/O log files.  If specified, location is the base directory
+       containing the zlib include and lib directories.  The special
+       values "system" and "builtin" can be used to indicate that
+       the system version of zlib should be used or that the version
+       of zlib shipped with sudo should be used instead.
+       If this option is not specified, configure will use the
+       system zlib if it is present.
 
   --disable-zlib
         Disable the use of the zlib compress library when storing
@@ -725,11 +719,9 @@ Mac OS X:
     is bug id #7952709.
 
 HP-UX:
-    The default C compiler shipped with HP-UX does not support
-    creating position independent code and so is unable to support
-    sudo's "noexec" functionality.  You must use either the HP ANSI
-    C compiler or gcc for noexec to work.  Binary packages of gcc
-    are available http://hpux.connect.org.uk/.
+    The default C compiler shipped with HP-UX is not an ANSI compiler.
+    You must use either the HP ANSI C compiler or gcc to build sudo.
+    Binary packages of gcc are available from http://hpux.connect.org.uk/.
 
     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:
@@ -765,12 +757,18 @@ SCO ODT:
     and /SLS/lng225b.ltr.Z.
 
 SunOS 4.x:
+    SunOS does not ship with an ANSI C compiler.  You will need to
+    install an ANSI compiler such as gcc to build sudo.
+
     The /bin/sh shipped with SunOS blows up while running configure.
     You can work around this by installing bash or zsh.  If you
     have bash or zsh in your path, configure will use it instead
     automatically.
 
 ULTRIX 4.x:
+    ULTRIX does not ship with an ANSI C compiler.  You will need to
+    install an ANSI compiler such as gcc to build sudo.
+
     The /bin/sh shipped with ULTRIX blows up while running configure.
     You can work around this by installing bash or zsh.  If you
     have bash or zsh in your path, configure will use it instead
diff --git a/LICENSE b/LICENSE
deleted file mode 100644 (file)
index 2af4e0f..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,101 +0,0 @@
-Sudo is distributed under the following ISC-style license:
-
-   Copyright (c) 1994-1996, 1998-2011
-        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.
-
-The files 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.
-
-   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.
-
-The files nonunix.h and vasgroups.c bear the following license:
-
-   Copyright (c) 2006 Quest Software, Inc.  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. Neither the name of Quest Software, Inc. 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 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.
-
-The embedded copy of zlib bears the following license:
-
-  Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Jean-loup Gailly        Mark Adler
-  jloup@gzip.org          madler@alumni.caltech.edu
diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..f50d03e
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,279 @@
+ChangeLog
+INSTALL
+INSTALL.configure
+MANIFEST
+Makefile.in
+NEWS
+README
+README.LDAP
+aclocal.m4
+common/Makefile.in
+common/aix.c
+common/alloc.c
+common/atobool.c
+common/fileops.c
+common/fmt_string.c
+common/lbuf.c
+common/list.c
+common/term.c
+common/zero_bytes.c
+compat/Makefile.in
+compat/charclass.h
+compat/closefrom.c
+compat/dlfcn.h
+compat/dlopen.c
+compat/fnmatch.c
+compat/fnmatch.h
+compat/getcwd.c
+compat/getline.c
+compat/getprogname.c
+compat/glob.c
+compat/glob.h
+compat/isblank.c
+compat/memrchr.c
+compat/mksiglist.c
+compat/mksiglist.h
+compat/mktemp.c
+compat/nanosleep.c
+compat/regress/fnmatch/fnm_test.c
+compat/regress/fnmatch/fnm_test.in
+compat/regress/glob/files
+compat/regress/glob/globtest.c
+compat/regress/glob/globtest.in
+compat/setenv.c
+compat/siglist.in
+compat/snprintf.c
+compat/strlcat.c
+compat/strlcpy.c
+compat/strsignal.c
+compat/timespec.h
+compat/unsetenv.c
+compat/utime.h
+compat/utimes.c
+config.guess
+config.h.in
+config.sub
+configure
+configure.in
+doc/HISTORY
+doc/LICENSE
+doc/Makefile.in
+doc/TROUBLESHOOTING
+doc/UPGRADE
+doc/history.pod
+doc/license.pod
+doc/sample.pam
+doc/sample.sudo.conf
+doc/sample.sudoers
+doc/sample.syslog.conf
+doc/schema.ActiveDirectory
+doc/schema.OpenLDAP
+doc/schema.iPlanet
+doc/sudo.cat
+doc/sudo.man.in
+doc/sudo.man.pl
+doc/sudo.pod
+doc/sudo_plugin.cat
+doc/sudo_plugin.man.in
+doc/sudo_plugin.pod
+doc/sudoers.cat
+doc/sudoers.ldap.cat
+doc/sudoers.ldap.man.in
+doc/sudoers.ldap.pod
+doc/sudoers.man.in
+doc/sudoers.man.pl
+doc/sudoers.pod
+doc/sudoreplay.cat
+doc/sudoreplay.man.in
+doc/sudoreplay.pod
+doc/visudo.cat
+doc/visudo.man.in
+doc/visudo.pod
+include/Makefile.in
+include/alloc.h
+include/error.h
+include/fileops.h
+include/lbuf.h
+include/list.h
+include/missing.h
+include/sudo_plugin.h
+indent.pro
+install-sh
+ltmain.sh
+m4/libtool.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+m4/lt~obsolete.m4
+mkinstalldirs
+mkpkg
+pathnames.h.in
+plugins/sample/Makefile.in
+plugins/sample/sample_plugin.c
+plugins/sample/sample_plugin.sym
+plugins/sample_group/Makefile.in
+plugins/sample_group/getgrent.c
+plugins/sample_group/plugin_test.c
+plugins/sample_group/sample_group.c
+plugins/sample_group/sample_group.sym
+plugins/sudoers/Makefile.in
+plugins/sudoers/aixcrypt.exp
+plugins/sudoers/alias.c
+plugins/sudoers/audit.c
+plugins/sudoers/auth/API
+plugins/sudoers/auth/afs.c
+plugins/sudoers/auth/aix_auth.c
+plugins/sudoers/auth/bsdauth.c
+plugins/sudoers/auth/dce.c
+plugins/sudoers/auth/fwtk.c
+plugins/sudoers/auth/kerb4.c
+plugins/sudoers/auth/kerb5.c
+plugins/sudoers/auth/pam.c
+plugins/sudoers/auth/passwd.c
+plugins/sudoers/auth/rfc1938.c
+plugins/sudoers/auth/secureware.c
+plugins/sudoers/auth/securid.c
+plugins/sudoers/auth/securid5.c
+plugins/sudoers/auth/sia.c
+plugins/sudoers/auth/sudo_auth.c
+plugins/sudoers/auth/sudo_auth.h
+plugins/sudoers/boottime.c
+plugins/sudoers/bsm_audit.c
+plugins/sudoers/bsm_audit.h
+plugins/sudoers/check.c
+plugins/sudoers/def_data.c
+plugins/sudoers/def_data.h
+plugins/sudoers/def_data.in
+plugins/sudoers/defaults.c
+plugins/sudoers/defaults.h
+plugins/sudoers/env.c
+plugins/sudoers/find_path.c
+plugins/sudoers/getdate.c
+plugins/sudoers/getdate.y
+plugins/sudoers/getspwuid.c
+plugins/sudoers/goodpath.c
+plugins/sudoers/gram.c
+plugins/sudoers/gram.h
+plugins/sudoers/gram.y
+plugins/sudoers/group_plugin.c
+plugins/sudoers/ins_2001.h
+plugins/sudoers/ins_classic.h
+plugins/sudoers/ins_csops.h
+plugins/sudoers/ins_goons.h
+plugins/sudoers/insults.h
+plugins/sudoers/interfaces.c
+plugins/sudoers/interfaces.h
+plugins/sudoers/iolog.c
+plugins/sudoers/iolog_path.c
+plugins/sudoers/ldap.c
+plugins/sudoers/linux_audit.c
+plugins/sudoers/linux_audit.h
+plugins/sudoers/logging.c
+plugins/sudoers/logging.h
+plugins/sudoers/match.c
+plugins/sudoers/mkdefaults
+plugins/sudoers/parse.c
+plugins/sudoers/parse.h
+plugins/sudoers/plugin_error.c
+plugins/sudoers/pwutil.c
+plugins/sudoers/redblack.c
+plugins/sudoers/redblack.h
+plugins/sudoers/regress/iolog_path/check_iolog_path.c
+plugins/sudoers/regress/iolog_path/data
+plugins/sudoers/regress/parser/check_fill.c
+plugins/sudoers/regress/sudoers/test1.in
+plugins/sudoers/regress/sudoers/test1.out.ok
+plugins/sudoers/regress/sudoers/test1.toke.ok
+plugins/sudoers/regress/sudoers/test2.in
+plugins/sudoers/regress/sudoers/test2.out.ok
+plugins/sudoers/regress/sudoers/test2.toke.ok
+plugins/sudoers/regress/sudoers/test3.in
+plugins/sudoers/regress/sudoers/test3.out.ok
+plugins/sudoers/regress/sudoers/test3.toke.ok
+plugins/sudoers/regress/sudoers/test4.in
+plugins/sudoers/regress/sudoers/test4.out.ok
+plugins/sudoers/regress/sudoers/test4.toke.ok
+plugins/sudoers/regress/sudoers/test5.in
+plugins/sudoers/regress/sudoers/test5.out.ok
+plugins/sudoers/regress/sudoers/test5.toke.ok
+plugins/sudoers/regress/sudoers/test6.in
+plugins/sudoers/regress/sudoers/test6.out.ok
+plugins/sudoers/regress/sudoers/test6.toke.ok
+plugins/sudoers/regress/sudoers/test7.in
+plugins/sudoers/regress/sudoers/test7.out.ok
+plugins/sudoers/regress/sudoers/test7.toke.ok
+plugins/sudoers/regress/sudoers/test8.in
+plugins/sudoers/regress/sudoers/test8.out.ok
+plugins/sudoers/regress/sudoers/test8.toke.ok
+plugins/sudoers/regress/testsudoers/test1.out.ok
+plugins/sudoers/regress/testsudoers/test1.sh
+plugins/sudoers/set_perms.c
+plugins/sudoers/sudo_nss.c
+plugins/sudoers/sudo_nss.h
+plugins/sudoers/sudoers.c
+plugins/sudoers/sudoers.h
+plugins/sudoers/sudoers.in
+plugins/sudoers/sudoers.sym
+plugins/sudoers/sudoers2ldif
+plugins/sudoers/sudoers_version.h
+plugins/sudoers/sudoreplay.c
+plugins/sudoers/testsudoers.c
+plugins/sudoers/timestr.c
+plugins/sudoers/toke.c
+plugins/sudoers/toke.h
+plugins/sudoers/toke.l
+plugins/sudoers/toke_util.c
+plugins/sudoers/tsgetgrpw.c
+plugins/sudoers/tsgetgrpw.h
+plugins/sudoers/visudo.c
+pp
+src/Makefile.in
+src/conversation.c
+src/error.c
+src/exec.c
+src/exec_pty.c
+src/get_pty.c
+src/load_plugins.c
+src/net_ifs.c
+src/parse_args.c
+src/preload.c
+src/selinux.c
+src/sesh.c
+src/sudo.c
+src/sudo.h
+src/sudo_edit.c
+src/sudo_exec.h
+src/sudo_noexec.c
+src/sudo_plugin_int.h
+src/sudo_usage.h.in
+src/tgetpass.c
+src/ttysize.c
+src/utmp.c
+sudo.pp
+zlib/Makefile.in
+zlib/adler32.c
+zlib/compress.c
+zlib/crc32.c
+zlib/crc32.h
+zlib/deflate.c
+zlib/deflate.h
+zlib/gzclose.c
+zlib/gzguts.h
+zlib/gzlib.c
+zlib/gzread.c
+zlib/gzwrite.c
+zlib/infback.c
+zlib/inffast.c
+zlib/inffast.h
+zlib/inffixed.h
+zlib/inflate.c
+zlib/inflate.h
+zlib/inftrees.c
+zlib/inftrees.h
+zlib/trees.c
+zlib/trees.h
+zlib/uncompr.c
+zlib/zconf.h.in
+zlib/zlib.h
+zlib/zutil.c
+zlib/zutil.h
index b16338b12a3a2ae6a6b4260506067a9c5e7e0441..6df0c07c32e01ea5c7f3ee84892732a2c7533667 100644 (file)
@@ -1,6 +1,5 @@
 #
-# Copyright (c) 1996, 1998-2005, 2007-2011
-#      Todd C. Miller <Todd.Miller@courtesan.com>
+# Copyright (c) 2010-2011 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.
 # 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.
-#
-# @configure_input@
-#
-
-#### Start of system configuration section. ####
 
 srcdir = @srcdir@
 devdir = @devdir@
-authdir = $(srcdir)/auth
-top_builddir = .
-
-# Compiler & tools to use
-CC = @CC@
-FLEX = @FLEX@
-YACC = @YACC@
-NROFF = @NROFFPROG@ -Tascii
-LIBTOOL = @LIBTOOL@
-AR=@AR@
-RANLIB=@RANLIB@
-
-# Our install program supports extra flags...
-INSTALL = $(SHELL) $(srcdir)/install-sh -c
-
-# Libraries
-LIBS = @LIBS@
-NET_LIBS = @NET_LIBS@
-SUDO_LIBS = @SUDO_LIBS@ @AFS_LIBS@ @GETGROUPS_LIB@ $(LIBS) $(NET_LIBS)
-
-# C preprocessor flags
-CPPFLAGS = -I. -I$(srcdir) @CPPFLAGS@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
 
-# Usually -O and/or -g
-CFLAGS = @CFLAGS@
-
-# Flags to pass to the link stage
-LDFLAGS = -L. @LDFLAGS@
-SUDO_LDFLAGS = @SUDO_LDFLAGS@ $(LDFLAGS)
-
-# Where to install things...
+# Installation paths for package building
 prefix = @prefix@
 exec_prefix = @exec_prefix@
 bindir = @bindir@
 sbindir = @sbindir@
 sysconfdir = @sysconfdir@
 libexecdir = @libexecdir@
+includedir = @includedir@
 datarootdir = @datarootdir@
 localstatedir = @localstatedir@
 docdir = @docdir@
 mandir = @mandir@
 timedir = @timedir@
-noexecfile = @NOEXECFILE@
-noexecdir = @NOEXECDIR@
-
-# Directory in which to install sudo.
-sudodir = $(bindir)
 
-# Directory in which to install visudo
-visudodir = $(sbindir)
-
-# Directory in which to install the sudoers file
+# sudoers owner and mode for package building
 sudoersdir = $(sysconfdir)
-
-# Directory in which to install the man page
-mantype = @MANTYPE@
-mansectsu = @mansectsu@
-mansectform = @mansectform@
-mandirsu = $(mandir)/$(mantype)$(mansectsu)
-mandirform = $(mandir)/$(mantype)$(mansectform)
-
-# User and group ids the installed files should be "owned" by
-install_uid = 0
-install_gid = 0
-
-# User, group, and mode the sudoers file should be "owned" by (configure)
 sudoers_uid = @SUDOERS_UID@
 sudoers_gid = @SUDOERS_GID@
 sudoers_mode = @SUDOERS_MODE@
 
-# Pass in paths and uid/gid + OS dependent defined
-DEFS = @OSDEFS@ -D_PATH_SUDOERS=\"$(sudoersdir)/sudoers\" -DSUDOERS_UID=$(sudoers_uid) -DSUDOERS_GID=$(sudoers_gid) -DSUDOERS_MODE=$(sudoers_mode)
-
-#### End of system configuration section. ####
-
-SHELL = @SHELL@
-
-PROGS = @PROGS@
-
-SRCS = aix.c alias.c alloc.c audit.c boottime.c bsm_audit.c check.c \
-       closefrom.c def_data.c defaults.c env.c error.c exec.c exec_pty.c \
-       fileops.c find_path.c fnmatch.c get_pty.c getcwd.c getprogname.c \
-       getspwuid.c gettime.c glob.c goodpath.c gram.c gram.y interfaces.c \
-       iolog.c isblank.c lbuf.c ldap.c linux_audit.c list.c logging.c match.c \
-       mksiglist.c mkstemps.c memrchr.c nanosleep.c parse.c parse_args.c \
-       pwutil.c set_perms.c setsid.c sigaction.c snprintf.c strcasecmp.c \
-       strerror.c strlcat.c strlcpy.c strsignal.c sudo.c sudo_noexec.c \
-       sudo_edit.c sudo_nss.c term.c testsudoers.c tgetpass.c toke.c toke.l \
-       toke_util.c tsgetgrpw.c utimes.c vasgroups.c visudo.c zero_bytes.c \
-       redblack.c selinux.c sesh.c sudoreplay.c getdate.c getdate.y getline.c \
-       timestr.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 = alloc.h bsm_audit.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 \
-       linux_audit.h list.h logging.h missing.h mksiglist.h nonunix.h \
-       redblack.h parse.h sudo.h sudo_exec.h sudo_nss.h gram.h toke.h \
-       auth/sudo_auth.h emul/charclass.h emul/fnmatch.h emul/glob.h \
-       emul/timespec.h emul/utime.h
-
-AUTH_OBJS = sudo_auth.o @AUTH_OBJS@
-
-COMMON_OBJS = alias.o alloc.o defaults.o error.o gram.o \
-             list.o match.o pwutil.o timestr.o toke.o toke_util.o redblack.o \
-             term.o zero_bytes.o @COMMON_OBJS@
-
-SUDO_OBJS = $(AUTH_OBJS) @SUDO_OBJS@ audit.o boottime.o check.o env.o \
-           exec.o gettime.o goodpath.o fileops.o find_path.o \
-           interfaces.o lbuf.o logging.o parse.o parse_args.o set_perms.o \
-           sudo.o sudo_edit.o sudo_nss.o tgetpass.o
-
-VISUDO_OBJS = visudo.o fileops.o gettime.o goodpath.o find_path.o
+SUBDIRS = compat common @ZLIB_SRC@ plugins/sudoers src include doc
 
-REPLAY_OBJS = getdate.o sudoreplay.o
-
-TEST_OBJS = interfaces.o testsudoers.o tsgetgrpw.o
-
-LIB_OBJS = @LIBOBJS@
-
-ZLIB_OBJS = adler32.o compress.o crc32.o deflate.o gzclose.o gzlib.o \
-           gzread.o gzwrite.o infback.o inffast.o inflate.o inftrees.o \
-           trees.o uncompr.o zutil.o
+SAMPLES = plugins/sample plugins/sample_group
 
 VERSION = @PACKAGE_VERSION@
 PACKAGE_TARNAME = @PACKAGE_TARNAME@
 
-DISTFILES = $(SRCS) $(HDRS) ChangeLog HISTORY INSTALL INSTALL.configure \
-           LICENSE Makefile.in NEWS PORTING README README.LDAP \
-           TROUBLESHOOTING UPGRADE aclocal.m4 aixcrypt.exp config.guess \
-           config.h.in config.sub configure configure.in def_data.in \
-           indent.pro install-sh ltmain.sh m4 mkdefaults mkinstalldirs \
-           mkpkg pathnames.h.in pp sample.pam sample.syslog.conf \
-           sample.sudoers schema.ActiveDirectory schema.OpenLDAP \
-           schema.iPlanet siglist.in sudo.cat sudo.man.in sudo.pod sudo.pp \
-           sudo_usage.h.in sudoers.in sudoers.cat sudoers.man.in sudoers.pod \
-           sudoers.ldap.cat sudoers.ldap.man.in sudoers.ldap.pod \
-           sudoers2ldif sudoreplay.cat sudoreplay.man.in sudoreplay.pod \
-           visudo.cat visudo.man.in visudo.pod auth/API sudo.man.pl \
-           sudoers.man.pl $(ZLIB_FILES)
-
-ZLIB_FILES = zlib/adler32.c zlib/compress.c zlib/crc32.c zlib/crc32.h \
-            zlib/deflate.c zlib/deflate.h zlib/gzclose.c zlib/gzguts.h \
-            zlib/gzlib.c zlib/gzread.c zlib/gzwrite.c zlib/infback.c \
-            zlib/inffast.c zlib/inffast.h zlib/inffixed.h zlib/inflate.c \
-            zlib/inflate.h zlib/inftrees.c zlib/inftrees.h zlib/trees.c \
-            zlib/trees.h zlib/uncompr.c zlib/zconf.h.in zlib/zlib.h \
-            zlib/zutil.c zlib/zutil.h
-
-SUDODEP = $(srcdir)/sudo.h $(srcdir)/alloc.h $(srcdir)/defaults.h \
-         $(srcdir)/error.h $(srcdir)/list.h $(srcdir)/logging.h \
-         $(srcdir)/missing.h $(srcdir)/sudo_nss.h $(devdir)/def_data.h \
-         pathnames.h config.h
-
-AUTHDEP = $(SUDODEP) $(authdir)/sudo_auth.h
-
-INSDEP = $(srcdir)/ins_2001.h $(srcdir)/ins_classic.h $(srcdir)/ins_csops.h \
-        $(srcdir)/ins_goons.h $(srcdir)/insults.h
-
-all: $(PROGS)
-
-.SUFFIXES: .o .c .h .l .y .lo
-
-.c.o:
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $<
-
-.c.lo:
-       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $<
-
-libsudo.a: $(LIB_OBJS) $(COMMON_OBJS)
-       $(AR) rv $@ $(LIB_OBJS) $(COMMON_OBJS)
-       $(RANLIB) $@
-
-libz.a: $(ZLIB_OBJS)
-       $(AR) rv $@ $(ZLIB_OBJS)
-       $(RANLIB) $@
-
-sudo: libsudo.a @ZLIB_DEP@ $(SUDO_OBJS)
-       $(CC) -o $@ $(SUDO_OBJS) $(SUDO_LDFLAGS) -lsudo $(SUDO_LIBS) @ZLIB@
-
-visudo: libsudo.a $(VISUDO_OBJS)
-       $(CC) -o $@ $(VISUDO_OBJS) $(LDFLAGS) -lsudo $(LIBS) $(NET_LIBS)
-
-sudoreplay: libsudo.a @ZLIB_DEP@ $(REPLAY_OBJS)
-       $(CC) -o $@ $(REPLAY_OBJS) $(LDFLAGS) -lsudo $(LIBS) @ZLIB@
-
-testsudoers: $(TEST_OBJS)
-       $(CC) -o $@ $(TEST_OBJS) $(LDFLAGS) -lsudo $(LIBS) $(NET_LIBS)
-
-sudo_noexec.lo: $(srcdir)/sudo_noexec.c
-       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_noexec.c
-
-libsudo_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@GENERATED = gram.h gram.c toke.c def_data.c def_data.h getdate
-
-# Uncomment the lines before -@true if you intend to modify gram.y
-$(devdir)/gram.c $(devdir)/gram.h: $(srcdir)/gram.y
-@DEV@  $(YACC) -d $(srcdir)/gram.y
-@DEV@  echo "#include <config.h>" > $(devdir)/gram.c
-@DEV@  cat y.tab.c >> $(devdir)/gram.c
-@DEV@  rm -f y.tab.c
-@DEV@  mv -f y.tab.h $(devdir)/gram.h
-       -@true
-
-# Uncomment the lines before -@true if you intend to modify toke.l
-$(devdir)/toke.c: $(srcdir)/toke.l
-@DEV@  $(FLEX) $(srcdir)/toke.l
-@DEV@  echo "#include <config.h>" > $(devdir)/toke.c
-@DEV@  cat lex.yy.c >> $(devdir)/toke.c
-@DEV@  rm -f lex.yy.c
-       -@true
-
-# Uncomment the lines before -@true if you intend to modify getdate.y
-$(devdir)/getdate.c: $(srcdir)/getdate.y
-@DEV@  echo "expect 10 shift/reduce conflicts"
-@DEV@  $(YACC) $(srcdir)/getdate.y
-@DEV@  echo "#include <config.h>" > $(devdir)/getdate.c
-@DEV@  cat y.tab.c >> $(devdir)/getdate.c
-@DEV@  rm -f y.tab.c
-       -@true
-
-# Uncomment the following if you intend to modify 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
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
 
-siglist.c: mksiglist
-       ./mksiglist > $@
-
-mksiglist: $(srcdir)/mksiglist.c $(srcdir)/mksiglist.h $(srcdir)/missing.h config.h
-       $(CC) $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/mksiglist.c -o $@
-
-@DEV@$(srcdir)/mksiglist.h: $(srcdir)/siglist.in
-@DEV@  awk 'BEGIN {print "/* public domain */\n"} /^    [A-Z]/ {printf("#ifdef SIG%s\n    if (my_sys_siglist[SIG%s] == NULL)\n\tmy_sys_siglist[SIG%s] = \"%s\";\n#endif\n", $$1, $$1, $$1, substr($$0, 13))}' < $(srcdir)/siglist.in > $@
-
-# Dependencies (not counting auth functions)
-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
-audit.o: $(srcdir)/audit.c $(SUDODEP) $(srcdir)/bsm_audit.h $(srcdir)/linux_audit.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/audit.c
-boottime.o: $(srcdir)/boottime.c config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/boottime.c
-bsm_audit.o: $(srcdir)/bsm_audit.c $(SUDODEP) $(srcdir)/bsm_audit.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/bsm_audit.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)/missing.h $(srcdir)/error.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/error.c
-exec.o: $(srcdir)/exec.c $(SUDODEP) $(srcdir)/sudo_exec.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/exec.c
-exec_pty.o: $(srcdir)/exec.c $(SUDODEP) $(srcdir)/sudo_exec.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/exec_pty.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)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/fnmatch.c
-get_pty.o: $(srcdir)/get_pty.c $(SUDODEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/get_pty.c
-getcwd.o: $(srcdir)/getcwd.c $(srcdir)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getcwd.c
-getdate.o: $(srcdir)/getdate.c $(srcdir)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getdate.c
-getline.o: $(srcdir)/getline.c config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getline.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)/missing.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
-iolog.o: $(srcdir)/iolog.c $(SUDODEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/iolog.c
-isblank.o: $(srcdir)/isblank.c $(srcdir)/missing.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
-linux_audit.o: $(srcdir)/linux_audit.c $(SUDODEP) $(srcdir)/linux_audit.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/linux_audit.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
-mkstemps.o: $(srcdir)/mkstemps.c $(SUDODEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/mkstemps.c
-nanosleep.o: $(srcdir)/nanosleep.c $(srcdir)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/nanosleep.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
-parse_args.o: $(srcdir)/parse_args.c $(SUDODEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/parse_args.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
-setsid.o: $(srcdir)/setsid.c $(srcdir)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/setsid.c
-sigaction.o: $(srcdir)/sigaction.c $(srcdir)/missing.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sigaction.c
-siglist.o: siglist.c $(srcdir)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/siglist.c
-snprintf.o: $(srcdir)/snprintf.c $(srcdir)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/snprintf.c
-strcasecmp.o: $(srcdir)/strcasecmp.c $(srcdir)/missing.h  config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strcasecmp.c
-strerror.o: $(srcdir)/strerror.c $(srcdir)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strerror.c
-strlcat.o: $(srcdir)/strlcat.c $(srcdir)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strlcat.c
-strlcpy.o: $(srcdir)/strlcpy.c $(srcdir)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strlcpy.c
-strsignal.o: $(srcdir)/strsignal.c $(srcdir)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strsignal.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
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo.c
-sudoreplay.o: $(srcdir)/sudoreplay.c $(srcdir)/alloc.h $(srcdir)/missing.h $(srcdir)/error.h $(srcdir)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudoreplay.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)/missing.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
-term.o: $(srcdir)/term.c $(SUDODEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/term.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
-timestr.o: $(srcdir)/timestr.c $(srcdir)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/timestr.c
-toke.o: $(devdir)/toke.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/toke.h $(devdir)/gram.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(devdir)/toke.c
-toke_util.o: $(srcdir)/toke_util.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/toke.h $(devdir)/gram.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/toke_util.c
-tsgetgrpw.o: $(srcdir)/tsgetgrpw.c $(SUDODEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/tsgetgrpw.c
-utimes.o: $(srcdir)/utimes.c $(srcdir)/missing.h $(srcdir)/emul/utime.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/utimes.c
-vasgroups.o: $(srcdir)/vasgroups.c $(srcdir)/nonunix.h $(SUDODEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/vasgroups.c
-visudo.o: $(srcdir)/visudo.c $(SUDODEP) $(devdir)/gram.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/visudo.c
-zero_bytes.o: $(srcdir)/zero_bytes.c $(srcdir)/missing.h config.h
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/zero_bytes.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)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/afs.c
-aix_auth.o: $(authdir)/aix_auth.c $(AUTHDEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/aix_auth.c
-bsdauth.o: $(authdir)/bsdauth.c $(AUTHDEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/bsdauth.c
-dce.o: $(authdir)/dce.c $(AUTHDEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/dce.c
-fwtk.o: $(authdir)/fwtk.c $(AUTHDEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/fwtk.c
-kerb4.o: $(authdir)/kerb4.c $(AUTHDEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/kerb4.c
-kerb5.o: $(authdir)/kerb5.c $(AUTHDEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/kerb5.c
-pam.o: $(authdir)/pam.c $(AUTHDEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/pam.c
-passwd.o: $(authdir)/passwd.c $(AUTHDEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/passwd.c
-rfc1938.o: $(authdir)/rfc1938.c $(AUTHDEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/rfc1938.c
-secureware.o: $(authdir)/secureware.c $(AUTHDEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/secureware.c
-securid.o: $(authdir)/securid.c $(AUTHDEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/securid.c
-securid5.o: $(authdir)/securid5.c $(AUTHDEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/securid5.c
-sia.o: $(authdir)/sia.c $(AUTHDEP)
-       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/sia.c
-
-# Zlib dependencies
-adler32.o: $(srcdir)/zlib/zutil.h $(srcdir)/zlib/zlib.h zlib/zconf.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/adler32.c
-compress.o: $(srcdir)/zlib/zlib.h zlib/zconf.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/compress.c
-crc32.o: $(srcdir)/zlib/zutil.h $(srcdir)/zlib/zlib.h zlib/zconf.h $(srcdir)/zlib/crc32.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/crc32.c
-deflate.o: $(srcdir)/zlib/deflate.h $(srcdir)/zlib/zutil.h $(srcdir)/zlib/zlib.h zlib/zconf.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/deflate.c
-gzclose.o: $(srcdir)/zlib/zlib.h zlib/zconf.h $(srcdir)/zlib/gzguts.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/gzclose.c
-gzlib.o: $(srcdir)/zlib/zlib.h zlib/zconf.h $(srcdir)/zlib/gzguts.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/gzlib.c
-gzread.o: $(srcdir)/zlib/zlib.h zlib/zconf.h $(srcdir)/zlib/gzguts.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/gzread.c
-gzwrite.o: $(srcdir)/zlib/zlib.h zlib/zconf.h $(srcdir)/zlib/gzguts.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/gzwrite.c
-infback.o: $(srcdir)/zlib/zutil.h $(srcdir)/zlib/zlib.h zlib/zconf.h $(srcdir)/zlib/inftrees.h $(srcdir)/zlib/inflate.h $(srcdir)/zlib/inffast.h $(srcdir)/zlib/inffixed.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/infback.c
-inffast.o: $(srcdir)/zlib/zutil.h $(srcdir)/zlib/zlib.h zlib/zconf.h $(srcdir)/zlib/inftrees.h $(srcdir)/zlib/inflate.h $(srcdir)/zlib/inffast.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/inffast.c
-inflate.o: $(srcdir)/zlib/zutil.h $(srcdir)/zlib/zlib.h zlib/zconf.h $(srcdir)/zlib/inftrees.h $(srcdir)/zlib/inflate.h $(srcdir)/zlib/inffast.h $(srcdir)/zlib/inffixed.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/inflate.c
-inftrees.o: $(srcdir)/zlib/zutil.h $(srcdir)/zlib/zlib.h zlib/zconf.h $(srcdir)/zlib/inftrees.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/inftrees.c
-trees.o: $(srcdir)/zlib/deflate.h $(srcdir)/zlib/zutil.h $(srcdir)/zlib/zlib.h zlib/zconf.h $(srcdir)/zlib/trees.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/trees.c
-uncompr.o: $(srcdir)/zlib/zlib.h zlib/zconf.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/uncompr.c
-zutil.o: $(srcdir)/zlib/zutil.h $(srcdir)/zlib/zlib.h zlib/zconf.h
-       $(CC) -c -I. -I$(srcdir)/zlib $(CFLAGS) $(srcdir)/zlib/zutil.c
-
-@DEV@varsub: $(srcdir)/configure.in
-@DEV@  printf 's#@%s@#1#\ns#@%s@#1#\ns#@%s@#1#\ns#@%s@#/etc#g\ns#@%s@#/usr/local#g\ns#@%s@#4#g\ns#@%s@#1m#g\n' SEMAN BAMAN LCMAN sysconfdir prefix mansectform mansectsu > $@; sed -n '/Begin initial values for man page substitution/,/End initial values for man page substitution/{;p;}' $(srcdir)/configure.in | sed -e '/^#/d' -e 's/^/s#@/' -e 's/=[\\"]*/@#/' -e 's/[\\"]*$$/#g/' >> $@
-
-@DEV@$(srcdir)/sudo.man.in: $(srcdir)/sudo.pod
-@DEV@  mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudo.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudo.pod | sed -e "s/(5)/($$mansectform)/" -e "s/(8)/($$mansectsu)/" | perl -p $(srcdir)/sudo.man.pl >> $@
-
-sudo.man: $(srcdir)/sudo.man.in
-       $(SHELL) config.status --file=$@
-
-@DEV@$(srcdir)/sudo.cat: varsub $(srcdir)/sudo.man.in
-@DEV@  sed -f varsub $(srcdir)/sudo.man.in | $(NROFF) -man > $@
-
-@DEV@$(srcdir)/visudo.man.in: $(srcdir)/visudo.pod
-@DEV@  mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/visudo.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/visudo.pod | sed -e "s/(5)/($$mansectform)/" -e "s/(8)/($$mansectsu)/" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@
-
-visudo.man: $(srcdir)/visudo.man.in
-       $(SHELL) config.status --file=$@
-
-@DEV@$(srcdir)/visudo.cat: varsub $(srcdir)/visudo.man.in
-@DEV@  sed -f varsub $(srcdir)/visudo.man.in | $(NROFF) -man > $@
-
-@DEV@$(srcdir)/sudoers.man.in: $(srcdir)/sudoers.pod
-@DEV@  mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudoers.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectform --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudoers.pod | sed -e "s/(5)/($$mansectform)/" -e "s/(8)/($$mansectsu)/" | perl -p $(srcdir)/sudoers.man.pl >> $@
-
-sudoers.man: $(srcdir)/sudoers.man.in
-       $(SHELL) config.status --file=$@
-
-@DEV@$(srcdir)/sudoers.cat: varsub $(srcdir)/sudoers.man.in
-@DEV@  sed -f varsub $(srcdir)/sudoers.man.in | $(NROFF) -man > $@
-
-@DEV@$(srcdir)/sudoers.ldap.man.in: $(srcdir)/sudoers.ldap.pod
-@DEV@  mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudoers.ldap.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectform --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudoers.ldap.pod | sed -e "s/(5)/($$mansectform)/" -e "s/(8)/($$mansectsu)/" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@
-
-sudoers.ldap.man: $(srcdir)/sudoers.ldap.man.in
-       $(SHELL) config.status --file=$@
-
-@DEV@$(srcdir)/sudoers.ldap.cat: varsub $(srcdir)/sudoers.ldap.man.in
-@DEV@  sed -f varsub $(srcdir)/sudoers.ldap.man.in | $(NROFF) -man > $@
-
-@DEV@$(srcdir)/sudoreplay.man.in: $(srcdir)/sudoreplay.pod
-@DEV@  mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudoreplay.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudoreplay.pod | sed -e "s/(5)/($$mansectform)/" -e "s/(8)/($$mansectsu)/" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@
-
-sudoreplay.man: $(srcdir)/sudoreplay.man.in
-       $(SHELL) config.status --file=$@
-
-@DEV@$(srcdir)/sudoreplay.cat: varsub $(srcdir)/sudoreplay.man.in
-@DEV@  sed -f varsub $(srcdir)/sudoreplay.man.in | $(NROFF) -man > $@
-
-@DEV@HISTORY: $(srcdir)/history.pod
-@DEV@  pod2text -l -i0 $(srcdir)/history.pod > $@
-@DEV@
-@DEV@LICENSE: $(srcdir)/license.pod
-@DEV@  pod2text -l -i0 $(srcdir)/license.pod | sed '1,2d' > $@
-
-sudoers: $(srcdir)/sudoers.in
-       (cd $(top_builddir) && $(SHELL) config.status --file=plugins/sudoers/$@)
+SHELL = @SHELL@
 
-# The 1.7 branch started Jan 18, 2010
+all: config.status
+       for d in $(SUBDIRS) $(SAMPLES); \
+           do (cd $$d && exec $(MAKE) $@) && continue; \
+           exit $$?; \
+       done
+
+check pre-install: config.status
+       for d in $(SUBDIRS); \
+           do (cd $$d && exec $(MAKE) $@) && continue; \
+           exit $$?; \
+       done
+
+install-dirs install-binaries install-includes install-plugin uninstall: config.status pre-install
+       for d in $(SUBDIRS); \
+           do (cd $$d && exec $(MAKE) $@) && continue; \
+           exit $$?; \
+       done
+
+install install-doc: config.status ChangeLog pre-install
+       for d in $(SUBDIRS); \
+           do (cd $$d && exec $(MAKE) $@) && continue; \
+           exit $$?; \
+       done
+
+autoconf:
+       autoconf -I m4
+
+# The 1.8 branch started February 25, 2011
 ChangeLog:
        if test -d $(srcdir)/.hg && cd $(srcdir); then \
-           if hg log --style=changelog -b 1.7 > $@.tmp && hg log --style=changelog -b default --date '<2010-01-18 00:00:00' >> $@.tmp; then \
+           if hg log --style=changelog -b 1.8 > $@.tmp && hg log --style=changelog -b default --date '<2011-02-25 21:30:00' >> $@.tmp; then \
                mv -f $@.tmp $@; \
            else \
                rm -f $@.tmp; \
            fi; \
        fi
 
-pre-install:
-       @if test -r $(DESTDIR)$(sudoersdir)/sudoers; then \
-           echo "Checking existing sudoers file for syntax errors."; \
-           ./visudo -c -f $(DESTDIR)$(sudoersdir)/sudoers; \
+config.status:
+       @if [ ! -s config.status ]; then \
+               echo "Please run configure first"; \
+               exit 1; \
        fi
 
-install: pre-install install-dirs install-binaries @INSTALL_NOEXEC@ install-sudoers install-doc
-
-install-dirs:
-       $(SHELL) $(srcdir)/mkinstalldirs $(DESTDIR)$(sudodir) \
-           $(DESTDIR)$(visudodir) $(DESTDIR)$(noexecdir) \
-           $(DESTDIR)$(sudoersdir) $(DESTDIR)$(docdir) \
-           $(DESTDIR)$(mandirsu) $(DESTDIR)$(mandirform)
-       $(SHELL) $(srcdir)/mkinstalldirs -m 0700 $(DESTDIR)$(timedir)
+libtool: $(LIBTOOL_DEPS)
+       $(SHELL) ./config.status --recheck
 
-install-binaries: install-dirs $(PROGS)
-       $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 04111 sudo $(DESTDIR)$(sudodir)/sudo
-       rm -f $(DESTDIR)$(sudodir)/sudoedit
-       ln $(DESTDIR)$(sudodir)/sudo $(DESTDIR)$(sudodir)/sudoedit
-       if [ -f sudoreplay ]; then $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0111 sudoreplay $(DESTDIR)$(sudodir)/sudoreplay; fi
-       $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0111 visudo $(DESTDIR)$(visudodir)/visudo
-       if [ -f sesh ]; then $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0111 sesh $(DESTDIR)$(libexecdir)/sesh; fi
+Makefile: $(srcdir)/Makefile.in
+       ./config.status --file Makefile
 
-install-noexec: install-dirs libsudo_noexec.la
-       if [ -f .libs/lib$(noexecfile) ]; then $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0755 .libs/lib$(noexecfile) $(DESTDIR)$(noexecdir)/$(noexecfile); fi
-
-install-sudoers: install-dirs
-       $(INSTALL) -d -O $(sudoers_uid) -G $(sudoers_gid) -M 0750 \
-           $(DESTDIR)$(sudoersdir)/sudoers.d
-       test -f $(DESTDIR)$(sudoersdir)/sudoers || \
-           $(INSTALL) -O $(sudoers_uid) -G $(sudoers_gid) -M $(sudoers_mode) \
-               sudoers $(DESTDIR)$(sudoersdir)/sudoers
-
-install-doc: install-dirs ChangeLog
-       (cd $(srcdir) && for f in ChangeLog HISTORY LICENSE NEWS README TROUBLESHOOTING UPGRADE sample.*; do $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 $$f $(DESTDIR)$(docdir); done)
-       @LDAP@(cd $(srcdir) && for f in README.LDAP schema.* sudoers2ldif; do $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 $$f $(DESTDIR)$(docdir); done)
-       $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 @mansrcdir@/sudo.$(mantype) $(DESTDIR)$(mandirsu)/sudo.$(mansectsu)
-       @rm -f $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu)
-       ln $(DESTDIR)$(mandirsu)/sudo.$(mansectsu) $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu)
-       @REPLAY@$(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 @mansrcdir@/sudoreplay.$(mantype) $(DESTDIR)$(mandirsu)/sudoreplay.$(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
-
-clean:
-       -rm -f *.a *.o *.lo stamp-* varsub $(PROGS) testsudoers core *.core core.*
-
-mostlyclean: clean
-
-distclean: clean
-       -rm -rf Makefile pathnames.h config.h config.status config.cache \
-               config.log libtool sudoers sudo_noexec.lo .libs $(GENERATED) \
-               sudo.man sudoers.man sudoers.ldap.man sudoreplay.man \
-               visudo.man sudo_usage.h Makefile.binary zlib/zconf.h
-
-clobber: distclean
-
-realclean: distclean
-       rm -f TAGS tags
-
-cleandir: realclean
-
-dist: ChangeLog
+dist: ChangeLog $(srcdir)/MANIFEST
        pax -w -x ustar -s '/^/$(PACKAGE_TARNAME)-$(VERSION)\//' \
-           -f ../$(PACKAGE_TARNAME)-$(VERSION).tar $(DISTFILES)
+           -f ../$(PACKAGE_TARNAME)-$(VERSION).tar \
+           `sed 's/[   ].*//' $(srcdir)/MANIFEST`
        gzip -9f ../$(PACKAGE_TARNAME)-$(VERSION).tar
        ls -l ../$(PACKAGE_TARNAME)-$(VERSION).tar.gz
 
@@ -616,6 +116,7 @@ package: sudo.pp
            bindir=$(bindir) \
            sbindir=$(sbindir) \
            libexecdir=$(libexecdir) \
+           includedir=$(includedir) \
            timedir=$(timedir) \
            mandir=$(mandir) \
            docdir=$(docdir) \
@@ -626,4 +127,24 @@ package: sudo.pp
            sudoers_mode=$(sudoers_mode) \
            version=$(VERSION) $(PPVARS)
 
-.PHONY:        ChangeLog
+clean: config.status
+       for d in $(SUBDIRS) $(SAMPLES); do \
+           (cd $$d && exec $(MAKE) $@); \
+       done
+
+mostlyclean: clean
+
+distclean: config.status
+       for d in $(SUBDIRS) $(SAMPLES); do \
+           (cd $$d && exec $(MAKE) $@); \
+       done
+       -rm -rf Makefile pathnames.h config.h config.status config.cache \
+               config.log libtool stamp-* autom4te.cache
+
+cleandir: distclean
+
+clobber: distclean
+
+realclean: distclean
+
+.PHONY: ChangeLog
diff --git a/NEWS b/NEWS
index 87bac52e1748ba18fc019ec587d8b15bfa580d82..729ad66eff669cbf0af546dbe440a5804e06a6fd 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,19 @@
-What's new in Sudo 1.7.6p1
+What's new in Sudo 1.8.1p2?
+
+ * Two-character CIDR-style IPv4 netmasks are now matched correctly
+   in the sudoers file.
+
+ * A build error with MIT Kerberos V has been resolved.
+
+ * A crash on HP-UX in the sudoers plugin when wildcards are
+   present in the sudoers file has been resolved.
+
+ * Sudo now works correctly on Tru64 Unix again.
+
+What's new in Sudo 1.8.1p1?
+
+ * Fixed a problem on AIX where sudo was unable to set the final
+   uid if the PAM module modified the effective uid.
 
  * A non-existent includedir is now treated the same as an empty
    directory and not reported as an error.
@@ -6,7 +21,9 @@ What's new in Sudo 1.7.6p1
  * Removed extraneous parens in LDAP filter when sudoers_search_filter
    is enabled that can cause an LDAP search error.
 
-What's new in Sudo 1.7.6?
+ * Fixed a "make -j" problem for "make install".
+
+What's new in Sudo 1.8.1?
 
  * A new LDAP setting, sudoers_search_filter, has been added to
    ldap.conf.  This setting can be used to restrict the set of
@@ -32,6 +49,62 @@ What's new in Sudo 1.7.6?
  * A bug that could result in corrupted output in "sudo -l" has been
    fixed.
 
+ * Sudo will now create an entry in the utmp (or utmpx) file when
+   allocating a pseudo-tty (e.g. when logging I/O).  The "set_utmp"
+   and "utmp_runas" sudoers file options can be used to control this.
+   Other policy plugins may use the "set_utmp" and "utmp_user"
+   entries in the command_info list.
+
+ * The sudoers policy now stores the TSID field in the logs
+   even when the "iolog_file" sudoers option is defined to a value
+   other than %{sessid}.  Previously, the TSID field was only
+   included in the log file when the "iolog_file" option was set
+   to its default value.
+
+ * The sudoreplay utility now supports arbitrary session IDs.
+   Previously, it would only work with the base-36 session IDs
+   that the sudoers plugin uses by default.
+
+ * Sudo now passes "run_shell=true" to the policy plugin in the
+   settings list when sudo's -s command line option is specified.
+   The sudoers policy plugin uses this to implement the "set_home"
+   sudoers option which was missing from sudo 1.8.0.
+
+ * The "noexec" functionality has been moved out of the sudoers
+   policy plugin and into the sudo front-end, which matches the
+   behavior documented in the plugin writer's guide.  As a result,
+   the path to the noexec file is now specified in the sudo.conf
+   file instead of the sudoers file.
+
+ * On Solaris 10, the PRIV_PROC_EXEC privilege is now used to
+   implement the "noexec" feature.  Previously, this was implemented
+   via the LD_PRELOAD environment variable.
+
+ * The exit values for "sudo -l", "sudo -v" and "sudo -l command"
+   have been fixed in the sudoers policy plugin.
+
+ * The sudoers policy plugin now passes the login class, if any,
+   back to the sudo front-end.
+
+ * The sudoers policy plugin was not being linked with requisite
+   libraries in certain configurations.
+
+ * Sudo now parses command line arguments before loading any plugins.
+   This allows "sudo -V" or "sudo -h" to work even if there is a problem
+   with sudo.conf
+
+ * Plugins are now linked with the static version of libgcc to allow
+   the plugin to run on a system where no shared libgcc is installed,
+   or where it is installed in a different location.
+
+What's new in Sudo 1.8.0?
+
+ * Sudo has been refactored to use a modular framework that can
+   support third-party policy and I/O logging plugins.  The default
+   plugin is "sudoers" which provides the traditional sudo functionality.
+   See the sudo_plugin manual for details on the plugin API and the
+   sample in the plugins directory for a simple example.
+
 What's new in Sudo 1.7.5?
 
  * When using visudo in check mode, a file named "-" may be used to
diff --git a/PORTING b/PORTING
deleted file mode 100644 (file)
index 861e0c0..0000000
--- a/PORTING
+++ /dev/null
@@ -1,85 +0,0 @@
-Sudo porting hints
-==================
-
-Before trying to port sudo to a new architecture, please join the
-sudo-workers mailing list (see the README file) and ask if anyone
-has a port working or in-progress.  Sudo should be fairly easy to
-port.  Since it uses a configure script, most of the work is often
-done for you.  As long as your operating system is reasonably POSIX
-compliant porting should be easy.  If your operating system has a
-separate library for POSIX compatibility you may need to add it by
-using configure's --with-libraries option.
-
-If your OS is an SVR4 derivative (or some approximation thereof), it may
-be sufficient to tell configure you are runnng SVR4, something like:
-    configure foo-bar-sysv4
-where foo is the hardware architecture and bar is the vendor.
-
-A possible pitfall is getdtablesize(2) which is used to get the
-maximum number of open files the process can have.  If an OS has
-the POSIX sysconf(2) it will be used instead of getdtablesize(2).
-ulimit(2) or getrlimit(2) can also be used on some OS's.  If all
-else fails you can use the value of NOFILE in <sys/param.h>.
-
-Sudo tries to clear the environment of dangerous environment variables
-such as LD_* to prevent shared library spoofing.  If you are porting
-sudo to a new OS that has shared libraries you'll want to mask out
-the variables that allow one to change the shared library path.
-See initial_badenv_table() in env.c to see how this is done for
-various operating systems.
-
-It is possible that on a really weird system, tgetpass() may not
-compile.  (The most common cause for this is that the "fd_set" type
-is not defined in a place that sudo expects it to be.  If you can
-find the header file where "fd_set" is typedef'd, have tgetpass.c
-include it and send in a bug report.)
-Alternately, tgetpass.c may compile but not work (nothing happens
-at the Password: prompt).  It is possible that your C library
-contains a broken or unusable crypt() function--try linking with
--lcrypt if that exists.  Another possibility is that select() is
-not fully functional; running configure with --with-password-timeout=0
-will disable the use of select().  If sudo prompts you for a
-password but never accepts it, see below.
-
-Sudo detects and recognizes most common shadow password schemes
-automatically.  If you find that sudo is not accepting your password
-and you are sure that it has been typed in correctly there are two
-likely problems.  One possibility is that your C library has a
-broken crypt() function (see above).  The other is that your operating
-system is using shadow passwords and sudo has not detected that
-fact.  Look in config.h to see what, if any, shadow password scheme
-was detected.  The most common are SVR4 (HAVE_GETSPNAM will be
-defined) and SecureWare (HAVE_GETPRPWNAM will be defined).  Check
-the manual pages on your system for "getspnam" and "getprpwnam".
-If one of those exist but the appropriate define does not exist in
-config.h then the problem is most likely that those routines live
-in a library that sudo does not know to link against.  The manual
-page should tell you what library this is.  You can then use the
---with-libraries option to configure to tell sudo to link with the
-library in question.  For example:
-    --with-libraries='-lgen'
-would cause sudo to link in libgen which contains "getspnam" on SCO
-systems.
-
-If you are trying to port to a system without standard Berkeley
-networking you may find that interfaces.c will not compile.  This
-is most likely on OS's with STREAMS-based networking.  It should
-be possible to make it work by modifying the ISC streams support
-(see the _ISC #ifdef's).  However, if you don't care about ip address
-and network address support, you can just run configure with the
---without-interfaces flag to get a do-nothing load_interfaces()
-stub function.
-
-Sudo wants POSIX signals (sigaction and friends).  If your system
-lacks sigaction but has the 4.3BSD sigvec() function, sigvec() will
-be used instead via the wrapper functions in sigaction.c.  It is
-not currently possible to use the old SVR3 and 4.2BSD signals, but
-this is due more to my lack of a test machine than anything else.
-
-If you port sudo to a new architecture, please send the output of
-"configure", the config.log file and your changes to:
-    sudo@courtesan.com
-
-If you are unable to get sudo working, and you are willing to
-give me an account on a machine, send mail to sudo@courtesan.com.
-Note, however, that I can't make any promises.
diff --git a/README b/README
index 387734f3841793c9786f43f38f732ecce29cdcbb..3ed6c5b78bf3c136657a0a0e192f377dab8da1a5 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-This is Sudo version 1.7.5
+This is Sudo version 1.8.0
 
 The sudo philosophy
 ===================
@@ -27,15 +27,16 @@ summary of major changes to the current stable release, see the web
 page, http://www.sudo.ws/sudo/stable.html.
 
 If you are upgrading from an earlier version of Sudo, please see
-the UPGRADE file.
+the UPGRADE file in the doc directory.
 
-For a history of sudo please see the HISTORY file.
+For a history of sudo please see the HISTORY file in the doc directory.
 
 System requirements
 ===================
-To build sudo from the source distribution you need a machine running
-Unix (most flavors of BSD, SYSV, or POSIX will do), a working C
-compiler, and the ar, make and ranlib utilities.
+To build sudo from the source distribution you need a nominally
+POSIX-compliant operating system (any modern version of BSD, Linux
+or UNIX should work), a working ANSI/ISO C compiler (C89 or higher),
+and the ar, make and ranlib utilities
 
 If you wish to modify the parser then you will need flex version
 2.5.2 or later and either bison or byacc (sudo comes with a pre-flex'd
@@ -92,6 +93,7 @@ Bug reports
 If you have found what you believe to be a bug, you can file a bug
 report in the sudo bug database, on the 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 version of
-sudo you are using as well as the platform you are running it on.
+Please read over the `TROUBLESHOOTING' file in the doc directory *before*
+submitting a bug report.  When reporting bugs, please be sure to include
+the version of sudo you are using as well as the platform you are running
+it on.
diff --git a/TROUBLESHOOTING b/TROUBLESHOOTING
deleted file mode 100644 (file)
index 9ed1817..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-Troubleshooting tips and FAQ for Sudo
-=====================================
-
-Q) When I run configure, it says "C compiler cannot create executables".
-A) This usually means you either don't have a working compiler.  This
-   could be due to the lack of a license or that some component of the
-   compiler suite could not be found.  Check config.log for clues as
-   to why this is happening.  On many systems, compiler components live
-   in /usr/ccs/bin which may not be in your PATH environment variable.
-
-Q) When I run configure, it says "sudo requires the 'ar' utility to build".
-A) As part of the build process, sudo creates a temporary library containing
-   objects that are shared amongst the different sudo executables.
-   On Unix systems, the "ar" utility is used to do this.  This error
-   indicates that "ar" is missing on your system.  On Solaris systems,
-   you may need to install the SUNWbtool package.  On other systems
-   "ar" may be included in the GNU binutils package.
-
-Q) Sudo compiles but when I run it I get "Sorry, sudo must be setuid root."
-   and sudo quits.
-A) Sudo must be setuid root to do its work.  You need to do something like
-   `chmod 4111 /usr/local/bin/sudo'.  Also, the file system sudo resides
-   on must *not* be mounted (or exported) with the nosuid option or sudo
-   will not be able to work.  Another possibility is you may have '.' in
-   your $PATH before the directory containing sudo.  If you are going
-   to have '.' in your path you should make sure it is at the end.
-
-Q) Sudo never gives me a chance to enter a password using PAM, it just
-   says 'Sorry, try again.' three times and exits.
-A) You didn't setup PAM to work with sudo.  On Redhat Linux or Fedora
-   Core this generally means installing sample.pam as /etc/pam.d/sudo.
-   See the sample.pam file for hints on what to use for other Linux
-   systems.
-
-Q) Sudo says 'Account expired or PAM config lacks an "account"
-   section for sudo, contact your system administrator' and exits
-   but I know my account has not expired.
-A) Your PAM config lacks an "account" specification.  On Linux this
-   usually means you are missing a line like:
-       account    required    pam_unix.so
-   in /etc/pam.d/sudo.
-
-Q) Sudo is setup to log via syslog(3) but I'm not getting any log
-   messages.
-A) Make sure you have an entry in your syslog.conf file to save
-   the sudo messages (see the sample.syslog.conf file).  The default
-   log facility is authpriv (changeable via configure or in sudoers).
-   Don't forget to send a SIGHUP to your syslogd so that it re-reads
-   its conf file.  Also, remember that syslogd does *not* create
-   log files, you need to create the file before syslogd will log
-   to it (ie: touch /var/log/sudo).
-   Note:  the facility (e.g. "auth.debug") must be separated from the 
-         destination (e.g. "/var/log/auth" or "@loghost") by
-         tabs, *not* spaces.  This is a common error.
-
-Q) When sudo asks me for my password it never accepts what I enter even
-   though I know I entered my password correctly.
-A) If your system uses shadow passwords, it is possible that sudo
-   didn't detect this.  Take a look at the generated config.h file
-   and verify that the C function used for shadow password lookups
-   was detected.  For instance, for SVR4-style shadow passwords,
-   HAVE_GETSPNAM should be defined (you can search for the string
-   "shadow passwords" in config.h with your editor).  Note that
-   there is no define for 4.4BSD-based shadow passwords since that
-   just uses the standard getpw* routines.
-
-Q) I don't want the sudoers file in /etc, how can I specify where it
-   should go?
-A) Use the --sysconfdir option to configure.  Ie:
-   configure --sysconfdir=/dir/you/want/sudoers/in
-
-Q) Can I put the sudoers file in NIS/NIS+ or do I have to have a
-   copy on each machine?
-A) There is no support for making an NIS/NIS+ map/table out of
-   the sudoers file at this time.  A good way to distribute the
-   sudoers file is via rdist(1).  It is also possible to NFS-mount
-   the sudoers file.
-
-Q) I don't run sendmail on my machine.  Does this mean that I cannot
-   use sudo?
-A) No, you just need to run use the --without-sendmail argument to configure
-   or add "!mailerpath" to the Defaults line in /etc/sudoers.
-
-Q) When I run visudo it uses vi as the editor and I hate vi.  How
-   can I make it use another editor?
-A) Your best bet is to run configure with the --with-env-editor switch.
-   This will make visudo use the editor specified by the user's
-   EDITOR environment variable.  Alternately, you can run configure
-   with the --with-editor=/path/to/another/editor.
-
-Q) Sudo appears to be removing some variables from my environment, why?
-A) Sudo removes the following "dangerous" environment variables
-   to guard against shared library spoofing, shell voodoo, and
-   kerberos server spoofing.
-     IFS
-     LOCALDOMAIN
-     RES_OPTIONS
-     HOSTALIASES
-     NLSPATH
-     PATH_LOCALE
-     TERMINFO
-     TERMINFO_DIRS
-     TERMPATH
-     TERMCAP
-     ENV
-     BASH_ENV
-     LC_ (if it contains a '/' or '%')
-     LANG (if it contains a '/' or '%')
-     LANGUAGE (if it contains a '/' or '%')
-     LD_*
-     _RLD_*
-     SHLIB_PATH (HP-UX only)
-     LIBPATH (AIX only)
-     KRB_CONF (kerb4 only)
-     KRBCONFDIR (kerb4 only)
-     KRBTKFILE (kerb4 only)
-     KRB5_CONFIG (kerb5 only)
-     VAR_ACE (SecurID only)
-     USR_ACE (SecurID only)
-     DLC_ACE (SecurID only)
-
-Q) How can I keep sudo from asking for a password?
-A) To specify this on a per-user (and per-command) basis, use the 'NOPASSWD'
-   tag right before the command list in sudoers.  See the sudoers man page
-   and sample.sudoers for details.  To disable passwords completely,
-   run configure with the --without-passwd option or add "!authenticate"
-   to the Defaults line in /etc/sudoers.  You can also turn off authentication
-   on a per-user or per-host basis using a user or host-specific Defaults
-   entry in sudoers.
-
-Q) When I run configure, it dies with the following error:
-   "no acceptable cc found in $PATH".
-A) /usr/ucb/cc was the only C compiler that configure could find.
-   You need to tell configure the path to the "real" C compiler
-   via the --with-CC option.  On Solaris, the path is probably
-   something like "/opt/SUNWspro/SC4.0/bin/cc".  If you have gcc
-   that will also work.
-
-Q) When I run configure, it dies with the following error:
-   Fatal Error: config.cache exists from another platform!
-   Please remove it and re-run configure.
-A) configure caches the results of its tests in a file called
-   config.cache to make re-running configure speedy.  However,
-   if you are building sudo for a different platform the results
-   in config.cache will be wrong so you need to remove config.cache.
-   You can do this by "rm config.cache" or "make realclean".
-   Note that "make realclean" will also remove any object files
-   and configure temp files that are laying around as well.
-
-Q) I built sudo on a Solaris >= 2.6 machine but the resulting binary
-   doesn't work on Solaris <= 2.5.1.  Why?
-A) Starting with Solaris 2.6, snprintf(3) is included in the standard
-   C library.  To build a version of sudo on a >= 2.6 machine that
-   will run on a <= 2.5.1 machine, edit config.h and comment out the lines:
-       #define HAVE_SNPRINTF 1
-       #define HAVE_VSNPRINTF 1
-   and run make.
-
-Q) When I run "visudo" it says "sudoers file busy, try again later."
-   and doesn't do anything.
-A) Someone else is currently editing the sudoers file with visudo.
-
-Q) When I try to use "cd" with sudo it says "cd: command not found".
-A) "cd" is a shell built-in command, you can't run it as a command
-   since a child process (sudo) cannot affect the current working
-   directory of the parent (your shell).
-
-Q) When I try to use "cd" with sudo the command completes without
-   errors but nothing happens.
-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.
-   My sudoers file entry looks like:
-    bob        ALL=(oracle) ALL
-A) The default user sudo tries to run things as is always root, even if
-   the invoking user can only run commands as a single, specific user.
-   This may change in the future but at the present time you have to
-   work around this using the 'runas_default' option in sudoers.
-   For example:
-    Defaults:bob       runas_default=oracle
-   would achieve the desired result ofr the preceding sudoers fragment.
-
-Q) When I try to run sudo via ssh, I get the error:
-    sudo: no tty present and no askpass program specified
-A) ssh does not allocate a tty by default when running a remote command.
-   Without a tty, sudo cannot disable echo when prompting for a password.
-   You can use ssh's "-t" option to force it to allocate a tty.
-   Alternately, if you do not mind your password being echoed to the
-   screen, you can use the "visiblepw" sudoers option to allow this.
-
-Q) How do you pronounce `sudo'?
-A) The official pronunciation is soo-doo (for su "do").  However, an
-   alternate pronunciation, a homophone of "pseudo", is also common.
diff --git a/UPGRADE b/UPGRADE
deleted file mode 100644 (file)
index 8b7da22..0000000
--- a/UPGRADE
+++ /dev/null
@@ -1,227 +0,0 @@
-Notes on upgrading from an older release
-========================================
-
-o Upgrading from a version prior to 1.7.6:
-
-    Changes in the sudoers parser could result in parse errors for
-    existing sudoers file.  These changes cause certain erroneous
-    entries to be flagged as errors where before they allowed.
-    Changes include:
-
-    Combining multiple Defaults entries with a backslash.  E.g.
-
-       Defaults set_path \
-       Defaults syslog
-
-    which should be:
-
-       Defaults set_path
-       Defaults syslog
-
-    Also, double-quoted strings with a missing end-quote are now
-    detected and result in an error.  Previously, text starting a
-    double quote and ending with a newline was ignored.  E.g.
-
-       Defaults set_path"foo
-
-    In previous versions of sudo, the `"foo' portion would have
-    been ignored.
-
-    To avoid problems, sudo 1.8.1's "make install" will not install
-    a new sudo binary if the existing sudoers file has errors.
-
-o Upgrading from a version prior to 1.7.5:
-
-    Sudo 1.7.5 includes an updated LDAP schema with support for
-    the sudoNotBefore, sudoNotAfter and sudoOrder attributes.
-
-    The sudoNotBefore and sudoNotAfter attribute support is only
-    used when the SUDOERS_TIMED setting is enabled in ldap.conf.
-    If enabled, those attributes are used directly when constructing
-    an LDAP filter.  As a result, your LDAP server must have the
-    updated schema if you want to use sudoNotBefore and sudoNotAfter.
-
-    The sudoOrder support does not affect the LDAP filter sudo
-    constructs and so there is no need to explicitly enable it in
-    ldap.conf.  If the sudoOrder attribute is not present in an
-    entry, a value of 0 is used.  If no entries contain sudoOrder
-    attributes, the results are in whatever order the LDAP server
-    returns them, as in past versions of sudo.
-
-    Older versions of sudo will simply ignore the new attributes
-    if they are present in an entry.  There are no compatibility
-    problems using the updated schema with older versions of sudo.
-
-o Upgrading from a version prior to 1.7.4:
-
-    Starting with sudo 1.7.4, the time stamp files have moved from
-    /var/run/sudo to either /var/db/sudo, /var/lib/sudo or /var/adm/sudo.
-    The directories are checked for existence in that order.  This
-    prevents users from receiving the sudo lecture every time the
-    system reboots.  Time stamp files older than the boot time are
-    ignored on systems where it is possible to determine this.
-
-    Additionally, the tty_tickets sudoers option is now enabled by
-    default.  To restore the old behavior (single time stamp per user),
-    add a line like:
-       Defaults !tty_tickets
-    to sudoers or use the --without-tty-tickets configure option.
-
-    The HOME and MAIL environment variables are now reset based on the
-    target user's password database entry when the env_reset sudoers option
-    is enabled (which is the case in the default configuration).  Users
-    wishing to preserve the original values should use a sudoers entry like:
-        Defaults env_keep += HOME
-    to preserve the old value of HOME and
-        Defaults env_keep += MAIL
-    to preserve the old value of MAIL.
-
-    NOTE: preserving HOME has security implications since many programs
-    use when searching for configuration files.  Adding HOME to env_keep
-    may enable a user to run unrestricted commands via sudo.
-
-    The default syslog facility has changed from "local2" to "authpriv"
-    (or "auth" if the operating system doesn't have "authpriv").
-    The --with-logfac configure option can be used to change this
-    or it can be changed in the sudoers file.
-
-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 NEWS 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
-    method such as PAM, it will be used by default by configure.
-
-    Environment variable handling has changed significantly in sudo
-    1.6.9.  Prior to version 1.6.9, sudo would preserve the user's
-    environment, pruning out potentially dangerous variables.
-    Beginning with sudo 1.6.9, the envionment is reset to a default
-    set of values with only a small number of "safe" variables
-    preserved.  To preserve specific environment variables, add
-    them to the "env_keep" list in sudoers.  E.g.
-
-       Defaults env_keep += "EDITOR"
-
-    The old behavior can be restored by negating the "env_reset"
-    option in sudoers.  E.g.
-
-       Defaults !env_reset
-
-    There have  also been changes to how the "env_keep" and
-    "env_check" options behave.
-
-    Prior to sudo 1.6.9, the TERM and PATH environment variables
-    would always be preserved even if the env_keep option was
-    redefined.  That is no longer the case.  Consequently, if
-    env_keep is set with "=" and not simply appended to (i.e. using
-    "+="), PATH and TERM must be explicitly included in the list
-    of environment variables to keep.  The LOGNAME, SHELL, USER,
-    and USERNAME environment variables are still always set.
-
-    Additionally, the env_check setting previously had no effect
-    when env_reset was set (which is now on by default).  Starting
-    with sudo 1.6.9, environment variables listed in env_check are
-    also preserved in the env_reset case, provided that they do not
-    contain a '/' or '%' character.  Note that it is not necessary
-    to also list a variable in env_keep--having it in env_check is
-    sufficent.
-
-    The default lists of variables to be preserved and/or checked
-    are displayed when sudo is run by root with the -V flag.
-
-o Upgrading from a version prior to 1.6.8:
-
-    Prior to sudo 1.6.8, if /var/run did not exist, sudo would put
-    the time stamp files in /tmp/.odus.  As of sudo 1.6.8, the
-    time stamp files will be placed in /var/adm/sudo or /usr/adm/sudo
-    if there is no /var/run directory.  This directory will be
-    created if it does not already exist.
-
-    Previously, a sudoers entry that explicitly prohibited running
-    a command as a certain user did not override a previous entry
-    allowing the same command.  This has been fixed in sudo 1.6.8
-    such that the last match is now used (as it is documented).
-    Hopefully no one was depending on the previous (buggy) beghavior.
-
-o Upgrading from a version prior to 1.6:
-
-    As of sudo 1.6, parsing of runas entries and the NOPASSWD tag
-    has changed.  Prior to 1.6, a runas specifier applied only to
-    a single command directly following it.  Likewise, the NOPASSWD
-    tag only allowed the command directly following it to be run
-    without a password.  Starting with sudo 1.6, both the runas
-    specifier and the NOPASSWD tag are "sticky" for an entire
-    command list.  So, given the following line in sudo < 1.6
-
-       millert ALL=(daemon) NOPASSWD:/usr/bin/whoami,/bin/ls
-
-    millert would be able to run /usr/bin/whoami as user daemon
-    without a password and /bin/ls as root with a password.
-
-    As of sudo 1.6, the same line now means that millert is able
-    to run run both /usr/bin/whoami and /bin/ls as user daemon
-    without a password.  To expand on this, take the following
-    example:
-
-       millert ALL=(daemon) NOPASSWD:/usr/bin/whoami, (root) /bin/ls, \
-           /sbin/dump
-
-    millert can run /usr/bin/whoami as daemon and /bin/ls and
-    /sbin/dump as root.  No password need be given for either
-    command.  In other words, the "(root)" sets the default runas
-    user to root for the rest of the list.  If we wanted to require
-    a password for /bin/ls and /sbin/dump the line could be written
-    thusly:
-
-       millert ALL=(daemon) NOPASSWD:/usr/bin/whoami, \
-           (root) PASSWD:/bin/ls, /sbin/dump
-
-    Additionally, sudo now uses a per-user time stamp directory
-    instead of a time stamp file.  This allows tty time stamps to
-    simply be files within the user's time stamp dir.  For the
-    default, non-tty case, the time stamp on the directory itself
-    is used.
-
-    Also, the temporary file used by visudo is now /etc/sudoers.tmp
-    since some versions of vipw on systems with shadow passwords use
-    /etc/stmp for the temporary shadow file.
-
-o Upgrading from a version prior to 1.5:
-
-    By default, sudo expects the sudoers file to be mode 0440 and
-    to be owned by user and group 0.  This differs from version 1.4
-    and below which expected the sudoers file to be mode 0400 and
-    to be owned by root.  Doing a `make install' will set the sudoers
-    file to the new mode and group.  If sudo encounters a sudoers
-    file with the old permissions it will attempt to update it to
-    the new scheme.  You cannot, however, use a sudoers file with
-    the new permissions with an old sudo binary.  It is suggested
-    that if have a means of distributing sudo you distribute the
-    new binaries first, then the new sudoers file (or you can leave
-    sudoers as is and sudo will fix the permissions itself as long
-    as sudoers is on a local file system).
index 255b91fb6a64563a0a3d2ec9261a9b1fcd0cadda..e83926cf9a4419545355efeb967b583175f24c76 100644 (file)
@@ -79,6 +79,24 @@ if test X"$found" != X"yes"; then
 fi
 ])dnl
 
+dnl
+dnl check for utmp file
+dnl
+AC_DEFUN([SUDO_PATH_UTMP], [AC_MSG_CHECKING([for utmp file path])
+found=no
+for p in "/var/run/utmp" "/var/adm/utmp" "/etc/utmp"; do
+    if test -r "$p"; then
+       found=yes
+       AC_MSG_RESULT([$p])
+       SUDO_DEFINE_UNQUOTED(_PATH_UTMP, "$p")
+       break
+    fi
+done
+if test X"$found" != X"yes"; then
+    AC_MSG_RESULT([not found])
+fi
+])dnl
+
 dnl
 dnl Where the log file goes, use /var/log if it exists, else /{var,usr}/adm
 dnl
@@ -234,22 +252,6 @@ AC_DEFUN([SUDO_FUNC_UNSETENV_VOID],
     fi
   ])
 
-dnl
-dnl check putenv() argument for const
-dnl
-AC_DEFUN([SUDO_FUNC_PUTENV_CONST],
-[AC_CACHE_CHECK([whether putenv has a const argument],
-sudo_cv_func_putenv_const,
-[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
-int putenv(const char *string) {return 0;}], [])],
-    [sudo_cv_func_putenv_const=yes],
-    [sudo_cv_func_putenv_const=no])
-  ])
-  if test $sudo_cv_func_putenv_const = yes; then
-    AC_DEFINE(PUTENV_CONST, 1, [Define to 1 if the `putenv' has a const argument.])
-  fi
-])
-
 dnl
 dnl check for sa_len field in struct sockaddr
 dnl
diff --git a/aix.c b/aix.c
deleted file mode 100644 (file)
index 873896e..0000000
--- a/aix.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (c) 2008, 2010 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 <uinfo.h>
-
-#include "missing.h"
-#include "alloc.h"
-#include "error.h"
-
-#ifdef HAVE_GETUSERATTR
-
-#ifndef HAVE_SETRLIMIT64
-# define setrlimit64(a, b) setrlimit(a, b)
-# define rlimit64 rlimit
-# define rlim64_t rlim_t
-# define RLIM64_INFINITY RLIM_INFINITY
-#endif /* HAVE_SETRLIMIT64 */
-
-#ifndef RLIM_SAVED_MAX
-# define RLIM_SAVED_MAX        RLIM64_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;
-    rlim64_t *valp;
-{
-    int val;
-
-    if (getuserattr(user, lim, &val, SEC_INT) != 0)
-       return -1;
-    *valp = val;
-    return 0;
-}
-
-static void
-aix_setlimits(user)
-    char *user;
-{
-    struct rlimit64 rlim;
-    rlim64_t val;
-    int n;
-
-    if (setuserdb(S_READ) != 0)
-       error(1, "unable to open userdb");
-
-    /*
-     * For each resource limit, get the soft/hard values for the user
-     * and set those values via setrlimit64().  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, &val) == 0) {
-           rlim.rlim_max = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor;
-           if (aix_getlimit(user, aix_limits[n].soft, &val) == 0)
-               rlim.rlim_cur = val == -1 ? RLIM64_INFINITY : val * 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, &val) == 0)
-               rlim.rlim_cur = val == -1 ? RLIM64_INFINITY : val * 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 = RLIM64_INFINITY;
-                   break;
-           }
-       }
-       (void)setrlimit64(aix_limits[n].resource, &rlim);
-    }
-    enduserdb();
-}
-
-#ifdef HAVE_SETAUTHDB
-/*
- * Look up administrative domain for user (SYSTEM in /etc/security/user) and
- * set it as the default for the process.  This ensures that password and
- * group lookups are made against the correct source (files, NIS, LDAP, etc).
- */
-void
-aix_setauthdb(user)
-    char *user;
-{
-    char *registry;
-
-    if (user != NULL) {
-       if (setuserdb(S_READ) != 0)
-           error(1, "unable to open userdb");
-       if (getuserattr(user, S_REGISTRY, &registry, SEC_CHAR) == 0) {
-           if (setauthdb(registry, NULL) != 0)
-               error(1, "unable to switch to registry \"%s\" for %s",
-                   registry, user);
-       }
-       enduserdb();
-    }
-}
-
-/*
- * Restore the saved administrative domain, if any.
- */
-void
-aix_restoreauthdb()
-{
-    if (setauthdb(NULL, NULL) != 0)
-       error(1, "unable to restore registry");
-}
-#endif
-
-void
-aix_prep_user(user, tty)
-    char *user;
-    char *tty;
-{
-    char *info;
-    int len;
-
-    /* set usrinfo, like login(1) does */
-    len = easprintf(&info, "NAME=%s%cLOGIN=%s%cLOGNAME=%s%cTTY=%s%c",
-       user, '\0', user, '\0', user, '\0', tty ? tty : "", '\0');
-    (void)usrinfo(SETUINFO, info, len);
-    efree(info);
-
-#ifdef HAVE_SETAUTHDB
-    /* set administrative domain */
-    aix_setauthdb(user);
-#endif
-
-    /* set resource limits */
-    aix_setlimits(user);
-}
-#endif /* HAVE_GETUSERATTR */
diff --git a/aixcrypt.exp b/aixcrypt.exp
deleted file mode 100644 (file)
index 5ee024e..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#!
-__setkey
-__encrypt
-__crypt
diff --git a/alias.c b/alias.c
deleted file mode 100644 (file)
index 238830c..0000000
--- a/alias.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (c) 2004-2005, 2007-2010
- *     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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#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>
-
-/*
- * Globals
- */
-struct rbtree *aliases;
-unsigned int alias_seqno;
-
-/*
- * Comparison function for the red-black tree.
- * Aliases are sorted by name with the type used as a tie-breaker.
- */
-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 *
-alias_find(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)) {
-       snprintf(errbuf, sizeof(errbuf), "Alias `%s' already defined", name);
-       alias_free(a);
-       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.
- */
-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, remove it from the tree and return it.
- */
-struct alias *
-alias_remove(name, type)
-    char *name;
-    int type;
-{
-    struct rbnode *node;
-    struct alias key;
-
-    key.name = name;
-    key.type = type;
-    if ((node = rbfind(aliases, &key)) == NULL)
-       return NULL;
-    return rbdelete(aliases, node);
-}
-
-void
-init_aliases()
-{
-    if (aliases != NULL)
-       rbdestroy(aliases, alias_free);
-    aliases = rbcreate(alias_compare);
-}
diff --git a/alloc.c b/alloc.c
deleted file mode 100644 (file)
index 535465c..0000000
--- a/alloc.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2007, 2010
- *     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/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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRING_H */
-#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
-# include <malloc.h>
-#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
-#ifdef HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-
-#include "missing.h"
-#include "alloc.h"
-#include "error.h"
-
-/*
- * 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).  This just means that
- * emalloc2() and erealloc3() cannot allocate huge amounts on such a
- * platform but that is OK since sudo doesn't need to do so anyway.
- */
-#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 */
-
-/*
- * emalloc() calls the system malloc(3) and exits with an error if
- * malloc(3) fails.
- */
-void *
-emalloc(size)
-    size_t size;
-{
-    void *ptr;
-
-    if (size == 0)
-       errorx(1, "internal error, tried to emalloc(0)");
-
-    if ((ptr = malloc(size)) == NULL)
-       errorx(1, "unable to allocate memory");
-    return ptr;
-}
-
-/*
- * emalloc2() allocates nmemb * size bytes and exits with an error
- * if overflow would occur or if the system malloc(3) fails.
- */
-void *
-emalloc2(nmemb, size)
-    size_t nmemb;
-    size_t size;
-{
-    void *ptr;
-
-    if (nmemb == 0 || size == 0)
-       errorx(1, "internal error, tried to emalloc2(0)");
-    if (nmemb > SIZE_MAX / size)
-       errorx(1, "internal error, emalloc2() overflow");
-
-    size *= nmemb;
-    if ((ptr = malloc(size)) == NULL)
-       errorx(1, "unable to allocate memory");
-    return ptr;
-}
-
-/*
- * erealloc() calls the system realloc(3) and exits with an error if
- * realloc(3) fails.  You can call erealloc() with a NULL pointer even
- * if the system realloc(3) does not support this.
- */
-void *
-erealloc(ptr, size)
-    void *ptr;
-    size_t size;
-{
-
-    if (size == 0)
-       errorx(1, "internal error, tried to erealloc(0)");
-
-    ptr = ptr ? realloc(ptr, size) : malloc(size);
-    if (ptr == NULL)
-       errorx(1, "unable to allocate memory");
-    return ptr;
-}
-
-/*
- * erealloc3() realloc(3)s nmemb * size bytes and exits with an error
- * if overflow would occur or if the system malloc(3)/realloc(3) fails.
- * You can call erealloc() with a NULL pointer even if the system realloc(3)
- * does not support this.
- */
-void *
-erealloc3(ptr, nmemb, size)
-    void *ptr;
-    size_t nmemb;
-    size_t size;
-{
-
-    if (nmemb == 0 || size == 0)
-       errorx(1, "internal error, tried to erealloc3(0)");
-    if (nmemb > SIZE_MAX / size)
-       errorx(1, "internal error, erealloc3() overflow");
-
-    size *= nmemb;
-    ptr = ptr ? realloc(ptr, size) : malloc(size);
-    if (ptr == NULL)
-       errorx(1, "unable to allocate memory");
-    return ptr;
-}
-
-/*
- * estrdup() is like strdup(3) except that it exits with an error if
- * malloc(3) fails.  NOTE: unlike strdup(3), estrdup(NULL) is legal.
- */
-char *
-estrdup(src)
-    const char *src;
-{
-    char *dst = NULL;
-    size_t len;
-
-    if (src != NULL) {
-       len = strlen(src);
-       dst = (char *) emalloc(len + 1);
-       (void) memcpy(dst, src, len);
-       dst[len] = '\0';
-    }
-    return dst;
-}
-
-/*
- * easprintf() calls vasprintf() and exits with an error if vasprintf()
- * returns -1 (out of memory).
- */
-int
-#ifdef __STDC__
-easprintf(char **ret, const char *fmt, ...)
-#else
-easprintf(ret, fmt, va_alist)
-    char **ret;
-    const char *fmt;
-    va_dcl
-#endif
-{
-    int len;
-    va_list ap;
-#ifdef __STDC__
-    va_start(ap, fmt);
-#else
-    va_start(ap);
-#endif
-    len = vasprintf(ret, fmt, ap);
-    va_end(ap);
-
-    if (len == -1)
-       errorx(1, "unable to allocate memory");
-    return len;
-}
-
-/*
- * evasprintf() calls vasprintf() and exits with an error if vasprintf()
- * returns -1 (out of memory).
- */
-int
-evasprintf(ret, format, args)
-    char **ret;
-    const char *format;
-    va_list args;
-{
-    int len;
-
-    if ((len = vasprintf(ret, format, args)) == -1)
-       errorx(1, "unable to allocate memory");
-    return len;
-}
-
-/*
- * Wrapper for free(3) so we can depend on C89 semantics.
- */
-void
-efree(ptr)
-    void *ptr;
-{
-    if (ptr != NULL)
-       free(ptr);
-}
diff --git a/alloc.h b/alloc.h
deleted file mode 100644 (file)
index d3e1b07..0000000
--- a/alloc.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2009-2010 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.
- */
-
-#ifndef _SUDO_ALLOC_H
-#define _SUDO_ALLOC_H
-
-#ifdef __STDC__
-# include <stdarg.h>
-int     easprintf(char **, const char *, ...) __printflike(2, 3);
-int     evasprintf(char **, const char *, va_list) __printflike(2, 0);
-void    efree(void *);
-void   *emalloc(size_t);
-void   *emalloc2(size_t, size_t);
-void   *erealloc(void *, size_t);
-void   *erealloc3(void *, size_t, size_t);
-char   *estrdup(const char *);
-#else
-# include <varargs.h>
-int     easprintf();
-int     evasprintf();
-void    efree();
-void   *emalloc();
-void   *emalloc2();
-void   *erealloc();
-void   *erealloc3();
-char   *estrdup();
-#endif /* __STDC__ */
-
-#endif /* _SUDO_ALLOC_H */
diff --git a/audit.c b/audit.c
deleted file mode 100644 (file)
index 15ac8ee..0000000
--- a/audit.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2009 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 <stdio.h>
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif /* STDC_HEADERS */
-#ifdef __STDC__
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
-
-#include "missing.h"
-#include "logging.h"
-
-#ifdef HAVE_BSM_AUDIT
-# include "bsm_audit.h"
-#endif
-#ifdef HAVE_LINUX_AUDIT
-# include "linux_audit.h"
-#endif
-
-void
-#ifdef __STDC__
-audit_success(char *exec_args[])
-#else
-audit_success(exec_args)
-    const char *exec_args[];
-#endif
-{
-#ifdef HAVE_BSM_AUDIT
-    bsm_audit_success(exec_args);
-#endif
-#ifdef HAVE_LINUX_AUDIT
-    linux_audit_command(exec_args, 1);
-#endif
-}
-
-void
-#ifdef __STDC__
-audit_failure(char *exec_args[], char const *const fmt, ...)
-#else
-audit_failure(exec_args, fmt, va_alist)
-    const char *exec_args[];
-    char const *const fmt;
-    va_dcl
-#endif
-{
-    va_list ap;
-
-#ifdef __STDC__
-    va_start(ap, fmt);
-#else
-    va_start(ap);
-#endif
-#ifdef HAVE_BSM_AUDIT
-    bsm_audit_failure(exec_args, fmt, ap);
-#endif
-#ifdef HAVE_LINUX_AUDIT
-    linux_audit_command(exec_args, 0);
-#endif
-    va_end(ap);
-}
diff --git a/auth/API b/auth/API
deleted file mode 100644 (file)
index fd183fe..0000000
--- a/auth/API
+++ /dev/null
@@ -1,128 +0,0 @@
-NOTE: the Sudo auth API is subject to change
-
-Purpose: to provide a simple API for authentication methods that
-         encapsulates things nicely without turning into a maze
-        of #ifdef's
-
-The sudo_auth struct looks like this:
-
-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 */
-
-    int (*init) __P((struct passwd *pw, char **prompt, sudo_auth *auth));
-    int (*setup) __P((struct passwd *pw, char **prompt, sudo_auth *auth));
-    int (*verify) __P((struct passwd *pw, char *p, sudo_auth *auth));
-    int (*cleanup) __P((struct passwd *pw, sudo_auth *auth));
-} sudo_auth;
-
-The variables in the struct are as follows:
-    flags      Bitwise binary flags, see below.
-
-    status     Contains the return value from the last run of
-               the "verify" function.  Starts out as AUTH_FAILURE.
-
-    name       The name of the authentication method as a C string.
-
-    data       A pointer to method-specific data.  This is passed to
-               all the functions of an auth method and is usually
-               initialized in the "init" or "setup" routines.
-
-Possible values of sudo_auth.flags:
-    FLAG_USER          Whether or not the auth functions should run with
-                       the euid of the invoking user instead of 0.
-
-    FLAG_CONFIGURED    If set then the auth method is assumed to have been
-                       configured successfully.  All auth methods start out
-                       with this set.  If an "init" or "setup" function
-                       fails, this bit is cleared.
-
-    FLAG_ONEANDONLY    If set, this indicates that the method is the
-                       only one in use.  Can be used by auth functions
-                       to determine whether to return a fatal or nonfatal
-                       error.
-
-The member functions can return the following values:
-    AUTH_SUCCESS       Function succeeded.  For a ``verify'' function
-                       this means the user correctly authenticated.
-
-    AUTH_FAILURE       Function failed.  If this is an ``init'' or
-                       ``setup'' routine, the auth method will be
-                       marked as !configured.
-
-    AUTH_FATAL         A fatal error occurred.  The routine should have
-                       written an error message to stderr and optionally
-                       sent mail to the administrator.  (If log_error()
-                       is called to do this, the NO_EXIT flag must be used.)
-                       When verify_user() gets AUTH_FATAL from an auth
-                       function it does an exit(1).
-
-The functions in the struct are as follows:
-
-    int init(struct passwd *pw, char **prompt, sudo_auth *auth)
-        Function to do any one-time initialization for the auth
-        method.  All of the "init" functions are run before anything
-        else.  A pointer to the prompt string may be used to add
-        method-specific info to the prompt.
-
-    int setup(struct passwd *pw, char **prompt, sudo_auth *auth)
-        Function to do method-specific setup.  All the "setup"
-        routines are run before any of the "verify" routines.  A
-        pointer to the prompt string may be used to add method-specific
-        info to the prompt.
-
-    int verify(struct passwd *pw, char *p, sudo_auth *auth)
-        Function to do user verification for this auth method.  For
-        standalone auth methods ``p'' is the prompt string.  For
-        normal auth methods, ``p'' is the password the user entered.
-        Note that standalone auth methods are responsible for
-        rerading the password themselves.
-
-    int cleanup(struct passwd *pw, sudo_auth *auth)
-        Function to do per-auth method cleanup.  This is only run
-        at the end of the authentication process, after the user
-        has completely failed or succeeded to authenticate.
-       The ``auth->status'' variable contains the result of the
-       last authentication attempt which may be interesting.
-
-A note about standalone methods.  Some authentication methods can't
-coexist with any others.  This may be because they encapsulate other
-methods (pam, sia) or because they have a special way of interacting
-with the user (securid).
-
-Adding a new authentication method:
-
-Each method should live in its own file.  Add prototypes for the functions
-in sudo_auth.h.
-
-If this is a standalone method, add it to the standalone #if cascade
-in sudo_auth.h.  For instance, for a method, ``fooauth'', add:
-
-#elif defined(HAVE_FOOAUTH)
-#  define AUTH_STANDALONE \
-        AUTH_ENTRY(0, "foo", \
-           foo_init, foo_setup, foo_verify, foo_cleanup)
-
-If the method needs to run as the user, not root, replace the first
-parameter to AUTH_ENTRY (0) with FLAG_USER.  If you don't have a
-init/setup/cleanup routine, just use a NULL for that field.
-
-For a normal authentication method, add it to the ``auth_switch'' in
-sudo_auth.c.  If ``fooauth'' is a normal auth method, its entry
-would look like:
-
-#  ifdef HAVE_FOOAUTH
-    AUTH_ENTRY(0, "foo", foo_init, foo_setup, foo_verify, foo_cleanup)
-#  endif
-
-Again, if the method doesn't need to run as root, replace the 0 with
-FLAG_USER.  Likewise, if you don't have a init/setup/cleanup routine,
-just use a NULL for that field.
-
-NOTE:  You should not make a method both ``standalone'' and
-       ``normal''.  Just use the --without-passwd configure argument
-       to disable passwd/shadow file checking and then have your
-       auth routines check the FLAG_ONEANDONLY flag to see if
-       they are running standalone and act accordingly.
diff --git a/auth/afs.c b/auth/afs.c
deleted file mode 100644 (file)
index 393605a..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 1999, 2001-2005, 2007, 2010
- *     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/param.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 */
-#ifdef HAVE_STRING_H
-# include <string.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-
-#include <afs/stds.h>
-#include <afs/kautils.h>
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-int
-afs_verify(pw, pass, auth)
-    struct passwd *pw;
-    char *pass;
-    sudo_auth *auth;
-{
-    struct ktc_encryptionKey afs_key;
-    struct ktc_token afs_token;
-
-    /* Try to just check the password */
-    ka_StringToKey(pass, NULL, &afs_key);
-    if (ka_GetAdminToken(pw->pw_name,          /* name */
-                        NULL,                  /* instance */
-                        NULL,                  /* realm */
-                        &afs_key,              /* key (contains password) */
-                        0,                     /* lifetime */
-                        &afs_token,            /* token */
-                        0) == 0)               /* new */
-       return AUTH_SUCCESS;
-
-    /* Fall back on old method XXX - needed? */
-    setpag();
-    if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
-                                  pw->pw_name, /* name */
-                                  NULL,        /* instance */
-                                  NULL,        /* realm */
-                                  pass,        /* password */
-                                  0,           /* lifetime */
-                                  NULL,        /* expiration ptr (unused) */
-                                  0,           /* spare */
-                                  NULL) == 0)  /* reason */
-       return AUTH_SUCCESS;
-
-    return AUTH_FAILURE;
-}
diff --git a/auth/aix_auth.c b/auth/aix_auth.c
deleted file mode 100644 (file)
index fe65b0b..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2007-2010 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/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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <usersec.h>
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-/*
- * For a description of the AIX authentication API, see
- * http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf1/authenticate.htm
- */
-int
-aixauth_verify(pw, prompt, auth)
-    struct passwd *pw;
-    char *prompt;
-    sudo_auth *auth;
-{
-    char *pass;
-    char *message = NULL;
-    int reenter = 1;
-    int rval = AUTH_FAILURE;
-
-    pass = tgetpass(prompt, def_passwd_timeout * 60, tgetpass_flags);
-    if (pass) {
-       /* XXX - should probably print message on failure. */
-       if (authenticate(pw->pw_name, pass, &reenter, &message) == 0)
-           rval = AUTH_SUCCESS;
-       free(message);
-       zero_bytes(pass, strlen(pass));
-    }
-    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. */
-    unsetenv("AUTHSTATE");
-
-    return AUTH_SUCCESS;
-}
diff --git a/auth/bsdauth.c b/auth/bsdauth.c
deleted file mode 100644 (file)
index 727df13..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (c) 2000-2005, 2007-2008, 2010
- *     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/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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <ctype.h>
-#include <pwd.h>
-#include <signal.h>
-
-#include <login_cap.h>
-#include <bsd_auth.h>
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-extern char *login_style;              /* from sudo.c */
-
-int
-bsdauth_init(pw, promptp, auth)
-    struct passwd *pw;
-    char **promptp;
-    sudo_auth *auth;
-{
-    static auth_session_t *as;
-    extern login_cap_t *lc;                    /* from sudo.c */
-
-    if ((as = auth_open()) == NULL) {
-       log_error(USE_ERRNO|NO_EXIT|NO_MAIL,
-           "unable to begin bsd authentication");
-       return AUTH_FATAL;
-    }
-
-    /* XXX - maybe sanity check the auth style earlier? */
-    login_style = login_getstyle(lc, login_style, "auth-sudo");
-    if (login_style == NULL) {
-       log_error(NO_EXIT|NO_MAIL, "invalid authentication type");
-       auth_close(as);
-       return AUTH_FATAL;
-    }
-
-     if (auth_setitem(as, AUTHV_STYLE, login_style) < 0 ||
-       auth_setitem(as, AUTHV_NAME, pw->pw_name) < 0 ||
-       auth_setitem(as, AUTHV_CLASS, login_class) < 0) {
-       log_error(NO_EXIT|NO_MAIL, "unable to setup authentication");
-       auth_close(as);
-       return AUTH_FATAL;
-    }
-
-    auth->data = (void *) as;
-    return AUTH_SUCCESS;
-}
-
-int
-bsdauth_verify(pw, prompt, auth)
-    struct passwd *pw;
-    char *prompt;
-    sudo_auth *auth;
-{
-    char *pass;
-    char *s;
-    size_t len;
-    int authok = 0;
-    sigaction_t sa, osa;
-    auth_session_t *as = (auth_session_t *) auth->data;
-
-    /* save old signal handler */
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = SA_RESTART;
-    sa.sa_handler = SIG_DFL;
-    (void) sigaction(SIGCHLD, &sa, &osa);
-
-    /*
-     * If there is a challenge then print that instead of the normal
-     * prompt.  If the user just hits return we prompt again with echo
-     * turned on, which is useful for challenge/response things like
-     * S/Key.
-     */
-    if ((s = auth_challenge(as)) == NULL) {
-       pass = tgetpass(prompt, def_passwd_timeout * 60, tgetpass_flags);
-    } else {
-       pass = tgetpass(s, def_passwd_timeout * 60, tgetpass_flags);
-       if (pass && *pass == '\0') {
-           if ((prompt = strrchr(s, '\n')))
-               prompt++;
-           else
-               prompt = s;
-
-           /*
-            * Append '[echo on]' to the last line of the challenge and
-            * reprompt with echo turned on.
-            */
-           len = strlen(prompt) - 1;
-           while (isspace(prompt[len]) || prompt[len] == ':')
-               prompt[len--] = '\0';
-           easprintf(&s, "%s [echo on]: ", prompt);
-           pass = tgetpass(s, def_passwd_timeout * 60,
-               tgetpass_flags | TGP_ECHO);
-           free(s);
-       }
-    }
-
-    if (pass) {
-       authok = auth_userresponse(as, pass, 1);
-       zero_bytes(pass, strlen(pass));
-    }
-
-    /* restore old signal handler */
-    (void) sigaction(SIGCHLD, &osa, NULL);
-
-    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;
-}
-
-int
-bsdauth_cleanup(pw, auth)
-    struct passwd *pw;
-    sudo_auth *auth;
-{
-    auth_session_t *as = (auth_session_t *) auth->data;
-
-    auth_close(as);
-
-    return AUTH_SUCCESS;
-}
diff --git a/auth/dce.c b/auth/dce.c
deleted file mode 100644 (file)
index 3333a72..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-2005, 2010
- *     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.
- */
-/*
- *  The code below basically comes from the examples supplied on
- *  the OSF DCE 1.0.3 manpages for the sec_login routines, with
- *  enough additional polishing to make the routine work with the
- *  rest of sudo.
- *
- *  This code is known to work on HP 700 and 800 series systems
- *  running HP-UX 9.X and 10.X, with either HP's version 1.2.1 of DCE.
- *  (aka, OSF DCE 1.0.3) or with HP's version 1.4 of DCE (aka, OSF
- *  DCE 1.1).
- */
-
-#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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-
-#include <dce/rpc.h>
-#include <dce/sec_login.h>
-#include <dce/dce_error.h> /* required to call dce_error_inq_text routine */
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-static int check_dce_status __P((error_status_t, char *));
-
-int
-dce_verify(pw, plain_pw, auth)
-    struct passwd *pw;
-    char *plain_pw;
-    sudo_auth *auth;
-{
-    struct passwd              temp_pw;
-    sec_passwd_rec_t           password_rec;
-    sec_login_handle_t         login_context;
-    boolean32                  reset_passwd;
-    sec_login_auth_src_t       auth_src;
-    error_status_t             status;
-
-    /*
-     * Create the local context of the DCE principal necessary
-     * to perform authenticated network operations.  The network
-     * identity set up by this operation cannot be used until it
-     * is validated via sec_login_validate_identity().
-     */
-    if (sec_login_setup_identity((unsigned_char_p_t) pw->pw_name,
-       sec_login_no_flags, &login_context, &status)) {
-
-       if (check_dce_status(status, "sec_login_setup_identity(1):"))
-           return AUTH_FAILURE;
-
-       password_rec.key.key_type = sec_passwd_plain;
-       password_rec.key.tagged_union.plain = (idl_char *) plain_pw;
-       password_rec.pepper = NULL;
-       password_rec.version_number = sec_passwd_c_version_none;
-
-       /* Validate the login context with the password */
-       if (sec_login_validate_identity(login_context, &password_rec,
-           &reset_passwd, &auth_src, &status)) {
-
-           if (check_dce_status(status, "sec_login_validate_identity(1):"))
-               return AUTH_FAILURE;
-
-           /*
-            * Certify that the DCE Security Server used to set
-            * up and validate a login context is legitimate.  Makes
-            * sure that we didn't get spoofed by another DCE server.
-            */
-           if (!sec_login_certify_identity(login_context, &status)) {
-               (void) fprintf(stderr, "Whoa! Bogus authentication server!\n");
-               (void) check_dce_status(status,"sec_login_certify_identity(1):");
-               return AUTH_FAILURE;
-           }
-           if (check_dce_status(status, "sec_login_certify_identity(2):"))
-               return AUTH_FAILURE;
-
-           /*
-            * Sets the network credentials to those specified
-            * by the now validated login context.
-            */
-           sec_login_set_context(login_context, &status);
-           if (check_dce_status(status, "sec_login_set_context:"))
-               return AUTH_FAILURE;
-
-           /*
-            * Oops, your credentials were no good. Possibly
-            * caused by clock times out of adjustment between
-            * DCE client and DCE security server...
-            */
-           if (auth_src != sec_login_auth_src_network) {
-                   (void) fprintf(stderr,
-                       "You have no network credentials.\n");
-                   return AUTH_FAILURE;
-           }
-           /* Check if the password has aged and is thus no good */
-           if (reset_passwd) {
-                   (void) fprintf(stderr,
-                       "Your DCE password needs resetting.\n");
-                   return AUTH_FAILURE;
-           }
-
-           /*
-            * We should be a valid user by this point.  Pull the
-            * user's password structure from the DCE security
-            * server just to make sure.  If we get it with no
-            * problems, then we really are legitimate...
-            */
-           sec_login_get_pwent(login_context, (sec_login_passwd_t) &temp_pw,
-               &status);
-           if (check_dce_status(status, "sec_login_get_pwent:"))
-               return AUTH_FAILURE;
-
-           /*
-            * If we get to here, then the pwent above properly fetched
-            * the password structure from the DCE registry, so the user
-            * must be valid.  We don't really care what the user's
-            * registry password is, just that the user could be
-            * validated.  In fact, if we tried to compare the local
-            * password to the DCE entry at this point, the operation
-            * would fail if the hidden password feature is turned on,
-            * because the password field would contain an asterisk.
-            * Also go ahead and destroy the user's DCE login context
-            * before we leave here (and don't bother checking the
-            * status), in order to clean up credentials files in
-            * /opt/dcelocal/var/security/creds.  By doing this, we are
-            * assuming that the user will not need DCE authentication
-            * later in the program, only local authentication.  If this
-            * is not true, then the login_context will have to be
-            * returned to the calling program, and the context purged
-            * somewhere later in the program.
-            */
-           sec_login_purge_context(&login_context, &status);
-           return AUTH_SUCCESS;
-       } else {
-           if(check_dce_status(status, "sec_login_validate_identity(2):"))
-               return AUTH_FAILURE;
-           sec_login_purge_context(&login_context, &status);
-           if(check_dce_status(status, "sec_login_purge_context:"))
-               return AUTH_FAILURE;
-       }
-    }
-    (void) check_dce_status(status, "sec_login_setup_identity(2):");
-    return AUTH_FAILURE;
-}
-
-/* Returns 0 for DCE "ok" status, 1 otherwise */
-static int
-check_dce_status(input_status, comment)
-    error_status_t input_status;
-    char *comment;
-{
-    int error_stat;
-    unsigned char error_string[dce_c_error_string_len];
-
-    if (input_status == rpc_s_ok)
-       return 0;
-    dce_error_inq_text(input_status, error_string, &error_stat);
-    (void) fprintf(stderr, "%s %s\n", comment, error_string);
-    return 1;
-}
diff --git a/auth/fwtk.c b/auth/fwtk.c
deleted file mode 100644 (file)
index f1c164e..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2008, 2010
- *     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/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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-
-#include <auth.h>
-#include <firewall.h>
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-int
-fwtk_init(pw, promptp, auth)
-    struct passwd *pw;
-    char **promptp;
-    sudo_auth *auth;
-{
-    static Cfg *confp;                 /* Configuration entry struct */
-    char resp[128];                    /* Response from the server */
-
-    if ((confp = cfg_read("sudo")) == (Cfg *)-1) {
-       warningx("cannot read fwtk config");
-       return AUTH_FATAL;
-    }
-
-    if (auth_open(confp)) {
-       warningx("cannot connect to authentication server");
-       return AUTH_FATAL;
-    }
-
-    /* Get welcome message from auth server */
-    if (auth_recv(resp, sizeof(resp))) {
-       warningx("lost connection to authentication server");
-       return AUTH_FATAL;
-    }
-    if (strncmp(resp, "Authsrv ready", 13) != 0) {
-       warningx("authentication server error:\n%s", resp);
-       return AUTH_FATAL;
-    }
-
-    return AUTH_SUCCESS;
-}
-
-int
-fwtk_verify(pw, prompt, auth)
-    struct passwd *pw;
-    char *prompt;
-    sudo_auth *auth;
-{
-    char *pass;                                /* Password from the user */
-    char buf[SUDO_PASS_MAX + 12];      /* General prupose buffer */
-    char resp[128];                    /* Response from the server */
-    int error;
-
-    /* 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))) {
-       warningx("lost connection to authentication server");
-       return AUTH_FATAL;
-    }
-
-    /* Get the password/response from the user. */
-    if (strncmp(resp, "challenge ", 10) == 0) {
-       (void) snprintf(buf, sizeof(buf), "%s\nResponse: ", &resp[10]);
-       pass = tgetpass(buf, def_passwd_timeout * 60, tgetpass_flags);
-       if (pass && *pass == '\0') {
-           pass = tgetpass("Response [echo on]: ",
-               def_passwd_timeout * 60, tgetpass_flags | TGP_ECHO);
-       }
-    } else if (strncmp(resp, "chalnecho ", 10) == 0) {
-       pass = tgetpass(&resp[10], def_passwd_timeout * 60, tgetpass_flags);
-    } else if (strncmp(resp, "password", 8) == 0) {
-       pass = tgetpass(prompt, def_passwd_timeout * 60,
-           tgetpass_flags);
-    } else if (strncmp(resp, "display ", 8) == 0) {
-       fprintf(stderr, "%s\n", &resp[8]);
-       strlcpy(buf, "response dummy", sizeof(buf));
-       goto restart;
-    } else {
-       warningx("%s", resp);
-       return AUTH_FATAL;
-    }
-    if (!pass) {                       /* ^C or error */
-       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))) {
-       warningx("lost connection to authentication server");
-       error = AUTH_FATAL;
-       goto done;
-    }
-
-    if (strncmp(resp, "ok", 2) == 0) {
-       error = AUTH_SUCCESS;
-       goto done;
-    }
-
-    /* Main loop prints "Permission Denied" or insult. */
-    if (strcmp(resp, "Permission Denied.") != 0)
-       warningx("%s", resp);
-    error = AUTH_FAILURE;
-done:
-    zero_bytes(pass, strlen(pass));
-    zero_bytes(buf, strlen(buf));
-    return error;
-}
-
-int
-fwtk_cleanup(pw, auth)
-    struct passwd *pw;
-    sudo_auth *auth;
-{
-
-    auth_close();
-    return AUTH_SUCCESS;
-}
diff --git a/auth/kerb4.c b/auth/kerb4.c
deleted file mode 100644 (file)
index 883035d..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2007, 2010
- *     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/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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <krb.h>
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-int
-kerb4_init(pw, promptp, auth)
-    struct passwd *pw;
-    char **promptp;
-    sudo_auth *auth;
-{
-    static char realm[REALM_SZ];
-
-    /* Don't try to verify root */
-    if (pw->pw_uid == 0)
-       return AUTH_FAILURE;
-
-    /* Get the local realm, or retrun failure (no krb.conf) */
-    if (krb_get_lrealm(realm, 1) != KSUCCESS)
-       return AUTH_FAILURE;
-
-    /* Stash a pointer to the realm (used in kerb4_verify) */
-    auth->data = (void *) realm;
-
-    return AUTH_SUCCESS;
-}
-
-int
-kerb4_verify(pw, pass, auth)
-    struct passwd *pw;
-    char *pass;
-    sudo_auth *auth;
-{
-    char tkfile[sizeof(_PATH_SUDO_TIMEDIR) + 4 + MAX_UID_T_LEN];
-    char *realm = (char *) auth->data;
-    int error;
-
-    /*
-     * Set the ticket file to be in sudo sudo timedir so we don't
-     * wipe out other (real) kerberos tickets.
-     */
-    (void) snprintf(tkfile, sizeof(tkfile), "%s/tkt%u",
-       _PATH_SUDO_TIMEDIR, (unsigned int) pw->pw_uid);
-    (void) krb_set_tkt_string(tkfile);
-
-    /* Convert the password to a ticket given. */
-    error = krb_get_pw_in_tkt(pw->pw_name, "", realm, "krbtgt", realm,
-       DEFAULT_TKT_LIFE, pass);
-
-    switch (error) {
-       case INTK_OK:
-           dest_tkt();                 /* we are done with the temp ticket */
-           return AUTH_SUCCESS;
-           break;
-       case INTK_BADPW:
-       case KDC_PR_UNKNOWN:
-           break;
-       default:
-           (void) fprintf(stderr, "Warning: Kerberos error: %s\n",
-               krb_err_txt[error]);
-    }
-
-    return AUTH_FAILURE;
-}
diff --git a/auth/kerb5.c b/auth/kerb5.c
deleted file mode 100644 (file)
index 4ce04aa..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2007-2008, 2010
- *     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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <krb5.h>
-#ifdef HAVE_HEIMDAL
-#include <com_err.h>
-#endif
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-#ifdef HAVE_HEIMDAL
-# define extract_name(c, p)            krb5_principal_get_comp_string(c, p, 1)
-# define krb5_free_data_contents(c, d) krb5_data_free(d)
-#else
-# define extract_name(c, p)            (krb5_princ_component(c, p, 1)->data)
-#endif
-
-#ifndef HAVE_KRB5_VERIFY_USER
-static int verify_krb_v5_tgt __P((krb5_context, krb5_creds *, char *));
-#endif
-static struct _sudo_krb5_data {
-    krb5_context       sudo_context;
-    krb5_principal     princ;
-    krb5_ccache                ccache;
-} 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));
-    krb5_get_init_creds_opt_init(*opts);
-    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;
-    char **promptp;
-    sudo_auth *auth;
-{
-    krb5_context       sudo_context;
-    krb5_ccache                ccache;
-    krb5_principal     princ;
-    krb5_error_code    error;
-    char               cache_name[64];
-    char               *pname;
-
-    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));
-#else
-    error = krb5_init_context(&(sudo_krb5_data.sudo_context));
-#endif
-    if (error)
-       return AUTH_FAILURE;
-    sudo_context = sudo_krb5_data.sudo_context;
-
-    if ((error = krb5_parse_name(sudo_context, pw->pw_name,
-       &(sudo_krb5_data.princ)))) {
-       log_error(NO_EXIT|NO_MAIL,
-                 "%s: unable to parse '%s': %s", auth->name, pw->pw_name,
-                 error_message(error));
-       return AUTH_FAILURE;
-    }
-    princ = sudo_krb5_data.princ;
-
-    /*
-     * Really, we need to tell the caller not to prompt for password.
-     * The API does not currently provide this unless the auth is standalone.
-     */
-#if 1
-    if ((error = krb5_unparse_name(sudo_context, princ, &pname))) {
-       log_error(NO_EXIT|NO_MAIL,
-                 "%s: unable to unparse princ ('%s'): %s", auth->name,
-                 pw->pw_name, error_message(error));
-       return AUTH_FAILURE;
-    }
-
-    /* Only rewrite prompt if user didn't specify their own. */
-    /*if (!strcmp(prompt, PASSPROMPT)) { */
-       easprintf(promptp, "Password for %s: ", pname);
-    /*}*/
-    free(pname);
-#endif
-
-    (void) snprintf(cache_name, sizeof(cache_name), "MEMORY:sudocc_%ld",
-                   (long) getpid());
-    if ((error = krb5_cc_resolve(sudo_context, cache_name,
-       &(sudo_krb5_data.ccache)))) {
-       log_error(NO_EXIT|NO_MAIL,
-                 "%s: unable to resolve ccache: %s", auth->name,
-                 error_message(error));
-       return AUTH_FAILURE;
-    }
-    ccache = sudo_krb5_data.ccache;
-
-    return AUTH_SUCCESS;
-}
-
-#ifdef HAVE_KRB5_VERIFY_USER
-int
-kerb5_verify(pw, pass, auth)
-    struct passwd *pw;
-    char *pass;
-    sudo_auth *auth;
-{
-    krb5_context       sudo_context;
-    krb5_principal     princ;
-    krb5_ccache                ccache;
-    krb5_error_code    error;
-
-    sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context;
-    princ = ((sudo_krb5_datap) auth->data)->princ;
-    ccache = ((sudo_krb5_datap) auth->data)->ccache;
-
-    error = krb5_verify_user(sudo_context, princ, ccache, pass, 1, NULL);
-    return error ? AUTH_FAILURE : AUTH_SUCCESS;
-}
-#else
-int
-kerb5_verify(pw, pass, auth)
-    struct passwd *pw;
-    char *pass;
-    sudo_auth *auth;
-{
-    krb5_context       sudo_context;
-    krb5_principal     princ;
-    krb5_creds         credbuf, *creds = NULL;
-    krb5_ccache                ccache;
-    krb5_error_code    error;
-    krb5_get_init_creds_opt *opts = NULL;
-
-    sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context;
-    princ = ((sudo_krb5_datap) auth->data)->princ;
-    ccache = ((sudo_krb5_datap) auth->data)->ccache;
-
-    /* Set default flags based on the local config file. */
-    error = krb5_get_init_creds_opt_alloc(sudo_context, &opts);
-    if (error) {
-       log_error(NO_EXIT|NO_MAIL,
-                 "%s: unable to allocate options: %s", auth->name,
-                 error_message(error));
-       goto done;
-    }
-#ifdef HAVE_HEIMDAL
-    krb5_get_init_creds_opt_set_default_flags(sudo_context, NULL,
-       krb5_principal_get_realm(sudo_context, princ), opts);
-#endif
-
-    /* Note that we always obtain a new TGT to verify the user */
-    if ((error = krb5_get_init_creds_password(sudo_context, &credbuf, princ,
-                                            pass, krb5_prompter_posix,
-                                            NULL, 0, NULL, opts))) {
-       /* Don't print error if just a bad password */
-       if (error != KRB5KRB_AP_ERR_BAD_INTEGRITY)
-           log_error(NO_EXIT|NO_MAIL,
-                     "%s: unable to get credentials: %s", auth->name,
-                     error_message(error));
-       goto done;
-    }
-    creds = &credbuf;
-
-    /* Verify the TGT to prevent spoof attacks. */
-    if ((error = verify_krb_v5_tgt(sudo_context, creds, auth->name)))
-       goto done;
-
-    /* Store cred in cred cache. */
-    if ((error = krb5_cc_initialize(sudo_context, ccache, princ))) {
-       log_error(NO_EXIT|NO_MAIL,
-                 "%s: unable to initialize ccache: %s", auth->name,
-                 error_message(error));
-    } else if ((error = krb5_cc_store_cred(sudo_context, ccache, creds))) {
-       log_error(NO_EXIT|NO_MAIL,
-                 "%s: unable to store cred in ccache: %s", auth->name,
-                 error_message(error));
-    }
-
-done:
-    if (opts) {
-#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)
-       krb5_free_cred_contents(sudo_context, creds);
-    return error ? AUTH_FAILURE : AUTH_SUCCESS;
-}
-#endif
-
-int
-kerb5_cleanup(pw, auth)
-    struct passwd *pw;
-    sudo_auth *auth;
-{
-    krb5_context       sudo_context;
-    krb5_principal     princ;
-    krb5_ccache                ccache;
-
-    sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context;
-    princ = ((sudo_krb5_datap) auth->data)->princ;
-    ccache = ((sudo_krb5_datap) auth->data)->ccache;
-
-    if (sudo_context) {
-       if (ccache)
-           krb5_cc_destroy(sudo_context, ccache);
-       if (princ)
-           krb5_free_principal(sudo_context, princ);
-       krb5_free_context(sudo_context);
-    }
-
-    return AUTH_SUCCESS;
-}
-
-#ifndef HAVE_KRB5_VERIFY_USER
-/*
- * Verify the Kerberos ticket-granting ticket just retrieved for the
- * user.  If the Kerberos server doesn't respond, assume the user is
- * trying to fake us out (since we DID just get a TGT from what is
- * supposedly our KDC).
- *
- * Returns 0 for successful authentication, non-zero for failure.
- */
-static int
-verify_krb_v5_tgt(sudo_context, cred, auth_name)
-    krb5_context       sudo_context;
-    krb5_creds         *cred;
-    char               *auth_name; /* For error reporting */
-{
-    krb5_error_code    error;
-    krb5_principal     server;
-    krb5_verify_init_creds_opt vopt;
-
-    /*
-     * Get the server principal for the local host.
-     * (Use defaults of "host" and canonicalized local name.)
-     */
-    if ((error = krb5_sname_to_principal(sudo_context, NULL, NULL,
-                                       KRB5_NT_SRV_HST, &server))) {
-       log_error(NO_EXIT|NO_MAIL,
-                 "%s: unable to get host principal: %s", auth_name,
-                 error_message(error));
-       return -1;
-    }
-
-    /* Initialize verify opts and set secure mode */
-    krb5_verify_init_creds_opt_init(&vopt);
-    krb5_verify_init_creds_opt_set_ap_req_nofail(&vopt, 1);
-
-    /* verify the Kerberos ticket-granting ticket we just retrieved */
-    error = krb5_verify_init_creds(sudo_context, cred, server, NULL,
-                                  NULL, &vopt);
-    krb5_free_principal(sudo_context, server);
-    if (error)
-       log_error(NO_EXIT|NO_MAIL,
-                 "%s: Cannot verify TGT! Possible attack!: %s", auth_name,
-                 error_message(error));
-    return error;
-}
-#endif
diff --git a/auth/pam.c b/auth/pam.c
deleted file mode 100644 (file)
index 265de36..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2007-2010 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/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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <errno.h>
-
-#ifdef HAVE_PAM_PAM_APPL_H
-# include <pam/pam_appl.h>
-#else
-# include <security/pam_appl.h>
-#endif
-
-#ifdef HAVE_DGETTEXT
-# include <libintl.h>
-# if defined(__LINUX_PAM__)
-#  define PAM_TEXT_DOMAIN      "Linux-PAM"
-# elif defined(__sun__)
-#  define PAM_TEXT_DOMAIN      "SUNW_OST_SYSOSPAM"
-# endif
-#endif
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-/* Only OpenPAM and Linux PAM use const qualifiers. */
-#if defined(_OPENPAM) || defined(OPENPAM_VERSION) || \
-    defined(__LIBPAM_VERSION) || defined(__LINUX_PAM__)
-# define PAM_CONST     const
-#else
-# define PAM_CONST
-#endif
-
-static int sudo_conv __P((int, PAM_CONST struct pam_message **,
-                         struct pam_response **, void *));
-static char *def_prompt = "Password:";
-static int gotintr;
-
-#ifndef PAM_DATA_SILENT
-#define PAM_DATA_SILENT        0
-#endif
-
-static pam_handle_t *pamh;     /* global due to pam_prep_user() */
-
-int
-pam_init(pw, promptp, auth)
-    struct passwd *pw;
-    char **promptp;
-    sudo_auth *auth;
-{
-    static struct pam_conv pam_conv;
-    static int pam_status;
-
-    /* Initial PAM setup */
-    if (auth != NULL)
-       auth->data = (void *) &pam_status;
-    pam_conv.conv = sudo_conv;
-#ifdef HAVE_PAM_LOGIN
-    if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
-       pam_status = pam_start("sudo-i", pw->pw_name, &pam_conv, &pamh);
-    else
-#endif
-       pam_status = pam_start("sudo", pw->pw_name, &pam_conv, &pamh);
-
-    if (pam_status != PAM_SUCCESS) {
-       log_error(USE_ERRNO|NO_EXIT|NO_MAIL, "unable to initialize PAM");
-       return AUTH_FATAL;
-    }
-
-    /*
-     * Set PAM_RUSER to the invoking user (the "from" user).
-     * We set PAM_RHOST to avoid a bug in Solaris 7 and below.
-     */
-    (void) pam_set_item(pamh, PAM_RUSER, user_name);
-#ifdef __sun__
-    (void) pam_set_item(pamh, PAM_RHOST, user_host);
-#endif
-
-    /*
-     * 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.
-     */
-    if (user_ttypath == NULL)
-       (void) pam_set_item(pamh, PAM_TTY, "");
-    else
-       (void) pam_set_item(pamh, PAM_TTY, user_ttypath);
-
-    return AUTH_SUCCESS;
-}
-
-int
-pam_verify(pw, prompt, auth)
-    struct passwd *pw;
-    char *prompt;
-    sudo_auth *auth;
-{
-    const char *s;
-    int *pam_status = (int *) auth->data;
-
-    def_prompt = prompt;       /* for sudo_conv */
-
-    /* PAM_SILENT prevents the authentication service from generating output. */
-    *pam_status = pam_authenticate(pamh, PAM_SILENT);
-    switch (*pam_status) {
-       case PAM_SUCCESS:
-           *pam_status = pam_acct_mgmt(pamh, PAM_SILENT);
-           switch (*pam_status) {
-               case PAM_SUCCESS:
-                   return AUTH_SUCCESS;
-               case PAM_AUTH_ERR:
-                   log_error(NO_EXIT|NO_MAIL,
-                       "account validation failure, is your account locked?");
-                   return AUTH_FATAL;
-               case PAM_NEW_AUTHTOK_REQD:
-                   log_error(NO_EXIT|NO_MAIL, "%s, %s",
-                       "Account or password is expired",
-                       "reset your password and try again");
-                   *pam_status = pam_chauthtok(pamh,
-                       PAM_CHANGE_EXPIRED_AUTHTOK);
-                   if (*pam_status == PAM_SUCCESS)
-                       return AUTH_SUCCESS;
-                   if ((s = pam_strerror(pamh, *pam_status)))
-                       log_error(NO_EXIT|NO_MAIL, "pam_chauthtok: %s", s);
-                   return AUTH_FAILURE;
-               case PAM_AUTHTOK_EXPIRED:
-                   log_error(NO_EXIT|NO_MAIL,
-                       "Password expired, contact your system administrator");
-                   return AUTH_FATAL;
-               case PAM_ACCT_EXPIRED:
-                   log_error(NO_EXIT|NO_MAIL, "%s %s",
-                       "Account expired or PAM config lacks an \"account\"",
-                       "section for sudo, contact your system administrator");
-                   return AUTH_FATAL;
-           }
-           /* 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;
-       default:
-           if ((s = pam_strerror(pamh, *pam_status)))
-               log_error(NO_EXIT|NO_MAIL, "pam_authenticate: %s", s);
-           return AUTH_FATAL;
-    }
-}
-
-int
-pam_cleanup(pw, auth)
-    struct passwd *pw;
-    sudo_auth *auth;
-{
-    int *pam_status = (int *) auth->data;
-
-    /* If successful, we can't close the session until pam_prep_user() */
-    if (auth->status == AUTH_SUCCESS)
-       return AUTH_SUCCESS;
-
-    *pam_status = pam_end(pamh, *pam_status | PAM_DATA_SILENT);
-    return *pam_status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
-}
-
-int
-pam_begin_session(pw)
-    struct passwd *pw;
-{
-    int status =  PAM_SUCCESS;
-
-    /* If the user did not have to authenticate there is no pam handle yet. */
-    if (pamh == NULL)
-       pam_init(pw, NULL, NULL);
-
-    /*
-     * Update PAM_USER to reference the user we are running the command
-     * as, as opposed to the user we authenticated as.
-     */
-    (void) pam_set_item(pamh, PAM_USER, pw->pw_name);
-
-    /*
-     * Set credentials (may include resource limits, device ownership, etc).
-     * We don't check the return value here because in Linux-PAM 0.75
-     * it 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.
-     * We can't call pam_acct_mgmt() with Linux-PAM for a similar reason.
-     */
-    (void) pam_setcred(pamh, PAM_ESTABLISH_CRED);
-
-#ifndef NO_PAM_SESSION
-    status = pam_open_session(pamh, 0);
-     if (status != PAM_SUCCESS) {
-       (void) pam_end(pamh, status | PAM_DATA_SILENT);
-       pamh = NULL;
-    }
-#endif
-    return status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
-}
-
-int
-pam_end_session()
-{
-    int status = PAM_SUCCESS;
-
-    if (pamh != NULL) {
-#ifndef NO_PAM_SESSION
-       (void) pam_close_session(pamh, 0);
-#endif
-       status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
-    }
-    return status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
-}
-
-/*
- * ``Conversation function'' for PAM.
- * XXX - does not handle PAM_BINARY_PROMPT
- */
-static int
-sudo_conv(num_msg, msg, response, appdata_ptr)
-    int num_msg;
-    PAM_CONST struct pam_message **msg;
-    struct pam_response **response;
-    void *appdata_ptr;
-{
-    struct pam_response *pr;
-    PAM_CONST struct pam_message *pm;
-    const char *prompt;
-    char *pass;
-    int n, flags, std_prompt;
-
-    if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL)
-       return PAM_SYSTEM_ERR;
-    zero_bytes(*response, num_msg * sizeof(struct pam_response));
-
-    for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) {
-       flags = tgetpass_flags;
-       switch (pm->msg_style) {
-           case PAM_PROMPT_ECHO_ON:
-               SET(flags, TGP_ECHO);
-           case PAM_PROMPT_ECHO_OFF:
-               prompt = def_prompt;
-
-               /* Error out if the last password read was interrupted. */
-               if (gotintr)
-                   goto err;
-
-               /* Is the sudo prompt standard? (If so, we'l just use PAM's) */
-               std_prompt =  strncmp(def_prompt, "Password:", 9) == 0 &&
-                   (def_prompt[9] == '\0' ||
-                   (def_prompt[9] == ' ' && def_prompt[10] == '\0'));
-
-               /* Only override PAM prompt if it matches /^Password: ?/ */
-#if defined(PAM_TEXT_DOMAIN) && defined(HAVE_DGETTEXT)
-               if (!def_passprompt_override && (std_prompt ||
-                   (strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password: ")) &&
-                   strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password:")))))
-                   prompt = pm->msg;
-#else
-               if (!def_passprompt_override && (std_prompt ||
-                   strncmp(pm->msg, "Password:", 9) || (pm->msg[9] != '\0'
-                   && (pm->msg[9] != ' ' || pm->msg[10] != '\0'))))
-                   prompt = pm->msg;
-#endif
-               /* 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. */
-                   if (errno == EINTR)
-                       gotintr = 1;
-#if defined(__darwin__) || defined(__APPLE__)
-                   pass = "";
-#else
-                   goto err;
-#endif
-               }
-               pr->resp = estrdup(pass);
-               zero_bytes(pass, strlen(pass));
-               break;
-           case PAM_TEXT_INFO:
-               if (pm->msg)
-                   (void) puts(pm->msg);
-               break;
-           case PAM_ERROR_MSG:
-               if (pm->msg) {
-                   (void) fputs(pm->msg, stderr);
-                   (void) fputc('\n', stderr);
-               }
-               break;
-           default:
-               goto err;
-       }
-    }
-
-    return PAM_SUCCESS;
-
-err:
-    /* Zero and free allocated memory and return an error. */
-    for (pr = *response, n = num_msg; n--; pr++) {
-       if (pr->resp != NULL) {
-           zero_bytes(pr->resp, strlen(pr->resp));
-           free(pr->resp);
-           pr->resp = NULL;
-       }
-    }
-    zero_bytes(*response, num_msg * sizeof(struct pam_response));
-    free(*response);
-    *response = NULL;
-    return gotintr ? PAM_AUTH_ERR : PAM_CONV_ERR;
-}
diff --git a/auth/passwd.c b/auth/passwd.c
deleted file mode 100644 (file)
index 8835c03..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2010
- *     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/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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-#define DESLEN                 13
-#define HAS_AGEINFO(p, l)      (l == 18 && p[DESLEN] == ',')
-
-int
-passwd_init(pw, promptp, auth)
-    struct passwd *pw;
-    char **promptp;
-    sudo_auth *auth;
-{
-#ifdef HAVE_SKEYACCESS
-    if (skeyaccess(pw, user_tty, NULL, NULL) == 0)
-       return AUTH_FAILURE;
-#endif
-    sudo_setspent();
-    auth->data = sudo_getepw(pw);
-    sudo_endspent();
-    return AUTH_SUCCESS;
-}
-
-int
-passwd_verify(pw, pass, auth)
-    struct passwd *pw;
-    char *pass;
-    sudo_auth *auth;
-{
-    char sav, *epass;
-    char *pw_epasswd = auth->data;
-    size_t pw_len;
-    int error;
-
-    pw_len = strlen(pw_epasswd);
-
-#ifdef HAVE_GETAUTHUID
-    /* Ultrix shadow passwords may use crypt16() */
-    error = strcmp(pw_epasswd, (char *) crypt16(pass, pw_epasswd));
-    if (!error)
-       return AUTH_SUCCESS;
-#endif /* HAVE_GETAUTHUID */
-
-    /*
-     * Truncate to 8 chars if standard DES since not all crypt()'s do this.
-     * If this turns out not to be safe we will have to use OS #ifdef's (sigh).
-     */
-    sav = pass[8];
-    if (pw_len == DESLEN || HAS_AGEINFO(pw_epasswd, pw_len))
-       pass[8] = '\0';
-
-    /*
-     * Normal UN*X password check.
-     * HP-UX may add aging info (separated by a ',') at the end so
-     * only compare the first DESLEN characters in that case.
-     */
-    epass = (char *) crypt(pass, pw_epasswd);
-    pass[8] = sav;
-    if (HAS_AGEINFO(pw_epasswd, pw_len) && strlen(epass) == DESLEN)
-       error = strncmp(pw_epasswd, epass, DESLEN);
-    else
-       error = strcmp(pw_epasswd, epass);
-
-    return error ? AUTH_FAILURE : AUTH_SUCCESS;
-}
-
-int
-passwd_cleanup(pw, auth)
-    struct passwd *pw;
-    sudo_auth *auth;
-{
-    char *pw_epasswd = auth->data;
-
-    if (pw_epasswd != NULL) {
-       zero_bytes(pw_epasswd, strlen(pw_epasswd));
-       efree(pw_epasswd);
-    }
-    return AUTH_SUCCESS;
-}
diff --git a/auth/rfc1938.c b/auth/rfc1938.c
deleted file mode 100644 (file)
index b0640e5..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (c) 1994-1996, 1998-2005, 2010
- *     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/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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-
-#if defined(HAVE_SKEY)
-# include <skey.h>
-# define RFC1938                               skey
-#  ifdef __NetBSD__
-#   define rfc1938challenge(a,b,c,d)   skeychallenge((a),(b),(c),(d))
-#  else
-#   define rfc1938challenge(a,b,c,d)   skeychallenge((a),(b),(c))
-#  endif
-# define rfc1938verify(a,b)            skeyverify((a),(b))
-#elif defined(HAVE_OPIE)
-# include <opie.h>
-# define RFC1938                       opie
-# define rfc1938challenge(a,b,c,d)     opiechallenge((a),(b),(c))
-# define rfc1938verify(a,b)            opieverify((a),(b))
-#endif
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-int
-rfc1938_setup(pw, promptp, auth)
-    struct passwd *pw;
-    char **promptp;
-    sudo_auth *auth;
-{
-    char challenge[256];
-    static char *orig_prompt = NULL, *new_prompt = NULL;
-    static int op_len, np_size;
-    static struct RFC1938 rfc1938;
-
-    /* Stash a pointer to the rfc1938 struct if we have not initialized */
-    if (!auth->data)
-       auth->data = &rfc1938;
-
-    /* Save the original prompt */
-    if (orig_prompt == NULL) {
-       orig_prompt = *promptp;
-       op_len = strlen(orig_prompt);
-
-       /* Ignore trailing colon (we will add our own) */
-       if (orig_prompt[op_len - 1] == ':')
-           op_len--;
-       else if (op_len >= 2 && orig_prompt[op_len - 1] == ' '
-           && orig_prompt[op_len - 2] == ':')
-           op_len -= 2;
-    }
-
-#ifdef HAVE_SKEY
-    /* Close old stream */
-    if (rfc1938.keyfile)
-       (void) fclose(rfc1938.keyfile);
-#endif
-
-    /*
-     * Look up the user and get the rfc1938 challenge.
-     * If the user is not in the OTP db, only post a fatal error if
-     * we are running alone (since they may just use a normal passwd).
-     */
-    if (rfc1938challenge(&rfc1938, pw->pw_name, challenge, sizeof(challenge))) {
-       if (IS_ONEANDONLY(auth)) {
-           warningx("you do not exist in the %s database", auth->name);
-           return AUTH_FATAL;
-       } else {
-           return AUTH_FAILURE;
-       }
-    }
-
-    /* Get space for new prompt with embedded challenge */
-    if (np_size < op_len + strlen(challenge) + 7) {
-       np_size = op_len + strlen(challenge) + 7;
-       new_prompt = (char *) erealloc(new_prompt, np_size);
-    }
-
-    if (def_long_otp_prompt)
-       (void) snprintf(new_prompt, np_size, "%s\n%s", challenge, orig_prompt);
-    else
-       (void) snprintf(new_prompt, np_size, "%.*s [ %s ]:", op_len,
-           orig_prompt, challenge);
-
-    *promptp = new_prompt;
-    return AUTH_SUCCESS;
-}
-
-int
-rfc1938_verify(pw, pass, auth)
-    struct passwd *pw;
-    char *pass;
-    sudo_auth *auth;
-{
-
-    if (rfc1938verify((struct RFC1938 *) auth->data, pass) == 0)
-       return AUTH_SUCCESS;
-    else
-       return AUTH_FAILURE;
-}
diff --git a/auth/secureware.c b/auth/secureware.c
deleted file mode 100644 (file)
index c1c43d0..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (c) 1998-2005, 2010 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/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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#ifdef __hpux
-#  undef MAXINT
-#  include <hpsecurity.h>
-#else
-#  include <sys/security.h>
-#endif /* __hpux */
-#include <prot.h>
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-int
-secureware_init(pw, promptp, auth)
-    struct passwd *pw;
-    char **promptp;
-    sudo_auth *auth;
-{
-#ifdef __alpha
-    extern int crypt_type;
-
-    if (crypt_type == INT_MAX)
-       return AUTH_FAILURE;                    /* no shadow */
-#endif
-    sudo_setspent();
-    auth->data = sudo_getepw(pw);
-    sudo_endspent();
-    return AUTH_SUCCESS;
-}
-
-int
-secureware_verify(pw, pass, auth)
-    struct passwd *pw;
-    char *pass;
-    sudo_auth *auth;
-{
-    char *pw_epasswd = auth->data;
-#ifdef __alpha
-    extern int crypt_type;
-
-#  ifdef HAVE_DISPCRYPT
-    if (strcmp(pw_epasswd, dispcrypt(pass, pw_epasswd, crypt_type)) == 0)
-       return AUTH_SUCCESS;
-#  else
-    if (crypt_type == AUTH_CRYPT_BIGCRYPT) {
-       if (strcmp(pw_epasswd, bigcrypt(pass, pw_epasswd)) == 0)
-           return AUTH_SUCCESS;
-    } else if (crypt_type == AUTH_CRYPT_CRYPT16) {
-       if (strcmp(pw_epasswd, crypt(pass, pw_epasswd)) == 0)
-           return AUTH_SUCCESS;
-    }
-#  endif /* HAVE_DISPCRYPT */
-#elif defined(HAVE_BIGCRYPT)
-    if (strcmp(pw_epasswd, bigcrypt(pass, pw_epasswd)) == 0)
-       return AUTH_SUCCESS;
-#endif /* __alpha */
-
-       return AUTH_FAILURE;
-}
-
-int
-secureware_cleanup(pw, auth)
-    struct passwd *pw;
-    sudo_auth *auth;
-{
-    char *pw_epasswd = auth->data;
-
-    if (pw_epasswd != NULL) {
-       zero_bytes(pw_epasswd, strlen(pw_epasswd));
-       efree(pw_epasswd);
-    }
-    return AUTH_SUCCESS;
-}
diff --git a/auth/securid.c b/auth/securid.c
deleted file mode 100644 (file)
index 83ff94c..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2007, 2010
- *     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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-
-#include <sdi_athd.h>
-#include <sdconf.h>
-#include <sdacmvls.h>
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-union config_record configure;
-
-int
-securid_init(pw, promptp, auth)
-    struct passwd *pw;
-    char **promptp;
-    sudo_auth *auth;
-{
-    static struct SD_CLIENT sd_dat;            /* SecurID data block */
-
-    auth->data = (void *) &sd_dat;             /* For method-specific data */
-
-    if (creadcfg() == 0)
-       return AUTH_SUCCESS;
-    else
-       return AUTH_FATAL;
-}
-
-int
-securid_setup(pw, promptp, auth)
-    struct passwd *pw;
-    char **promptp;
-    sudo_auth *auth;
-{
-    struct SD_CLIENT *sd = (struct SD_CLIENT *) auth->data;
-
-    /* Re-initialize SecurID every time. */
-    if (sd_init(sd) == 0) {
-       /* The programmer's guide says username is 32 bytes */
-       strlcpy(sd->username, pw->pw_name, 32);
-       return AUTH_SUCCESS;
-    } else {
-       warningx("unable to contact the SecurID server");
-       return AUTH_FATAL;
-    }
-}
-
-int
-securid_verify(pw, pass, auth)
-    struct passwd *pw;
-    char *pass;
-    sudo_auth *auth;
-{
-    struct SD_CLIENT *sd = (struct SD_CLIENT *) auth->data;
-    int rval;
-
-    rval = sd_auth(sd);
-    sd_close();
-    if (rval == ACM_OK)
-       return AUTH_SUCCESS;
-    else
-       return AUTH_FAILURE;
-}
diff --git a/auth/securid5.c b/auth/securid5.c
deleted file mode 100644 (file)
index 6880c1a..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2007, 2010
- *     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
- * 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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-
-/* Needed for SecurID v5.0 Authentication on UNIX */
-#define UNIX 1
-#include <acexport.h>
-#include <sdacmvls.h>
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-/*
- * securid_init - Initialises communications with ACE server
- * Arguments in:
- *     pw - UNUSED
- *     promptp - UNUSED
- *     auth - sudo authentication structure
- *
- * Results out:
- *     auth - auth->data contains pointer to new SecurID handle
- *     return code - Fatal if initialization unsuccessful, otherwise
- *                   success.
- */
-int
-securid_init(pw, promptp, auth)
-    struct passwd *pw;
-    char **promptp;
-    sudo_auth *auth;
-{
-    static SDI_HANDLE sd_dat;                  /* SecurID handle */
-
-    auth->data = (void *) &sd_dat;             /* For method-specific data */
-
-    /* Start communications */
-    if (AceInitialize() != SD_FALSE)
-       return AUTH_SUCCESS;
-
-    warningx("failed to initialise the ACE API library");
-    return AUTH_FATAL;
-}
-
-/*
- * securid_setup - Initialises a SecurID transaction and locks out other
- *     ACE servers
- *
- * Arguments in:
- *     pw - struct passwd for username
- *     promptp - UNUSED
- *     auth - sudo authentication structure for SecurID handle
- *
- * Results out:
- *     return code - Success if transaction started correctly, fatal
- *                   otherwise
- */
-int
-securid_setup(pw, promptp, auth)
-    struct passwd *pw;
-    char **promptp;
-    sudo_auth *auth;
-{
-    SDI_HANDLE *sd = (SDI_HANDLE *) auth->data;
-    int retval;
-
-    /* Re-initialize SecurID every time. */
-    if (SD_Init(sd) != ACM_OK) {
-       warningx("unable to contact the SecurID server");
-       return AUTH_FATAL;
-    }
-
-    /* Lock new PIN code */
-    retval = SD_Lock(*sd, pw->pw_name);
-
-    switch (retval) {
-       case ACM_OK:
-               warningx("User ID locked for SecurID Authentication");
-               return AUTH_SUCCESS;
-
-        case ACE_UNDEFINED_USERNAME:
-               warningx("invalid username length for SecurID");
-               return AUTH_FATAL;
-
-       case ACE_ERR_INVALID_HANDLE:
-               warningx("invalid Authentication Handle for SecurID");
-               return AUTH_FATAL;
-
-       case ACM_ACCESS_DENIED:
-               warningx("SecurID communication failed");
-               return AUTH_FATAL;
-
-       default:
-               warningx("unknown SecurID error");
-               return AUTH_FATAL;
-       }
-}
-
-/*
- * securid_verify - Authenticates user and handles ACE responses
- *
- * Arguments in:
- *     pw - struct passwd for username
- *     pass - UNUSED
- *     auth - sudo authentication structure for SecurID handle
- *
- * Results out:
- *     return code - Success on successful authentication, failure on
- *                   incorrect authentication, fatal on errors
- */
-int
-securid_verify(pw, pass, auth)
-    struct passwd *pw;
-    char *pass;
-    sudo_auth *auth;
-{
-    SDI_HANDLE *sd = (SDI_HANDLE *) auth->data;
-    int rval;
-
-    pass = (char *) tgetpass("Enter your PASSCODE: ",
-       def_passwd_timeout * 60, tgetpass_flags);
-
-    /* Have ACE verify password */
-    switch (SD_Check(*sd, pass, pw->pw_name)) {
-       case ACM_OK:
-               rval = AUTH_SUCESS;
-               break;
-
-       case ACE_UNDEFINED_PASSCODE:
-               warningx("invalid passcode length for SecurID");
-               rval = AUTH_FATAL;
-               break;
-
-       case ACE_UNDEFINED_USERNAME:
-               warningx("invalid username length for SecurID");
-               rval = AUTH_FATAL;
-               break;
-
-       case ACE_ERR_INVALID_HANDLE:
-               warningx("invalid Authentication Handle for SecurID");
-               rval = AUTH_FATAL;
-               break;
-
-       case ACM_ACCESS_DENIED:
-               rval = AUTH_FAILURE;
-               break;
-
-       case ACM_NEXT_CODE_REQUIRED:
-                /* Sometimes (when current token close to expire?)
-                   ACE challenges for the next token displayed
-                   (entered without the PIN) */
-               pass = (char *) tgetpass("\
-!!! ATTENTION !!!\n\
-Wait for the token code to change, \n\
-then enter the new token code.\n", \
-               def_passwd_timeout * 60, tgetpass_flags);
-
-               if (SD_Next(*sd, pass) == ACM_OK) {
-                       rval = AUTH_SUCCESS;
-                       break;
-               }
-
-               rval = AUTH_FAILURE;
-               break;
-
-       case ACM_NEW_PIN_REQUIRED:
-                /*
-                * This user's SecurID has not been activated yet,
-                 * or the pin has been reset
-                */
-               /* XXX - Is setting up a new PIN within sudo's scope? */
-               SD_Pin(*sd, "");
-               fprintf(stderr, "Your SecurID access has not yet been set up.\n");
-               fprintf(stderr, "Please set up a PIN before you try to authenticate.\n");
-               rval = AUTH_FATAL;
-               break;
-
-       default:
-               warningx("unknown SecurID error");
-               rval = AUTH_FATAL;
-               break;
-    }
-
-    /* Free resources */
-    SD_Close(*sd);
-
-    /* Return stored state to calling process */
-    return rval;
-}
diff --git a/auth/sia.c b/auth/sia.c
deleted file mode 100644 (file)
index 6c972c6..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2007, 2010
- *     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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <siad.h>
-
-#include "sudo.h"
-#include "sudo_auth.h"
-
-static int sudo_collect        __P((int, int, uchar_t *, int, prompt_t *));
-
-static char *def_prompt;
-
-/*
- * Collection routine (callback) for limiting the timeouts in SIA
- * prompts and (possibly) setting a custom prompt.
- */
-static int
-sudo_collect(timeout, rendition, title, nprompts, prompts)
-    int timeout;
-    int rendition;
-    uchar_t *title;
-    int nprompts;
-    prompt_t *prompts;
-{
-    switch (rendition) {
-       case SIAFORM:
-       case SIAONELINER:
-           if (timeout <= 0 || timeout > def_passwd_timeout * 60)
-               timeout = def_passwd_timeout * 60;
-           /*
-            * Substitute custom prompt if a) the sudo prompt is not "Password:"
-            * and b) the SIA prompt is "Password:" (so we know it is safe).
-            * This keeps us from overwriting things like S/Key challenges.
-            */
-           if (strcmp((char *)prompts[0].prompt, "Password:") == 0 &&
-               strcmp(def_prompt, "Password:") != 0)
-               prompts[0].prompt = (unsigned char *)def_prompt;
-           break;
-       default:
-           break;
-    }
-
-    return sia_collect_trm(timeout, rendition, title, nprompts, prompts);
-}
-
-int
-sia_setup(pw, promptp, auth)
-    struct passwd *pw;
-    char **promptp;
-    sudo_auth *auth;
-{
-    SIAENTITY *siah = NULL;
-    extern int Argc;
-    extern char **Argv;
-
-    if (sia_ses_init(&siah, Argc, Argv, NULL, pw->pw_name, ttyname(0), 1, NULL)
-       != SIASUCCESS) {
-
-       log_error(USE_ERRNO|NO_EXIT|NO_MAIL,
-           "unable to initialize SIA session");
-       return AUTH_FATAL;
-    }
-
-    auth->data = (void *) siah;
-    return AUTH_SUCCESS;
-}
-
-int
-sia_verify(pw, prompt, auth)
-    struct passwd *pw;
-    char *prompt;
-    sudo_auth *auth;
-{
-    SIAENTITY *siah = (SIAENTITY *) auth->data;
-
-    def_prompt = prompt;               /* for sudo_collect */
-
-    /* XXX - need a way to detect user hitting return or EOF at prompt */
-    if (sia_ses_reauthent(sudo_collect, siah) == SIASUCCESS)
-       return AUTH_SUCCESS;
-    else
-       return AUTH_FAILURE;
-}
-
-int
-sia_cleanup(pw, auth)
-    struct passwd *pw;
-    sudo_auth *auth;
-{
-    SIAENTITY *siah = (SIAENTITY *) auth->data;
-
-    (void) sia_ses_release(&siah);
-    return AUTH_SUCCESS;
-}
diff --git a/auth/sudo_auth.c b/auth/sudo_auth.c
deleted file mode 100644 (file)
index 42455ee..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2008-2010 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/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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <time.h>
-#include <signal.h>
-
-#include "sudo.h"
-#include "sudo_auth.h"
-#include "insults.h"
-
-sudo_auth auth_switch[] = {
-#ifdef AUTH_STANDALONE
-    AUTH_STANDALONE
-#else
-#  ifndef WITHOUT_PASSWD
-    AUTH_ENTRY(0, "passwd", passwd_init, NULL, passwd_verify, passwd_cleanup)
-#  endif
-#  if defined(HAVE_GETPRPWNAM) && !defined(WITHOUT_PASSWD)
-    AUTH_ENTRY(0, "secureware", secureware_init, NULL, secureware_verify, secureware_cleanup)
-#  endif
-#  ifdef HAVE_AFS
-    AUTH_ENTRY(0, "afs", NULL, NULL, afs_verify, NULL)
-#  endif
-#  ifdef HAVE_DCE
-    AUTH_ENTRY(0, "dce", NULL, NULL, dce_verify, NULL)
-#  endif
-#  ifdef HAVE_KERB4
-    AUTH_ENTRY(0, "kerb4", kerb4_init, NULL, kerb4_verify, NULL)
-#  endif
-#  ifdef HAVE_KERB5
-    AUTH_ENTRY(0, "kerb5", kerb5_init, NULL, kerb5_verify, kerb5_cleanup)
-#  endif
-#  ifdef HAVE_SKEY
-    AUTH_ENTRY(0, "S/Key", NULL, rfc1938_setup, rfc1938_verify, NULL)
-#  endif
-#  ifdef HAVE_OPIE
-    AUTH_ENTRY(0, "OPIE", NULL, rfc1938_setup, rfc1938_verify, NULL)
-#  endif
-#endif /* AUTH_STANDALONE */
-    AUTH_ENTRY(0, NULL, NULL, NULL, NULL, NULL)
-};
-
-void
-verify_user(pw, prompt)
-    struct passwd *pw;
-    char *prompt;
-{
-    int counter = def_passwd_tries + 1;
-    int success = AUTH_FAILURE;
-    int status;
-    int flags;
-    char *p;
-    sudo_auth *auth;
-    sigaction_t sa, osa;
-#ifdef HAVE_BSM_AUDIT
-    extern char **NewArgv;
-#endif
-
-    /* Enable suspend during password entry. */
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = SA_RESTART;
-    sa.sa_handler = SIG_DFL;
-    (void) sigaction(SIGTSTP, &sa, &osa);
-
-    /* Make sure we have at least one auth method. */
-    if (auth_switch[0].name == NULL) {
-#ifdef HAVE_BSM_AUDIT
-       audit_failure(NewArgv, "no authentication methods");
-#endif
-       log_error(0, "%s  %s %s",
-           "There are no authentication methods compiled into sudo!",
-           "If you want to turn off authentication, use the",
-           "--disable-authentication configure option.");
-    }
-
-    /* Set FLAG_ONEANDONLY if there is only one auth method. */
-    if (auth_switch[1].name == NULL)
-       SET(auth_switch[0].flags, FLAG_ONEANDONLY);
-
-    /* Initialize auth methods and unconfigure the method if necessary. */
-    for (auth = auth_switch; auth->name; auth++) {
-       if (auth->init && IS_CONFIGURED(auth)) {
-           if (NEEDS_USER(auth))
-               set_perms(PERM_USER);
-
-           status = (auth->init)(pw, &prompt, auth);
-           if (status == AUTH_FAILURE)
-               CLR(auth->flags, FLAG_CONFIGURED);
-           else if (status == AUTH_FATAL) {    /* XXX log */
-#ifdef HAVE_BSM_AUDIT
-               audit_failure(NewArgv, "authentication failure");
-#endif
-               exit(1);                /* assume error msg already printed */
-           }
-
-           if (NEEDS_USER(auth))
-               set_perms(PERM_ROOT);
-       }
-    }
-
-    while (--counter) {
-       /* Do any per-method setup and unconfigure the method if needed */
-       for (auth = auth_switch; auth->name; auth++) {
-           if (auth->setup && IS_CONFIGURED(auth)) {
-               if (NEEDS_USER(auth))
-                   set_perms(PERM_USER);
-
-               status = (auth->setup)(pw, &prompt, auth);
-               if (status == AUTH_FAILURE)
-                   CLR(auth->flags, FLAG_CONFIGURED);
-               else if (status == AUTH_FATAL) {/* XXX log */
-#ifdef HAVE_BSM_AUDIT
-                   audit_failure(NewArgv, "authentication failure");
-#endif
-                   exit(1);            /* assume error msg already printed */
-               }
-
-               if (NEEDS_USER(auth))
-                   set_perms(PERM_ROOT);
-           }
-       }
-
-       /* Get the password unless the auth function will do it for us */
-#ifdef AUTH_STANDALONE
-       p = prompt;
-#else
-       p = (char *) tgetpass(prompt, def_passwd_timeout * 60,
-           tgetpass_flags);
-#endif /* AUTH_STANDALONE */
-
-       /* Call authentication functions. */
-       for (auth = auth_switch; p && auth->name; auth++) {
-           if (!IS_CONFIGURED(auth))
-               continue;
-
-           if (NEEDS_USER(auth))
-               set_perms(PERM_USER);
-
-           success = auth->status = (auth->verify)(pw, (char *)p, auth);
-
-           if (NEEDS_USER(auth))
-               set_perms(PERM_ROOT);
-
-           if (auth->status != AUTH_FAILURE)
-               goto cleanup;
-       }
-#ifndef AUTH_STANDALONE
-       if (p == NULL)
-           break;
-       zero_bytes(p, strlen(p));
-#endif
-       if (!ISSET(tgetpass_flags, TGP_ASKPASS))
-           pass_warn(stderr);
-    }
-
-cleanup:
-    /* Call cleanup routines. */
-    for (auth = auth_switch; auth->name; auth++) {
-       if (auth->cleanup && IS_CONFIGURED(auth)) {
-           if (NEEDS_USER(auth))
-               set_perms(PERM_USER);
-
-           status = (auth->cleanup)(pw, auth);
-           if (status == AUTH_FATAL) { /* XXX log */
-#ifdef HAVE_BSM_AUDIT
-               audit_failure(NewArgv, "authentication failure");
-#endif
-               exit(1);                /* assume error msg already printed */
-           }
-
-           if (NEEDS_USER(auth))
-               set_perms(PERM_ROOT);
-       }
-    }
-
-    switch (success) {
-       case AUTH_SUCCESS:
-           (void) sigaction(SIGTSTP, &osa, NULL);
-           return;
-       case AUTH_INTR:
-       case AUTH_FAILURE:
-           if (counter != def_passwd_tries) {
-               if (def_mail_badpass || def_mail_always)
-                   flags = 0;
-               else
-                   flags = NO_MAIL;
-#ifdef HAVE_BSM_AUDIT
-               audit_failure(NewArgv, "authentication failure");
-#endif
-               log_error(flags, "%d incorrect password attempt%s",
-                   def_passwd_tries - counter,
-                   (def_passwd_tries - counter == 1) ? "" : "s");
-           }
-           /* FALLTHROUGH */
-       case AUTH_FATAL:
-#ifdef HAVE_BSM_AUDIT
-           audit_failure(NewArgv, "authentication failure");
-#endif
-           exit(1);
-    }
-    /* NOTREACHED */
-}
-
-void
-pass_warn(fp)
-    FILE *fp;
-{
-
-#ifdef INSULT
-    if (def_insults)
-       (void) fprintf(fp, "%s\n", INSULT);
-    else
-#endif
-       (void) fprintf(fp, "%s\n", def_badpass_message);
-}
-
-void
-dump_auth_methods()
-{
-    sudo_auth *auth;
-
-    (void) fputs("Authentication methods:", stdout);
-    for (auth = auth_switch; auth->name; auth++)
-        (void) printf(" '%s'", auth->name);
-    (void) putchar('\n');
-}
diff --git a/auth/sudo_auth.h b/auth/sudo_auth.h
deleted file mode 100644 (file)
index 5024955..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2007-2009 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.
- */
-
-#ifndef SUDO_AUTH_H
-#define SUDO_AUTH_H
-
-/* Auth function return values.  */
-#define AUTH_SUCCESS   0
-#define AUTH_FAILURE   1
-#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 */
-    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));
-    int (*cleanup) __P((struct passwd *pw, struct sudo_auth *auth));
-} sudo_auth;
-
-/* Values for sudo_auth.flags.  */
-/* XXX - these names are too long for my liking */
-#define FLAG_USER      0x01    /* functions must run as the user, not root */
-#define FLAG_CONFIGURED        0x02    /* method configured ok */
-#define FLAG_ONEANDONLY        0x04    /* one and only auth method */
-
-/* Shortcuts for using the flags above. */
-#define NEEDS_USER(x)          ((x)->flags & FLAG_USER)
-#define IS_CONFIGURED(x)       ((x)->flags & FLAG_CONFIGURED)
-#define IS_ONEANDONLY(x)       ((x)->flags & FLAG_ONEANDONLY)
-
-/* Prototypes for standalone methods */
-int fwtk_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
-int fwtk_verify __P((struct passwd *pw, char *prompt, sudo_auth *auth));
-int fwtk_cleanup __P((struct passwd *pw, sudo_auth *auth));
-int pam_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
-int pam_verify __P((struct passwd *pw, char *prompt, sudo_auth *auth));
-int pam_cleanup __P((struct passwd *pw, sudo_auth *auth));
-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));
-
-/* Prototypes for normal methods */
-int passwd_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
-int passwd_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
-int passwd_cleanup __P((struct passwd *pw, sudo_auth *auth));
-int secureware_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
-int secureware_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
-int secureware_cleanup __P((struct passwd *pw, sudo_auth *auth));
-int rfc1938_setup __P((struct passwd *pw, char **prompt, sudo_auth *auth));
-int rfc1938_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
-int afs_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
-int dce_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
-int kerb4_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
-int kerb4_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
-int kerb5_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
-int kerb5_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
-int kerb5_cleanup __P((struct passwd *pw, sudo_auth *auth));
-int securid_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
-int securid_setup __P((struct passwd *pw, char **prompt, sudo_auth *auth));
-int securid_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
-
-/* Fields: need_root, name, init, setup, verify, cleanup */
-#define AUTH_ENTRY(r, n, i, s, v, c) \
-       { (r|FLAG_CONFIGURED), AUTH_FAILURE, n, NULL, i, s, v, c },
-
-/* Some methods cannots (or should not) interoperate with any others */
-#if defined(HAVE_PAM)
-#  define AUTH_STANDALONE \
-       AUTH_ENTRY(0, "pam", \
-           pam_init, NULL, pam_verify, pam_cleanup)
-#elif defined(HAVE_SECURID)
-#  define AUTH_STANDALONE \
-       AUTH_ENTRY(0, "SecurId", \
-           securid_init, securid_setup, securid_verify, NULL)
-#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, aixauth_cleanup)
-#elif defined(HAVE_FWTK)
-#  define AUTH_STANDALONE \
-       AUTH_ENTRY(0, "fwtk", \
-           fwtk_init, NULL, fwtk_verify, fwtk_cleanup)
-#elif defined(HAVE_BSD_AUTH_H)
-#  define AUTH_STANDALONE \
-       AUTH_ENTRY(0, "bsdauth", \
-           bsdauth_init, NULL, bsdauth_verify, bsdauth_cleanup)
-#endif
-
-#endif /* SUDO_AUTH_H */
diff --git a/boottime.c b/boottime.c
deleted file mode 100644 (file)
index bdcd1f2..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (c) 2009-2010 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/param.h>
-#include <sys/types.h>
-#include <sys/time.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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#include <limits.h>
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-#ifdef HAVE_GETUTXID
-# include <utmpx.h>
-#endif
-#ifdef HAVE_GETUTID
-# include <utmp.h>
-#endif
-#ifdef HAVE_SYSCTL
-# include <sys/sysctl.h>
-#endif
-
-#include "missing.h"
-
-/*
- * Fill in a struct timeval with the time the system booted.
- * Returns 1 on success and 0 on failure.
- */
-
-#if defined(__linux__)
-int
-get_boottime(tv)
-    struct timeval *tv;
-{
-    char *line = NULL;
-    size_t linesize = 0;
-    ssize_t len;
-    FILE * fp;
-
-    /* read btime from /proc/stat */
-    fp = fopen("/proc/stat", "r");
-    if (fp != NULL) {
-       while ((len = getline(&line, &linesize, fp)) != -1) {
-           if (strncmp(line, "btime ", 6) == 0) {
-               tv->tv_sec = atoi(line + 6);
-               tv->tv_usec = 0;
-               return 1;
-           }
-       }
-       fclose(fp);
-       free(line);
-    }
-
-    return 0;
-}
-
-#elif defined(HAVE_SYSCTL) && defined(KERN_BOOTTIME)
-
-int
-get_boottime(tv)
-    struct timeval *tv;
-{
-    size_t size;
-    int mib[2];
-
-    mib[0] = CTL_KERN;
-    mib[1] = KERN_BOOTTIME;
-    size = sizeof(*tv);
-    if (sysctl(mib, 2, tv, &size, NULL, 0) != -1)
-       return 1;
-
-    return 0;
-}
-
-#elif defined(HAVE_GETUTXID)
-
-int
-get_boottime(tv)
-    struct timeval *tv;
-{
-    struct utmpx *ut, key;
-
-    memset(&key, 0, sizeof(key));
-    key.ut_type = BOOT_TIME;
-    if ((ut = getutxid(&key)) != NULL) {
-       tv->tv_sec = ut->ut_tv.tv_sec;
-       tv->tv_usec = ut->ut_tv.tv_usec;
-       endutxent();
-    }
-    return ut != NULL;
-}
-
-#elif defined(HAVE_GETUTID)
-
-int
-get_boottime(tv)
-    struct timeval *tv;
-{
-    struct utmp *ut, key;
-
-    memset(&key, 0, sizeof(key));
-    key.ut_type = BOOT_TIME;
-    if ((ut = getutid(&key)) != NULL) {
-       tv->tv_sec = ut->ut_time;
-       tv->tv_usec = 0;
-       endutent();
-    }
-    return ut != NULL;
-}
-
-#else
-
-int
-get_boottime(tv)
-    struct timeval *tv;
-{
-    return 0;
-}
-#endif
diff --git a/bsm_audit.c b/bsm_audit.c
deleted file mode 100644 (file)
index 94ed4a8..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
- * Copyright (c) 2009 Christian S.J. Peron
- *
- * 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 <bsm/audit.h>
-#include <bsm/libbsm.h>
-#include <bsm/audit_uevents.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <pwd.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include "bsm_audit.h"
-
-/*
- * Solaris auditon() returns EINVAL if BSM audit not configured.
- * OpenBSM returns ENOSYS for unimplemented options.
- */
-#ifdef __sun
-# define AUDIT_NOT_CONFIGURED  EINVAL
-#else
-# define AUDIT_NOT_CONFIGURED  ENOSYS
-#endif
-
-void log_error(int flags, const char *fmt, ...) __attribute__((__noreturn__));
-
-static int
-audit_sudo_selected(int sf)
-{
-       auditinfo_addr_t ainfo_addr;
-       struct au_mask *mask;
-       auditinfo_t ainfo;
-       int rc, sorf;
-
-       if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) {
-               if (errno == ENOSYS) {
-                       if (getaudit(&ainfo) < 0)
-                               log_error(0, "getaudit: failed");
-                       mask = &ainfo.ai_mask;
-               } else
-                       log_error(0, "getaudit: failed");
-        } else
-               mask = &ainfo_addr.ai_mask;
-       sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE;
-       rc = au_preselect(AUE_sudo, mask, sorf, AU_PRS_REREAD);
-        return rc;
-}
-
-void
-bsm_audit_success(char **exec_args)
-{
-       auditinfo_addr_t ainfo_addr;
-       auditinfo_t ainfo;
-       token_t *tok;
-       au_id_t auid;
-       long au_cond;
-       int aufd;
-       pid_t pid;
-
-       pid = getpid();
-       /*
-        * If we are not auditing, don't cut an audit record; just return.
-        */
-       if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) {
-               if (errno == AUDIT_NOT_CONFIGURED)
-                       return;
-               log_error(0, "Could not determine audit condition");
-       }
-       if (au_cond == AUC_NOAUDIT)
-               return;
-       /*
-        * Check to see if the preselection masks are interested in seeing
-        * this event.
-        */
-       if (!audit_sudo_selected(0))
-               return;
-       if (getauid(&auid) < 0)
-               log_error(0, "getauid failed");
-       if ((aufd = au_open()) == -1)
-               log_error(0, "au_open: failed");
-       if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) {
-               tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
-                   getuid(), pid, pid, &ainfo_addr.ai_termid);
-       } else if (errno == ENOSYS) {
-               /*
-                * NB: We should probably watch out for ERANGE here.
-                */
-               if (getaudit(&ainfo) < 0)
-                       log_error(0, "getaudit: failed");
-               tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
-                   getuid(), pid, pid, &ainfo.ai_termid);
-       } else
-               log_error(0, "getaudit: failed");
-       if (tok == NULL)
-               log_error(0, "au_to_subject: failed");
-       au_write(aufd, tok);
-       tok = au_to_exec_args(exec_args);
-       if (tok == NULL)
-               log_error(0, "au_to_exec_args: failed");
-       au_write(aufd, tok);
-       tok = au_to_return32(0, 0);
-       if (tok == NULL)
-               log_error(0, "au_to_return32: failed");
-       au_write(aufd, tok);
-       if (au_close(aufd, 1, AUE_sudo) == -1)
-               log_error(0, "unable to commit audit record");
-}
-
-void
-bsm_audit_failure(char **exec_args, char const *const fmt, va_list ap)
-{
-       auditinfo_addr_t ainfo_addr;
-       auditinfo_t ainfo;
-       char text[256];
-       token_t *tok;
-       long au_cond;
-       au_id_t auid;
-       pid_t pid;
-       int aufd;
-
-       pid = getpid();
-       /*
-        * If we are not auditing, don't cut an audit record; just return.
-        */
-       if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
-               if (errno == AUDIT_NOT_CONFIGURED)
-                       return;
-               log_error(0, "Could not determine audit condition");
-       }
-       if (au_cond == AUC_NOAUDIT)
-               return;
-       if (!audit_sudo_selected(1))
-               return;
-       if (getauid(&auid) < 0)
-               log_error(0, "getauid: failed");
-       if ((aufd = au_open()) == -1)
-               log_error(0, "au_open: failed");
-       if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) { 
-               tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
-                   getuid(), pid, pid, &ainfo_addr.ai_termid);
-       } else if (errno == ENOSYS) {
-               if (getaudit(&ainfo) < 0) 
-                       log_error(0, "getaudit: failed");
-               tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
-                   getuid(), pid, pid, &ainfo.ai_termid);
-       } else
-               log_error(0, "getaudit: failed");
-       if (tok == NULL)
-               log_error(0, "au_to_subject: failed");
-       au_write(aufd, tok);
-       tok = au_to_exec_args(exec_args);
-       if (tok == NULL)
-               log_error(0, "au_to_exec_args: failed");
-       au_write(aufd, tok);
-       (void) vsnprintf(text, sizeof(text), fmt, ap);
-       tok = au_to_text(text);
-       if (tok == NULL)
-               log_error(0, "au_to_text: failed");
-       au_write(aufd, tok);
-       tok = au_to_return32(EPERM, 1);
-       if (tok == NULL)
-               log_error(0, "au_to_return32: failed");
-       au_write(aufd, tok);
-       if (au_close(aufd, 1, AUE_sudo) == -1)
-               log_error(0, "unable to commit audit record");
-}
diff --git a/bsm_audit.h b/bsm_audit.h
deleted file mode 100644 (file)
index 37be345..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
- * Copyright (c) 2009 Christian S.J. Peron
- *
- * 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.
- */
-
-#ifndef _SUDO_BSM_AUDIT_H
-#define        _SUDO_BSM_AUDIT_H
-
-void   bsm_audit_success(char **);
-void   bsm_audit_failure(char **, char const * const, va_list);
-
-#endif /* _SUDO_BSM_AUDIT_H */
diff --git a/check.c b/check.c
deleted file mode 100644 (file)
index df44bfc..0000000
--- a/check.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * Copyright (c) 1993-1996,1998-2005, 2007-2011
- *     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/param.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#ifdef __linux__
-# include <sys/vfs.h>
-#endif
-#if defined(__sun) && defined(__SVR4)
-# include <sys/statvfs.h>
-#endif
-#ifndef __TANDEM
-# include <sys/file.h>
-#endif
-#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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <pwd.h>
-#include <grp.h>
-
-#include "sudo.h"
-
-/* Status codes for timestamp_status() */
-#define TS_CURRENT             0
-#define TS_OLD                 1
-#define TS_MISSING             2
-#define TS_NOFILE              3
-#define TS_ERROR               4
-
-/* Flags for timestamp_status() */
-#define TS_MAKE_DIRS           1
-#define TS_REMOVE              2
-
-/*
- * Info stored in tty ticket from stat(2) to help with tty matching.
- */
-static struct tty_info {
-    dev_t dev;                 /* ID of device tty resides on */
-    dev_t rdev;                        /* tty device ID */
-    ino_t ino;                 /* tty inode number */
-    struct timeval ctime;      /* tty inode change time */
-} tty_info;
-
-static void  build_timestamp   __P((char **, char **));
-static int   timestamp_status  __P((char *, char *, char *, int));
-static char *expand_prompt     __P((char *, char *, char *));
-static void  lecture           __P((int));
-static void  update_timestamp  __P((char *, char *));
-static int   tty_is_devpts     __P((const char *));
-static struct passwd *get_authpw __P((void));
-
-/*
- * This function only returns if the user can successfully
- * verify who he/she is.
- */
-void
-check_user(validated, mode)
-    int validated;
-    int mode;
-{
-    char *timestampdir = NULL;
-    char *timestampfile = NULL;
-    char *prompt;
-    struct stat sb;
-    int status;
-
-    /* Stash the tty's ctime for tty ticket comparison. */
-    if (def_tty_tickets && user_ttypath && stat(user_ttypath, &sb) == 0) {
-       tty_info.dev = sb.st_dev;
-       tty_info.ino = sb.st_ino;
-       tty_info.rdev = sb.st_rdev;
-       if (tty_is_devpts(user_ttypath))
-           ctim_get(&sb, &tty_info.ctime);
-    }
-
-    /* Always prompt for a password when -k was specified with the command. */
-    if (ISSET(mode, MODE_INVALIDATE)) {
-       SET(validated, FLAG_CHECK_USER);
-    } else {
-       /*
-        * Don't prompt for the root passwd or if the user is exempt.
-        * If the user is not changing uid/gid, no need for a password.
-        */
-       if (user_uid == 0 || (user_uid == runas_pw->pw_uid &&
-           (!runas_gr || user_in_group(sudo_user.pw, runas_gr->gr_name))) ||
-           user_is_exempt())
-           return;
-    }
-
-    build_timestamp(&timestampdir, &timestampfile);
-    status = timestamp_status(timestampdir, timestampfile, user_name,
-       TS_MAKE_DIRS);
-
-    if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) {
-       struct passwd *auth_pw;
-
-       /* Bail out if we are non-interactive and a password is required */
-       if (ISSET(mode, MODE_NONINTERACTIVE))
-           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,
-           user_name, user_shost);
-
-       auth_pw = get_authpw();
-       verify_user(auth_pw, prompt);
-       pw_delref(auth_pw);
-    }
-    /* Only update timestamp if user was validated. */
-    if (ISSET(validated, VALIDATE_OK) && !ISSET(mode, MODE_INVALIDATE) && status != TS_ERROR)
-       update_timestamp(timestampdir, timestampfile);
-    efree(timestampdir);
-    efree(timestampfile);
-}
-
-/*
- * Standard sudo lecture.
- */
-static void
-lecture(status)
-    int status;
-{
-    FILE *fp;
-    char buf[BUFSIZ];
-    ssize_t nread;
-
-    if (def_lecture == never ||
-       (def_lecture == once && status != TS_MISSING && status != TS_ERROR))
-       return;
-
-    if (def_lecture_file && (fp = fopen(def_lecture_file, "r")) != NULL) {
-       while ((nread = fread(buf, sizeof(char), sizeof(buf), fp)) != 0)
-           fwrite(buf, nread, 1, stderr);
-       fclose(fp);
-    } else {
-       (void) fputs("\n\
-We trust you have received the usual lecture from the local System\n\
-Administrator. It usually boils down to these three things:\n\
-\n\
-    #1) Respect the privacy of others.\n\
-    #2) Think before you type.\n\
-    #3) With great power comes great responsibility.\n\n",
-    stderr);
-    }
-}
-
-/*
- * Update the time on the timestamp file/dir or create it if necessary.
- */
-static void
-update_timestamp(timestampdir, timestampfile)
-    char *timestampdir;
-    char *timestampfile;
-{
-    /* If using tty timestamps but we have no tty there is nothing to do. */
-    if (def_tty_tickets && !user_ttypath)
-       return;
-
-    if (timestamp_uid != 0)
-       set_perms(PERM_TIMESTAMP);
-    if (timestampfile) {
-       /*
-        * Store tty info in timestamp file
-        */
-       int fd = open(timestampfile, O_WRONLY|O_CREAT, 0600);
-       if (fd == -1)
-           log_error(NO_EXIT|USE_ERRNO, "Can't open %s", timestampfile);
-       else {
-           lock_file(fd, SUDO_LOCK);
-           if (write(fd, &tty_info, sizeof(tty_info)) != sizeof(tty_info))
-               log_error(NO_EXIT|USE_ERRNO, "Can't write %s", timestampfile);
-           close(fd);
-       }
-    } else {
-       if (touch(-1, timestampdir, NULL) == -1) {
-           if (mkdir(timestampdir, 0700) == -1)
-               log_error(NO_EXIT|USE_ERRNO, "Can't mkdir %s", timestampdir);
-       }
-    }
-    if (timestamp_uid != 0)
-       set_perms(PERM_ROOT);
-}
-
-/*
- * Expand %h and %u escapes in the prompt and pass back the dynamically
- * allocated result.  Returns the same string if there are no escapes.
- */
-static char *
-expand_prompt(old_prompt, user, host)
-    char *old_prompt;
-    char *user;
-    char *host;
-{
-    size_t len, n;
-    int subst;
-    char *p, *np, *new_prompt, *endp;
-
-    /* How much space do we need to malloc for the prompt? */
-    subst = 0;
-    for (p = old_prompt, len = strlen(old_prompt); *p; p++) {
-       if (p[0] =='%') {
-           switch (p[1]) {
-               case 'h':
-                   p++;
-                   len += strlen(user_shost) - 2;
-                   subst = 1;
-                   break;
-               case 'H':
-                   p++;
-                   len += strlen(user_host) - 2;
-                   subst = 1;
-                   break;
-               case 'p':
-                   p++;
-                   if (def_rootpw)
-                           len += 2;
-                   else if (def_targetpw || def_runaspw)
-                           len += strlen(runas_pw->pw_name) - 2;
-                   else
-                           len += strlen(user_name) - 2;
-                   subst = 1;
-                   break;
-               case 'u':
-                   p++;
-                   len += strlen(user_name) - 2;
-                   subst = 1;
-                   break;
-               case 'U':
-                   p++;
-                   len += strlen(runas_pw->pw_name) - 2;
-                   subst = 1;
-                   break;
-               case '%':
-                   p++;
-                   len--;
-                   subst = 1;
-                   break;
-               default:
-                   break;
-           }
-       }
-    }
-
-    if (subst) {
-       new_prompt = emalloc(++len);
-       endp = new_prompt + len;
-       for (p = old_prompt, np = new_prompt; *p; p++) {
-           if (p[0] =='%') {
-               switch (p[1]) {
-                   case 'h':
-                       p++;
-                       n = strlcpy(np, user_shost, np - endp);
-                       if (n >= np - endp)
-                           goto oflow;
-                       np += n;
-                       continue;
-                   case 'H':
-                       p++;
-                       n = strlcpy(np, user_host, np - endp);
-                       if (n >= np - endp)
-                           goto oflow;
-                       np += n;
-                       continue;
-                   case 'p':
-                       p++;
-                       if (def_rootpw)
-                               n = strlcpy(np, "root", np - endp);
-                       else if (def_targetpw || def_runaspw)
-                               n = strlcpy(np, runas_pw->pw_name, np - endp);
-                       else
-                               n = strlcpy(np, user_name, np - endp);
-                       if (n >= np - endp)
-                               goto oflow;
-                       np += n;
-                       continue;
-                   case 'u':
-                       p++;
-                       n = strlcpy(np, user_name, np - endp);
-                       if (n >= np - endp)
-                           goto oflow;
-                       np += n;
-                       continue;
-                   case 'U':
-                       p++;
-                       n = strlcpy(np,  runas_pw->pw_name, np - endp);
-                       if (n >= np - endp)
-                           goto oflow;
-                       np += n;
-                       continue;
-                   case '%':
-                       /* convert %% -> % */
-                       p++;
-                       break;
-                   default:
-                       /* no conversion */
-                       break;
-               }
-           }
-           *np++ = *p;
-           if (np >= endp)
-               goto oflow;
-       }
-       *np = '\0';
-    } else
-       new_prompt = old_prompt;
-
-    return new_prompt;
-
-oflow:
-    /* We pre-allocate enough space, so this should never happen. */
-    errorx(1, "internal error, expand_prompt() overflow");
-}
-
-/*
- * Checks if the user is exempt from supplying a password.
- */
-int
-user_is_exempt()
-{
-    if (!def_exempt_group)
-       return FALSE;
-    return user_in_group(sudo_user.pw, def_exempt_group);
-}
-
-/*
- * Fills in timestampdir as well as timestampfile if using tty tickets.
- */
-static void
-build_timestamp(timestampdir, timestampfile)
-    char **timestampdir;
-    char **timestampfile;
-{
-    char *dirparent;
-    int len;
-
-    dirparent = def_timestampdir;
-    len = easprintf(timestampdir, "%s/%s", dirparent, user_name);
-    if (len >= PATH_MAX)
-       log_error(0, "timestamp path too long: %s", *timestampdir);
-
-    /*
-     * Timestamp file may be a file in the directory or NUL to use
-     * the directory as the timestamp.
-     */
-    if (def_tty_tickets) {
-       char *p;
-
-       if ((p = strrchr(user_tty, '/')))
-           p++;
-       else
-           p = user_tty;
-       if (def_targetpw)
-           len = easprintf(timestampfile, "%s/%s/%s:%s", dirparent, user_name,
-               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,
-           runas_pw->pw_name);
-       if (len >= PATH_MAX)
-           log_error(0, "timestamp path too long: %s", *timestampfile);
-    } else
-       *timestampfile = NULL;
-}
-
-/*
- * Check the timestamp file and directory and return their status.
- */
-static int
-timestamp_status(timestampdir, timestampfile, user, flags)
-    char *timestampdir;
-    char *timestampfile;
-    char *user;
-    int flags;
-{
-    struct stat sb;
-    struct timeval boottime, mtime;
-    time_t now;
-    char *dirparent = def_timestampdir;
-    int status = TS_ERROR;             /* assume the worst */
-
-    if (timestamp_uid != 0)
-       set_perms(PERM_TIMESTAMP);
-
-    /*
-     * Sanity check dirparent and make it if it doesn't already exist.
-     * We start out assuming the worst (that the dir is not sane) and
-     * if it is ok upgrade the status to ``no timestamp file''.
-     * Note that we don't check the parent(s) of dirparent for
-     * sanity since the sudo dir is often just located in /tmp.
-     */
-    if (lstat(dirparent, &sb) == 0) {
-       if (!S_ISDIR(sb.st_mode))
-           log_error(NO_EXIT, "%s exists but is not a directory (0%o)",
-               dirparent, (unsigned int) sb.st_mode);
-       else if (sb.st_uid != timestamp_uid)
-           log_error(NO_EXIT, "%s owned by uid %u, should be uid %u",
-               dirparent, (unsigned int) sb.st_uid,
-               (unsigned int) timestamp_uid);
-       else if ((sb.st_mode & 0000022))
-           log_error(NO_EXIT,
-               "%s writable by non-owner (0%o), should be mode 0700",
-               dirparent, (unsigned int) sb.st_mode);
-       else {
-           if ((sb.st_mode & 0000777) != 0700)
-               (void) chmod(dirparent, 0700);
-           status = TS_MISSING;
-       }
-    } else if (errno != ENOENT) {
-       log_error(NO_EXIT|USE_ERRNO, "can't stat %s", dirparent);
-    } else {
-       /* No dirparent, try to make one. */
-       if (ISSET(flags, TS_MAKE_DIRS)) {
-           if (mkdir(dirparent, S_IRWXU))
-               log_error(NO_EXIT|USE_ERRNO, "can't mkdir %s",
-                   dirparent);
-           else
-               status = TS_MISSING;
-       }
-    }
-    if (status == TS_ERROR) {
-       if (timestamp_uid != 0)
-           set_perms(PERM_ROOT);
-       return status;
-    }
-
-    /*
-     * Sanity check the user's ticket dir.  We start by downgrading
-     * the status to TS_ERROR.  If the ticket dir exists and is sane
-     * this will be upgraded to TS_OLD.  If the dir does not exist,
-     * it will be upgraded to TS_MISSING.
-     */
-    status = TS_ERROR;                 /* downgrade status again */
-    if (lstat(timestampdir, &sb) == 0) {
-       if (!S_ISDIR(sb.st_mode)) {
-           if (S_ISREG(sb.st_mode)) {
-               /* convert from old style */
-               if (unlink(timestampdir) == 0)
-                   status = TS_MISSING;
-           } else
-               log_error(NO_EXIT, "%s exists but is not a directory (0%o)",
-                   timestampdir, (unsigned int) sb.st_mode);
-       } else if (sb.st_uid != timestamp_uid)
-           log_error(NO_EXIT, "%s owned by uid %u, should be uid %u",
-               timestampdir, (unsigned int) sb.st_uid,
-               (unsigned int) timestamp_uid);
-       else if ((sb.st_mode & 0000022))
-           log_error(NO_EXIT,
-               "%s writable by non-owner (0%o), should be mode 0700",
-               timestampdir, (unsigned int) sb.st_mode);
-       else {
-           if ((sb.st_mode & 0000777) != 0700)
-               (void) chmod(timestampdir, 0700);
-           status = TS_OLD;            /* do date check later */
-       }
-    } else if (errno != ENOENT) {
-       log_error(NO_EXIT|USE_ERRNO, "can't stat %s", timestampdir);
-    } else
-       status = TS_MISSING;
-
-    /*
-     * If there is no user ticket dir, AND we are in tty ticket mode,
-     * AND the TS_MAKE_DIRS flag is set, create the user ticket dir.
-     */
-    if (status == TS_MISSING && timestampfile && ISSET(flags, TS_MAKE_DIRS)) {
-       if (mkdir(timestampdir, S_IRWXU) == -1) {
-           status = TS_ERROR;
-           log_error(NO_EXIT|USE_ERRNO, "can't mkdir %s", timestampdir);
-       }
-    }
-
-    /*
-     * Sanity check the tty ticket file if it exists.
-     */
-    if (timestampfile && status != TS_ERROR) {
-       if (status != TS_MISSING)
-           status = TS_NOFILE;                 /* dir there, file missing */
-       if (def_tty_tickets && !user_ttypath)
-           goto done;                          /* no tty, always prompt */
-       if (lstat(timestampfile, &sb) == 0) {
-           if (!S_ISREG(sb.st_mode)) {
-               status = TS_ERROR;
-               log_error(NO_EXIT, "%s exists but is not a regular file (0%o)",
-                   timestampfile, (unsigned int) sb.st_mode);
-           } else {
-               /* If bad uid or file mode, complain and kill the bogus file. */
-               if (sb.st_uid != timestamp_uid) {
-                   log_error(NO_EXIT,
-                       "%s owned by uid %u, should be uid %u",
-                       timestampfile, (unsigned int) sb.st_uid,
-                       (unsigned int) timestamp_uid);
-                   (void) unlink(timestampfile);
-               } else if ((sb.st_mode & 0000022)) {
-                   log_error(NO_EXIT,
-                       "%s writable by non-owner (0%o), should be mode 0600",
-                       timestampfile, (unsigned int) sb.st_mode);
-                   (void) unlink(timestampfile);
-               } else {
-                   /* If not mode 0600, fix it. */
-                   if ((sb.st_mode & 0000777) != 0600)
-                       (void) chmod(timestampfile, 0600);
-
-                   /*
-                    * Check for stored tty info.  If the file is zero-sized
-                    * it is an old-style timestamp with no tty info in it.
-                    * If removing, we don't care about the contents.
-                    * The actual mtime check is done later.
-                    */
-                   if (ISSET(flags, TS_REMOVE)) {
-                       status = TS_OLD;
-                   } else if (sb.st_size != 0) {
-                       struct tty_info info;
-                       int fd = open(timestampfile, O_RDONLY, 0644);
-                       if (fd != -1) {
-                           if (read(fd, &info, sizeof(info)) == sizeof(info) &&
-                               memcmp(&info, &tty_info, sizeof(info)) == 0) {
-                               status = TS_OLD;
-                           }
-                           close(fd);
-                       }
-                   }
-               }
-           }
-       } else if (errno != ENOENT) {
-           log_error(NO_EXIT|USE_ERRNO, "can't stat %s", timestampfile);
-           status = TS_ERROR;
-       }
-    }
-
-    /*
-     * If the file/dir exists and we are not removing it, check its mtime.
-     */
-    if (status == TS_OLD && !ISSET(flags, TS_REMOVE)) {
-       mtim_get(&sb, &mtime);
-       /* Negative timeouts only expire manually (sudo -k). */
-       if (def_timestamp_timeout < 0 && mtime.tv_sec != 0)
-           status = TS_CURRENT;
-       else {
-           now = time(NULL);
-           if (def_timestamp_timeout &&
-               now - mtime.tv_sec < 60 * def_timestamp_timeout) {
-               /*
-                * Check for bogus time on the stampfile.  The clock may
-                * have been set back or someone could be trying to spoof us.
-                */
-               if (mtime.tv_sec > now + 60 * def_timestamp_timeout * 2) {
-                   time_t tv_sec = (time_t)mtime.tv_sec;
-                   log_error(NO_EXIT,
-                       "timestamp too far in the future: %20.20s",
-                       4 + ctime(&tv_sec));
-                   if (timestampfile)
-                       (void) unlink(timestampfile);
-                   else
-                       (void) rmdir(timestampdir);
-                   status = TS_MISSING;
-               } else if (get_boottime(&boottime) && timevalcmp(&mtime, &boottime, <)) {
-                   status = TS_OLD;
-               } else {
-                   status = TS_CURRENT;
-               }
-           }
-       }
-    }
-
-done:
-    if (timestamp_uid != 0)
-       set_perms(PERM_ROOT);
-    return status;
-}
-
-/*
- * Remove the timestamp ticket file/dir.
- */
-void
-remove_timestamp(remove)
-    int remove;
-{
-    struct timeval tv;
-    char *timestampdir, *timestampfile, *path;
-    int status;
-
-    build_timestamp(&timestampdir, &timestampfile);
-    status = timestamp_status(timestampdir, timestampfile, user_name,
-       TS_REMOVE);
-    if (status == TS_OLD || status == TS_CURRENT) {
-       path = timestampfile ? timestampfile : timestampdir;
-       if (remove) {
-           if (timestampfile)
-               status = unlink(timestampfile);
-           else
-               status = rmdir(timestampdir);
-           if (status == -1 && errno != ENOENT) {
-               log_error(NO_EXIT, "can't remove %s (%s), will reset to Epoch",
-                   path, strerror(errno));
-               remove = FALSE;
-           }
-       } else {
-           timevalclear(&tv);
-           if (touch(-1, path, &tv) == -1 && errno != ENOENT)
-               error(1, "can't reset %s to Epoch", path);
-       }
-    }
-
-    efree(timestampdir);
-    efree(timestampfile);
-}
-
-/*
- * Returns TRUE if tty lives on a devpts or /devices filesystem, else FALSE.
- * Unlike most filesystems, the ctime of devpts nodes is not updated when
- * the device node is written to, only when the inode's status changes,
- * typically via the chmod, chown, link, rename, or utimes system calls.
- * Since the ctime is "stable" in this case, we can stash it the tty ticket
- * file and use it to determine whether the tty ticket file is stale.
- */
-static int
-tty_is_devpts(tty)
-    const char *tty;
-{
-    int retval = FALSE;
-#ifdef __linux__
-    struct statfs sfs;
-
-#ifndef DEVPTS_SUPER_MAGIC
-# define DEVPTS_SUPER_MAGIC 0x1cd1
-#endif
-
-    if (statfs(tty, &sfs) == 0) {
-       if (sfs.f_type == DEVPTS_SUPER_MAGIC)
-           retval = TRUE;
-    }
-#elif defined(__sun) && defined(__SVR4)
-    struct statvfs sfs;
-
-    if (statvfs(tty, &sfs) == 0) {
-       if (strcmp(sfs.f_fstr, "devices") == 0)
-           retval = TRUE;
-    }
-#endif /* __linux__ */
-    return retval;
-}
-
-/*
- * Get passwd entry for the user we are going to authenticate as.
- * By default, this is the user invoking sudo.  In the most common
- * case, this matches sudo_user.pw or runas_pw.
- */
-static struct passwd *
-get_authpw()
-{
-    struct passwd *pw;
-
-    if (def_rootpw) {
-       if ((pw = sudo_getpwuid(0)) == NULL)
-           log_error(0, "unknown uid: 0");
-    } else if (def_runaspw) {
-       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, "unknown uid: %u",
-               (unsigned int) runas_pw->pw_uid);
-       pw_addref(runas_pw);
-       pw = runas_pw;
-    } else {
-       pw_addref(sudo_user.pw);
-       pw = sudo_user.pw;
-    }
-
-    return pw;
-}
diff --git a/closefrom.c b/closefrom.c
deleted file mode 100644 (file)
index 68da392..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 2004-2005, 2007, 2010
- *     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 <unistd.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 <fcntl.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 "missing.h"
-
-#ifndef HAVE_FCNTL_CLOSEM
-# ifndef HAVE_DIRFD
-#   define closefrom_fallback  closefrom
-# endif
-#endif
-
-/*
- * Close all file descriptors greater than or equal to lowfd.
- * This is the expensive (ballback) method.
- */
-void
-closefrom_fallback(lowfd)
-    int lowfd;
-{
-    long fd, maxfd;
-
-    /*
-     * Fall back on sysconf() or getdtablesize().  We avoid checking
-     * resource limits since it is possible to open a file descriptor
-     * and then drop the rlimit such that it is below the open fd.
-     */
-#ifdef HAVE_SYSCONF
-    maxfd = sysconf(_SC_OPEN_MAX);
-#else
-    maxfd = getdtablesize();
-#endif /* HAVE_SYSCONF */
-    if (maxfd < 0)
-       maxfd = OPEN_MAX;
-
-    for (fd = lowfd; fd < maxfd; fd++)
-       (void) close((int) fd);
-}
-
-/*
- * Close all file descriptors greater than or equal to lowfd.
- * We try the fast way first, falling back on the slow method.
- */
-#ifdef HAVE_FCNTL_CLOSEM
-void
-closefrom(lowfd)
-    int lowfd;
-{
-    if (fcntl(lowfd, F_CLOSEM, 0) == -1)
-       closefrom_fallback(lowfd);
-}
-#else
-# ifdef HAVE_DIRFD
-void
-closefrom(lowfd)
-    int lowfd;
-{
-    struct dirent *dent;
-    DIR *dirp;
-    char *endp;
-    long fd;
-
-    /* Use /proc/self/fd directory if it exists. */
-    if ((dirp = opendir("/proc/self/fd")) != NULL) {
-       while ((dent = readdir(dirp)) != NULL) {
-           fd = strtol(dent->d_name, &endp, 10);
-           if (dent->d_name != endp && *endp == '\0' &&
-               fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
-               (void) close((int) fd);
-       }
-       (void) closedir(dirp);
-    } else
-       closefrom_fallback(lowfd);
-}
-#endif /* HAVE_DIRFD */
-#endif /* HAVE_FCNTL_CLOSEM */
diff --git a/common/Makefile.in b/common/Makefile.in
new file mode 100644 (file)
index 0000000..a0fd01d
--- /dev/null
@@ -0,0 +1,112 @@
+#
+# Copyright (c) 2011 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.
+#
+# @configure_input@
+#
+
+#### Start of system configuration section. ####
+
+srcdir = @srcdir@
+devdir = @devdir@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+incdir = $(top_srcdir)/include
+
+# Compiler & tools to use
+CC = @CC@
+LIBTOOL = @LIBTOOL@
+
+# C preprocessor flags
+CPPFLAGS = -I. -I$(top_builddir) -I$(incdir) @CPPFLAGS@
+
+# Usually -O and/or -g
+CFLAGS = @CFLAGS@
+
+# OS dependent defines
+DEFS = @OSDEFS@
+
+#### End of system configuration section. ####
+
+SHELL = @SHELL@
+
+LTOBJS = alloc.lo atobool.lo fileops.lo fmt_string.lo \
+        lbuf.lo list.lo term.lo zero_bytes.lo @COMMON_OBJS@
+
+all: libcommon.la
+
+Makefile: $(srcdir)/Makefile.in
+       (cd $(top_builddir) && ./config.status --file common/Makefile)
+
+.SUFFIXES: .c .h .lo
+
+.c.lo:
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $<
+
+libcommon.la: $(LTOBJS)
+       $(LIBTOOL) --mode=link $(CC) -o $@ $(LTOBJS) -no-install
+
+# Dependencies
+aix.lo: $(srcdir)/aix.c $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/aix.c
+alloc.lo: $(srcdir)/alloc.c $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/alloc.c
+atobool.lo: $(srcdir)/atobool.c $(incdir)/missing.h $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/atobool.c
+fileops.lo: $(srcdir)/fileops.c $(incdir)/fileops.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/fileops.c
+fmt_string.lo: $(srcdir)/fmt_string.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/fmt_string.c
+lbuf.lo: $(srcdir)/lbuf.c $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h $(incdir)/missing.h $(incdir)/lbuf.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/lbuf.c
+list.lo: $(srcdir)/list.c $(incdir)/missing.h $(incdir)/list.h $(incdir)/error.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/list.c
+term.lo: $(srcdir)/term.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/term.c
+zero_bytes.lo: $(srcdir)/zero_bytes.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/zero_bytes.c
+
+pre-install:
+
+install:
+
+install-dirs:
+
+install-binaries:
+
+install-includes:
+
+install-doc:
+
+install-plugin:
+
+uninstall:
+
+check:
+
+clean:
+       -$(LIBTOOL) --mode=clean rm -f *.lo *.o *.la *.a stamp-* core *.core core.*
+
+mostlyclean: clean
+
+distclean: clean
+       -rm -rf Makefile .libs
+
+clobber: distclean
+
+realclean: distclean
+       rm -f TAGS tags
+
+cleandir: realclean
diff --git a/common/aix.c b/common/aix.c
new file mode 100644 (file)
index 0000000..00c0f6a
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2008, 2010-2011 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 <uinfo.h>
+
+#include "missing.h"
+#include "alloc.h"
+#include "error.h"
+
+#ifdef HAVE_GETUSERATTR
+
+#ifndef HAVE_SETRLIMIT64
+# define setrlimit64(a, b) setrlimit(a, b)
+# define rlimit64 rlimit
+# define rlim64_t rlim_t
+# define RLIM64_INFINITY RLIM_INFINITY
+#endif /* HAVE_SETRLIMIT64 */
+
+#ifndef RLIM_SAVED_MAX
+# define RLIM_SAVED_MAX        RLIM64_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(char *user, char *lim, rlim64_t *valp)
+{
+    int val;
+
+    if (getuserattr(user, lim, &val, SEC_INT) != 0)
+       return -1;
+    *valp = val;
+    return 0;
+}
+
+static void
+aix_setlimits(char *user)
+{
+    struct rlimit64 rlim;
+    rlim64_t val;
+    int n;
+
+    if (setuserdb(S_READ) != 0)
+       error(1, "unable to open userdb");
+
+    /*
+     * For each resource limit, get the soft/hard values for the user
+     * and set those values via setrlimit64().  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, &val) == 0) {
+           rlim.rlim_max = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor;
+           if (aix_getlimit(user, aix_limits[n].soft, &val) == 0)
+               rlim.rlim_cur = val == -1 ? RLIM64_INFINITY : val * 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, &val) == 0)
+               rlim.rlim_cur = val == -1 ? RLIM64_INFINITY : val * 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 = RLIM64_INFINITY;
+                   break;
+           }
+       }
+       (void)setrlimit64(aix_limits[n].resource, &rlim);
+    }
+    enduserdb();
+}
+
+#ifdef HAVE_SETAUTHDB
+/*
+ * Look up administrative domain for user (SYSTEM in /etc/security/user) and
+ * set it as the default for the process.  This ensures that password and
+ * group lookups are made against the correct source (files, NIS, LDAP, etc).
+ */
+void
+aix_setauthdb(char *user)
+{
+    char *registry;
+
+    if (user != NULL) {
+       if (setuserdb(S_READ) != 0)
+           error(1, "unable to open userdb");
+       if (getuserattr(user, S_REGISTRY, &registry, SEC_CHAR) == 0) {
+           if (setauthdb(registry, NULL) != 0)
+               error(1, "unable to switch to registry \"%s\" for %s",
+                   registry, user);
+       }
+       enduserdb();
+    }
+}
+
+/*
+ * Restore the saved administrative domain, if any.
+ */
+void
+aix_restoreauthdb(void)
+{
+    if (setauthdb(NULL, NULL) != 0)
+       error(1, "unable to restore registry");
+}
+#endif
+
+void
+aix_prep_user(char *user, const char *tty)
+{
+    char *info;
+    int len;
+
+    /* set usrinfo, like login(1) does */
+    len = easprintf(&info, "NAME=%s%cLOGIN=%s%cLOGNAME=%s%cTTY=%s%c",
+       user, '\0', user, '\0', user, '\0', tty ? tty : "", '\0');
+    (void)usrinfo(SETUINFO, info, len);
+    efree(info);
+
+#ifdef HAVE_SETAUTHDB
+    /* set administrative domain */
+    aix_setauthdb(user);
+#endif
+
+    /* set resource limits */
+    aix_setlimits(user);
+}
+#endif /* HAVE_GETUSERATTR */
diff --git a/common/alloc.c b/common/alloc.c
new file mode 100644 (file)
index 0000000..7fbf3c8
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 1999-2005, 2007, 2010-2011
+ *     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/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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRING_H */
+#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
+# include <malloc.h>
+#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#include "missing.h"
+#include "alloc.h"
+#include "error.h"
+
+/*
+ * 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).  This just means that
+ * emalloc2() and erealloc3() cannot allocate huge amounts on such a
+ * platform but that is OK since sudo doesn't need to do so anyway.
+ */
+#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 */
+
+/*
+ * emalloc() calls the system malloc(3) and exits with an error if
+ * malloc(3) fails.
+ */
+void *
+emalloc(size_t size)
+{
+    void *ptr;
+
+    if (size == 0)
+       errorx(1, "internal error, tried to emalloc(0)");
+
+    if ((ptr = malloc(size)) == NULL)
+       errorx(1, "unable to allocate memory");
+    return ptr;
+}
+
+/*
+ * emalloc2() allocates nmemb * size bytes and exits with an error
+ * if overflow would occur or if the system malloc(3) fails.
+ */
+void *
+emalloc2(size_t nmemb, size_t size)
+{
+    void *ptr;
+
+    if (nmemb == 0 || size == 0)
+       errorx(1, "internal error, tried to emalloc2(0)");
+    if (nmemb > SIZE_MAX / size)
+       errorx(1, "internal error, emalloc2() overflow");
+
+    size *= nmemb;
+    if ((ptr = malloc(size)) == NULL)
+       errorx(1, "unable to allocate memory");
+    return ptr;
+}
+
+/*
+ * erealloc() calls the system realloc(3) and exits with an error if
+ * realloc(3) fails.  You can call erealloc() with a NULL pointer even
+ * if the system realloc(3) does not support this.
+ */
+void *
+erealloc(void *ptr, size_t size)
+{
+
+    if (size == 0)
+       errorx(1, "internal error, tried to erealloc(0)");
+
+    ptr = ptr ? realloc(ptr, size) : malloc(size);
+    if (ptr == NULL)
+       errorx(1, "unable to allocate memory");
+    return ptr;
+}
+
+/*
+ * erealloc3() realloc(3)s nmemb * size bytes and exits with an error
+ * if overflow would occur or if the system malloc(3)/realloc(3) fails.
+ * You can call erealloc() with a NULL pointer even if the system realloc(3)
+ * does not support this.
+ */
+void *
+erealloc3(void *ptr, size_t nmemb, size_t size)
+{
+
+    if (nmemb == 0 || size == 0)
+       errorx(1, "internal error, tried to erealloc3(0)");
+    if (nmemb > SIZE_MAX / size)
+       errorx(1, "internal error, erealloc3() overflow");
+
+    size *= nmemb;
+    ptr = ptr ? realloc(ptr, size) : malloc(size);
+    if (ptr == NULL)
+       errorx(1, "unable to allocate memory");
+    return ptr;
+}
+
+/*
+ * estrdup() is like strdup(3) except that it exits with an error if
+ * malloc(3) fails.  NOTE: unlike strdup(3), estrdup(NULL) is legal.
+ */
+char *
+estrdup(const char *src)
+{
+    char *dst = NULL;
+    size_t len;
+
+    if (src != NULL) {
+       len = strlen(src);
+       dst = (char *) emalloc(len + 1);
+       (void) memcpy(dst, src, len);
+       dst[len] = '\0';
+    }
+    return dst;
+}
+
+/*
+ * estrdup() is like strndup(3) except that it exits with an error if
+ * malloc(3) fails.  NOTE: unlike strdup(3), estrdup(NULL) is legal.
+ */
+char *
+estrndup(const char *src, size_t maxlen)
+{
+    char *dst = NULL;
+    size_t len;
+
+    if (src != NULL) {
+       len = strlen(src);
+       if (len > maxlen)
+           len = maxlen;
+       dst = (char *) emalloc(len + 1);
+       (void) memcpy(dst, src, len);
+       dst[len] = '\0';
+    }
+    return dst;
+}
+
+/*
+ * easprintf() calls vasprintf() and exits with an error if vasprintf()
+ * returns -1 (out of memory).
+ */
+int
+easprintf(char **ret, const char *fmt, ...)
+{
+    int len;
+    va_list ap;
+    va_start(ap, fmt);
+    len = vasprintf(ret, fmt, ap);
+    va_end(ap);
+
+    if (len == -1)
+       errorx(1, "unable to allocate memory");
+    return len;
+}
+
+/*
+ * evasprintf() calls vasprintf() and exits with an error if vasprintf()
+ * returns -1 (out of memory).
+ */
+int
+evasprintf(char **ret, const char *format, va_list args)
+{
+    int len;
+
+    if ((len = vasprintf(ret, format, args)) == -1)
+       errorx(1, "unable to allocate memory");
+    return len;
+}
+
+/*
+ * Wrapper for free(3) so we can depend on C89 semantics.
+ */
+void
+efree(void *ptr)
+{
+    if (ptr != NULL)
+       free(ptr);
+}
diff --git a/common/atobool.c b/common/atobool.c
new file mode 100644 (file)
index 0000000..f22aae8
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010 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
+# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+
+#include "missing.h"
+
+int
+atobool(const char *str)
+{
+    switch (*str) {
+       case '0':
+       case '1':
+           if (str[1] == '\0')
+               return *str - '0';
+           break;
+       case 'y':
+       case 'Y':
+           if (strcasecmp(str, "yes") == 0)
+               return 1;
+           break;
+       case 't':
+       case 'T':
+           if (strcasecmp(str, "true") == 0)
+               return 1;
+           break;
+       case 'o':
+       case 'O':
+           if (strcasecmp(str, "on") == 0)
+               return 1;
+           if (strcasecmp(str, "off") == 0)
+               return 0;
+           break;
+       case 'n':
+       case 'N':
+           if (strcasecmp(str, "no") == 0)
+               return 0;
+           break;
+       case 'f':
+       case 'F':
+           if (strcasecmp(str, "false") == 0)
+               return 0;
+           break;
+    }
+    return -1;
+}
diff --git a/common/fileops.c b/common/fileops.c
new file mode 100644 (file)
index 0000000..38cc0c1
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 1999-2005, 2007, 2009-2011
+ *     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/param.h>
+#include <sys/time.h>
+#ifdef HAVE_FLOCK
+# include <sys/file.h>
+#endif /* HAVE_FLOCK */
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <ctype.h>
+#include <limits.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <fcntl.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#ifndef HAVE_TIMESPEC
+# include "compat/timespec.h"
+#endif
+
+#include "missing.h"
+#include "fileops.h"
+
+#ifndef LINE_MAX
+# define LINE_MAX 2048
+#endif
+
+/*
+ * Update the access and modify times on an fd or file.
+ */
+int
+touch(int fd, char *path, struct timeval *tvp)
+{
+    struct timeval times[2];
+
+    if (tvp != NULL) {
+       times[0].tv_sec = times[1].tv_sec = tvp->tv_sec;
+       times[0].tv_usec = times[1].tv_usec = tvp->tv_usec;
+    }
+
+#if defined(HAVE_FUTIME) || defined(HAVE_FUTIMES)
+    if (fd != -1)
+       return futimes(fd, tvp ? times : NULL);
+    else
+#endif
+    if (path != NULL)
+       return utimes(path, tvp ? times : NULL);
+    else
+       return -1;
+}
+
+/*
+ * Lock/unlock a file.
+ */
+#ifdef HAVE_LOCKF
+int
+lock_file(int fd, int lockit)
+{
+    int op = 0;
+
+    switch (lockit) {
+       case SUDO_LOCK:
+           op = F_LOCK;
+           break;
+       case SUDO_TLOCK:
+           op = F_TLOCK;
+           break;
+       case SUDO_UNLOCK:
+           op = F_ULOCK;
+           break;
+    }
+    return lockf(fd, op, 0) == 0;
+}
+#elif HAVE_FLOCK
+int
+lock_file(int fd, int lockit)
+{
+    int op = 0;
+
+    switch (lockit) {
+       case SUDO_LOCK:
+           op = LOCK_EX;
+           break;
+       case SUDO_TLOCK:
+           op = LOCK_EX | LOCK_NB;
+           break;
+       case SUDO_UNLOCK:
+           op = LOCK_UN;
+           break;
+    }
+    return flock(fd, op) == 0;
+}
+#else
+int
+lock_file(int fd, int lockit)
+{
+#ifdef F_SETLK
+    int func;
+    struct flock lock;
+
+    lock.l_start = 0;
+    lock.l_len = 0;
+    lock.l_pid = getpid();
+    lock.l_type = (lockit == SUDO_UNLOCK) ? F_UNLCK : F_WRLCK;
+    lock.l_whence = SEEK_SET;
+    func = (lockit == SUDO_LOCK) ? F_SETLKW : F_SETLK;
+
+    return fcntl(fd, func, &lock) == 0;
+#else
+    return TRUE;
+#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(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((unsigned char)buf[len - 1]))
+           buf[--len] = '\0';
+       for (cp = buf; isblank((unsigned char)*cp); cp++)
+           continue;
+    }
+    return cp;
+}
diff --git a/common/fmt_string.c b/common/fmt_string.c
new file mode 100644 (file)
index 0000000..a9c7232
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2010-2011 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
+# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+
+#include "missing.h"
+
+/*
+ * Allocate storage for a name=value string and return it.
+ */
+char *
+fmt_string(const char *var, const char *val)
+{
+    size_t var_len = strlen(var);
+    size_t val_len = strlen(val);
+    char *cp, *str;
+
+    cp = str = malloc(var_len + 1 + val_len + 1);
+       if (str != NULL) {
+       memcpy(cp, var, var_len);
+       cp += var_len;
+       *cp++ = '=';
+       memcpy(cp, val, val_len);
+       cp += val_len;
+       *cp = '\0';
+    }
+
+    return str;
+}
diff --git a/common/lbuf.c b/common/lbuf.c
new file mode 100644 (file)
index 0000000..92f489e
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2007-2011 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
+# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <ctype.h>
+
+#include "missing.h"
+#include "alloc.h"
+#include "error.h"
+#include "lbuf.h"
+
+void
+lbuf_init(struct lbuf *lbuf, int (*output)(const char *),
+    int indent, const char *continuation, int cols)
+{
+    lbuf->output = output;
+    lbuf->continuation = continuation;
+    lbuf->indent = indent;
+    lbuf->cols = cols;
+    lbuf->len = 0;
+    lbuf->size = 0;
+    lbuf->buf = NULL;
+}
+
+void
+lbuf_destroy(struct lbuf *lbuf)
+{
+    efree(lbuf->buf);
+    lbuf->buf = NULL;
+}
+
+/*
+ * Append strings to the buffer, expanding it as needed.
+ */
+void
+lbuf_append_quoted(struct lbuf *lbuf, const char *set, ...)
+{
+    va_list ap;
+    int len = 0;
+    char *cp, *s;
+
+    va_start(ap, set);
+    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);
+    }
+
+    va_start(ap, set);
+    /* 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
+lbuf_append(struct lbuf *lbuf, ...)
+{
+    va_list ap;
+    int len = 0;
+    char *s;
+
+    va_start(ap, lbuf);
+    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);
+    }
+
+    va_start(ap, lbuf);
+    /* 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);
+}
+
+static void
+lbuf_println(struct lbuf *lbuf, char *line, int len)
+{
+    char *cp, save;
+    int i, have, contlen;
+
+    contlen = lbuf->continuation ? strlen(lbuf->continuation) : 0;
+
+    /*
+     * Print the buffer, splitting the line as needed on a word
+     * boundary.
+     */
+    cp = line;
+    have = lbuf->cols;
+    while (cp != NULL && *cp != '\0') {
+       char *ep = NULL;
+       int need = len - (int)(cp - line);
+
+       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 != line) {
+           /* indent continued lines */
+           /* XXX - build up string instead? */
+           for (i = 0; i < lbuf->indent; i++)
+               lbuf->output(" ");
+       }
+       /* NUL-terminate cp for the output function and restore afterwards */
+       save = cp[need];
+       cp[need] = '\0';
+       lbuf->output(cp);
+       cp[need] = save;
+       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 = lbuf->cols - lbuf->indent;
+           ep = line + len;
+           while (cp < ep && isblank((unsigned char)*cp)) {
+               cp++;
+           }
+           if (contlen)
+               lbuf->output(lbuf->continuation);
+       }
+       lbuf->output("\n");
+    }
+}
+
+/*
+ * Print the buffer with word wrap based on the tty width.
+ * The lbuf is reset on return.
+ */
+void
+lbuf_print(struct lbuf *lbuf)
+{
+    char *cp, *ep;
+    int len;
+
+    if (lbuf->buf == NULL || lbuf->len == 0)
+       goto done;
+
+    /* For very small widths just give up... */
+    len = lbuf->continuation ? strlen(lbuf->continuation) : 0;
+    if (lbuf->cols <= lbuf->indent + len + 20) {
+       lbuf->buf[lbuf->len] = '\0';
+       lbuf->output(lbuf->buf);
+       goto done;
+    }
+
+    /* Print each line in the buffer */
+    for (cp = lbuf->buf; cp != NULL && *cp != '\0'; ) {
+       if (*cp == '\n') {
+           lbuf->output("\n");
+           cp++;
+       } else {
+           len = lbuf->len - (cp - lbuf->buf);
+           if ((ep = memchr(cp, '\n', len)) != NULL)
+               len = (int)(ep - cp);
+           if (len)
+               lbuf_println(lbuf, cp, len);
+           cp = ep ? ep + 1 : NULL;
+       }
+    }
+
+done:
+    lbuf->len = 0;             /* reset the buffer for re-use. */
+}
diff --git a/common/list.c b/common/list.c
new file mode 100644 (file)
index 0000000..6933177
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2007-2008, 2010-2011 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 "missing.h"
+#include "list.h"
+#ifdef DEBUG
+# include "error.h"
+#endif
+
+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(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(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(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(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;
+}
+
+/*
+ * Remove element from the tail_queue
+ */
+void
+tq_remove(void *vh, void *vl)
+{
+    struct list_head_proto *h = (struct list_head_proto *)vh;
+    struct list_proto *l = (struct list_proto *)vl;
+
+    if (h->first == l && h->last == l) {
+       /* Single element in the list. */
+       h->first = NULL;
+       h->last = NULL;
+    } else {
+       /* At least two elements in the list. */
+       if (h->first == l) {
+           h->first = l->next;
+           h->first->prev = h->first;
+       } else if (h->last == l) {
+           h->last = l->prev;
+           h->last->next = NULL;
+       } else {
+           l->prev->next = l->next;
+           l->next->prev = l->prev;
+       }
+    }
+}
diff --git a/common/term.c b/common/term.c
new file mode 100644 (file)
index 0000000..b8f03db
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2011 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
+# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <termios.h>
+
+#include "missing.h"
+
+#ifndef TCSASOFT
+# define TCSASOFT      0
+#endif
+#ifndef ECHONL
+# define ECHONL                0
+#endif
+#ifndef IEXTEN
+# define IEXTEN                0
+#endif
+#ifndef IUCLC
+# define IUCLC         0
+#endif
+
+#ifndef _POSIX_VDISABLE
+# ifdef VDISABLE
+#  define _POSIX_VDISABLE      VDISABLE
+# else
+#  define _POSIX_VDISABLE      0
+# endif
+#endif
+
+static struct termios term, oterm;
+static int changed;
+int term_erase;
+int term_kill;
+
+int
+term_restore(int fd, int flush)
+{
+    if (changed) {
+       int flags = TCSASOFT;
+       flags |= flush ? TCSAFLUSH : TCSADRAIN;
+       if (tcsetattr(fd, flags, &oterm) != 0)
+           return 0;
+       changed = 0;
+    }
+    return 1;
+}
+
+int
+term_noecho(int fd)
+{
+    if (!changed && tcgetattr(fd, &oterm) != 0)
+       return 0;
+    (void) memcpy(&term, &oterm, sizeof(term));
+    CLR(term.c_lflag, ECHO|ECHONL);
+#ifdef VSTATUS
+    term.c_cc[VSTATUS] = _POSIX_VDISABLE;
+#endif
+    if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
+       changed = 1;
+       return 1;
+    }
+    return 0;
+}
+
+int
+term_raw(int fd, int isig)
+{
+    struct termios term;
+
+    if (!changed && tcgetattr(fd, &oterm) != 0)
+       return 0;
+    (void) memcpy(&term, &oterm, sizeof(term));
+    /* Set terminal to raw mode */
+    term.c_cc[VMIN] = 1;
+    term.c_cc[VTIME] = 0;
+    CLR(term.c_iflag, ICRNL | IGNCR | INLCR | IUCLC | IXON);
+    CLR(term.c_oflag, OPOST);
+    CLR(term.c_lflag, ECHO | ICANON | ISIG | IEXTEN);
+    if (isig)
+       SET(term.c_lflag, ISIG);
+    if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
+       changed = 1;
+       return 1;
+    }
+    return 0;
+}
+
+int
+term_cbreak(int fd)
+{
+    if (!changed && tcgetattr(fd, &oterm) != 0)
+       return 0;
+    (void) memcpy(&term, &oterm, sizeof(term));
+    /* Set terminal to half-cooked mode */
+    term.c_cc[VMIN] = 1;
+    term.c_cc[VTIME] = 0;
+    CLR(term.c_lflag, ECHO | ECHONL | ICANON | IEXTEN);
+    SET(term.c_lflag, ISIG);
+#ifdef VSTATUS
+    term.c_cc[VSTATUS] = _POSIX_VDISABLE;
+#endif
+    if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
+       term_erase = term.c_cc[VERASE];
+       term_kill = term.c_cc[VKILL];
+       changed = 1;
+       return 1;
+    }
+    return 0;
+}
+
+int
+term_copy(int src, int dst)
+{
+    struct termios tt;
+
+    if (tcgetattr(src, &tt) != 0)
+       return 0;
+    if (tcsetattr(dst, TCSANOW|TCSASOFT, &tt) != 0)
+       return 0;
+    return 1;
+}
diff --git a/common/zero_bytes.c b/common/zero_bytes.c
new file mode 100644 (file)
index 0000000..f6f22bc
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2003-2005, 2007, 2010
+ *     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 "missing.h"
+
+/*
+ * Like bzero(3) but with a volatile pointer.  The hope is that
+ * the compiler will not be able to optimize away this function.
+ */
+void
+zero_bytes(volatile void *v, size_t n)
+{
+    volatile char *p, *ep;
+
+    for (p = v, ep = p + n; p < ep; p++)
+       *p = 0;
+    return;
+}
diff --git a/compat/Makefile.in b/compat/Makefile.in
new file mode 100644 (file)
index 0000000..79b7da4
--- /dev/null
@@ -0,0 +1,162 @@
+#
+# Copyright (c) 2011 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.
+#
+# @configure_input@
+#
+
+#### Start of system configuration section. ####
+
+srcdir = @srcdir@
+devdir = @devdir@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+incdir = $(top_srcdir)/include
+
+# Compiler & tools to use
+CC = @CC@
+LIBTOOL = @LIBTOOL@
+
+# C preprocessor flags
+CPPFLAGS = -I$(top_builddir) -I$(incdir) @CPPFLAGS@
+
+# Usually -O and/or -g
+CFLAGS = @CFLAGS@
+
+# OS dependent defines
+DEFS = @OSDEFS@
+
+#### End of system configuration section. ####
+
+SHELL = @SHELL@
+
+LIBOBJDIR = 
+
+LTLIBOBJS = @LTLIBOBJS@
+
+all: libreplace.la
+
+Makefile: $(srcdir)/Makefile.in
+       (cd $(top_builddir) && ./config.status --file compat/Makefile)
+
+.SUFFIXES: .o .c .h .lo
+
+.c.lo:
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $<
+
+libreplace.la: $(LTLIBOBJS)
+       $(LIBTOOL) --mode=link $(CC) -o $@ $(LTLIBOBJS) -no-install
+
+./siglist.c: ./mksiglist
+       ./mksiglist > $@
+
+./mksiglist: $(srcdir)/mksiglist.c $(srcdir)/mksiglist.h $(incdir)/missing.h $(top_builddir)/config.h
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/mksiglist.c -o $@
+
+fnm_test.o: $(srcdir)/regress/fnmatch/fnm_test.c
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/regress/fnmatch/fnm_test.c
+
+fnm_test: fnm_test.o libreplace.la
+       $(LIBTOOL) --mode=link $(CC) -o $@ fnm_test.o libreplace.la
+
+globtest.o: $(srcdir)/regress/glob/globtest.c
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/regress/glob/globtest.c
+
+globtest: globtest.o libreplace.la
+       $(LIBTOOL) --mode=link $(CC) -o $@ globtest.o libreplace.la
+
+@DEV@$(srcdir)/mksiglist.h: $(srcdir)/siglist.in
+@DEV@  awk 'BEGIN {print "/* public domain */\n"} /^    [A-Z]/ {printf("#ifdef SIG%s\n    if (my_sys_siglist[SIG%s] == NULL)\n\tmy_sys_siglist[SIG%s] = \"%s\";\n#endif\n", $$1, $$1, $$1, substr($$0, 13))}' < $(srcdir)/siglist.in > $@
+
+# Dependencies
+closefrom.lo: $(srcdir)/closefrom.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/closefrom.c
+dlopen.lo: $(srcdir)/dlopen.c $(srcdir)/dlfcn.h $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/dlopen.c
+fnmatch.lo: $(srcdir)/fnmatch.c $(srcdir)/fnmatch.h $(srcdir)/charclass.h $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/fnmatch.c
+getcwd.lo: $(srcdir)/getcwd.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/getcwd.c
+getline.lo: $(srcdir)/getline.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/getline.c
+getprogname.lo: $(srcdir)/getprogname.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/getprogname.c
+glob.lo: $(srcdir)/glob.c $(srcdir)/glob.h $(srcdir)/charclass.h $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/glob.c
+isblank.lo: $(srcdir)/isblank.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/isblank.c
+memrchr.lo: $(srcdir)/memrchr.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/memrchr.c
+mktemp.lo: $(srcdir)/mktemp.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/mktemp.c
+nanosleep.lo: $(srcdir)/nanosleep.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/nanosleep.c
+siglist.lo: ./siglist.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) ./siglist.c
+snprintf.lo: $(srcdir)/snprintf.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/snprintf.c
+strcasecmp.lo: $(srcdir)/strcasecmp.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/strcasecmp.c
+strerror.lo: $(srcdir)/strerror.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/strerror.c
+strlcat.lo: $(srcdir)/strlcat.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/strlcat.c
+strlcpy.lo: $(srcdir)/strlcpy.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/strlcpy.c
+strsignal.lo: $(srcdir)/strsignal.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/strsignal.c
+utimes.lo: $(srcdir)/utimes.c $(incdir)/missing.h $(srcdir)/utime.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/utimes.c
+
+pre-install:
+
+install:
+
+install-dirs:
+
+install-binaries:
+
+install-includes:
+
+install-doc:
+
+install-plugin:
+
+uninstall:
+
+check: fnm_test globtest
+       @./fnm_test $(srcdir)/regress/fnmatch/fnm_test.in
+       @mkdir -p `sed 's@/[^/]*$$@@' $(srcdir)/regress/glob/files | sort -u`
+       @touch `cat $(srcdir)/regress/glob/files`
+       @chmod 0755 `grep '/r[^/]*$$' $(srcdir)/regress/glob/files`
+       @chmod 0444 `grep '/s[^/]*$$' $(srcdir)/regress/glob/files`
+       @chmod 0711 `grep '/t[^/]*$$' $(srcdir)/regress/glob/files`
+       @./globtest $(srcdir)/regress/glob/globtest.in
+       @rm -rf fake
+
+clean:
+       -$(LIBTOOL) --mode=clean rm -f mksiglist siglist.c *.lo *.o *.la *.a stamp-* core *.core core.*
+
+mostlyclean: clean
+
+distclean: clean
+       -rm -rf Makefile .libs
+
+clobber: distclean
+
+realclean: distclean
+       rm -f TAGS tags
+
+cleandir: realclean
diff --git a/compat/charclass.h b/compat/charclass.h
new file mode 100644 (file)
index 0000000..4fcf15e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2008, 2010 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.
+ */
+
+/*
+ * POSIX character class support for fnmatch() and glob().
+ */
+static struct cclass {
+       const char *name;
+       int (*isctype)(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/compat/closefrom.c b/compat/closefrom.c
new file mode 100644 (file)
index 0000000..71777e7
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2004-2005, 2007, 2010
+ *     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 <unistd.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 <fcntl.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 "missing.h"
+
+#ifndef HAVE_FCNTL_CLOSEM
+# ifndef HAVE_DIRFD
+#   define closefrom_fallback  closefrom
+# endif
+#endif
+
+/*
+ * Close all file descriptors greater than or equal to lowfd.
+ * This is the expensive (ballback) method.
+ */
+void
+closefrom_fallback(int lowfd)
+{
+    long fd, maxfd;
+
+    /*
+     * Fall back on sysconf() or getdtablesize().  We avoid checking
+     * resource limits since it is possible to open a file descriptor
+     * and then drop the rlimit such that it is below the open fd.
+     */
+#ifdef HAVE_SYSCONF
+    maxfd = sysconf(_SC_OPEN_MAX);
+#else
+    maxfd = getdtablesize();
+#endif /* HAVE_SYSCONF */
+    if (maxfd < 0)
+       maxfd = OPEN_MAX;
+
+    for (fd = lowfd; fd < maxfd; fd++)
+       (void) close((int) fd);
+}
+
+/*
+ * Close all file descriptors greater than or equal to lowfd.
+ * We try the fast way first, falling back on the slow method.
+ */
+#ifdef HAVE_FCNTL_CLOSEM
+void
+closefrom(int lowfd)
+{
+    if (fcntl(lowfd, F_CLOSEM, 0) == -1)
+       closefrom_fallback(lowfd);
+}
+#else
+# ifdef HAVE_DIRFD
+void
+closefrom(int lowfd)
+{
+    struct dirent *dent;
+    DIR *dirp;
+    char *endp;
+    long fd;
+
+    /* Use /proc/self/fd directory if it exists. */
+    if ((dirp = opendir("/proc/self/fd")) != NULL) {
+       while ((dent = readdir(dirp)) != NULL) {
+           fd = strtol(dent->d_name, &endp, 10);
+           if (dent->d_name != endp && *endp == '\0' &&
+               fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
+               (void) close((int) fd);
+       }
+       (void) closedir(dirp);
+    } else
+       closefrom_fallback(lowfd);
+}
+#endif /* HAVE_DIRFD */
+#endif /* HAVE_FCNTL_CLOSEM */
diff --git a/compat/dlfcn.h b/compat/dlfcn.h
new file mode 100644 (file)
index 0000000..922c755
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef _DLFCN_H_
+#define _DLFCN_H_
+
+/* Emulated functions. */
+void *sudo_dlopen(const char *path, int mode);
+int sudo_dlclose(void *handle);
+void *sudo_dlsym(void *handle, const char *symbol);
+char *sudo_dlerror(void);
+
+/* Map emulated functions to standard names. */
+#define dlopen(p, m)   sudo_dlopen(p, m)
+#define dlclose(h)     sudo_dlclose(h)
+#define dlsym(h, s)    sudo_dlsym(h, s)
+#define dlerror()      sudo_dlerror()
+
+/* Values for dlopen() mode. */
+#define RTLD_LAZY      0x1
+#define RTLD_NOW       0x2
+#define RTLD_GLOBAL    0x4
+#define RTLD_LOCAL     0x8
+
+/* Special handle arguments for dlsym(). */
+#define        RTLD_NEXT       ((void *) -1)   /* Search subsequent objects. */
+#define        RTLD_DEFAULT    ((void *) -2)   /* Use default search algorithm. */
+#define        RTLD_SELF       ((void *) -3)   /* Search the caller itself. */
+
+#endif /* !_DLFCN_H_ */
diff --git a/compat/dlopen.c b/compat/dlopen.c
new file mode 100644 (file)
index 0000000..fa7fd71
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2010 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 <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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <errno.h>
+
+#include "compat/dlfcn.h"
+#include "missing.h"
+
+#ifdef HAVE_SHL_LOAD
+/*
+ * Emulate dlopen() using shl_load().
+ */
+#include <dl.h>
+
+#ifndef DYNAMIC_PATH
+# define DYNAMIC_PATH  0
+#endif
+
+void *
+sudo_dlopen(const char *path, int mode)
+{
+    int flags = DYNAMIC_PATH;
+
+    if (mode == 0)
+       mode = RTLD_LAZY;       /* default behavior */
+
+    /* We don't support RTLD_GLOBAL or RTLD_LOCAL yet. */
+    if (ISSET(mode, RTLD_LAZY))
+       flags |= BIND_DEFERRED;
+    if (ISSET(mode, RTLD_NOW))
+       flags |= BIND_IMMEDIATE;
+
+    return (void *)shl_load(path, flags, 0L);
+}
+
+int
+sudo_dlclose(void *handle)
+{
+    return shl_unload((shl_t)handle);
+}
+
+void *
+sudo_dlsym(void *vhandle, const char *symbol)
+{
+    shl_t handle = vhandle;
+    void *value = NULL;
+
+    (void)shl_findsym(&handle, symbol, TYPE_UNDEFINED, &value);
+
+    return value;
+}
+
+char *
+sudo_dlerror(void)
+{
+    return strerror(errno);
+}
+
+#else /* !HAVE_SHL_LOAD */
+
+/*
+ * Emulate dlopen() using a static list of symbols compiled into sudo.
+ */
+
+struct sudo_preload_table {
+    const char *name;
+    void *address;
+};
+extern struct sudo_preload_table sudo_preload_table[];
+
+void *
+sudo_dlopen(const char *path, int mode)
+{
+    return (void *)path;
+}
+
+int
+sudo_dlclose(void *handle)
+{
+    return 0;
+}
+
+void *
+sudo_dlsym(void *handle, const char *symbol)
+{
+    struct sudo_preload_table *sym;
+
+    for (sym = sudo_preload_table; sym->name != NULL; sym++) {
+       if (strcmp(symbol, sym->name) == 0)
+           return sym->address;
+    }
+    return NULL;
+}
+
+char *
+sudo_dlerror(void)
+{
+    return strerror(errno);
+}
+
+#endif /* HAVE_SHL_LOAD */
diff --git a/compat/fnmatch.c b/compat/fnmatch.c
new file mode 100644 (file)
index 0000000..91ef814
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2008, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1989, 1993, 1994
+ *     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.
+ */
+
+/*
+ * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
+ * Compares a filename or pathname to a pattern.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+
+#include "missing.h"
+#include "compat/charclass.h"
+#include "compat/fnmatch.h"
+
+#undef EOS
+#define        EOS     '\0'
+
+#define        RANGE_MATCH     1
+#define        RANGE_NOMATCH   0
+#define        RANGE_ERROR     (-1)
+
+#if defined(LIBC_SCCS) && !defined(lint)
+__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(const char *, int, int, char **);
+static int classmatch(const char *, int, int, const char **);
+
+int
+rpl_fnmatch(const char *pattern, const char *string, int flags)
+{
+       const char *stringstart;
+       char *newp;
+       char c, test;
+
+       for (stringstart = string;;)
+               switch (c = *pattern++) {
+               case EOS:
+                       if (ISSET(flags, FNM_LEADING_DIR) && *string == '/')
+                               return 0;
+                       return *string == EOS ? 0 : FNM_NOMATCH;
+               case '?':
+                       if (*string == EOS)
+                               return FNM_NOMATCH;
+                       if (*string == '/' && ISSET(flags, FNM_PATHNAME))
+                               return FNM_NOMATCH;
+                       if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
+                           (string == stringstart ||
+                           (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
+                               return FNM_NOMATCH;
+                       ++string;
+                       break;
+               case '*':
+                       c = *pattern;
+                       /* Collapse multiple stars. */
+                       while (c == '*')
+                               c = *++pattern;
+
+                       if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
+                           (string == stringstart ||
+                           (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
+                               return FNM_NOMATCH;
+
+                       /* Optimize for pattern with * at end or before /. */
+                       if (c == EOS) {
+                               if (ISSET(flags, FNM_PATHNAME))
+                                       return (ISSET(flags, FNM_LEADING_DIR) ||
+                                           strchr(string, '/') == NULL ?
+                                           0 : FNM_NOMATCH);
+                               else
+                                       return 0;
+                       } else if (c == '/' && ISSET(flags, FNM_PATHNAME)) {
+                               if ((string = strchr(string, '/')) == NULL)
+                                       return FNM_NOMATCH;
+                               break;
+                       }
+
+                       /* General case, use recursion. */
+                       while ((test = *string) != EOS) {
+                               if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
+                                       return 0;
+                               if (test == '/' && ISSET(flags, FNM_PATHNAME))
+                                       break;
+                               ++string;
+                       }
+                       return FNM_NOMATCH;
+               case '[':
+                       if (*string == EOS)
+                               return FNM_NOMATCH;
+                       if (*string == '/' && ISSET(flags, FNM_PATHNAME))
+                               return FNM_NOMATCH;
+                       if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
+                           (string == stringstart ||
+                           (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
+                               return FNM_NOMATCH;
+
+                       switch (rangematch(pattern, *string, flags, &newp)) {
+                       case RANGE_ERROR:
+                               /* not a good range, treat as normal text */
+                               goto normal;
+                       case RANGE_MATCH:
+                               pattern = newp;
+                               break;
+                       case RANGE_NOMATCH:
+                               return FNM_NOMATCH;
+                       }
+                       ++string;
+                       break;
+               case '\\':
+                       if (!ISSET(flags, FNM_NOESCAPE)) {
+                               if ((c = *pattern++) == EOS) {
+                                       c = '\\';
+                                       --pattern;
+                               }
+                       }
+                       /* FALLTHROUGH */
+               default:
+               normal:
+                       if (c != *string && !(ISSET(flags, FNM_CASEFOLD) &&
+                                (tolower((unsigned char)c) ==
+                                tolower((unsigned char)*string))))
+                               return FNM_NOMATCH;
+                       ++string;
+                       break;
+               }
+       /* NOTREACHED */
+}
+
+static int
+rangematch(const char *pattern, int test, int flags, char **newp)
+{
+       int negate, ok, rv;
+       char c, c2;
+
+       /*
+        * A bracket expression starting with an unquoted circumflex
+        * character produces unspecified results (IEEE 1003.2-1992,
+        * 3.13.2).  This implementation treats it like '!', for
+        * consistency with the regular expression syntax.
+        * J.T. Conklin (conklin@ngai.kaleida.com)
+        */
+       if ((negate = (*pattern == '!' || *pattern == '^')))
+               ++pattern;
+
+       if (ISSET(flags, FNM_CASEFOLD))
+               test = tolower(test);
+
+       /*
+        * A right bracket shall lose its special meaning and represent
+        * itself in a bracket expression if it occurs first in the list.
+        * -- POSIX.2 2.8.3.2
+        */
+       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)
+                       return RANGE_ERROR;
+               if (c == '/' && ISSET(flags, FNM_PATHNAME))
+                       return RANGE_NOMATCH;
+               if (ISSET(flags, FNM_CASEFOLD))
+                       c = tolower((unsigned char)c);
+               if (*pattern == '-'
+                   && (c2 = *(pattern+1)) != EOS && c2 != ']') {
+                       pattern += 2;
+                       if (c2 == '\\' && !ISSET(flags, FNM_NOESCAPE))
+                               c2 = *pattern++;
+                       if (c2 == EOS)
+                               return RANGE_ERROR;
+                       if (ISSET(flags, FNM_CASEFOLD))
+                               c2 = tolower((unsigned char)c2);
+                       if (c <= test && test <= c2)
+                               ok = 1;
+               } else if (c == test)
+                       ok = 1;
+       } while ((c = *pattern++) != ']');
+
+       *newp = (char *)pattern;
+       return ok == negate ? RANGE_NOMATCH : RANGE_MATCH;
+}
+
+static int
+classmatch(const char *pattern, int test, int foldcase, const char **ep)
+{
+       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;
+}
diff --git a/compat/fnmatch.h b/compat/fnmatch.h
new file mode 100644 (file)
index 0000000..b7504ce
--- /dev/null
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1992, 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. 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.h   8.1 (Berkeley) 6/2/93
+ *     $OpenBSD: fnmatch.h,v 1.4 1997/09/22 05:25:32 millert Exp $
+ */
+
+#ifndef        _FNMATCH_H_
+#define        _FNMATCH_H_
+
+#define        FNM_NOMATCH     1       /* Match failed. */
+
+#define        FNM_NOESCAPE    0x01    /* Disable backslash escaping. */
+#define        FNM_PATHNAME    0x02    /* Slash must be matched by slash. */
+#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. */
+
+int     rpl_fnmatch(const char *, const char *, int);
+
+#define fnmatch(_a, _b, _c)    rpl_fnmatch((_a), (_b), (_c))
+
+#endif /* !_FNMATCH_H_ */
diff --git a/compat/getcwd.c b/compat/getcwd.c
new file mode 100644 (file)
index 0000000..3185504
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 1989, 1991, 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. 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/param.h>
+#include <sys/stat.h>
+
+#include <errno.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
+# include <malloc.h>
+#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_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 "missing.h"
+
+#define        ISDOT(dp) \
+       (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
+           (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
+
+char *
+getcwd(char *pt, size_t size)
+{
+       struct dirent *dp;
+       DIR *dir = NULL;
+       dev_t dev;
+       ino_t ino;
+       int first;
+       char *bpt, *bup;
+       struct stat s;
+       dev_t root_dev;
+       ino_t root_ino;
+       size_t ptsize, upsize;
+       int save_errno;
+       char *ept, *eup, *up;
+
+       /*
+        * If no buffer specified by the user, allocate one as necessary.
+        * If a buffer is specified, the size has to be non-zero.  The path
+        * is built from the end of the buffer backwards.
+        */
+       if (pt) {
+               ptsize = 0;
+               if (!size) {
+                       errno = EINVAL;
+                       return NULL;
+               }
+               ept = pt + size;
+       } else {
+               if ((pt = malloc(ptsize = 1024 - 4)) == NULL)
+                       return NULL;
+               ept = pt + ptsize;
+       }
+       bpt = ept - 1;
+       *bpt = '\0';
+
+       /*
+        * Allocate bytes (1024 - malloc space) for the string of "../"'s.
+        * Should always be enough (it's 340 levels).  If it's not, allocate
+        * as necessary.  Special * case the first stat, it's ".", not "..".
+        */
+       if ((up = malloc(upsize = 1024 - 4)) == NULL)
+               goto err;
+       eup = up + PATH_MAX;
+       bup = up;
+       up[0] = '.';
+       up[1] = '\0';
+
+       /* Save root values, so know when to stop. */
+       if (stat("/", &s))
+               goto err;
+       root_dev = s.st_dev;
+       root_ino = s.st_ino;
+
+       errno = 0;                      /* XXX readdir has no error return. */
+
+       for (first = 1;; first = 0) {
+               /* Stat the current level. */
+               if (lstat(up, &s))
+                       goto err;
+
+               /* Save current node values. */
+               ino = s.st_ino;
+               dev = s.st_dev;
+
+               /* Check for reaching root. */
+               if (root_dev == dev && root_ino == ino) {
+                       *--bpt = '/';
+                       /*
+                        * It's unclear that it's a requirement to copy the
+                        * path to the beginning of the buffer, but it's always
+                        * been that way and stuff would probably break.
+                        */
+                       bcopy(bpt, pt, ept - bpt);
+                       free(up);
+                       return pt;
+               }
+
+               /*
+                * Build pointer to the parent directory, allocating memory
+                * as necessary.  Max length is 3 for "../", the largest
+                * possible component name, plus a trailing NULL.
+                */
+               if (bup + 3  + MAXNAMLEN + 1 >= eup) {
+                       char *nup;
+
+                       if ((nup = realloc(up, upsize *= 2)) == NULL)
+                               goto err;
+                       up = nup;
+                       bup = up;
+                       eup = up + upsize;
+               }
+               *bup++ = '.';
+               *bup++ = '.';
+               *bup = '\0';
+
+               /* Open and stat parent directory. */
+               if (!(dir = opendir(up)) || fstat(dirfd(dir), &s))
+                       goto err;
+
+               /* Add trailing slash for next directory. */
+               *bup++ = '/';
+
+               /*
+                * If it's a mount point, have to stat each element because
+                * the inode number in the directory is for the entry in the
+                * parent directory, not the inode number of the mounted file.
+                */
+               save_errno = 0;
+               if (s.st_dev == dev) {
+                       for (;;) {
+                               if (!(dp = readdir(dir)))
+                                       goto notfound;
+                               if (dp->d_fileno == ino)
+                                       break;
+                       }
+               } else
+                       for (;;) {
+                               if (!(dp = readdir(dir)))
+                                       goto notfound;
+                               if (ISDOT(dp))
+                                       continue;
+                               bcopy(dp->d_name, bup, NAMLEN(dp) + 1);
+
+                               /* Save the first error for later. */
+                               if (lstat(up, &s)) {
+                                       if (!save_errno)
+                                               save_errno = errno;
+                                       errno = 0;
+                                       continue;
+                               }
+                               if (s.st_dev == dev && s.st_ino == ino)
+                                       break;
+                       }
+
+               /*
+                * Check for length of the current name, preceding slash,
+                * leading slash.
+                */
+               if (bpt - pt <= NAMLEN(dp) + (first ? 1 : 2)) {
+                       size_t len, off;
+                       char *npt;
+
+                       if (!ptsize) {
+                               errno = ERANGE;
+                               goto err;
+                       }
+                       off = bpt - pt;
+                       len = ept - bpt;
+                       if ((npt = realloc(pt, ptsize *= 2)) == NULL)
+                               goto err;
+                       pt = npt;
+                       bpt = pt + off;
+                       ept = pt + ptsize;
+                       bcopy(bpt, ept - len, len);
+                       bpt = ept - len;
+               }
+               if (!first)
+                       *--bpt = '/';
+               bpt -= NAMLEN(dp);
+               bcopy(dp->d_name, bpt, NAMLEN(dp));
+               (void)closedir(dir);
+
+               /* Truncate any file name. */
+               *bup = '\0';
+       }
+
+notfound:
+       /*
+        * If readdir set errno, use it, not any saved error; otherwise,
+        * didn't find the current directory in its parent directory, set
+        * errno to ENOENT.
+        */
+       if (!errno)
+               errno = save_errno ? save_errno : ENOENT;
+       /* FALLTHROUGH */
+err:
+       if (ptsize)
+               free(pt);
+       if (up)
+               free(up);
+       if (dir)
+               (void)closedir(dir);
+       return NULL;
+}
diff --git a/compat/getline.c b/compat/getline.c
new file mode 100644 (file)
index 0000000..606fd0e
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2009-2010 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 <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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <limits.h>
+
+#include "missing.h"
+
+#ifndef LINE_MAX
+# define LINE_MAX 2048
+#endif
+
+#ifdef HAVE_FGETLN
+ssize_t
+getline(char **bufp, size_t *bufsizep, FILE *fp)
+{
+    char *buf, *cp;
+    size_t bufsize;
+    size_t len;
+
+    buf = fgetln(fp, &len);
+    if (buf) {
+       bufsize = *bufp ? *bufsizep : 0;
+       if (bufsize < len + 1) {
+           bufsize = len + 1;
+           cp = *bufp ? realloc(*bufp, bufsize) : malloc(bufsize);
+           if (cp == NULL)
+               return -1;
+           *bufp = cp;
+           *bufsizep = bufsize;
+       }
+       memcpy(*bufp, buf, len);
+       (*bufp)[len] = '\0';
+    }
+    return buf ? len : -1;
+}
+#else
+ssize_t
+getline(char **bufp, size_t *bufsizep, FILE *fp)
+{
+    char *buf, *cp;
+    size_t bufsize;
+    ssize_t len = 0;
+
+    buf = *bufp;
+    bufsize = *bufsizep;
+    if (buf == NULL || bufsize == 0) {
+       bufsize = LINE_MAX;
+       cp = buf ? realloc(buf, bufsize) : malloc(bufsize);
+       if (cp == NULL)
+           return -1;
+       buf = cp;
+    }
+
+    for (;;) {
+       if (fgets(buf + len, bufsize - len, fp) == NULL) {
+           len = -1;
+           break;
+       }
+       len = strlen(buf);
+       if (!len || buf[len - 1] == '\n' || feof(fp))
+           break;
+       bufsize *= 2;
+       cp = realloc(buf, bufsize);
+       if (cp == NULL)
+           return -1;
+       buf = cp;
+    }
+    *bufp = buf;
+    *bufsizep = bufsize;
+    return len;
+}
+#endif
diff --git a/compat/getprogname.c b/compat/getprogname.c
new file mode 100644 (file)
index 0000000..34673f5
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010 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 <stdio.h>
+#include <string.h>
+
+#include "missing.h"
+
+static const char *progname = "sudo";
+
+void
+setprogname(const char *name)
+{
+    const char *base;
+
+    if ((base = strrchr(name, '/')) != NULL) {
+       base++;
+    } else {
+       base = name;
+    }
+    if (strcmp(progname, base) != 0)
+       progname = base;
+}
+
+const char *
+getprogname(void)
+{
+    return progname;
+}
diff --git a/compat/glob.c b/compat/glob.c
new file mode 100644 (file)
index 0000000..cf9a4e2
--- /dev/null
@@ -0,0 +1,901 @@
+/*
+ * Copyright (c) 2008-2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1989, 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.
+ *
+ *     @(#)glob.c      8.3 (Berkeley) 10/13/93
+ */
+
+/*
+ * glob(3) -- a superset of the one defined in POSIX 1003.2.
+ *
+ * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
+ *
+ * Optional extra services, controlled by flags not defined by POSIX:
+ *
+ * GLOB_MAGCHAR:
+ *     Set in gl_flags if pattern contained a globbing character.
+ * GLOB_TILDE:
+ *     expand ~user/foo to the /home/dir/of/user/foo
+ * GLOB_BRACE:
+ *     expand {1,2}{a,b} to 1a 1b 2a 2b
+ * gl_matchc:
+ *     Number of matches in the current invocation of glob.
+ */
+
+#include <config.h>
+
+#include <sys/param.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 */
+#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
+# include <malloc.h>
+#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <ctype.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# 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 <errno.h>
+#include <limits.h>
+#include <pwd.h>
+
+#include "missing.h"
+#include "compat/glob.h"
+#include "compat/charclass.h"
+
+#define        DOLLAR          '$'
+#define        DOT             '.'
+#define        EOS             '\0'
+#define        LBRACKET        '['
+#define        NOT             '!'
+#define        QUESTION        '?'
+#define        QUOTE           '\\'
+#define        RANGE           '-'
+#define        RBRACKET        ']'
+#define        SEP             '/'
+#define        STAR            '*'
+#define        TILDE           '~'
+#define        UNDERSCORE      '_'
+#define        LBRACE          '{'
+#define        RBRACE          '}'
+#define        SLASH           '/'
+#define        COMMA           ','
+
+#ifndef DEBUG
+
+#define        M_QUOTE         0x8000
+#define        M_PROTECT       0x4000
+#define        M_MASK          0xffff
+#define        M_ASCII         0x00ff
+
+typedef unsigned short Char;
+
+#else
+
+#define        M_QUOTE         0x80
+#define        M_PROTECT       0x40
+#define        M_MASK          0xff
+#define        M_ASCII         0x7f
+
+typedef char Char;
+
+#endif
+
+
+#define        CHAR(c)         ((Char)((c)&M_ASCII))
+#define        META(c)         ((Char)((c)|M_QUOTE))
+#define        M_ALL           META('*')
+#define        M_END           META(']')
+#define        M_NOT           META('!')
+#define        M_ONE           META('?')
+#define        M_RNG           META('-')
+#define        M_SET           META('[')
+#define        M_CLASS         META(':')
+#define        ismeta(c)       (((c)&M_QUOTE) != 0)
+
+
+static int      compare(const void *, const void *);
+static int      g_Ctoc(const Char *, char *, unsigned int);
+static int      g_lstat(Char *, struct stat *, glob_t *);
+static DIR     *g_opendir(Char *, glob_t *);
+static Char    *g_strchr(const Char *, int);
+static int      g_strncmp(const Char *, const char *, size_t);
+static int      g_stat(Char *, struct stat *, glob_t *);
+static int      glob0(const Char *, glob_t *);
+static int      glob1(Char *, Char *, glob_t *);
+static int      glob2(Char *, Char *, Char *, Char *, Char *, Char *,
+                   glob_t *);
+static int      glob3(Char *, Char *, Char *, Char *, Char *, Char *,
+                   Char *, Char *, glob_t *);
+static int      globextend(const Char *, glob_t *);
+static const Char *
+                globtilde(const Char *, Char *, size_t, glob_t *);
+static int      globexp1(const Char *, glob_t *);
+static int      globexp2(const Char *, const Char *, glob_t *, int *);
+static int      match(Char *, Char *, Char *);
+#ifdef DEBUG
+static void     qprintf(const char *, Char *);
+#endif
+
+int
+rpl_glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
+       glob_t *pglob)
+{
+       const unsigned char *patnext;
+       int c;
+       Char *bufnext, *bufend, patbuf[PATH_MAX];
+
+       patnext = (unsigned char *) pattern;
+       if (!(flags & GLOB_APPEND)) {
+               pglob->gl_pathc = 0;
+               pglob->gl_pathv = NULL;
+               if (!(flags & GLOB_DOOFFS))
+                       pglob->gl_offs = 0;
+       }
+       pglob->gl_flags = flags & ~GLOB_MAGCHAR;
+       pglob->gl_errfunc = errfunc;
+       pglob->gl_matchc = 0;
+
+       bufnext = patbuf;
+       bufend = bufnext + PATH_MAX - 1;
+       if (flags & GLOB_NOESCAPE)
+               while (bufnext < bufend && (c = *patnext++) != EOS)
+                       *bufnext++ = c;
+       else {
+               /* Protect the quoted characters. */
+               while (bufnext < bufend && (c = *patnext++) != EOS)
+                       if (c == QUOTE) {
+                               if ((c = *patnext++) == EOS) {
+                                       c = QUOTE;
+                                       --patnext;
+                               }
+                               *bufnext++ = c | M_PROTECT;
+                       } else
+                               *bufnext++ = c;
+       }
+       *bufnext = EOS;
+
+       if (flags & GLOB_BRACE)
+               return globexp1(patbuf, pglob);
+       else
+               return glob0(patbuf, pglob);
+}
+
+/*
+ * Expand recursively a glob {} pattern. When there is no more expansion
+ * invoke the standard globbing routine to glob the rest of the magic
+ * characters
+ */
+static int
+globexp1(const Char *pattern, glob_t *pglob)
+{
+       const Char* ptr = pattern;
+       int rv;
+
+       /* Protect a single {}, for find(1), like csh */
+       if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
+               return glob0(pattern, pglob);
+
+       while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
+               if (!globexp2(ptr, pattern, pglob, &rv))
+                       return rv;
+
+       return glob0(pattern, pglob);
+}
+
+
+/*
+ * Recursive brace globbing helper. Tries to expand a single brace.
+ * If it succeeds then it invokes globexp1 with the new pattern.
+ * If it fails then it tries to glob the rest of the pattern and returns.
+ */
+static int
+globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv)
+{
+       int     i;
+       Char   *lm, *ls;
+       const Char *pe, *pm, *pl;
+       Char    patbuf[PATH_MAX];
+
+       /* copy part up to the brace */
+       for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
+               continue;
+       *lm = EOS;
+       ls = lm;
+
+       /* Find the balanced brace */
+       for (i = 0, pe = ++ptr; *pe; pe++)
+               if (*pe == LBRACKET) {
+                       /* Ignore everything between [] */
+                       for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
+                               continue;
+                       if (*pe == EOS) {
+                               /*
+                                * We could not find a matching RBRACKET.
+                                * Ignore and just look for RBRACE
+                                */
+                               pe = pm;
+                       }
+               } else if (*pe == LBRACE)
+                       i++;
+               else if (*pe == RBRACE) {
+                       if (i == 0)
+                               break;
+                       i--;
+               }
+
+       /* Non matching braces; just glob the pattern */
+       if (i != 0 || *pe == EOS) {
+               *rv = glob0(patbuf, pglob);
+               return 0;
+       }
+
+       for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
+               switch (*pm) {
+               case LBRACKET:
+                       /* Ignore everything between [] */
+                       for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
+                               continue;
+                       if (*pm == EOS) {
+                               /*
+                                * We could not find a matching RBRACKET.
+                                * Ignore and just look for RBRACE
+                                */
+                               pm = pl;
+                       }
+                       break;
+
+               case LBRACE:
+                       i++;
+                       break;
+
+               case RBRACE:
+                       if (i) {
+                               i--;
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               case COMMA:
+                       if (i && *pm == COMMA)
+                               break;
+                       else {
+                               /* Append the current string */
+                               for (lm = ls; (pl < pm); *lm++ = *pl++)
+                                       continue;
+
+                               /*
+                                * Append the rest of the pattern after the
+                                * closing brace
+                                */
+                               for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
+                                       continue;
+
+                               /* Expand the current pattern */
+#ifdef DEBUG
+                               qprintf("globexp2:", patbuf);
+#endif
+                               *rv = globexp1(patbuf, pglob);
+
+                               /* move after the comma, to the next string */
+                               pl = pm + 1;
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+       *rv = 0;
+       return 0;
+}
+
+
+
+/*
+ * expand tilde from the passwd file.
+ */
+static const Char *
+globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
+{
+       struct passwd *pwd;
+       char *h;
+       const Char *p;
+       Char *b, *eb;
+
+       if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
+               return pattern;
+
+       /* Copy up to the end of the string or / */
+       eb = &patbuf[patbuf_len - 1];
+       for (p = pattern + 1, h = (char *) patbuf;
+           h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
+               continue;
+
+       *h = EOS;
+
+       if (((char *) patbuf)[0] == EOS) {
+               /*
+                * handle a plain ~ or ~/ by expanding $HOME
+                * first and then trying the password file
+                */
+               if ((h = getenv("HOME")) == NULL) {
+                       if ((pwd = getpwuid(getuid())) == NULL)
+                               return pattern;
+                       else
+                               h = pwd->pw_dir;
+               }
+       } else {
+               /*
+                * Expand a ~user
+                */
+               if ((pwd = getpwnam((char*) patbuf)) == NULL)
+                       return pattern;
+               else
+                       h = pwd->pw_dir;
+       }
+
+       /* Copy the home directory */
+       for (b = patbuf; b < eb && *h; *b++ = *h++)
+               continue;
+
+       /* Append the rest of the pattern */
+       while (b < eb && (*b++ = *p++) != EOS)
+               continue;
+       *b = EOS;
+
+       return patbuf;
+}
+
+static int
+g_strncmp(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(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
+ * quotes), calls glob1() to do the real pattern matching, and finally
+ * sorts the list (unless unsorted operation is requested).  Returns 0
+ * if things went well, nonzero if errors occurred.  It is not an error
+ * to find no matches.
+ */
+static int
+glob0(const Char *pattern, glob_t *pglob)
+{
+       const Char *qpatnext;
+       int c, err, oldpathc;
+       Char *bufnext, patbuf[PATH_MAX];
+
+       qpatnext = globtilde(pattern, patbuf, PATH_MAX, pglob);
+       oldpathc = pglob->gl_pathc;
+       bufnext = patbuf;
+
+       /* We don't need to check for buffer overflow any more. */
+       while ((c = *qpatnext++) != EOS) {
+               switch (c) {
+               case LBRACKET:
+                       c = *qpatnext;
+                       if (c == NOT)
+                               ++qpatnext;
+                       if (*qpatnext == EOS ||
+                           g_strchr(qpatnext+1, RBRACKET) == NULL) {
+                               *bufnext++ = LBRACKET;
+                               if (c == NOT)
+                                       --qpatnext;
+                               break;
+                       }
+                       *bufnext++ = M_SET;
+                       if (c == NOT)
+                               *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) {
+                                       *bufnext++ = M_RNG;
+                                       *bufnext++ = CHAR(c);
+                                       qpatnext += 2;
+                               }
+                       } while ((c = *qpatnext++) != RBRACKET);
+                       pglob->gl_flags |= GLOB_MAGCHAR;
+                       *bufnext++ = M_END;
+                       break;
+               case QUESTION:
+                       pglob->gl_flags |= GLOB_MAGCHAR;
+                       *bufnext++ = M_ONE;
+                       break;
+               case STAR:
+                       pglob->gl_flags |= GLOB_MAGCHAR;
+                       /* collapse adjacent stars to one,
+                        * to avoid exponential behavior
+                        */
+                       if (bufnext == patbuf || bufnext[-1] != M_ALL)
+                               *bufnext++ = M_ALL;
+                       break;
+               default:
+                       *bufnext++ = CHAR(c);
+                       break;
+               }
+       }
+       *bufnext = EOS;
+#ifdef DEBUG
+       qprintf("glob0:", patbuf);
+#endif
+
+       if ((err = glob1(patbuf, patbuf + PATH_MAX - 1, pglob)) != 0)
+               return err;
+
+       /*
+        * If there was no match we are going to append the pattern
+        * if GLOB_NOCHECK was specified.
+        */
+       if (pglob->gl_pathc == oldpathc) {
+               if (pglob->gl_flags & GLOB_NOCHECK)
+                       return globextend(pattern, pglob);
+               else
+                       return GLOB_NOMATCH;
+       }
+       if (!(pglob->gl_flags & GLOB_NOSORT))
+               qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
+                   pglob->gl_pathc - oldpathc, sizeof(char *), compare);
+       return 0;
+}
+
+static int
+compare(const void *p, const void *q)
+{
+       return strcmp(*(char **)p, *(char **)q);
+}
+
+static int
+glob1(Char *pattern, Char *pattern_last, glob_t *pglob)
+{
+       Char pathbuf[PATH_MAX];
+
+       /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
+       if (*pattern == EOS)
+               return 0;
+       return glob2(pathbuf, pathbuf + PATH_MAX - 1,
+           pathbuf, pathbuf + PATH_MAX - 1,
+           pattern, pattern_last, pglob);
+}
+
+/*
+ * The functions glob2 and glob3 are mutually recursive; there is one level
+ * of recursion for each segment in the pattern that contains one or more
+ * meta characters.
+ */
+static int
+glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
+       Char *pattern, Char *pattern_last, glob_t *pglob)
+{
+       struct stat sb;
+       Char *p, *q;
+       int anymeta;
+
+       /*
+        * Loop over pattern segments until end of pattern or until
+        * segment with meta character found.
+        */
+       for (anymeta = 0;;) {
+               if (*pattern == EOS) {          /* End of pattern? */
+                       *pathend = EOS;
+                       if (g_lstat(pathbuf, &sb, pglob))
+                               return 0;
+
+                       if (((pglob->gl_flags & GLOB_MARK) &&
+                           pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
+                           (S_ISLNK(sb.st_mode) &&
+                           (g_stat(pathbuf, &sb, pglob) == 0) &&
+                           S_ISDIR(sb.st_mode)))) {
+                               if (pathend+1 > pathend_last)
+                                       return 1;
+                               *pathend++ = SEP;
+                               *pathend = EOS;
+                       }
+                       ++pglob->gl_matchc;
+                       return globextend(pathbuf, pglob);
+               }
+
+               /* Find end of next segment, copy tentatively to pathend. */
+               q = pathend;
+               p = pattern;
+               while (*p != EOS && *p != SEP) {
+                       if (ismeta(*p))
+                               anymeta = 1;
+                       if (q+1 > pathend_last)
+                               return 1;
+                       *q++ = *p++;
+               }
+
+               if (!anymeta) {         /* No expansion, do next segment. */
+                       pathend = q;
+                       pattern = p;
+                       while (*pattern == SEP) {
+                               if (pathend+1 > pathend_last)
+                                       return 1;
+                               *pathend++ = *pattern++;
+                       }
+               } else
+                       /* Need expansion, recurse. */
+                       return glob3(pathbuf, pathbuf_last, pathend,
+                           pathend_last, pattern, pattern_last,
+                           p, pattern_last, pglob);
+       }
+       /* NOTREACHED */
+}
+
+static int
+glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
+       Char *pattern, Char *pattern_last, Char *restpattern,
+       Char *restpattern_last, glob_t *pglob)
+{
+       struct dirent *dp;
+       DIR *dirp;
+       int err;
+       char buf[PATH_MAX];
+
+       if (pathend > pathend_last)
+               return 1;
+       *pathend = EOS;
+       errno = 0;
+
+       if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
+               /* TODO: don't call for ENOENT or ENOTDIR? */
+               if (pglob->gl_errfunc) {
+                       if (g_Ctoc(pathbuf, buf, sizeof(buf)))
+                               return GLOB_ABORTED;
+                       if (pglob->gl_errfunc(buf, errno) ||
+                           pglob->gl_flags & GLOB_ERR)
+                               return GLOB_ABORTED;
+               }
+               return 0;
+       }
+
+       err = 0;
+
+       /* Search directory for matching names. */
+       while ((dp = readdir(dirp))) {
+               unsigned char *sc;
+               Char *dc;
+
+               /* Initial DOT must be matched literally. */
+               if (dp->d_name[0] == DOT && *pattern != DOT)
+                       continue;
+               dc = pathend;
+               sc = (unsigned char *) dp->d_name;
+               while (dc < pathend_last && (*dc++ = *sc++) != EOS)
+                       continue;
+               if (dc >= pathend_last) {
+                       *dc = EOS;
+                       err = 1;
+                       break;
+               }
+
+               if (!match(pathend, pattern, restpattern)) {
+                       *pathend = EOS;
+                       continue;
+               }
+               err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
+                   restpattern, restpattern_last, pglob);
+               if (err)
+                       break;
+       }
+
+       closedir(dirp);
+       return err;
+}
+
+/*
+ * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
+ * add the new item, and update gl_pathc.
+ *
+ * This assumes the BSD realloc, which only copies the block when its size
+ * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
+ * behavior.
+ *
+ * Return 0 if new item added, error code if memory couldn't be allocated.
+ *
+ * Invariant of the glob_t structure:
+ *     Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
+ *     gl_pathv points to (gl_offs + gl_pathc + 1) items.
+ */
+static int
+globextend(const Char *path, glob_t *pglob)
+{
+       char **pathv;
+       int i;
+       unsigned int newsize, len;
+       char *copy;
+       const Char *p;
+
+       newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
+       pathv = pglob->gl_pathv ?
+           (char **)realloc((char *)pglob->gl_pathv, newsize) :
+           (char **)malloc(newsize);
+       if (pathv == NULL) {
+               if (pglob->gl_pathv) {
+                       free(pglob->gl_pathv);
+                       pglob->gl_pathv = NULL;
+               }
+               return GLOB_NOSPACE;
+       }
+
+       if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
+               /* first time around -- clear initial gl_offs items */
+               pathv += pglob->gl_offs;
+               for (i = pglob->gl_offs; --i >= 0; )
+                       *--pathv = NULL;
+       }
+       pglob->gl_pathv = pathv;
+
+       for (p = path; *p++;)
+               continue;
+       len = (size_t)(p - path);
+       if ((copy = malloc(len)) != NULL) {
+               if (g_Ctoc(path, copy, len)) {
+                       free(copy);
+                       return GLOB_NOSPACE;
+               }
+               pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
+       }
+       pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+
+       return copy == NULL ? GLOB_NOSPACE : 0;
+}
+
+/*
+ * pattern matching function for filenames.  Each occurrence of the *
+ * pattern causes a recursion level.
+ */
+static int
+match(Char *name, Char *pat, Char *patend)
+{
+       int ok, negate_range;
+       Char c, k;
+
+       while (pat < patend) {
+               c = *pat++;
+               switch (c & M_MASK) {
+               case M_ALL:
+                       if (pat == patend)
+                               return 1;
+                       do {
+                           if (match(name, pat, patend))
+                                   return 1;
+                       } while (*name++ != EOS);
+                       return 0;
+               case M_ONE:
+                       if (*name++ == EOS)
+                               return 0;
+                       break;
+               case M_SET:
+                       ok = 0;
+                       if ((k = *name++) == EOS)
+                               return 0;
+                       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;
+                                       pat += 2;
+                               } else if (c == k)
+                                       ok = 1;
+                       }
+                       if (ok == negate_range)
+                               return 0;
+                       break;
+               default:
+                       if (*name++ != c)
+                               return 0;
+                       break;
+               }
+       }
+       return *name == EOS;
+}
+
+/* Free allocated data belonging to a glob_t structure. */
+void
+rpl_globfree(glob_t *pglob)
+{
+       int i;
+       char **pp;
+
+       if (pglob->gl_pathv != NULL) {
+               pp = pglob->gl_pathv + pglob->gl_offs;
+               for (i = pglob->gl_pathc; i--; ++pp)
+                       if (*pp)
+                               free(*pp);
+               free(pglob->gl_pathv);
+               pglob->gl_pathv = NULL;
+       }
+}
+
+static DIR *
+g_opendir(Char *str, glob_t *pglob)
+{
+       char buf[PATH_MAX];
+
+       if (!*str) {
+               buf[0] = '.';
+               buf[1] = '\0';
+       } else {
+               if (g_Ctoc(str, buf, sizeof(buf)))
+                       return NULL;
+       }
+       return opendir(buf);
+}
+
+static int
+g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
+{
+       char buf[PATH_MAX];
+
+       if (g_Ctoc(fn, buf, sizeof(buf)))
+               return -1;
+       return lstat(buf, sb);
+}
+
+static int
+g_stat(Char *fn, struct stat *sb, glob_t *pglob)
+{
+       char buf[PATH_MAX];
+
+       if (g_Ctoc(fn, buf, sizeof(buf)))
+               return -1;
+       return stat(buf, sb);
+}
+
+static Char *
+g_strchr(const Char *str, int ch)
+{
+       do {
+               if (*str == ch)
+                       return (Char *)str;
+       } while (*str++);
+       return NULL;
+}
+
+static int
+g_Ctoc(const Char *str, char *buf, unsigned int len)
+{
+
+       while (len--) {
+               if ((*buf++ = *str++) == EOS)
+                       return 0;
+       }
+       return 1;
+}
+
+#ifdef DEBUG
+static void
+qprintf(const char *str, Char *s)
+{
+       Char *p;
+
+       (void)printf("%s:\n", str);
+       for (p = s; *p; p++)
+               (void)printf("%c", CHAR(*p));
+       (void)printf("\n");
+       for (p = s; *p; p++)
+               (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
+       (void)printf("\n");
+       for (p = s; *p; p++)
+               (void)printf("%c", ismeta(*p) ? '_' : ' ');
+       (void)printf("\n");
+}
+#endif
diff --git a/compat/glob.h b/compat/glob.h
new file mode 100644 (file)
index 0000000..7e7153b
--- /dev/null
@@ -0,0 +1,78 @@
+/*     $OpenBSD: glob.h,v 1.8 2003/06/02 19:34:12 millert Exp $        */
+
+/*
+ * Copyright (c) 1989, 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.
+ *
+ *     @(#)glob.h      8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _GLOB_H_
+#define        _GLOB_H_
+
+struct stat;
+typedef struct {
+       int gl_pathc;           /* Count of total paths so far. */
+       int gl_matchc;          /* Count of paths matching pattern. */
+       int gl_offs;            /* Reserved at beginning of gl_pathv. */
+       int gl_flags;           /* Copy of flags parameter to glob. */
+       char **gl_pathv;        /* List of paths matching pattern. */
+                               /* Copy of errfunc parameter to glob. */
+       int (*gl_errfunc)(const char *, int);
+} glob_t;
+
+/* Flags */
+#define        GLOB_APPEND     0x0001  /* Append to output from previous call. */
+#define        GLOB_DOOFFS     0x0002  /* Use gl_offs. */
+#define        GLOB_ERR        0x0004  /* Return on error. */
+#define        GLOB_MARK       0x0008  /* Append / to matching directories. */
+#define        GLOB_NOCHECK    0x0010  /* Return pattern itself if nothing matches. */
+#define        GLOB_NOSORT     0x0020  /* Don't sort. */
+#define        GLOB_NOESCAPE   0x0040  /* Disable backslash escaping. */
+
+/* Non-POSIX extensions */
+#define        GLOB_MAGCHAR    0x0080  /* Pattern had globbing characters. */
+#define        GLOB_BRACE      0x0100  /* Expand braces ala csh. */
+#define        GLOB_TILDE      0x0200  /* Expand tilde names from the passwd file. */
+
+/* Error values returned by glob(3) */
+#define        GLOB_NOSPACE    (-1)    /* Malloc call failed. */
+#define        GLOB_ABORTED    (-2)    /* Unignored error. */
+#define        GLOB_NOMATCH    (-3)    /* No match and GLOB_NOCHECK not set. */
+#define        GLOB_NOSYS      (-4)    /* Function not supported. */
+#define GLOB_ABEND     GLOB_ABORTED
+
+int    rpl_glob(const char *, int, int (*)(const char *, int), glob_t *);
+void   rpl_globfree(glob_t *);
+
+#define glob(_a, _b, _c, _d) rpl_glob((_a), (_b), (_c), (_d))
+#define globfree(_a) rpl_globfree((_a))
+
+#endif /* !_GLOB_H_ */
diff --git a/compat/isblank.c b/compat/isblank.c
new file mode 100644 (file)
index 0000000..083d805
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2008, 2010-2011 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 "missing.h"
+
+#undef isblank
+int
+isblank(int ch)
+{
+    return ch == ' ' || ch == '\t';
+}
diff --git a/compat/memrchr.c b/compat/memrchr.c
new file mode 100644 (file)
index 0000000..0b1e3a5
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2007, 2010-2011 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 "missing.h"
+
+/*
+ * Reverse memchr()
+ * Find the last occurrence of 'c' in the buffer 's' of size 'n'.
+ */
+void *
+memrchr(const void *s, int c, size_t n)
+{
+    const unsigned char *cp;
+
+    if (n != 0) {
+       cp = (unsigned char *)s + n;
+       do {
+           if (*(--cp) == (unsigned char)c)
+               return (void *)cp;
+       } while (--n != 0);
+    }
+    return (void *)0;
+}
diff --git a/compat/mksiglist.c b/compat/mksiglist.c
new file mode 100644 (file)
index 0000000..ce88919
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2010-2011 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 <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#include <signal.h>
+
+#include "missing.h"
+
+int
+main(int argc, char *argv[])
+{
+    static char *my_sys_siglist[NSIG];
+    int i;
+
+#include "compat/mksiglist.h"
+
+    printf("#include <config.h>\n");
+    printf("#include <signal.h>\n");
+    printf("#include \"missing.h\"\n\n");
+    printf("const char *const my_sys_siglist[NSIG] = {\n");
+    for (i = 0; i < NSIG; i++) {
+       if (my_sys_siglist[i] != NULL) {
+           printf("    \"%s\",\n", my_sys_siglist[i]);
+       } else {
+           printf("    \"Signal %d\",\n", i);
+       }
+    }
+    printf("};\n");
+
+    exit(0);
+}
diff --git a/compat/mksiglist.h b/compat/mksiglist.h
new file mode 100644 (file)
index 0000000..f9f3294
--- /dev/null
@@ -0,0 +1,174 @@
+/* public domain */
+
+#ifdef SIGHUP
+    if (my_sys_siglist[SIGHUP] == NULL)
+       my_sys_siglist[SIGHUP] = "Hangup";
+#endif
+#ifdef SIGINT
+    if (my_sys_siglist[SIGINT] == NULL)
+       my_sys_siglist[SIGINT] = "Interrupt";
+#endif
+#ifdef SIGQUIT
+    if (my_sys_siglist[SIGQUIT] == NULL)
+       my_sys_siglist[SIGQUIT] = "Quit";
+#endif
+#ifdef SIGILL
+    if (my_sys_siglist[SIGILL] == NULL)
+       my_sys_siglist[SIGILL] = "Illegal instruction";
+#endif
+#ifdef SIGTRAP
+    if (my_sys_siglist[SIGTRAP] == NULL)
+       my_sys_siglist[SIGTRAP] = "Trace trap";
+#endif
+#ifdef SIGABRT
+    if (my_sys_siglist[SIGABRT] == NULL)
+       my_sys_siglist[SIGABRT] = "Abort";
+#endif
+#ifdef SIGIOT
+    if (my_sys_siglist[SIGIOT] == NULL)
+       my_sys_siglist[SIGIOT] = "IOT instruction";
+#endif
+#ifdef SIGEMT
+    if (my_sys_siglist[SIGEMT] == NULL)
+       my_sys_siglist[SIGEMT] = "EMT trap";
+#endif
+#ifdef SIGFPE
+    if (my_sys_siglist[SIGFPE] == NULL)
+       my_sys_siglist[SIGFPE] = "Floating point exception";
+#endif
+#ifdef SIGKILL
+    if (my_sys_siglist[SIGKILL] == NULL)
+       my_sys_siglist[SIGKILL] = "Killed";
+#endif
+#ifdef SIGUNUSED
+    if (my_sys_siglist[SIGUNUSED] == NULL)
+       my_sys_siglist[SIGUNUSED] = "Unused";
+#endif
+#ifdef SIGBUS
+    if (my_sys_siglist[SIGBUS] == NULL)
+       my_sys_siglist[SIGBUS] = "Bus error";
+#endif
+#ifdef SIGSEGV
+    if (my_sys_siglist[SIGSEGV] == NULL)
+       my_sys_siglist[SIGSEGV] = "Memory fault";
+#endif
+#ifdef SIGSYS
+    if (my_sys_siglist[SIGSYS] == NULL)
+       my_sys_siglist[SIGSYS] = "Bad system call";
+#endif
+#ifdef SIGPIPE
+    if (my_sys_siglist[SIGPIPE] == NULL)
+       my_sys_siglist[SIGPIPE] = "Broken pipe";
+#endif
+#ifdef SIGALRM
+    if (my_sys_siglist[SIGALRM] == NULL)
+       my_sys_siglist[SIGALRM] = "Alarm clock";
+#endif
+#ifdef SIGTERM
+    if (my_sys_siglist[SIGTERM] == NULL)
+       my_sys_siglist[SIGTERM] = "Terminated";
+#endif
+#ifdef SIGSTKFLT
+    if (my_sys_siglist[SIGSTKFLT] == NULL)
+       my_sys_siglist[SIGSTKFLT] = "Stack fault";
+#endif
+#ifdef SIGIO
+    if (my_sys_siglist[SIGIO] == NULL)
+       my_sys_siglist[SIGIO] = "I/O possible";
+#endif
+#ifdef SIGXCPU
+    if (my_sys_siglist[SIGXCPU] == NULL)
+       my_sys_siglist[SIGXCPU] = "CPU time limit exceeded";
+#endif
+#ifdef SIGXFSZ
+    if (my_sys_siglist[SIGXFSZ] == NULL)
+       my_sys_siglist[SIGXFSZ] = "File size limit exceeded";
+#endif
+#ifdef SIGVTALRM
+    if (my_sys_siglist[SIGVTALRM] == NULL)
+       my_sys_siglist[SIGVTALRM] = "Virtual timer expired";
+#endif
+#ifdef SIGPROF
+    if (my_sys_siglist[SIGPROF] == NULL)
+       my_sys_siglist[SIGPROF] = "Profiling timer expired";
+#endif
+#ifdef SIGWINCH
+    if (my_sys_siglist[SIGWINCH] == NULL)
+       my_sys_siglist[SIGWINCH] = "Window size change";
+#endif
+#ifdef SIGLOST
+    if (my_sys_siglist[SIGLOST] == NULL)
+       my_sys_siglist[SIGLOST] = "File lock lost";
+#endif
+#ifdef SIGUSR1
+    if (my_sys_siglist[SIGUSR1] == NULL)
+       my_sys_siglist[SIGUSR1] = "User defined signal 1";
+#endif
+#ifdef SIGUSR2
+    if (my_sys_siglist[SIGUSR2] == NULL)
+       my_sys_siglist[SIGUSR2] = "User defined signal 2";
+#endif
+#ifdef SIGPWR
+    if (my_sys_siglist[SIGPWR] == NULL)
+       my_sys_siglist[SIGPWR] = "Power-fail/Restart";
+#endif
+#ifdef SIGPOLL
+    if (my_sys_siglist[SIGPOLL] == NULL)
+       my_sys_siglist[SIGPOLL] = "Pollable event occurred";
+#endif
+#ifdef SIGSTOP
+    if (my_sys_siglist[SIGSTOP] == NULL)
+       my_sys_siglist[SIGSTOP] = "Stopped (signal)";
+#endif
+#ifdef SIGTSTP
+    if (my_sys_siglist[SIGTSTP] == NULL)
+       my_sys_siglist[SIGTSTP] = "Stopped";
+#endif
+#ifdef SIGCONT
+    if (my_sys_siglist[SIGCONT] == NULL)
+       my_sys_siglist[SIGCONT] = "Continued";
+#endif
+#ifdef SIGCHLD
+    if (my_sys_siglist[SIGCHLD] == NULL)
+       my_sys_siglist[SIGCHLD] = "Child exited";
+#endif
+#ifdef SIGCLD
+    if (my_sys_siglist[SIGCLD] == NULL)
+       my_sys_siglist[SIGCLD] = "Child exited";
+#endif
+#ifdef SIGTTIN
+    if (my_sys_siglist[SIGTTIN] == NULL)
+       my_sys_siglist[SIGTTIN] = "Stopped (tty input)";
+#endif
+#ifdef SIGTTOU
+    if (my_sys_siglist[SIGTTOU] == NULL)
+       my_sys_siglist[SIGTTOU] = "Stopped (tty output)";
+#endif
+#ifdef SIGINFO
+    if (my_sys_siglist[SIGINFO] == NULL)
+       my_sys_siglist[SIGINFO] = "Information request";
+#endif
+#ifdef SIGURG
+    if (my_sys_siglist[SIGURG] == NULL)
+       my_sys_siglist[SIGURG] = "Urgent I/O condition";
+#endif
+#ifdef SIGWAITING
+    if (my_sys_siglist[SIGWAITING] == NULL)
+       my_sys_siglist[SIGWAITING] = "No runnable LWPs";
+#endif
+#ifdef SIGLWP
+    if (my_sys_siglist[SIGLWP] == NULL)
+       my_sys_siglist[SIGLWP] = "Inter-LWP signal";
+#endif
+#ifdef SIGFREEZE
+    if (my_sys_siglist[SIGFREEZE] == NULL)
+       my_sys_siglist[SIGFREEZE] = "Checkpoint freeze";
+#endif
+#ifdef SIGTHAW
+    if (my_sys_siglist[SIGTHAW] == NULL)
+       my_sys_siglist[SIGTHAW] = "Checkpoint thaw";
+#endif
+#ifdef SIGCANCEL
+    if (my_sys_siglist[SIGCANCEL] == NULL)
+       my_sys_siglist[SIGCANCEL] = "Thread cancellation";
+#endif
diff --git a/compat/mktemp.c b/compat/mktemp.c
new file mode 100644 (file)
index 0000000..ce7a4e5
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2001, 2003, 2004, 2008-2011
+ *     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/time.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#include <ctype.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+
+#include "missing.h"
+
+#define MKTEMP_FILE    1
+#define MKTEMP_DIR     2
+
+#define TEMPCHARS      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+#define NUM_CHARS      (sizeof(TEMPCHARS) - 1)
+
+#ifndef INT_MAX
+#define INT_MAX        0x7fffffff
+#endif
+
+#ifdef HAVE_RANDOM
+# define RAND          random
+# define SRAND         srandom
+# define SEED_T                unsigned int
+#else
+# ifdef HAVE_LRAND48
+#  define RAND         lrand48
+#  define SRAND                srand48
+#  define SEED_T       long
+# else
+#  define RAND         rand
+#  define SRAND                srand
+#  define SEED_T       unsigned int
+# endif
+#endif
+
+static void
+seed_random(void)
+{
+       SEED_T seed;
+       struct timeval tv;
+
+       /*
+        * Seed from time of day and process id multiplied by small primes.
+        */
+       (void) gettimeofday(&tv, NULL);
+       seed = (tv.tv_sec % 10000) * 523 + tv.tv_usec * 13 +
+           (getpid() % 1000) * 983;
+       SRAND(seed);
+}
+
+static unsigned int
+get_random(void)
+{
+       static int initialized;
+
+       if (!initialized) {
+               seed_random();
+               initialized = 1;
+       }
+
+       return RAND() & 0xffffffff;
+}
+
+static int
+mktemp_internal(char *path, int slen, int mode)
+{
+       char *start, *cp, *ep;
+       const char *tempchars = TEMPCHARS;
+       unsigned int r, tries;
+       int fd;
+
+       for (ep = path; *ep; ep++)
+               ;
+       if (path + slen >= ep) {
+               errno = EINVAL;
+               return -1;
+       }
+       ep -= slen;
+
+       tries = 1;
+       for (start = ep; start > path && start[-1] == 'X'; start--) {
+               if (tries < INT_MAX / NUM_CHARS)
+                       tries *= NUM_CHARS;
+       }
+       tries *= 2;
+
+       do {
+               for (cp = start; *cp; cp++) {
+                       r = get_random() % NUM_CHARS;
+                       *cp = tempchars[r];
+               }
+
+               switch (mode) {
+               case MKTEMP_FILE:
+                       fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
+                       if (fd != -1 || errno != EEXIST)
+                               return fd;
+                       break;
+               case MKTEMP_DIR:
+                       if (mkdir(path, S_IRWXU) == 0)
+                               return 0;
+                       if (errno != EEXIST)
+                               return -1;
+                       break;
+               }
+       } while (--tries);
+
+       errno = EEXIST;
+       return -1;
+}
+
+#ifndef HAVE_MKSTEMPS
+int
+mkstemps(char *path, int slen)
+{
+       return mktemp_internal(path, slen, MKTEMP_FILE);
+}
+#endif /* HAVE_MKSTEMPS */
+
+#ifndef HAVE_MKDTEMP
+char *
+mkdtemp(char *path)
+{
+       if (mktemp_internal(path, 0, MKTEMP_DIR) == -1)
+               return NULL;
+       return path;
+}
+#endif /* HAVE_MKDTEMP */
diff --git a/compat/nanosleep.c b/compat/nanosleep.c
new file mode 100644 (file)
index 0000000..9490d72
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009-2011 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/time.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_H */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#ifndef HAVE_TIMESPEC
+# include "compat/timespec.h"
+#endif
+#include <errno.h>
+
+#include "missing.h"
+
+int
+nanosleep(const struct timespec *ts, struct timespec *rts)
+{
+    struct timeval timeout, endtime, now;
+    int rval;
+
+    timeout.tv_sec = ts->tv_sec;
+    timeout.tv_usec = ts->tv_nsec / 1000;
+    if (rts != NULL) {
+       gettimeofday(&endtime, NULL);
+       timevaladd(&endtime, &timeout);
+    }
+    rval = select(0, NULL, NULL, NULL, &timeout);
+    if (rts != NULL && rval == -1 && errno == EINTR) {
+       gettimeofday(&now, NULL);
+       timevalsub(&endtime, &now);
+       rts->tv_sec = endtime.tv_sec;
+       rts->tv_nsec = endtime.tv_usec * 1000;
+    }
+    return rval;
+}
diff --git a/compat/regress/fnmatch/fnm_test.c b/compat/regress/fnmatch/fnm_test.c
new file mode 100644 (file)
index 0000000..2079e3b
--- /dev/null
@@ -0,0 +1,76 @@
+/*     $OpenBSD: fnm_test.c,v 1.1 2008/10/01 23:04:58 millert Exp $    */
+
+/*
+ * Public domain, 2008, Todd C. Miller <Todd.Miller@courtesan.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_FNMATCH
+# include <fnmatch.h>
+#else
+# include "compat/fnmatch.h"
+#endif
+
+int
+main(int argc, char *argv[])
+{
+       FILE *fp = stdin;
+       char pattern[1024], string[1024], flagstr[1024];
+       int errors = 0, tests = 0, flags, got, want;
+
+       if (argc > 1) {
+               if ((fp = fopen(argv[1], "r")) == NULL) {
+                       perror(argv[1]);
+                       exit(1);
+               }
+       }
+
+       /*
+        * Read in test file, which is formatted thusly:
+        *
+        * pattern string flags expected_result
+        *
+        */
+       for (;;) {
+               got = fscanf(fp, "%s %s %s %d\n", pattern, string, flagstr,
+                   &want);
+               if (got == EOF)
+                       break;
+               if (got == 4) {
+                       flags = 0;
+                       if (strcmp(flagstr, "FNM_NOESCAPE") == 0)
+                               flags |= FNM_NOESCAPE;
+                       else if (strcmp(flagstr, "FNM_PATHNAME") == 0)
+                               flags |= FNM_PATHNAME;
+                       else if (strcmp(flagstr, "FNM_PERIOD") == 0)
+                               flags |= FNM_PERIOD;
+                       else if (strcmp(flagstr, "FNM_LEADING_DIR") == 0)
+                               flags |= FNM_LEADING_DIR;
+                       else if (strcmp(flagstr, "FNM_CASEFOLD") == 0)
+                               flags |= FNM_CASEFOLD;
+                       got = fnmatch(pattern, string, flags);
+                       if (got != want) {
+                               fprintf(stderr,
+                                   "fnmatch: %s %s %d: want %d, got %d\n",
+                                   pattern, string, flags, want, got);
+                               errors++;
+                       }
+                       tests++;
+               }
+       }
+       if (tests != 0) {
+               printf("fnmatch: %d test%s run, %d errors, %d%% success rate\n",
+                   tests, tests == 1 ? "" : "s", errors,
+                   (tests - errors) * 100 / tests);
+       }
+       exit(errors);
+}
diff --git a/compat/regress/fnmatch/fnm_test.in b/compat/regress/fnmatch/fnm_test.in
new file mode 100644 (file)
index 0000000..5d452ef
--- /dev/null
@@ -0,0 +1,5 @@
+/bin/[[:alpha:][:alnum:]]* /bin/ls FNM_PATHNAME 0
+/bin/[[:alpha:][:alnum:]]* /bin/LS FNM_CASEFOLD 0
+/bin/[[:opper:][:alnum:]]* /bin/ls NONE 1
+[[:alpha:][:alnum:]]*.c foo1.c FNM_PERIOD 0
+[[:upper:]]* FOO NONE 0
diff --git a/compat/regress/glob/files b/compat/regress/glob/files
new file mode 100644 (file)
index 0000000..c5e92aa
--- /dev/null
@@ -0,0 +1,47 @@
+fake/bin/[
+fake/bin/cat
+fake/bin/chgrp
+fake/bin/chio
+fake/bin/chmod
+fake/bin/cksum
+fake/bin/cp
+fake/bin/cpio
+fake/bin/csh
+fake/bin/date
+fake/bin/dd
+fake/bin/df
+fake/bin/domainname
+fake/bin/echo
+fake/bin/ed
+fake/bin/eject
+fake/bin/expr
+fake/bin/hostname
+fake/bin/kill
+fake/bin/ksh
+fake/bin/ln
+fake/bin/ls
+fake/bin/md5
+fake/bin/mkdir
+fake/bin/mt
+fake/bin/mv
+fake/bin/pax
+fake/bin/ps
+fake/bin/pwd
+fake/bin/rcp
+fake/bin/rksh
+fake/bin/rm
+fake/bin/rmail
+fake/bin/rmd160
+fake/bin/rmdir
+fake/bin/sh
+fake/bin/sha1
+fake/bin/sha256
+fake/bin/sha384
+fake/bin/sha512
+fake/bin/sleep
+fake/bin/stty
+fake/bin/sum
+fake/bin/sync
+fake/bin/systrace
+fake/bin/tar
+fake/bin/test
diff --git a/compat/regress/glob/globtest.c b/compat/regress/glob/globtest.c
new file mode 100644 (file)
index 0000000..0c966fe
--- /dev/null
@@ -0,0 +1,213 @@
+/*     $OpenBSD: globtest.c,v 1.1 2008/10/01 23:04:36 millert Exp $    */
+
+/*
+ * Public domain, 2008, Todd C. Miller <Todd.Miller@courtesan.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_EXTENDED_GLOB
+# include <glob.h>
+#else
+# include "compat/glob.h"
+#endif
+#include <errno.h>
+
+#define MAX_RESULTS    256
+
+#ifndef errno
+extern int errno;
+#endif
+
+struct gl_entry {
+       int flags;
+       int nresults;
+       char pattern[1024];
+       char *results[MAX_RESULTS];
+};
+
+int test_glob(struct gl_entry *);
+
+int
+main(int argc, char **argv)
+{
+       FILE *fp = stdin;
+       char buf[2048], *cp, *ep;
+       int errors = 0, tests = 0, lineno;
+       struct gl_entry entry;
+       size_t len;
+
+       if (argc > 1) {
+               if ((fp = fopen(argv[1], "r")) == NULL) {
+                       perror(argv[1]);
+                       exit(1);
+               }
+       }
+
+       /*
+        * Read in test file, which is formatted thusly:
+        *
+        * [pattern] <flags>
+        * result1
+        * result2
+        * result3
+        * ...
+        *
+        */
+       lineno = 0;
+       memset(&entry, 0, sizeof(entry));
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               lineno++;
+               len = strlen(buf);
+               if (len > 0) {
+                       if (buf[len - 1] != '\n') {
+                               fprintf(stderr,
+                                   "globtest: missing newline at EOF\n");
+                               exit(1);
+                       }
+                       buf[--len] = '\0';
+               }
+               if (len == 0)
+                       continue; /* blank line */
+
+               if (buf[0] == '[') {
+                       /* check previous pattern */
+                       if (entry.pattern[0]) {
+                               errors += test_glob(&entry);
+                               tests++;
+                       }
+
+                       /* start new entry */
+                       if ((cp = strrchr(buf + 1, ']')) == NULL) {
+                               fprintf(stderr,
+                                   "globtest: invalid entry on line %d\n",
+                                   lineno);
+                               exit(1);
+                       }
+                       len = cp - buf - 1;
+                       if (len >= sizeof(entry.pattern)) {
+                               fprintf(stderr,
+                                   "globtest: pattern too big on line %d\n",
+                                   lineno);
+                               exit(1);
+                       }
+                       memcpy(entry.pattern, buf + 1, len);
+                       entry.pattern[len] = '\0';
+
+                       cp += 2;
+                       if (*cp++ != '<') {
+                               fprintf(stderr,
+                                   "globtest: invalid entry on line %d\n",
+                                   lineno);
+                               exit(1);
+                       }
+                       ep = strchr(cp, '>');
+                       if (ep == NULL) {
+                               fprintf(stderr,
+                                   "globtest: invalid entry on line %d\n",
+                                   lineno);
+                               exit(1);
+                       }
+                       *ep = '\0';
+                       entry.flags = 0;
+                       for ((cp = strtok(cp, "|")); cp != NULL; (cp = strtok(NULL, "|"))) {
+                               if (strcmp(cp, "GLOB_APPEND") == 0)
+                                       entry.flags |= GLOB_APPEND;
+                               else if (strcmp(cp, "GLOB_DOOFFS") == 0)
+                                       entry.flags |= GLOB_DOOFFS;
+                               else if (strcmp(cp, "GLOB_ERR") == 0)
+                                       entry.flags |= GLOB_ERR;
+                               else if (strcmp(cp, "GLOB_MARK") == 0)
+                                       entry.flags |= GLOB_MARK;
+                               else if (strcmp(cp, "GLOB_NOCHECK") == 0)
+                                       entry.flags |= GLOB_NOCHECK;
+                               else if (strcmp(cp, "GLOB_NOSORT") == 0)
+                                       entry.flags |= GLOB_NOSORT;
+                               else if (strcmp(cp, "GLOB_NOESCAPE") == 0)
+                                       entry.flags |= GLOB_NOESCAPE;
+                               else if (strcmp(cp, "GLOB_BRACE") == 0)
+                                       entry.flags |= GLOB_BRACE;
+                               else if (strcmp(cp, "GLOB_TILDE") == 0)
+                                       entry.flags |= GLOB_TILDE;
+                               else if (strcmp(cp, "NONE") != 0) {
+                                       fprintf(stderr,
+                                           "globtest: invalid flags on line %d\n",
+                                           lineno);
+                                       exit(1);
+                               }
+                       }
+                       entry.nresults = 0;
+                       continue;
+               }
+               if (!entry.pattern[0]) {
+                       fprintf(stderr, "globtest: missing entry on line %d\n",
+                           lineno);
+                       exit(1);
+               }
+
+               if (entry.nresults + 1 > MAX_RESULTS) {
+                       fprintf(stderr,
+                           "globtest: too many results for %s, max %d\n",
+                           entry.pattern, MAX_RESULTS);
+                       exit(1);
+               }
+               entry.results[entry.nresults++] = strdup(buf);
+       }
+       if (entry.pattern[0]) {
+               errors += test_glob(&entry); /* test last pattern */
+               tests++;
+       }
+        if (tests != 0) {
+               printf("glob: %d test%s run, %d errors, %d%% success rate\n",
+                   tests, tests == 1 ? "" : "s", errors,
+                   (tests - errors) * 100 / tests);
+        }
+       exit(errors);
+}
+
+int test_glob(struct gl_entry *entry)
+{
+       glob_t gl;
+       char **ap;
+       int nmatches = 0, i = 0;
+
+       if (glob(entry->pattern, entry->flags, NULL, &gl) != 0) {
+               fprintf(stderr, "glob failed: %s: %s\n", entry->pattern,
+                   strerror(errno));
+               exit(1);
+       }
+
+       for (ap = gl.gl_pathv; *ap != NULL; ap++)
+               nmatches++;
+
+       if (nmatches != entry->nresults)
+               goto mismatch;
+
+       for (i = 0; i < entry->nresults; i++) {
+               if (strcmp(gl.gl_pathv[i], entry->results[i]) != 0)
+                       goto mismatch;
+               free(entry->results[i]);
+       }
+       return 0;
+ mismatch:
+       if (nmatches != entry->nresults) {
+               fprintf(stderr,
+                   "globtest: mismatch in number of results (found %d, expected %d) for pattern %s\n",
+                   nmatches, entry->nresults, entry->pattern);
+       } else {
+               fprintf(stderr, "globtest: mismatch for pattern %s, flags 0x%x "
+                   "(found \"%s\", expected \"%s\")\n", entry->pattern, entry->flags,
+                   gl.gl_pathv[i], entry->results[i]);
+               while (i < entry->nresults)
+                       free(entry->results[i++]);
+       }
+       return 1;
+}
diff --git a/compat/regress/glob/globtest.in b/compat/regress/glob/globtest.in
new file mode 100644 (file)
index 0000000..20a86c1
--- /dev/null
@@ -0,0 +1,64 @@
+[fake/bin/[[:alpha:]]*] <NONE>
+fake/bin/cat
+fake/bin/chgrp
+fake/bin/chio
+fake/bin/chmod
+fake/bin/cksum
+fake/bin/cp
+fake/bin/cpio
+fake/bin/csh
+fake/bin/date
+fake/bin/dd
+fake/bin/df
+fake/bin/domainname
+fake/bin/echo
+fake/bin/ed
+fake/bin/eject
+fake/bin/expr
+fake/bin/hostname
+fake/bin/kill
+fake/bin/ksh
+fake/bin/ln
+fake/bin/ls
+fake/bin/md5
+fake/bin/mkdir
+fake/bin/mt
+fake/bin/mv
+fake/bin/pax
+fake/bin/ps
+fake/bin/pwd
+fake/bin/rcp
+fake/bin/rksh
+fake/bin/rm
+fake/bin/rmail
+fake/bin/rmd160
+fake/bin/rmdir
+fake/bin/sh
+fake/bin/sha1
+fake/bin/sha256
+fake/bin/sha384
+fake/bin/sha512
+fake/bin/sleep
+fake/bin/stty
+fake/bin/sum
+fake/bin/sync
+fake/bin/systrace
+fake/bin/tar
+fake/bin/test
+
+[fake/bin/rm{,dir,ail}] <GLOB_BRACE>
+fake/bin/rm
+fake/bin/rmdir
+fake/bin/rmail
+
+[fake/bin/sha[[:digit:]]] <NONE>
+fake/bin/sha1
+
+[fake/bin/sha[[:digit:]]*] <NONE>
+fake/bin/sha1
+fake/bin/sha256
+fake/bin/sha384
+fake/bin/sha512
+
+[fake/bin/ca[a-z]] <NONE>
+fake/bin/cat
diff --git a/compat/setenv.c b/compat/setenv.c
new file mode 100644 (file)
index 0000000..cff0c26
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2010 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 <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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
+# include <malloc.h>
+#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
+#include <errno.h>
+
+#include "missing.h"
+
+int
+setenv(const char *var, const char *val, int overwrite)
+{
+    char *envstr, *dst;
+    const char *src;
+    size_t esize;
+
+    if (!var || *var == '\0') {
+       errno = EINVAL;
+       return -1;
+    }
+
+    /*
+     * POSIX says a var name with '=' is an error but BSD
+     * just ignores the '=' and anything after it.
+     */
+    for (src = var; *src != '\0' && *src != '='; src++)
+       ;
+    esize = (size_t)(src - var) + 2;
+    if (val) {
+        esize += strlen(val);  /* glibc treats a NULL val as "" */
+    }
+
+    /* Allocate and fill in envstr. */
+    if ((envstr = malloc(esize)) == NULL)
+       return -1;
+    for (src = var, dst = envstr; *src != '\0' && *src != '=';)
+       *dst++ = *src++;
+    *dst++ = '=';
+    if (val) {
+       for (src = val; *src != '\0';)
+           *dst++ = *src++;
+    }
+    *dst = '\0';
+
+    if (!overwrite && getenv(var) != NULL) {
+       free(envstr);
+       return 0;
+    }
+    return putenv(envstr);
+}
diff --git a/compat/siglist.in b/compat/siglist.in
new file mode 100644 (file)
index 0000000..f149eb5
--- /dev/null
@@ -0,0 +1,56 @@
+#
+# List of signals used to build sys_siglist (see mksiglist.c)
+# Adapted from pdksh; public domain
+#
+# Note that if a system has multiple defines for the same signal
+# (eg, SIGABRT vs SIGIOT, SIGCHLD vs SIGCLD), only the first one
+# will be seen, so the order in this list is important.
+#
+    HUP     Hangup
+    INT     Interrupt
+    QUIT    Quit
+    ILL     Illegal instruction
+    TRAP    Trace trap
+# before IOT (ABRT is posix and ABRT is sometimes the same as IOT)
+    ABRT    Abort
+    IOT     IOT instruction
+    EMT     EMT trap
+    FPE     Floating point exception
+    KILL    Killed
+# before BUS (Older Linux doesn't really have a BUS, but defines it to UNUSED)
+    UNUSED  Unused
+    BUS     Bus error
+    SEGV    Memory fault
+    SYS     Bad system call
+    PIPE    Broken pipe
+    ALRM    Alarm clock
+    TERM    Terminated
+    STKFLT  Stack fault
+# before POLL (POLL is sometimes the same as IO)
+    IO      I/O possible
+    XCPU    CPU time limit exceeded
+    XFSZ    File size limit exceeded
+    VTALRM  Virtual timer expired
+    PROF    Profiling timer expired
+    WINCH   Window size change
+    LOST    File lock lost
+    USR1    User defined signal 1
+    USR2    User defined signal 2
+    PWR     Power-fail/Restart
+    POLL    Pollable event occurred
+    STOP    Stopped (signal)
+    TSTP    Stopped
+    CONT    Continued
+# before CLD (CHLD is posix and CHLD is sometimes the same as CLD)
+    CHLD    Child exited
+    CLD     Child exited
+    TTIN    Stopped (tty input)
+    TTOU    Stopped (tty output)
+    INFO    Information request
+    URG     Urgent I/O condition
+# Solaris (svr4?) signals
+    WAITING No runnable LWPs
+    LWP            Inter-LWP signal
+    FREEZE  Checkpoint freeze
+    THAW    Checkpoint thaw
+    CANCEL  Thread cancellation
diff --git a/compat/snprintf.c b/compat/snprintf.c
new file mode 100644 (file)
index 0000000..8a77a5b
--- /dev/null
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 1999-2005, 2008, 2010-2011
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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.
+ *
+ * From: @(#)vfprintf.c        8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * v?snprintf/v?asprintf based on 4.4BSD stdio.
+ * NOTE: does not support floating point.
+ */
+
+#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_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_STRING_H
+# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
+# include <malloc.h>
+#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
+#include <limits.h>
+#include <stdarg.h>
+
+#include "missing.h"
+
+static int xxxprintf(char **, size_t, int, const char *, va_list);
+
+/*
+ * Some systems may not have these defined in <limits.h>
+ */
+#ifndef ULONG_MAX
+# define ULONG_MAX     ((unsigned long)-1)
+#endif
+#ifndef LONG_MAX
+# define LONG_MAX      (ULONG_MAX / 2)
+#endif
+#ifdef HAVE_LONG_LONG_INT
+# ifndef ULLONG_MAX
+#  ifdef UQUAD_MAX
+#   define ULLONG_MAX  UQUAD_MAX
+#  else
+#   define ULLONG_MAX  ((unsigned long long)-1)
+#  endif
+# endif
+# ifndef LLONG_MAX
+#  ifdef QUAD_MAX
+#   define LLONG_MAX   QUAD_MAX
+#  else
+#   define LLONG_MAX   (ULLONG_MAX / 2)
+#  endif
+# endif
+#endif /* HAVE_LONG_LONG_INT */
+
+/*
+ * Macros for converting digits to letters and vice versa
+ */
+#define        to_digit(c)     ((c) - '0')
+#define is_digit(c)    ((unsigned int)to_digit(c) <= 9)
+#define        to_char(n)      ((n) + '0')
+
+/*
+ * Flags used during conversion.
+ */
+#define        ALT             0x001           /* alternate form */
+#define        HEXPREFIX       0x002           /* add 0x or 0X prefix */
+#define        LADJUST         0x004           /* left adjustment */
+#define        LONGDBL         0x008           /* long double; unimplemented */
+#define        LONGINT         0x010           /* long integer */
+#define        QUADINT         0x020           /* quad integer */
+#define        SHORTINT        0x040           /* short integer */
+#define        ZEROPAD         0x080           /* zero (as opposed to blank) pad */
+
+#define BUF            68
+
+/*
+ * Convert an unsigned long to ASCII for printf purposes, returning
+ * a pointer to the first character of the string representation.
+ * Octal numbers can be forced to have a leading zero; hex numbers
+ * use the given digits.
+ */
+static char *
+__ultoa(unsigned long val, char *endp, int base, int octzero, char *xdigs)
+{
+       char *cp = endp;
+       long sval;
+
+       /*
+        * Handle the three cases separately, in the hope of getting
+        * better/faster code.
+        */
+       switch (base) {
+       case 10:
+               if (val < 10) { /* many numbers are 1 digit */
+                       *--cp = to_char(val);
+                       return cp;
+               }
+               /*
+                * On many machines, unsigned arithmetic is harder than
+                * signed arithmetic, so we do at most one unsigned mod and
+                * divide; this is sufficient to reduce the range of
+                * the incoming value to where signed arithmetic works.
+                */
+               if (val > LONG_MAX) {
+                       *--cp = to_char(val % 10);
+                       sval = val / 10;
+               } else
+                       sval = val;
+               do {
+                       *--cp = to_char(sval % 10);
+                       sval /= 10;
+               } while (sval != 0);
+               break;
+
+       case 8:
+               do {
+                       *--cp = to_char(val & 7);
+                       val >>= 3;
+               } while (val);
+               if (octzero && *cp != '0')
+                       *--cp = '0';
+               break;
+
+       case 16:
+               do {
+                       *--cp = xdigs[val & 15];
+                       val >>= 4;
+               } while (val);
+               break;
+
+       default:                        /* oops */
+               abort();
+       }
+       return cp;
+}
+
+/* Identical to __ultoa, but for quads. */
+#ifdef HAVE_LONG_LONG_INT
+# if SIZEOF_LONG_INT == 8
+#  define __uqtoa(v, e, b, o, x) __ultoa((unsigned long)(v), (e), (b), (o), (x))
+# else
+static char *
+__uqtoa(unsigned long long val, char *endp, int base, int octzero, char *xdigs)
+{
+       char *cp = endp;
+       long long sval;
+
+       /* quick test for small values; __ultoa is typically much faster */
+       /* (perhaps instead we should run until small, then call __ultoa?) */
+       if (val <= (unsigned long long)ULONG_MAX)
+               return __ultoa((unsigned long)val, endp, base, octzero, xdigs);
+       switch (base) {
+       case 10:
+               if (val < 10) {
+                       *--cp = to_char(val % 10);
+                       return cp;
+               }
+               if (val > LLONG_MAX) {
+                       *--cp = to_char(val % 10);
+                       sval = val / 10;
+               } else
+                       sval = val;
+               do {
+                       *--cp = to_char(sval % 10);
+                       sval /= 10;
+               } while (sval != 0);
+               break;
+
+       case 8:
+               do {
+                       *--cp = to_char(val & 7);
+                       val >>= 3;
+               } while (val);
+               if (octzero && *cp != '0')
+                       *--cp = '0';
+               break;
+
+       case 16:
+               do {
+                       *--cp = xdigs[val & 15];
+                       val >>= 4;
+               } while (val);
+               break;
+
+       default:                        /* oops */
+               abort();
+       }
+       return cp;
+}
+# endif /* !SIZEOF_LONG_INT */
+#endif /* HAVE_LONG_LONG_INT */
+
+/*
+ * Actual printf innards.
+ */
+static int
+xxxprintf(char **strp, size_t strsize, int alloc, const char *fmt0, va_list ap)
+{
+       char *fmt;              /* format string */
+       int ch;                 /* character from fmt */
+       int n;                  /* handy integer (short term usage) */
+       char *cp;               /* handy char pointer (short term usage) */
+       int flags;              /* flags as above */
+       int ret;                /* return value accumulator */
+       int width;              /* width from format (%8d), or 0 */
+       int prec;               /* precision from format (%.3d), or -1 */
+       char sign;              /* sign prefix (' ', '+', '-', or \0) */
+       unsigned long ulval = 0; /* integer arguments %[diouxX] */
+#ifdef HAVE_LONG_LONG_INT
+       unsigned long long uqval = 0; /* %q (quad) integers */
+#endif
+       int base;               /* base for [diouxX] conversion */
+       int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
+       int fieldsz;            /* field size expanded by sign, etc */
+       int realsz;             /* field size expanded by dprec */
+       int size;               /* size of converted field or string */
+       char *xdigs = "";       /* digits for [xX] conversion */
+       char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
+       char ox[2];             /* space for 0x hex-prefix */
+       char *str;              /* pointer to string to fill */
+       char *estr;             /* pointer to last char in str */
+
+       /*
+        * Choose PADSIZE to trade efficiency vs. size.  If larger printf
+        * fields occur frequently, increase PADSIZE and make the initialisers
+        * below longer.
+        */
+#define        PADSIZE 16              /* pad chunk size */
+       static char blanks[PADSIZE] =
+        {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+       static char zeroes[PADSIZE] =
+        {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
+
+       /* Print chars to "str", (allocate as needed if alloc is set). */
+#define        PRINT(ptr, len) do { \
+       const char *p = ptr; \
+       const char *endp = ptr + len; \
+       while (p < endp && (str < estr || alloc)) { \
+               if (alloc && str >= estr) { \
+                       char *t; \
+                       strsize = (strsize << 1) + 1; \
+                       if (!(t = (char *)realloc(*strp, strsize))) { \
+                               free(str); \
+                               *strp = NULL; \
+                               ret = -1; \
+                               goto done; \
+                       } \
+                       str = t + (str - *strp); \
+                       estr = t + strsize - 1; \
+                       *strp = t; \
+               } \
+               *str++ = *p++; \
+       } \
+} while (0)
+
+       /* BEWARE, PAD uses `n'. */
+#define        PAD(plen, pstr) do { \
+       if ((n = (plen)) > 0) { \
+               while (n > PADSIZE) { \
+                       PRINT(pstr, PADSIZE); \
+                       n -= PADSIZE; \
+               } \
+               PRINT(pstr, n); \
+       } \
+} while (0)
+
+       /*
+        * To extend shorts properly, we need both signed and unsigned
+        * argument extraction methods.
+        */
+#define        SARG() \
+       (flags&LONGINT ? va_arg(ap, long) : \
+           flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
+           (long)va_arg(ap, int))
+#define        UARG() \
+       (flags&LONGINT ? va_arg(ap, unsigned long) : \
+           flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
+           (unsigned long)va_arg(ap, unsigned int))
+
+       fmt = (char *)fmt0;
+       ret = 0;
+
+       if (alloc) {
+               strsize = 128;
+               *strp = str = (char *)malloc(strsize);
+               if (str == NULL) {
+                       ret = -1;
+                       goto done;
+               }
+               estr = str + 127;
+       } else {
+               str = *strp;
+               if (strsize)
+                       estr = str + strsize - 1;
+               else
+                       estr = NULL;
+       }
+
+       /*
+        * Scan the format for conversions (`%' character).
+        */
+       for (;;) {
+               for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
+                       /* void */;
+               if ((n = fmt - cp) != 0) {
+                       PRINT(cp, n);
+                       ret += n;
+               }
+               if (ch == '\0')
+                       goto done;
+               fmt++;          /* skip over '%' */
+
+               flags = 0;
+               dprec = 0;
+               width = 0;
+               prec = -1;
+               sign = '\0';
+
+rflag:         ch = *fmt++;
+reswitch:      switch (ch) {
+               case ' ':
+                       /*
+                        * ``If the space and + flags both appear, the space
+                        * flag will be ignored.''
+                        *      -- ANSI X3J11
+                        */
+                       if (!sign)
+                               sign = ' ';
+                       goto rflag;
+               case '#':
+                       flags |= ALT;
+                       goto rflag;
+               case '*':
+                       /*
+                        * ``A negative field width argument is taken as a
+                        * - flag followed by a positive field width.''
+                        *      -- ANSI X3J11
+                        * They don't exclude field widths read from args.
+                        */
+                       if ((width = va_arg(ap, int)) >= 0)
+                               goto rflag;
+                       width = -width;
+                       /* FALLTHROUGH */
+               case '-':
+                       flags |= LADJUST;
+                       goto rflag;
+               case '+':
+                       sign = '+';
+                       goto rflag;
+               case '.':
+                       if ((ch = *fmt++) == '*') {
+                               n = va_arg(ap, int);
+                               prec = n < 0 ? -1 : n;
+                               goto rflag;
+                       }
+                       n = 0;
+                       while (is_digit(ch)) {
+                               n = 10 * n + to_digit(ch);
+                               ch = *fmt++;
+                       }
+                       prec = n < 0 ? -1 : n;
+                       goto reswitch;
+               case '0':
+                       /*
+                        * ``Note that 0 is taken as a flag, not as the
+                        * beginning of a field width.''
+                        *      -- ANSI X3J11
+                        */
+                       flags |= ZEROPAD;
+                       goto rflag;
+               case '1': case '2': case '3': case '4':
+               case '5': case '6': case '7': case '8': case '9':
+                       n = 0;
+                       do {
+                               n = 10 * n + to_digit(ch);
+                               ch = *fmt++;
+                       } while (is_digit(ch));
+                       width = n;
+                       goto reswitch;
+               case 'h':
+                       flags |= SHORTINT;
+                       goto rflag;
+               case 'l':
+                       flags |= LONGINT;
+                       goto rflag;
+#ifdef HAVE_LONG_LONG_INT
+               case 'q':
+                       flags |= QUADINT;
+                       goto rflag;
+#endif /* HAVE_LONG_LONG_INT */
+               case 'c':
+                       *(cp = buf) = va_arg(ap, int);
+                       size = 1;
+                       sign = '\0';
+                       break;
+               case 'D':
+                       flags |= LONGINT;
+                       /*FALLTHROUGH*/
+               case 'd':
+               case 'i':
+#ifdef HAVE_LONG_LONG_INT
+                       if (flags & QUADINT) {
+                               uqval = va_arg(ap, long long);
+                               if ((long long)uqval < 0) {
+                                       uqval = -uqval;
+                                       sign = '-';
+                               }
+                       }
+                       else
+#endif /* HAVE_LONG_LONG_INT */
+                       {
+                               ulval = SARG();
+                               if ((long)ulval < 0) {
+                                       ulval = -ulval;
+                                       sign = '-';
+                               }
+                       }
+                       base = 10;
+                       goto number;
+               case 'n':
+#ifdef HAVE_LONG_LONG_INT
+                       if (flags & QUADINT)
+                               *va_arg(ap, long long *) = ret;
+                       else
+#endif /* HAVE_LONG_LONG_INT */
+                       if (flags & LONGINT)
+                               *va_arg(ap, long *) = ret;
+                       else if (flags & SHORTINT)
+                               *va_arg(ap, short *) = ret;
+                       else
+                               *va_arg(ap, int *) = ret;
+                       continue;       /* no output */
+               case 'O':
+                       flags |= LONGINT;
+                       /*FALLTHROUGH*/
+               case 'o':
+#ifdef HAVE_LONG_LONG_INT
+                       if (flags & QUADINT)
+                               uqval = va_arg(ap, unsigned long long);
+                       else
+#endif /* HAVE_LONG_LONG_INT */
+                               ulval = UARG();
+                       base = 8;
+                       goto nosign;
+               case 'p':
+                       /*
+                        * ``The argument shall be a pointer to void.  The
+                        * value of the pointer is converted to a sequence
+                        * of printable characters, in an implementation-
+                        * defined manner.''
+                        *      -- ANSI X3J11
+                        */
+                       ulval = (unsigned long)va_arg(ap, void *);
+                       base = 16;
+                       xdigs = "0123456789abcdef";
+                       flags = (flags & ~QUADINT) | HEXPREFIX;
+                       ch = 'x';
+                       goto nosign;
+               case 's':
+                       if ((cp = va_arg(ap, char *)) == NULL)
+                               cp = "(null)";
+                       if (prec >= 0) {
+                               /*
+                                * can't use strlen; can only look for the
+                                * NUL in the first `prec' characters, and
+                                * strlen() will go further.
+                                */
+                               char *p = memchr(cp, 0, prec);
+
+                               if (p != NULL) {
+                                       size = p - cp;
+                                       if (size > prec)
+                                               size = prec;
+                               } else
+                                       size = prec;
+                       } else
+                               size = strlen(cp);
+                       sign = '\0';
+                       break;
+               case 'U':
+                       flags |= LONGINT;
+                       /*FALLTHROUGH*/
+               case 'u':
+#ifdef HAVE_LONG_LONG_INT
+                       if (flags & QUADINT)
+                               uqval = va_arg(ap, unsigned long long);
+                       else
+#endif /* HAVE_LONG_LONG_INT */
+                               ulval = UARG();
+                       base = 10;
+                       goto nosign;
+               case 'X':
+                       xdigs = "0123456789ABCDEF";
+                       goto hex;
+               case 'x':
+                       xdigs = "0123456789abcdef";
+hex:
+#ifdef HAVE_LONG_LONG_INT
+                       if (flags & QUADINT)
+                               uqval = va_arg(ap, unsigned long long);
+                       else
+#endif /* HAVE_LONG_LONG_INT */
+                               ulval = UARG();
+                       base = 16;
+                       /* leading 0x/X only if non-zero */
+                       if (flags & ALT &&
+#ifdef HAVE_LONG_LONG_INT
+                           (flags & QUADINT ? uqval != 0 : ulval != 0))
+#else
+                           ulval != 0)
+#endif /* HAVE_LONG_LONG_INT */
+                               flags |= HEXPREFIX;
+
+                       /* unsigned conversions */
+nosign:                        sign = '\0';
+                       /*
+                        * ``... diouXx conversions ... if a precision is
+                        * specified, the 0 flag will be ignored.''
+                        *      -- ANSI X3J11
+                        */
+number:                        if ((dprec = prec) >= 0)
+                               flags &= ~ZEROPAD;
+
+                       /*
+                        * ``The result of converting a zero value with an
+                        * explicit precision of zero is no characters.''
+                        *      -- ANSI X3J11
+                        */
+                       cp = buf + BUF;
+#ifdef HAVE_LONG_LONG_INT
+                       if (flags & QUADINT) {
+                               if (uqval != 0 || prec != 0)
+                                       cp = __uqtoa(uqval, cp, base,
+                                           flags & ALT, xdigs);
+                       }
+                       else
+#endif /* HAVE_LONG_LONG_INT */
+                       {
+                               if (ulval != 0 || prec != 0)
+                                       cp = __ultoa(ulval, cp, base,
+                                           flags & ALT, xdigs);
+                       }
+                       size = buf + BUF - cp;
+                       break;
+               default:        /* "%?" prints ?, unless ? is NUL */
+                       if (ch == '\0')
+                               goto done;
+                       /* pretend it was %c with argument ch */
+                       cp = buf;
+                       *cp = ch;
+                       size = 1;
+                       sign = '\0';
+                       break;
+               }
+
+               /*
+                * All reasonable formats wind up here.  At this point, `cp'
+                * points to a string which (if not flags&LADJUST) should be
+                * padded out to `width' places.  If flags&ZEROPAD, it should
+                * first be prefixed by any sign or other prefix; otherwise,
+                * it should be blank padded before the prefix is emitted.
+                * After any left-hand padding and prefixing, emit zeroes
+                * required by a decimal [diouxX] precision, then print the
+                * string proper, then emit zeroes required by any leftover
+                * floating precision; finally, if LADJUST, pad with blanks.
+                *
+                * Compute actual size, so we know how much to pad.
+                * fieldsz excludes decimal prec; realsz includes it.
+                */
+               fieldsz = size;
+               if (sign)
+                       fieldsz++;
+               else if (flags & HEXPREFIX)
+                       fieldsz += 2;
+               realsz = dprec > fieldsz ? dprec : fieldsz;
+
+               /* right-adjusting blank padding */
+               if ((flags & (LADJUST|ZEROPAD)) == 0)
+                       PAD(width - realsz, blanks);
+
+               /* prefix */
+               if (sign) {
+                       PRINT(&sign, 1);
+               } else if (flags & HEXPREFIX) {
+                       ox[0] = '0';
+                       ox[1] = ch;
+                       PRINT(ox, 2);
+               }
+
+               /* right-adjusting zero padding */
+               if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
+                       PAD(width - realsz, zeroes);
+
+               /* leading zeroes from decimal precision */
+               PAD(dprec - fieldsz, zeroes);
+
+               /* the string or number proper */
+               PRINT(cp, size);
+
+               /* left-adjusting padding (always blank) */
+               if (flags & LADJUST)
+                       PAD(width - realsz, blanks);
+
+               /* finally, adjust ret */
+               ret += width > realsz ? width : realsz;
+       }
+done:
+       if (strsize)
+               *str = '\0';
+       return ret;
+       /* NOTREACHED */
+}
+
+#ifndef HAVE_VSNPRINTF
+int
+vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
+{
+
+       return xxxprintf(&str, n, 0, fmt, ap);
+}
+#endif /* HAVE_VSNPRINTF */
+
+#ifndef HAVE_SNPRINTF
+int
+snprintf(char *str, size_t n, char const *fmt, ...)
+{
+       int ret;
+       va_list ap;
+
+       va_start(ap, fmt);
+       ret = xxxprintf(&str, n, 0, fmt, ap);
+       va_end(ap);
+       return ret;
+}
+#endif /* HAVE_SNPRINTF */
+
+#ifndef HAVE_VASPRINTF
+int
+vasprintf(char **str, const char *fmt, va_list ap)
+{
+
+       return xxxprintf(str, 0, 1, fmt, ap);
+}
+#endif /* HAVE_VASPRINTF */
+
+#ifndef HAVE_ASPRINTF
+int
+asprintf(char **str, char const *fmt, ...)
+{
+       int ret;
+       va_list ap;
+
+       va_start(ap, fmt);
+       ret = xxxprintf(str, 0, 1, fmt, ap);
+       va_end(ap);
+       return ret;
+}
+#endif /* HAVE_ASPRINTF */
diff --git a/compat/strlcat.c b/compat/strlcat.c
new file mode 100644 (file)
index 0000000..57e3ca5
--- /dev/null
@@ -0,0 +1,60 @@
+/*     $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $     */
+
+/*
+ * Copyright (c) 1998, 2003-2005, 2010-2011
+ *     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 <string.h>
+
+#include "missing.h"
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+       char *d = dst;
+       const char *s = src;
+       size_t n = siz;
+       size_t dlen;
+
+       /* Find the end of dst and adjust bytes left but don't go past end */
+       while (n-- != 0 && *d != '\0')
+               d++;
+       dlen = d - dst;
+       n = siz - dlen;
+
+       if (n == 0)
+               return dlen + strlen(s);
+       while (*s != '\0') {
+               if (n != 1) {
+                       *d++ = *s;
+                       n--;
+               }
+               s++;
+       }
+       *d = '\0';
+
+       return dlen + (s - src);        /* count does not include NUL */
+}
diff --git a/compat/strlcpy.c b/compat/strlcpy.c
new file mode 100644 (file)
index 0000000..89fb01b
--- /dev/null
@@ -0,0 +1,55 @@
+/*     $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $     */
+
+/*
+ * Copyright (c) 1998, 2003-2005, 2010-2011
+ *     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 "missing.h"
+
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+       char *d = dst;
+       const char *s = src;
+       size_t n = siz;
+
+       /* Copy as many bytes as will fit */
+       if (n != 0 && --n != 0) {
+               do {
+                       if ((*d++ = *s++) == 0)
+                               break;
+               } while (--n != 0);
+       }
+
+       /* Not enough room in dst, add NUL and traverse rest of src */
+       if (n == 0) {
+               if (siz != 0)
+                       *d = '\0';              /* NUL-terminate dst */
+               while (*s++)
+                       ;
+       }
+
+       return s - src - 1;     /* count does not include NUL */
+}
diff --git a/compat/strsignal.c b/compat/strsignal.c
new file mode 100644 (file)
index 0000000..1e5d791
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2009-2011 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 <stdio.h>
+#include <signal.h>
+
+#include "missing.h"
+
+#if defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST == 1
+# define my_sys_siglist        sys_siglist
+#elif defined(HAVE_DECL__SYS_SIGLIST) && HAVE_DECL__SYS_SIGLIST == 1
+# define my_sys_siglist        _sys_siglist
+#elif defined(HAVE_DECL___SYS_SIGLIST) && HAVE_DECL___SYS_SIGLIST == 1
+# define my_sys_siglist        __sys_siglist
+#else
+extern const char *const my_sys_siglist[NSIG];
+#endif
+
+/*
+ * Get signal description string
+ */
+char *
+strsignal(int signo)
+{
+    if (signo > 0 && signo < NSIG)
+       return (char *)my_sys_siglist[signo];
+    return "Unknown signal";
+}
diff --git a/compat/timespec.h b/compat/timespec.h
new file mode 100644 (file)
index 0000000..4c9dedc
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2005, 2010 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.
+ */
+
+#ifndef _SUDO_TIMESPEC_H
+#define _SUDO_TIMESPEC_H
+
+struct timespec {
+    time_t     tv_sec;
+    long       tv_nsec;
+};
+
+#endif /* _SUDO_TIMESPEC_H */
diff --git a/compat/unsetenv.c b/compat/unsetenv.c
new file mode 100644 (file)
index 0000000..f7cfaa7
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2010 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 <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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <errno.h>
+
+#include "missing.h"
+
+extern char **environ; /* global environment */
+
+#ifdef UNSETENV_VOID
+void
+#else
+int
+#endif
+unsetenv(const char *var)
+{
+    char **ep = environ;
+    size_t len;
+
+    if (var == NULL || *var == '\0' || strchr(var, '=') != NULL) {
+       errno = EINVAL;
+#ifdef UNSETENV_VOID
+       return;
+#else
+       return -1;
+#endif
+    }
+
+    len = strlen(var);
+    while (*ep != NULL) {
+       if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
+           /* Found it; shift remainder + NULL over by one. */
+           char **cur = ep;
+           while ((*cur = *(cur + 1)) != NULL)
+               cur++;
+           /* Keep going, could be multiple instances of the var. */
+       } else {
+           ep++;
+       }
+    }
+#ifndef UNSETENV_VOID
+    return 0;
+#endif
+}
diff --git a/compat/utime.h b/compat/utime.h
new file mode 100644 (file)
index 0000000..0a1eb86
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2010
+ *     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.
+ */
+
+#ifndef        _UTIME_H
+#define        _UTIME_H
+
+struct utimbuf {
+       time_t  actime;         /* access time */
+       time_t  modtime;        /* mod time */
+};
+
+int utime(const char *, const struct utimbuf *);
+
+#endif /* _UTIME_H */
diff --git a/compat/utimes.c b/compat/utimes.c
new file mode 100644 (file)
index 0000000..455ecd2
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2004-2005, 2007, 2010-2011
+ *     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/time.h>
+#include <stdio.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+
+#ifdef HAVE_UTIME_H
+# include <utime.h>
+#else
+# include "compat/utime.h"
+#endif
+
+#include "missing.h"
+
+#ifndef HAVE_UTIMES
+/*
+ * Emulate utimes() via utime()
+ */
+int
+utimes(const char *file, const struct timeval *times)
+{
+    if (times != NULL) {
+       struct utimbuf utb;
+
+       utb.actime = (time_t)(times[0].tv_sec + times[0].tv_usec / 1000000);
+       utb.modtime = (time_t)(times[1].tv_sec + times[1].tv_usec / 1000000);
+       return utime(file, &utb);
+    } else
+       return utime(file, NULL);
+}
+#endif /* !HAVE_UTIMES */
+
+#ifdef HAVE_FUTIME
+/*
+ * Emulate futimes() via futime()
+ */
+int
+futimes(int fd, const struct timeval *times)
+{
+    if (times != NULL) {
+       struct utimbuf utb;
+
+       utb.actime = (time_t)(times[0].tv_sec + times[0].tv_usec / 1000000);
+       utb.modtime = (time_t)(times[1].tv_sec + times[1].tv_usec / 1000000);
+       return futime(fd, &utb);
+    } else
+       return futime(fd, NULL);
+}
+#endif /* HAVE_FUTIME */
index a4b000db0a3e1f9fbd4db5b12d8d2f22e1cc1811..0f7384dd3b11330cc5dc1d777dbb9e8b7f8110d0 100644 (file)
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #undef HAVE_DLFCN_H
 
+/* Define to 1 if you have the `dlopen' function. */
+#undef HAVE_DLOPEN
+
 /* Define to 1 if your glob.h defines the GLOB_BRACE and GLOB_TILDE flags. */
 #undef HAVE_EXTENDED_GLOB
 
    passwords) */
 #undef HAVE_GETPWANAM
 
+/* Define to 1 if you have the `getresuid' function. */
+#undef HAVE_GETRESUID
+
 /* Define to 1 if you have the `getspnam' function (SVR4-style shadow
    passwords) */
 #undef HAVE_GETSPNAM
    passwords) */
 #undef HAVE_GETSPWUID
 
-/* Define to 1 if you have the `gettimeofday' function. */
-#undef HAVE_GETTIMEOFDAY
+/* Define to 1 if you have the `getttyent' function. */
+#undef HAVE_GETTTYENT
 
 /* Define to 1 if you have the `getuserattr' function. */
 #undef HAVE_GETUSERATTR
 /* 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 `dl' library (-ldl). */
-#undef HAVE_LIBDL
-
 /* Define to 1 to enable Linux audit support. */
 #undef HAVE_LINUX_AUDIT
 
 /* Define to 1 if you have the `mbr_check_membership' function. */
 #undef HAVE_MBR_CHECK_MEMBERSHIP
 
-/* Define to 1 if you have the `memchr' function. */
-#undef HAVE_MEMCHR
-
-/* Define to 1 if you have the `memcpy' function. */
-#undef HAVE_MEMCPY
-
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
 /* Define to 1 if you have the `memrchr' function. */
 #undef HAVE_MEMRCHR
 
-/* Define to 1 if you have the `memset' function. */
-#undef HAVE_MEMSET
+/* Define to 1 if you have the `mkdtemp' function. */
+#undef HAVE_MKDTEMP
 
 /* Define to 1 if you have the `mkstemps' function. */
 #undef HAVE_MKSTEMPS
 /* Define to 1 if you have the `posix_openpt' function. */
 #undef HAVE_POSIX_OPENPT
 
+/* Define to 1 if you have the `priv_set' function. */
+#undef HAVE_PRIV_SET
+
 /* Define to 1 if you have the <project.h> header file. */
 #undef HAVE_PROJECT_H
 
 /* Define to 1 if you have the `revoke' function. */
 #undef HAVE_REVOKE
 
+/* Define to 1 if the skeychallenge() function is RFC1938-compliant and takes
+   4 arguments */
+#undef HAVE_RFC1938_SKEYCHALLENGE
+
 /* Define to 1 if you have the <sasl.h> header file. */
 #undef HAVE_SASL_H
 
 /* Define to 1 if you have the `setreuid' function. */
 #undef HAVE_SETREUID
 
-/* Define to 1 if you have the `setrlimit' function. */
-#undef HAVE_SETRLIMIT
-
 /* Define to 1 if you have the `setrlimit64' function. */
 #undef HAVE_SETRLIMIT64
 
-/* Define to 1 if you have the `setsid' function. */
-#undef HAVE_SETSID
-
 /* Define to 1 if you have the `set_auth_parameters' function. */
 #undef HAVE_SET_AUTH_PARAMETERS
 
+/* Define to 1 if you have the `shl_load' function. */
+#undef HAVE_SHL_LOAD
+
 /* Define to 1 if you have the `sia_ses_init' function. */
 #undef HAVE_SIA_SES_INIT
 
-/* Define to 1 if you have the `sigaction' function. */
-#undef HAVE_SIGACTION
-
 /* Define to 1 if <signal.h> has the sigaction_t typedef. */
 #undef HAVE_SIGACTION_T
 
 /* Define to 1 if you have the <stdlib.h> header file. */
 #undef HAVE_STDLIB_H
 
-/* Define to 1 if you have the `strcasecmp' function. */
-#undef HAVE_STRCASECMP
-
-/* Define to 1 if you have the `strchr' function. */
-#undef HAVE_STRCHR
-
-/* Define to 1 if you have the `strerror' function. */
-#undef HAVE_STRERROR
-
 /* Define to 1 if you have the `strftime' function. */
 #undef HAVE_STRFTIME
 
 /* Define to 1 if the system has the type `struct in6_addr'. */
 #undef HAVE_STRUCT_IN6_ADDR
 
+/* Define to 1 if `ut_exit' is a member of `struct utmpx'. */
+#undef HAVE_STRUCT_UTMPX_UT_EXIT
+
+/* Define to 1 if `ut_exit.e_termination' is a member of `struct utmpx'. */
+#undef HAVE_STRUCT_UTMPX_UT_EXIT_E_TERMINATION
+
+/* Define to 1 if `ut_exit.__e_termination' is a member of `struct utmpx'. */
+#undef HAVE_STRUCT_UTMPX_UT_EXIT___E_TERMINATION
+
+/* Define to 1 if `ut_id' is a member of `struct utmpx'. */
+#undef HAVE_STRUCT_UTMPX_UT_ID
+
+/* Define to 1 if `ut_pid' is a member of `struct utmpx'. */
+#undef HAVE_STRUCT_UTMPX_UT_PID
+
+/* Define to 1 if `ut_tv' is a member of `struct utmpx'. */
+#undef HAVE_STRUCT_UTMPX_UT_TV
+
+/* Define to 1 if `ut_type' is a member of `struct utmpx'. */
+#undef HAVE_STRUCT_UTMPX_UT_TYPE
+
+/* Define to 1 if `ut_exit' is a member of `struct utmp'. */
+#undef HAVE_STRUCT_UTMP_UT_EXIT
+
+/* Define to 1 if `ut_exit.e_termination' is a member of `struct utmp'. */
+#undef HAVE_STRUCT_UTMP_UT_EXIT_E_TERMINATION
+
+/* Define to 1 if `ut_exit.__e_termination' is a member of `struct utmp'. */
+#undef HAVE_STRUCT_UTMP_UT_EXIT___E_TERMINATION
+
+/* Define to 1 if `ut_id' is a member of `struct utmp'. */
+#undef HAVE_STRUCT_UTMP_UT_ID
+
+/* Define to 1 if `ut_pid' is a member of `struct utmp'. */
+#undef HAVE_STRUCT_UTMP_UT_PID
+
+/* Define to 1 if `ut_tv' is a member of `struct utmp'. */
+#undef HAVE_STRUCT_UTMP_UT_TV
+
+/* Define to 1 if `ut_type' is a member of `struct utmp'. */
+#undef HAVE_STRUCT_UTMP_UT_TYPE
+
+/* Define to 1 if `ut_user' is a member of `struct utmp'. */
+#undef HAVE_STRUCT_UTMP_UT_USER
+
 /* Define to 1 if your struct stat has an st_mtim member */
 #undef HAVE_ST_MTIM
 
 /* Define to 1 if you have the <sys/types.h> header file. */
 #undef HAVE_SYS_TYPES_H
 
-/* Define to 1 if you have the `tcsetpgrp' function. */
-#undef HAVE_TCSETPGRP
-
-/* Define to 1 if you have the <termios.h> header file and the `tcgetattr'
-   function. */
-#undef HAVE_TERMIOS_H
-
-/* Define to 1 if you have the <termio.h> header file. */
-#undef HAVE_TERMIO_H
-
 /* Define to 1 if you have struct timespec in sys/time.h */
 #undef HAVE_TIMESPEC
 
+/* Define to 1 if you have the `ttyslot' function. */
+#undef HAVE_TTYSLOT
+
 /* Define to 1 if you have the `tzset' function. */
 #undef HAVE_TZSET
 
 /* Define to 1 if you have the <utime.h> header file. */
 #undef HAVE_UTIME_H
 
+/* Define to 1 if you have the <utmpx.h> header file. */
+#undef HAVE_UTMPX_H
+
 /* Define to 1 if you have the `vasprintf' function. */
 #undef HAVE_VASPRINTF
 
 /* Define to 1 if you have the `vsnprintf' function. */
 #undef HAVE_VSNPRINTF
 
-/* Define to 1 if you have the `wait3' function. */
-#undef HAVE_WAIT3
-
-/* Define to 1 if you have the `waitpid' function. */
-#undef HAVE_WAITPID
-
 /* Define to 1 if you have the <zlib.h> header file. */
 #undef HAVE_ZLIB_H
 
 /* The message given when a bad password is entered. */
 #undef INCORRECT_PASSWORD
 
-/* The name of libvas.so */
-#undef LIBVAS_SO
-
 /* The syslog facility sudo will use. */
 #undef LOGFAC
 
 /* The syslog priority sudo will use for successful attempts. */
 #undef PRI_SUCCESS
 
-/* Define to 1 if the `putenv' has a const argument. */
-#undef PUTENV_CONST
-
-/* Define as the return type of signal handlers (`int' or `void'). */
-#undef RETSIGTYPE
-
 /* The user sudo should run commands as by default. */
 #undef RUNAS_DEFAULT
 
 /* Define to 1 to send mail when the user is not in the sudoers file. */
 #undef SEND_MAIL_WHEN_NO_USER
 
-/* Define to 1 if the `setpgrp' function takes no argument. */
-#undef SETPGRP_VOID
-
 /* Define to 1 if you want sudo to start a shell if given no arguments. */
 #undef SHELL_IF_NO_ARGS
 
 /* Define to 1 if the code in interfaces.c does not compile for you. */
 #undef STUB_LOAD_INTERFACES
 
+/* The name of the sudoers plugin, including extension. */
+#undef SUDOERS_PLUGIN
+
 /* The umask that the sudo-run prog should use. */
 #undef SUDO_UMASK
 
 /* Define to 1 if you use GNU stow packaging. */
 #undef USE_STOW
 
-/* Define to 1 if using a non-Unix group lookup implementation. */
-#undef USING_NONUNIX_GROUPS
-
 /* Define to avoid using the passwd/shadow file for authentication. */
 #undef WITHOUT_PASSWD
 
 # endif /* HAVE_ST_MTIMESPEC */
 #endif /* HAVE_ST_MTIM */
 
-/*
- * Emulate a subset of waitpid() if we don't have it.
- */
-#ifdef HAVE_WAITPID
-# define sudo_waitpid(p, s, o) waitpid(p, s, o)
-#else
-# ifdef HAVE_WAIT3
-#  define sudo_waitpid(p, s, o)        wait3(s, o, NULL)
-# endif
-#endif
-
 /* GNU stow needs /etc/sudoers to be a symlink. */
 #ifdef USE_STOW
 # define stat_sudoers  stat
index 4ac04df652acd93f7a370c99aeae1d806a09851e..cad0d5c70ee6c127a071d8a281e168652939850e 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.65 for sudo 1.7.6p1.
+# Generated by GNU Autoconf 2.65 for sudo 1.8.1p2.
 #
 # Report bugs to <http://www.sudo.ws/bugs/>.
 #
@@ -173,6 +173,14 @@ test x\$exitcode = x0 || exit 1"
   as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
   eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
   test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+
+  test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+      || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1
 test \$(( 1 + 1 )) = 2 || exit 1"
   if (eval "$as_required") 2>/dev/null; then :
   as_have_required=yes
@@ -528,155 +536,8 @@ as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
 # Sed expression to map a string onto a valid variable name.
 as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
 
-
-
-# Check that we are running under the correct shell.
 SHELL=${CONFIG_SHELL-/bin/sh}
 
-case X$lt_ECHO in
-X*--fallback-echo)
-  # Remove one level of quotation (which was required for Make).
-  ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','`
-  ;;
-esac
-
-ECHO=${lt_ECHO-echo}
-if test "X$1" = X--no-reexec; then
-  # Discard the --no-reexec flag, and continue.
-  shift
-elif test "X$1" = X--fallback-echo; then
-  # Avoid inline document here, it may be left over
-  :
-elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then
-  # Yippee, $ECHO works!
-  :
-else
-  # Restart under the correct shell.
-  exec $SHELL "$0" --no-reexec ${1+"$@"}
-fi
-
-if test "X$1" = X--fallback-echo; then
-  # used as fallback echo
-  shift
-  cat <<_LT_EOF
-$*
-_LT_EOF
-  exit 0
-fi
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-if test -z "$lt_ECHO"; then
-  if test "X${echo_test_string+set}" != Xset; then
-    # find a string as large as possible, as long as the shell can cope with it
-    for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
-      # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
-      if { echo_test_string=`eval $cmd`; } 2>/dev/null &&
-        { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null
-      then
-        break
-      fi
-    done
-  fi
-
-  if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
-     echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
-     test "X$echo_testing_string" = "X$echo_test_string"; then
-    :
-  else
-    # The Solaris, AIX, and Digital Unix default echo programs unquote
-    # backslashes.  This makes it impossible to quote backslashes using
-    #   echo "$something" | sed 's/\\/\\\\/g'
-    #
-    # So, first we look for a working echo in the user's PATH.
-
-    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
-    for dir in $PATH /usr/ucb; do
-      IFS="$lt_save_ifs"
-      if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
-         test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
-         echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
-         test "X$echo_testing_string" = "X$echo_test_string"; then
-        ECHO="$dir/echo"
-        break
-      fi
-    done
-    IFS="$lt_save_ifs"
-
-    if test "X$ECHO" = Xecho; then
-      # We didn't find a better echo, so look for alternatives.
-      if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' &&
-         echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` &&
-         test "X$echo_testing_string" = "X$echo_test_string"; then
-        # This shell has a builtin print -r that does the trick.
-        ECHO='print -r'
-      elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } &&
-          test "X$CONFIG_SHELL" != X/bin/ksh; then
-        # If we have ksh, try running configure again with it.
-        ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
-        export ORIGINAL_CONFIG_SHELL
-        CONFIG_SHELL=/bin/ksh
-        export CONFIG_SHELL
-        exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"}
-      else
-        # Try using printf.
-        ECHO='printf %s\n'
-        if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
-          echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
-          test "X$echo_testing_string" = "X$echo_test_string"; then
-         # Cool, printf works
-         :
-        elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
-            test "X$echo_testing_string" = 'X\t' &&
-            echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
-            test "X$echo_testing_string" = "X$echo_test_string"; then
-         CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
-         export CONFIG_SHELL
-         SHELL="$CONFIG_SHELL"
-         export SHELL
-         ECHO="$CONFIG_SHELL $0 --fallback-echo"
-        elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
-            test "X$echo_testing_string" = 'X\t' &&
-            echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
-            test "X$echo_testing_string" = "X$echo_test_string"; then
-         ECHO="$CONFIG_SHELL $0 --fallback-echo"
-        else
-         # maybe with a smaller string...
-         prev=:
-
-         for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
-           if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null
-           then
-             break
-           fi
-           prev="$cmd"
-         done
-
-         if test "$prev" != 'sed 50q "$0"'; then
-           echo_test_string=`eval $prev`
-           export echo_test_string
-           exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"}
-         else
-           # Oops.  We lost completely, so just stick with echo.
-           ECHO=echo
-         fi
-        fi
-      fi
-    fi
-  fi
-fi
-
-# Copy echo and quote the copy suitably for passing to libtool from
-# the Makefile, instead of quoting the original, which is used later.
-lt_ECHO=$ECHO
-if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then
-   lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo"
-fi
-
-
-
 
 test -n "$DJDIR" || exec 7<&0 </dev/null
 exec 6>&1
@@ -701,11 +562,12 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='sudo'
 PACKAGE_TARNAME='sudo'
-PACKAGE_VERSION='1.7.6p1'
-PACKAGE_STRING='sudo 1.7.6p1'
+PACKAGE_VERSION='1.8.1p2'
+PACKAGE_STRING='sudo 1.8.1p2'
 PACKAGE_BUGREPORT='http://www.sudo.ws/bugs/'
 PACKAGE_URL=''
 
+ac_config_libobj_dir=compat
 # Factoring default headers for most tests.
 ac_includes_default="\
 #include <stdio.h>
@@ -756,7 +618,7 @@ OTOOL
 LIPO
 NMEDIT
 DSYMUTIL
-lt_ECHO
+AWK
 STRIP
 OBJDUMP
 LN_S
@@ -818,17 +680,22 @@ password_timeout
 timeout
 timedir
 iolog_dir
+LT_STATIC
+LIBDL
 CONFIGURE_ARGS
-ZLIB_DEP
+ac_config_libobj_dir
+LIBTOOL_DEPS
+ZLIB_SRC
 ZLIB
 LOGINCAP_USAGE
-REPLAY
 LDAP
 SELINUX_USAGE
 BSDAUTH_USAGE
 DONT_LEAK_PATH_INFO
 INSTALL_NOEXEC
 noexec_file
+SOEXT
+PLUGINDIR
 NOEXECDIR
 NOEXECFILE
 mansrcdir
@@ -847,12 +714,16 @@ MANTYPE
 AUTH_OBJS
 OSDEFS
 GETGROUPS_LIB
+REPLAY_LIBS
 AFS_LIBS
 NET_LIBS
+SUDOERS_LIBS
 SUDO_LIBS
 SUDO_OBJS
-SUDO_LDFLAGS
+SUDOERS_OBJS
 COMMON_OBJS
+LTLDFLAGS
+SUDOERS_LDFLAGS
 LDFLAGS
 CPPFLAGS
 PROGS
@@ -975,8 +846,7 @@ with_secure_path
 with_interfaces
 with_stow
 with_askpass
-with_libvas
-with_libvas_rpath
+with_plugindir
 enable_authentication
 enable_root_mailer
 enable_setreuid
@@ -988,6 +858,7 @@ enable_noargs_shell
 enable_shell_sets_home
 enable_path_info
 enable_env_debug
+enable_zlib
 enable_env_reset
 enable_warnings
 enable_admin_flag
@@ -1005,7 +876,6 @@ enable_sia
 enable_largefile
 with_pam_login
 enable_pam_session
-enable_zlib
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1559,7 +1429,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.7.6p1 to adapt to many kinds of systems.
+\`configure' configures sudo 1.8.1p2 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1624,7 +1494,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of sudo 1.7.6p1:";;
+     short | recursive ) echo "Configuration of sudo 1.8.1p2:";;
    esac
   cat <<\_ACEOF
 
@@ -1645,6 +1515,7 @@ Optional Features:
                           Set $HOME to target user in shell mode
   --disable-path-info     Print 'command not allowed' not 'command not found'
   --enable-env-debug      Whether to enable environment debugging.
+  --enable-zlib[=PATH]    Whether to enable or disable zlib
   --enable-env-reset      Whether to enable environment resetting by default.
   --enable-warnings       Whether to enable compiler warnings
   --enable-admin-flag     Whether to create a Ubuntu-style admin flag file
@@ -1658,7 +1529,6 @@ Optional Features:
   --disable-sia           Disable SIA on Digital UNIX
   --disable-largefile     omit support for large files
   --disable-pam-session   Disable PAM session support
-  --enable-zlib[=PATH]    Whether to enable or disable zlib
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1746,10 +1616,7 @@ Optional Packages:
   --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-libvas=NAME      Name of the libvas shared library
-                          (default=libvas.so)
-  --with-libvas-rpath=PATH
-                          Path to look for libvas in [default=/opt/quest/lib]
+  --with-plugindir        set directory to load plugins from
   --with-selinux          enable SELinux support
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
@@ -1839,7 +1706,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-sudo configure 1.7.6p1
+sudo configure 1.8.1p2
 generated by GNU Autoconf 2.65
 
 Copyright (C) 2009 Free Software Foundation, Inc.
@@ -2538,7 +2405,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.7.6p1, which was
+It was created by sudo $as_me 1.8.1p2, which was
 generated by GNU Autoconf 2.65.  Invocation command line was
 
   $ $0 $@
@@ -2885,7 +2752,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
-ac_config_headers="$ac_config_headers config.h pathnames.h zlib/zconf.h"
+ac_config_headers="$ac_config_headers config.h pathnames.h"
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: Configuring Sudo version $PACKAGE_VERSION" >&5
 $as_echo "$as_me: Configuring Sudo version $PACKAGE_VERSION" >&6;}
@@ -2955,6 +2822,15 @@ $as_echo "$as_me: Configuring Sudo version $PACKAGE_VERSION" >&6;}
 
 
 
+
+
+
+
+
+
+
+
+
 
 
 
@@ -3009,7 +2885,7 @@ secure_path="not set"
 #
 INSTALL_NOEXEC=
 devdir='$(srcdir)'
-PROGS="sudo visudo"
+PROGS="sudo"
 : ${MANTYPE='man'}
 : ${mansrcdir='.'}
 : ${SUDOERS_MODE='0440'}
@@ -3017,12 +2893,11 @@ PROGS="sudo visudo"
 : ${SUDOERS_GID='0'}
 DEV="#"
 LDAP="#"
-REPLAY="#"
 BAMAN=0
 LCMAN=0
 SEMAN=0
 ZLIB=
-ZLIB_DEP=
+ZLIB_SRC=
 AUTH_OBJS=
 AUTH_REG=
 AUTH_EXCL=
@@ -3034,11 +2909,12 @@ shadow_defs=
 shadow_funcs=
 shadow_libs=
 shadow_libs_optional=
-
 CONFIGURE_ARGS="$@"
 
 
 
+
+
 # Check whether --with-otp-only was given.
 if test "${with_otp_only+set}" = set; then :
   withval=$with_otp_only; case $with_otp_only in
@@ -3069,7 +2945,6 @@ if test "${with_devel+set}" = set; then :
   withval=$with_devel; case $with_devel in
     yes)       { $as_echo "$as_me:${as_lineno-$LINENO}: Setting up for development: -Wall, flex, yacc" >&5
 $as_echo "$as_me: Setting up for development: -Wall, flex, yacc" >&6;}
-               PROGS="${PROGS} testsudoers"
                OSDEFS="${OSDEFS} -DSUDO_DEVEL"
                DEV=""
                devdir=.
@@ -3125,8 +3000,8 @@ if test "${with_bsm_audit+set}" = set; then :
   withval=$with_bsm_audit; case $with_bsm_audit in
     yes)       $as_echo "#define HAVE_BSM_AUDIT 1" >>confdefs.h
 
-               SUDO_LIBS="${SUDO_LIBS} -lbsm"
-               SUDO_OBJS="${SUDO_OBJS} bsm_audit.o"
+               SUDOERS_LIBS="${SUDOERS_LIBS} -lbsm"
+               SUDOERS_OBJS="${SUDOERS_OBJS} bsm_audit.lo"
                ;;
     no)                ;;
     *)         as_fn_error "\"--with-bsm-audit does not take an argument.\"" "$LINENO" 5
@@ -3947,7 +3822,8 @@ if ac_fn_c_try_compile "$LINENO"; then :
                    $as_echo "#define HAVE_LINUX_AUDIT 1" >>confdefs.h
 
                    SUDO_LIBS="${SUDO_LIBS} -laudit"
-                   SUDO_OBJS="${SUDO_OBJS} linux_audit.o"
+                   SUDOERS_LIBS="${SUDO_LIBS} -laudit"
+                   SUDOERS_OBJS="${SUDOERS_OBJS} linux_audit.lo"
 
 else
 
@@ -4685,8 +4561,9 @@ fi
 # Check whether --with-iologdir was given.
 if test "${with_iologdir+set}" = set; then :
   withval=$with_iologdir; case $with_iologdir in
-    yes)       ;;
-    no)                ;;
+    yes)    ;;
+    no)     as_fn_error "\"--without-iologdir not supported.\"" "$LINENO" 5
+           ;;
 esac
 fi
 
@@ -5279,77 +5156,15 @@ fi
 
 
 
-# Check whether --with-libvas was given.
-if test "${with_libvas+set}" = set; then :
-  withval=$with_libvas; case $with_libvas in
-    yes)       with_libvas=libvas.so
-               ;;
-    no)                ;;
-    *)
-cat >>confdefs.h <<_ACEOF
-#define LIBVAS_SO "$with_libvas"
-_ACEOF
-
+# Check whether --with-plugindir was given.
+if test "${with_plugindir+set}" = set; then :
+  withval=$with_plugindir; case $with_plugindir in
+    no)                as_fn_error "\"illegal argument: --without-plugindir.\"" "$LINENO" 5
                ;;
+    *)         ;;
 esac
-if test X"$with_libvas" != X"no"; then
-
-cat >>confdefs.h <<_ACEOF
-#define LIBVAS_SO "$with_libvas"
-_ACEOF
-
-    $as_echo "#define USING_NONUNIX_GROUPS 1" >>confdefs.h
-
-    COMMON_OBJS="$COMMON_OBJS vasgroups.o"
-
-# Check whether --with-libvas-rpath was given.
-if test "${with_libvas_rpath+set}" = set; then :
-  withval=$with_libvas_rpath; LIBVAS_RPATH=$withval
-else
-  LIBVAS_RPATH=/opt/quest/lib
-fi
-
-                { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -ldl" >&5
-$as_echo_n "checking for main in -ldl... " >&6; }
-if test "${ac_cv_lib_dl_main+set}" = set; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-
-int
-main ()
-{
-return main ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_dl_main=yes
 else
-  ac_cv_lib_dl_main=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_main" >&5
-$as_echo "$ac_cv_lib_dl_main" >&6; }
-if test "x$ac_cv_lib_dl_main" = x""yes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBDL 1
-_ACEOF
-
-  LIBS="-ldl $LIBS"
-
-fi
-
-fi
-
+  with_plugindir="$libexecdir"
 fi
 
 
@@ -5608,6 +5423,12 @@ $as_echo "no" >&6; }
 fi
 
 
+# Check whether --enable-zlib was given.
+if test "${enable_zlib+set}" = set; then :
+  enableval=$enable_zlib;
+fi
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable environment resetting by default" >&5
 $as_echo_n "checking whether to enable environment resetting by default... " >&6; }
 # Check whether --enable-env_reset was given.
@@ -6117,6 +5938,10 @@ if test X"$AR" = X"false"; then
     as_fn_error "the \"ar\" utility is required to build sudo" "$LINENO" 5
 fi
 
+if test "x$ac_cv_prog_cc_c89" = "xno"; then
+    as_fn_error "Sudo version $PACKAGE_VERSION requires an ANSI C compiler to build." "$LINENO" 5
+fi
+
 ac_aux_dir=
 for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
   for ac_t in install-sh install.sh shtool; do
@@ -6221,8 +6046,8 @@ esac
 
 
 
-macro_version='2.2.6b'
-macro_revision='1.3017'
+macro_version='2.2.10'
+macro_revision='1.3175'
 
 
 
@@ -6238,6 +6063,75 @@ macro_revision='1.3017'
 
 ltmain="$ac_aux_dir/ltmain.sh"
 
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`print -r -- -n 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO ""
+}
+
+case "$ECHO" in
+  printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+  print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+  *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
 $as_echo_n "checking for a sed that does not truncate output... " >&6; }
 if test "${ac_cv_path_SED+set}" = set; then :
@@ -6703,8 +6597,11 @@ if test "$lt_cv_path_NM" != "no"; then
   NM="$lt_cv_path_NM"
 else
   # Didn't find any BSD compatible name lister, look for dumpbin.
-  if test -n "$ac_tool_prefix"; then
-  for ac_prog in "dumpbin -symbols" "link -dump -symbols"
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in dumpbin "link -dump"
   do
     # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
 set dummy $ac_tool_prefix$ac_prog; ac_word=$2
@@ -6748,7 +6645,7 @@ fi
 fi
 if test -z "$DUMPBIN"; then
   ac_ct_DUMPBIN=$DUMPBIN
-  for ac_prog in "dumpbin -symbols" "link -dump -symbols"
+  for ac_prog in dumpbin "link -dump"
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
@@ -6803,6 +6700,15 @@ esac
   fi
 fi
 
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
 
   if test "$DUMPBIN" != ":"; then
     NM="$DUMPBIN"
@@ -6822,13 +6728,13 @@ if test "${lt_cv_nm_interface+set}" = set; then :
 else
   lt_cv_nm_interface="BSD nm"
   echo "int some_variable = 0;" > conftest.$ac_ext
-  (eval echo "\"\$as_me:6825: $ac_compile\"" >&5)
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
   (eval "$ac_compile" 2>conftest.err)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:6828: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
   (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:6831: output\"" >&5)
+  (eval echo "\"\$as_me:$LINENO: output\"" >&5)
   cat conftest.out >&5
   if $GREP 'External.*some_variable' conftest.out > /dev/null; then
     lt_cv_nm_interface="MS dumpbin"
@@ -6885,6 +6791,11 @@ else
     lt_cv_sys_max_cmd_len=8192;
     ;;
 
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
   amigaos*)
     # On AmigaOS with pdksh, this test takes hours, literally.
     # So we just punt and use a minimum line length of 8192.
@@ -6949,8 +6860,8 @@ else
       # If test is not a shell built-in, we'll probably end up computing a
       # maximum length that is only half of the actual maximum length, but
       # we can't tell.
-      while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \
-                = "XX$teststring$teststring"; } >/dev/null 2>&1 &&
+      while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \
+                = "X$teststring$teststring"; } >/dev/null 2>&1 &&
              test $i != 17 # 1/2 MB should be enough
       do
         i=`expr $i + 1`
@@ -7221,16 +7132,18 @@ mingw* | pw32*)
   # Base MSYS/MinGW do not provide the 'file' command needed by
   # func_win32_libid shell function, so use a weaker test based on 'objdump',
   # unless we find 'file', for example because we are cross-compiling.
-  if ( file / ) >/dev/null 2>&1; then
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
     lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
     lt_cv_file_magic_cmd='func_win32_libid'
   else
-    lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
     lt_cv_file_magic_cmd='$OBJDUMP -f'
   fi
   ;;
 
-cegcc)
+cegcc*)
   # use the weaker test based on 'objdump'. See mingw*.
   lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
   lt_cv_file_magic_cmd='$OBJDUMP -f'
@@ -7260,6 +7173,10 @@ gnu*)
   lt_cv_deplibs_check_method=pass_all
   ;;
 
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
 hpux10.20* | hpux11*)
   lt_cv_file_magic_cmd=/usr/bin/file
   case $host_cpu in
@@ -7268,11 +7185,11 @@ hpux10.20* | hpux11*)
     lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
     ;;
   hppa*64*)
-    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
     lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
     ;;
   *)
-    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
     lt_cv_file_magic_test_file=/usr/lib/libc.sl
     ;;
   esac
@@ -7294,7 +7211,7 @@ irix5* | irix6* | nonstopux*)
   ;;
 
 # This must be Linux ELF.
-linux* | k*bsd*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
   lt_cv_deplibs_check_method=pass_all
   ;;
 
@@ -7710,6 +7627,17 @@ if test -n "$RANLIB"; then
   old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
 fi
 
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
 
 
 
@@ -7725,6 +7653,49 @@ fi
 
 
 
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
 
 
 
@@ -7879,8 +7850,8 @@ _LT_EOF
   test $ac_status = 0; }; then
     # Now try to grab the symbols.
     nlist=conftest.nm
-    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5
-  (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5
+    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+  (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; } && test -s "$nlist"; then
@@ -8033,7 +8004,7 @@ ia64-*-hpux*)
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 8036 "configure"' > conftest.$ac_ext
+  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
   if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -8745,6 +8716,38 @@ rm -f core conftest.err conftest.$ac_objext \
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if test "${lt_cv_ld_force_load+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+      echo "$AR cru libconftest.a conftest.o" >&5
+      $AR cru libconftest.a conftest.o 2>&5
+      echo "$RANLIB libconftest.a" >&5
+      $RANLIB libconftest.a 2>&5
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then
+       lt_cv_ld_force_load=yes
+      else
+       cat conftest.err >&5
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
     case $host_os in
     rhapsody* | darwin1.[012])
       _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
@@ -8772,7 +8775,7 @@ $as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
     else
       _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
     fi
-    if test "$DSYMUTIL" != ":"; then
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
       _lt_dsymutil='~$DSYMUTIL $lib || :'
     else
       _lt_dsymutil=
@@ -8926,11 +8929,12 @@ done
 
 
 
-# Set options
 
 
+# Set options
+enable_dlopen=yes
+
 
-        enable_dlopen=no
 
 
   enable_win32_dll=no
@@ -9076,6 +9080,7 @@ LIBTOOL='$(SHELL) $(top_builddir)/libtool'
 
 
 
+
 
 
 test -z "$LN_S" && LN_S="ln -s"
@@ -9127,19 +9132,6 @@ _ACEOF
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
 case $host_os in
 aix3*)
   # AIX sometimes has problems with the GCC collect2 program.  For some
@@ -9152,32 +9144,15 @@ aix3*)
   ;;
 esac
 
-# Sed substitution that helps us do robust quoting.  It backslashifies
-# metacharacters that are still active within double-quoted strings.
-sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+# Global variables:
+ofile=libtool
+can_build_shared=yes
 
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\(["`\\]\)/\\\1/g'
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
 
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
-
-# Sed substitution to delay expansion of an escaped single quote.
-delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
-
-# Sed substitution to avoid accidental globbing in evaled expressions
-no_glob_subst='s/\*/\\\*/g'
-
-# Global variables:
-ofile=libtool
-can_build_shared=yes
-
-# All known linkers require a `.a' archive for static linking (except MSVC,
-# which needs '.lib').
-libext=a
-
-with_gnu_ld="$lt_cv_prog_gnu_ld"
+with_gnu_ld="$lt_cv_prog_gnu_ld"
 
 old_CC="$CC"
 old_CFLAGS="$CFLAGS"
@@ -9197,7 +9172,7 @@ for cc_temp in $compiler""; do
     *) break;;
   esac
 done
-cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
 
 
 # Only perform the check for file, if the check method requires it
@@ -9406,7 +9381,12 @@ if test -n "$compiler"; then
 lt_prog_compiler_no_builtin_flag=
 
 if test "$GCC" = yes; then
-  lt_prog_compiler_no_builtin_flag=' -fno-builtin'
+  case $cc_basename in
+  nvcc*)
+    lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+  *)
+    lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+  esac
 
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
@@ -9426,15 +9406,15 @@ 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:9429: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:9433: \$? = $ac_status" >&5
+   echo "$as_me:$LINENO: \$? = $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.
-     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
      $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
      if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
        lt_cv_prog_compiler_rtti_exceptions=yes
@@ -9512,6 +9492,12 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
       lt_prog_compiler_pic='-fno-common'
       ;;
 
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static=
+      ;;
+
     hpux*)
       # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
       # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
@@ -9554,6 +9540,13 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
       lt_prog_compiler_pic='-fPIC'
       ;;
     esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      lt_prog_compiler_wl='-Xlinker '
+      lt_prog_compiler_pic='-Xcompiler -fPIC'
+      ;;
+    esac
   else
     # PORTME Check for flag to pass linker flags through the system compiler.
     case $host_os in
@@ -9595,7 +9588,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
       lt_prog_compiler_static='-non_shared'
       ;;
 
-    linux* | k*bsd*-gnu)
+    linux* | k*bsd*-gnu | kopensolaris*-gnu)
       case $cc_basename in
       # old Intel for x86_64 which still supported -KPIC.
       ecc*)
@@ -9616,7 +9609,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
        lt_prog_compiler_pic='--shared'
        lt_prog_compiler_static='--static'
        ;;
-      pgcc* | pgf77* | pgf90* | pgf95*)
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
         # Portland Group compilers (*not* the Pentium gcc compiler,
        # which looks to be a dead project)
        lt_prog_compiler_wl='-Wl,'
@@ -9628,25 +9621,25 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
         # All Alpha code is PIC.
         lt_prog_compiler_static='-non_shared'
         ;;
-      xl*)
-       # IBM XL C 8.0/Fortran 10.1 on PPC
+      xl* | bgxl* | bgf* | mpixl*)
+       # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
        lt_prog_compiler_wl='-Wl,'
        lt_prog_compiler_pic='-qpic'
        lt_prog_compiler_static='-qstaticlink'
        ;;
       *)
        case `$CC -V 2>&1 | sed 5q` in
-       *Sun\ C*)
-         # Sun C 5.9
+       *Sun\ F* | *Sun*Fortran*)
+         # Sun Fortran 8.3 passes all unrecognized flags to the linker
          lt_prog_compiler_pic='-KPIC'
          lt_prog_compiler_static='-Bstatic'
-         lt_prog_compiler_wl='-Wl,'
+         lt_prog_compiler_wl=''
          ;;
-       *Sun\ F*)
-         # Sun Fortran 8.3 passes all unrecognized flags to the linker
+       *Sun\ C*)
+         # Sun C 5.9
          lt_prog_compiler_pic='-KPIC'
          lt_prog_compiler_static='-Bstatic'
-         lt_prog_compiler_wl=''
+         lt_prog_compiler_wl='-Wl,'
          ;;
        esac
        ;;
@@ -9678,7 +9671,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
       lt_prog_compiler_pic='-KPIC'
       lt_prog_compiler_static='-Bstatic'
       case $cc_basename in
-      f77* | f90* | f95*)
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
        lt_prog_compiler_wl='-Qoption ld ';;
       *)
        lt_prog_compiler_wl='-Wl,';;
@@ -9765,15 +9758,15 @@ 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:9768: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:9772: \$? = $ac_status" >&5
+   echo "$as_me:$LINENO: \$? = $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.
-     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
      $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
      if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
        lt_cv_prog_compiler_pic_works=yes
@@ -9821,7 +9814,7 @@ else
      if test -s conftest.err; then
        # Append any errors to the config.log.
        cat conftest.err 1>&5
-       $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
        $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
        if diff conftest.exp conftest.er2 >/dev/null; then
          lt_cv_prog_compiler_static_works=yes
@@ -9870,16 +9863,16 @@ 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:9873: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:9877: \$? = $ac_status" >&5
+   echo "$as_me:$LINENO: \$? = $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
      # So say no if there are warnings
-     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
      $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
      if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
        lt_cv_prog_compiler_c_o=yes
@@ -9925,16 +9918,16 @@ 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:9928: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:9932: \$? = $ac_status" >&5
+   echo "$as_me:$LINENO: \$? = $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
      # So say no if there are warnings
-     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
      $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
      if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
        lt_cv_prog_compiler_c_o=yes
@@ -10047,7 +10040,33 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
   esac
 
   ld_shlibs=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
   if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+       # The AIX port of GNU ld has always aspired to compatibility
+       # with the native linker.  However, as the warning in the GNU ld
+       # block says, versions before 2.19.5* couldn't really create working
+       # shared libraries, regardless of the interface used.
+       case `$LD -v 2>&1` in
+         *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+         *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+         *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+         *)
+           lt_use_gnu_ld_interface=yes
+           ;;
+       esac
+       ;;
+      *)
+       lt_use_gnu_ld_interface=yes
+       ;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
     # If archive_cmds runs LD, not CC, wlarc should be empty
     wlarc='${wl}'
 
@@ -10065,6 +10084,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
     fi
     supports_anon_versioning=no
     case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
       *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
       *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
       *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
@@ -10080,11 +10100,12 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
        ld_shlibs=no
        cat <<_LT_EOF 1>&2
 
-*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** Warning: the GNU linker, at least up to release 2.19, is reported
 *** to be unable to reliably create shared libraries on AIX.
 *** Therefore, libtool is disabling shared libraries support.  If you
-*** really care for shared libraries, you may want to modify your PATH
-*** so that a non-GNU linker is found, and then restart.
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
 
 _LT_EOF
       fi
@@ -10120,6 +10141,7 @@ _LT_EOF
       # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
       # as there is no search path for DLLs.
       hardcode_libdir_flag_spec='-L$libdir'
+      export_dynamic_flag_spec='${wl}--export-all-symbols'
       allow_undefined_flag=unsupported
       always_export_symbols=no
       enable_shared_with_static_runtimes=yes
@@ -10141,6 +10163,11 @@ _LT_EOF
       fi
       ;;
 
+    haiku*)
+      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      link_all_deplibs=yes
+      ;;
+
     interix[3-9]*)
       hardcode_direct=no
       hardcode_shlibpath_var=no
@@ -10156,7 +10183,7 @@ _LT_EOF
       archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
       ;;
 
-    gnu* | linux* | tpf* | k*bsd*-gnu)
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
       tmp_diet=no
       if test "$host_os" = linux-dietlibc; then
        case $cc_basename in
@@ -10170,11 +10197,12 @@ _LT_EOF
        tmp_sharedflag='-shared'
        case $cc_basename,$host_cpu in
         pgcc*)                         # Portland Group C compiler
-         whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+         whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
          tmp_addflag=' $pic_flag'
          ;;
-       pgf77* | pgf90* | pgf95*)       # Portland Group f77 and f90 compilers
-         whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+       pgf77* | pgf90* | pgf95* | pgfortran*)
+                                       # Portland Group f77 and f90 compilers
+         whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
          tmp_addflag=' $pic_flag -Mnomain' ;;
        ecc*,ia64* | icc*,ia64*)        # Intel C compiler on ia64
          tmp_addflag=' -i_dynamic' ;;
@@ -10185,13 +10213,17 @@ _LT_EOF
        lf95*)                          # Lahey Fortran 8.1
          whole_archive_flag_spec=
          tmp_sharedflag='--shared' ;;
-       xl[cC]*)                        # IBM XL C 8.0 on PPC (deal with xlf below)
+       xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
          tmp_sharedflag='-qmkshrobj'
          tmp_addflag= ;;
+       nvcc*)  # Cuda Compiler Driver 2.2
+         whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         compiler_needs_object=yes
+         ;;
        esac
        case `$CC -V 2>&1 | sed 5q` in
        *Sun\ C*)                       # Sun C 5.9
-         whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+         whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
          compiler_needs_object=yes
          tmp_sharedflag='-G' ;;
        *Sun\ F*)                       # Sun Fortran 8.3
@@ -10207,17 +10239,17 @@ _LT_EOF
         fi
 
        case $cc_basename in
-       xlf*)
+       xlf* | bgf* | bgxlf* | mpixlf*)
          # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
          whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
          hardcode_libdir_flag_spec=
          hardcode_libdir_flag_spec_ld='-rpath $libdir'
-         archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+         archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
          if test "x$supports_anon_versioning" = xyes; then
            archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
              cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
              echo "local: *; };" >> $output_objdir/$libname.ver~
-             $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+             $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
          fi
          ;;
        esac
@@ -10338,8 +10370,10 @@ _LT_EOF
       else
        # If we're using GNU nm, then we don't want the "-C" option.
        # -C means demangle to AIX nm, but means don't demangle with GNU nm
+       # Also, AIX nm treats weak defined symbols like other global
+       # defined symbols, whereas GNU nm marks them as "W".
        if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-         export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+         export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
        else
          export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
        fi
@@ -10457,7 +10491,7 @@ rm -f core conftest.err conftest.$ac_objext \
 if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
 
         hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
-        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
       else
        if test "$host_cpu" = ia64; then
          hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
@@ -10501,8 +10535,13 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
          # -berok will link without error, but may produce a broken library.
          no_undefined_flag=' ${wl}-bernotok'
          allow_undefined_flag=' ${wl}-berok'
-         # Exported symbols can be pulled into shared objects from archives
-         whole_archive_flag_spec='$convenience'
+         if test "$with_gnu_ld" = yes; then
+           # We only use this code for GNU lds that support --whole-archive.
+           whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+         else
+           # Exported symbols can be pulled into shared objects from archives
+           whole_archive_flag_spec='$convenience'
+         fi
          archive_cmds_need_lc=yes
          # This is similar to how AIX traditionally builds its shared libraries.
          archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
@@ -10541,7 +10580,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
       # Tell ltmain to make .dll files, not .so files.
       shrext_cmds=".dll"
       # FIXME: Setting linknames here is a bad hack.
-      archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames='
+      archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
       # The linker will automatically build a .lib file if we build a DLL.
       old_archive_from_new_cmds='true'
       # FIXME: Should let the user specify the lib program.
@@ -10557,7 +10596,11 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
   hardcode_direct=no
   hardcode_automatic=yes
   hardcode_shlibpath_var=unsupported
-  whole_archive_flag_spec=''
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    whole_archive_flag_spec='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+  else
+    whole_archive_flag_spec=''
+  fi
   link_all_deplibs=yes
   allow_undefined_flag="$_lt_dar_allow_undefined"
   case $cc_basename in
@@ -10565,7 +10608,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
      *) _lt_dar_can_shared=$GCC ;;
   esac
   if test "$_lt_dar_can_shared" = "yes"; then
-    output_verbose_link_cmd=echo
+    output_verbose_link_cmd=func_echo_all
     archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
     module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
     archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
@@ -10631,7 +10674,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
       ;;
 
     hpux10*)
-      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
        archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
       else
        archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
@@ -10650,7 +10693,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
       ;;
 
     hpux11*)
-      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
        case $host_cpu in
        hppa*64*)
          archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
@@ -10671,7 +10714,46 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
          archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
          ;;
        *)
-         archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+
+         # Older versions of the 11.00 compiler do not understand -b yet
+         # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+         { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if test "${lt_cv_prog_compiler__b+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler__b=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS -b"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler__b=yes
+       fi
+     else
+       lt_cv_prog_compiler__b=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+    archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+    archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
          ;;
        esac
       fi
@@ -10699,7 +10781,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
 
     irix5* | irix6* | nonstopux*)
       if test "$GCC" = yes; then
-       archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
        # Try to use the -exported_symbol ld option, if it does not
        # work, assume that -exports_file does not work either and
        # implicitly export all symbols.
@@ -10710,15 +10792,15 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
 int foo(void) {}
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
-  archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+  archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
 
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
         LDFLAGS="$save_LDFLAGS"
       else
-       archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
-       archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+       archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+       archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
       fi
       archive_cmds_need_lc='no'
       hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
@@ -10780,17 +10862,17 @@ rm -f core conftest.err conftest.$ac_objext \
       hardcode_libdir_flag_spec='-L$libdir'
       hardcode_minus_L=yes
       allow_undefined_flag=unsupported
-      archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
       old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
       ;;
 
     osf3*)
       if test "$GCC" = yes; then
        allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
-       archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
       else
        allow_undefined_flag=' -expect_unresolved \*'
-       archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+       archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
       fi
       archive_cmds_need_lc='no'
       hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
@@ -10800,13 +10882,13 @@ rm -f core conftest.err conftest.$ac_objext \
     osf4* | osf5*)     # as osf3* with the addition of -msym flag
       if test "$GCC" = yes; then
        allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
-       archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
        hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
       else
        allow_undefined_flag=' -expect_unresolved \*'
-       archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+       archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
        archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
-       $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+       $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
 
        # Both c and cxx compiler support -rpath directly
        hardcode_libdir_flag_spec='-rpath $libdir'
@@ -11009,44 +11091,50 @@ x|xyes)
       # to ld, don't add -lc before -lgcc.
       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
-      $RM conftest*
-      echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+if test "${lt_cv_archive_cmds_need_lc+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  $RM conftest*
+       echo "$lt_simple_compile_test_code" > conftest.$ac_ext
 
-      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+       if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; } 2>conftest.err; then
-        soname=conftest
-        lib=conftest
-        libobjs=conftest.$ac_objext
-        deplibs=
-        wl=$lt_prog_compiler_wl
-       pic_flag=$lt_prog_compiler_pic
-        compiler_flags=-v
-        linker_flags=-v
-        verstring=
-        output_objdir=.
-        libname=conftest
-        lt_save_allow_undefined_flag=$allow_undefined_flag
-        allow_undefined_flag=
-        if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+         soname=conftest
+         lib=conftest
+         libobjs=conftest.$ac_objext
+         deplibs=
+         wl=$lt_prog_compiler_wl
+         pic_flag=$lt_prog_compiler_pic
+         compiler_flags=-v
+         linker_flags=-v
+         verstring=
+         output_objdir=.
+         libname=conftest
+         lt_save_allow_undefined_flag=$allow_undefined_flag
+         allow_undefined_flag=
+         if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
   (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }
-        then
-         archive_cmds_need_lc=no
-        else
-         archive_cmds_need_lc=yes
-        fi
-        allow_undefined_flag=$lt_save_allow_undefined_flag
-      else
-        cat conftest.err 1>&5
-      fi
-      $RM conftest*
-      { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5
-$as_echo "$archive_cmds_need_lc" >&6; }
+         then
+           lt_cv_archive_cmds_need_lc=no
+         else
+           lt_cv_archive_cmds_need_lc=yes
+         fi
+         allow_undefined_flag=$lt_save_allow_undefined_flag
+       else
+         cat conftest.err 1>&5
+       fi
+       $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+      archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
       ;;
     esac
   fi
@@ -11217,16 +11305,23 @@ if test "$GCC" = yes; then
     darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
     *) lt_awk_arg="/^libraries:/" ;;
   esac
-  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
-  if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
     # if the path contains ";" then we assume it to be the separator
     # otherwise default to the standard path separator (i.e. ":") - it is
     # assumed that no part of a normal pathname contains ";" but that should
     # okay in the real world where ";" in dirpaths is itself problematic.
-    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'`
-  else
-    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
-  fi
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
   # Ok, now we have the path, separated by spaces, we can step through it
   # and add multilib dir if necessary.
   lt_tmp_lt_search_path_spec=
@@ -11239,7 +11334,7 @@ if test "$GCC" = yes; then
        lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
     fi
   done
-  lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk '
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
 BEGIN {RS=" "; FS="/|\n";} {
   lt_foo="";
   lt_count=0;
@@ -11259,7 +11354,13 @@ BEGIN {RS=" "; FS="/|\n";} {
   if (lt_foo != "") { lt_freq[lt_foo]++; }
   if (lt_freq[lt_foo] == 1) { print lt_foo; }
 }'`
-  sys_lib_search_path_spec=`$ECHO $lt_search_path_spec`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
 else
   sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
 fi
@@ -11347,7 +11448,7 @@ amigaos*)
   m68k)
     library_names_spec='$libname.ixlibrary $libname.a'
     # Create ${libname}_ixlibrary.a entries in /sys/libs.
-    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
     ;;
   esac
   ;;
@@ -11400,23 +11501,12 @@ cygwin* | mingw* | pw32* | cegcc*)
     cygwin*)
       # Cygwin DLLs use 'cyg' prefix rather than 'lib'
       soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
-      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
       ;;
     mingw* | cegcc*)
       # MinGW DLLs use traditional 'lib' prefix
       soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
-      sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
-      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
-        # It is most probably a Windows format PATH printed by
-        # mingw gcc, but we are running on Cygwin. Gcc prints its search
-        # path with ; separators, and with drive letters. We can handle the
-        # drive letters (cygwin fileutils understands them), so leave them,
-        # especially as we might pass files found there to a mingw objdump,
-        # which wouldn't understand a cygwinified path. Ahh.
-        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
-      else
-        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
-      fi
       ;;
     pw32*)
       # pw32 DLLs use 'pw' prefix rather than 'lib'
@@ -11516,6 +11606,19 @@ gnu*)
   hardcode_into_libs=yes
   ;;
 
+haiku*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
 hpux9* | hpux10* | hpux11*)
   # Give a soname corresponding to the major version so that dld.sl refuses to
   # link against other versions.
@@ -11558,8 +11661,10 @@ hpux9* | hpux10* | hpux11*)
     soname_spec='${libname}${release}${shared_ext}$major'
     ;;
   esac
-  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
   postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
   ;;
 
 interix[3-9]*)
@@ -11617,7 +11722,7 @@ linux*oldld* | linux*aout* | linux*coff*)
   ;;
 
 # This must be Linux ELF.
-linux* | k*bsd*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
   version_type=linux
   need_lib_prefix=no
   need_version=no
@@ -11626,12 +11731,17 @@ linux* | k*bsd*-gnu)
   finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
+
   # Some binutils ld are patched to set DT_RUNPATH
-  save_LDFLAGS=$LDFLAGS
-  save_libdir=$libdir
-  eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
-       LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+  if test "${lt_cv_shlibpath_overrides_runpath+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+        LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -11644,13 +11754,17 @@ main ()
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
   if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
-  shlibpath_overrides_runpath=yes
+  lt_cv_shlibpath_overrides_runpath=yes
 fi
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
-  LDFLAGS=$save_LDFLAGS
-  libdir=$save_libdir
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
 
   # This implies no fast_install, which is unacceptable.
   # Some rework will be needed to allow for fast_install
@@ -11659,7 +11773,7 @@ rm -f core conftest.err conftest.$ac_objext \
 
   # Append ld.so.conf contents to the search path
   if test -f /etc/ld.so.conf; then
-    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[      ]*hwcap[        ]/d;s/[:,      ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[      ]*hwcap[        ]/d;s/[:,      ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
     sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
   fi
 
 
 
 
+
+
+
+
+
 
 
 
@@ -12292,7 +12411,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12295 "configure"
+#line $LINENO "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12333,7 +12452,13 @@ else
 #  endif
 #endif
 
-void fnord() { int i=42;}
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
 int main ()
 {
   void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
@@ -12342,7 +12467,11 @@ int main ()
   if (self)
     {
       if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
-      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      else
+        {
+         if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+       }
       /* dlclose (self); */
     }
   else
@@ -12388,7 +12517,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12391 "configure"
+#line $LINENO "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12429,7 +12558,13 @@ else
 #  endif
 #endif
 
-void fnord() { int i=42;}
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
 int main ()
 {
   void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
@@ -12438,7 +12573,11 @@ int main ()
   if (self)
     {
       if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
-      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      else
+        {
+         if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+       }
       /* dlclose (self); */
     }
   else
@@ -12618,8 +12757,17 @@ CC="$lt_save_CC"
 
 if test "$enable_shared" = "no"; then
     with_noexec=no
+    enable_dlopen=no
+    lt_cv_dlopen=none
+    lt_cv_dlopen_libs=
 else
     eval _shrext="$shrext_cmds"
+    # Darwin uses .dylib for libraries but .so for modules
+    if test X"$_shrext" = X".dylib"; then
+       SOEXT=".so"
+    else
+       SOEXT="$_shrext"
+    fi
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking path to sudo_noexec.so" >&5
 $as_echo_n "checking path to sudo_noexec.so... " >&6; }
@@ -12824,11 +12972,22 @@ case "$host" in
                : ${mansectform='4'}
                : ${with_rpath='yes'}
                test -z "$with_pam" && AUTH_EXCL_DEF="PAM"
+               for ac_func in priv_set
+do :
+  ac_fn_c_check_func "$LINENO" "priv_set" "ac_cv_func_priv_set"
+if test "x$ac_cv_func_priv_set" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_PRIV_SET 1
+_ACEOF
+
+fi
+done
+
                ;;
     *-*-aix*)
                # To get all prototypes (so we pass -Wall)
                OSDEFS="${OSDEFS} -D_ALL_SOURCE -D_LINUX_SOURCE_COMPAT"
-               SUDO_LDFLAGS="${SUDO_LDFLAGS} -Wl,-bI:\$(srcdir)/aixcrypt.exp"
+               SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -Wl,-bI:\$(srcdir)/aixcrypt.exp"
                if test X"$with_blibpath" != X"no"; then
                    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if linker accepts -Wl,-blibpath" >&5
 $as_echo_n "checking if linker accepts -Wl,-blibpath... " >&6; }
@@ -12911,7 +13070,7 @@ _ACEOF
 fi
 done
 
-               COMMON_OBJS="$COMMON_OBJS aix.o"
+               COMMON_OBJS="$COMMON_OBJS aix.lo"
                ;;
     *-*-hiuxmpp*)
                : ${mansectsu='1m'}
@@ -12926,11 +13085,6 @@ done
                : ${mansectform='4'}
 
                if test -z "$GCC"; then
-                   # HP-UX bundled compiler can't generate shared objects
-                   if test "x$ac_cv_prog_cc_c89" = "xno"; then
-                       with_noexec=no
-                   fi
-
                    # Use the +DAportable flag on hppa if it is supported
                    case "$host_cpu" in
                    hppa*)
@@ -12976,13 +13130,6 @@ $as_echo "$sudo_cv_var_daportable" >&6; }
                        *-*-hpux1-8.*)
                            $as_echo "#define BROKEN_SYSLOG 1" >>confdefs.h
 
-
-                           # Not sure if setuid binaries are safe in < 9.x
-                           if test -n "$GCC"; then
-                               SUDO_LDFLAGS="${SUDO_LDFLAGS} -static"
-                           else
-                               SUDO_LDFLAGS="${SUDO_LDFLAGS} -Wl,-a,archive"
-                           fi
                        ;;
                        *-*-hpux9.*)
                            $as_echo "#define BROKEN_SYSLOG 1" >>confdefs.h
@@ -12993,7 +13140,7 @@ $as_echo "$sudo_cv_var_daportable" >&6; }
                            # DCE support (requires ANSI C compiler)
                            if test "$with_DCE" = "yes"; then
                                # order of libs in 9.X is important. -lc_r must be last
-                               SUDO_LIBS="${SUDO_LIBS} -ldce -lM -lc_r"
+                               SUDOERS_LIBS="${SUDOERS_LIBS} -ldce -lM -lc_r"
                                LIBS="${LIBS} -ldce -lM -lc_r"
                                CPPFLAGS="${CPPFLAGS} -D_REENTRANT -I/usr/include/reentrant"
                            fi
@@ -13013,7 +13160,7 @@ $as_echo "$sudo_cv_var_daportable" >&6; }
                ;;
     *-dec-osf*)
                # ignore envariables wrt dynamic lib path
-               SUDO_LDFLAGS="${SUDO_LDFLAGS} -Wl,-no_library_replacement"
+               SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -Wl,-no_library_replacement"
 
                : ${CHECKSIA='true'}
                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to disable sia support on Digital UNIX" >&5
@@ -13186,8 +13333,7 @@ fi
     *-*-isc*)
                OSDEFS="${OSDEFS} -D_ISC"
                LIB_CRYPT=1
-               SUDO_LIBS="${SUDO_LIBS} -lcrypt"
-               LIBS="${LIBS} -lcrypt"
+               SUDOERS_LIBS="${SUDOERS_LIBS} -lcrypt"
 
                shadow_funcs="getspnam"
                shadow_libs="-lsec"
@@ -13252,8 +13398,7 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c89_strcasecmp" >&5
 $as_echo "$ac_cv_lib_c89_strcasecmp" >&6; }
 if test "x$ac_cv_lib_c89_strcasecmp" = x""yes; then :
-  $as_echo "#define HAVE_STRCASECMP 1" >>confdefs.h
- LIBS="${LIBS} -lc89"; ac_cv_func_strcasecmp=yes
+  LIBS="${LIBS} -lc89"
 fi
 
                : ${mansectsu='1m'}
@@ -13262,7 +13407,6 @@ fi
                ;;
     *-ccur-sysv4*|*-ccur-sysvr4*)
                LIBS="${LIBS} -lgen"
-               SUDO_LIBS="${SUDO_LIBS} -lgen"
                : ${mansectsu='1m'}
                : ${mansectform='4'}
                : ${with_rpath='yes'}
@@ -13303,7 +13447,7 @@ done
                    ;;
                esac
                if test "${with_skey-'no'}" = "yes"; then
-                    SUDO_LIBS="${SUDO_LIBS} -lmd"
+                    SUDOERS_LIBS="${SUDOERS_LIBS} -lmd"
                fi
                CHECKSHADOW="false"
                test -z "$with_pam" && AUTH_EXCL_DEF="PAM"
@@ -13339,7 +13483,7 @@ done
                ;;
     *-*-dragonfly*)
                if test "${with_skey-'no'}" = "yes"; then
-                    SUDO_LIBS="${SUDO_LIBS} -lmd"
+                    SUDOERS_LIBS="${SUDOERS_LIBS} -lmd"
                fi
                CHECKSHADOW="false"
                test -z "$with_pam" && AUTH_EXCL_DEF="PAM"
@@ -13581,6 +13725,9 @@ $as_echo "#define volatile /**/" >>confdefs.h
 
 fi
 
+if test X"$with_gnu_ld" != "yes" -a -n "$GCC"; then
+    LTLDFLAGS="$LTLDFLAGS -Wc,-static-libgcc"
+fi
 for ac_prog in 'bison -y' byacc
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
@@ -13727,8 +13874,7 @@ $as_echo "not found" >&6; }
 fi
 
 fi
-if test -z "$with_editor"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for vi" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for vi" >&5
 $as_echo_n "checking for vi... " >&6; }
 found=no
 for editor in "/usr/bin/vi" "/bin/vi" "/usr/ucb/vi" "/usr/bsd/vi" "/usr/local/bin/vi"; do
@@ -13748,7 +13894,6 @@ if test X"$found" != X"yes"; then
 $as_echo "not found" >&6; }
 fi
 
-fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking which syslog facility sudo should log with" >&5
 $as_echo_n "checking which syslog facility sudo should log with... " >&6; }
 if test X"$with_logfac" = X""; then
@@ -14081,7 +14226,7 @@ $as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
 
 fi
 
-for ac_header in malloc.h paths.h utime.h netgroup.h sys/sockio.h sys/bsdtypes.h sys/select.h sys/stropts.h sys/sysmacros.h
+for ac_header in malloc.h paths.h utime.h netgroup.h utmpx.h sys/sockio.h sys/bsdtypes.h sys/select.h sys/stropts.h sys/sysmacros.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_posix_termios" >&5
 $as_echo "$ac_cv_sys_posix_termios" >&6; }
 
-if test "$ac_cv_sys_posix_termios" = "yes"; then
-    $as_echo "#define HAVE_TERMIOS_H 1" >>confdefs.h
-
-else
-    for ac_header in termio.h
-do :
-  ac_fn_c_check_header_mongrel "$LINENO" "termio.h" "ac_cv_header_termio_h" "$ac_includes_default"
-if test "x$ac_cv_header_termio_h" = x""yes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_TERMIO_H 1
-_ACEOF
-
-fi
-
-done
-
+if test "$ac_cv_sys_posix_termios" != "yes"; then
+    as_fn_error "Must have POSIX termios to build sudo" "$LINENO" 5
 fi
 
 maildir=no
@@ -14469,8 +14600,10 @@ if test "x$ac_cv_header_login_cap_h" = x""yes; then :
 _ACEOF
  LOGINCAP_USAGE='[-c class|-] '; LCMAN=1
        case "$OS" in
-           freebsd|netbsd)     SUDO_LIBS="${SUDO_LIBS} -lutil"
-           ;;
+           freebsd|netbsd)
+               SUDO_LIBS="${SUDO_LIBS} -lutil"
+               SUDOERS_LIBS="${SUDOERS_LIBS} -lutil"
+               ;;
        esac
 
 fi
@@ -14914,121 +15047,277 @@ $as_echo "#define HAVE_SA_LEN 1" >>confdefs.h
 fi
 
 
-case "$DEFS" in
-    *"RETSIGTYPE"*)    ;;
-    *)                 { $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5
-$as_echo_n "checking return type of signal handlers... " >&6; }
-if test "${ac_cv_type_signal+set}" = set; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <sys/types.h>
-#include <signal.h>
+_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS $OSDEFS"
+if test $ac_cv_header_utmpx_h = "yes"; then
+    ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_id" "ac_cv_member_struct_utmpx_ut_id" "
+       #include <sys/types.h>
+       #include <utmpx.h>
 
-int
-main ()
-{
-return *(signal (0, 0)) (0) == 1;
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_cv_type_signal=int
-else
-  ac_cv_type_signal=void
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5
-$as_echo "$ac_cv_type_signal" >&6; }
+"
+if test "x$ac_cv_member_struct_utmpx_ut_id" = x""yes; then :
 
 cat >>confdefs.h <<_ACEOF
-#define RETSIGTYPE $ac_cv_type_signal
+#define HAVE_STRUCT_UTMPX_UT_ID 1
 _ACEOF
 
-;;
-esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking type of array argument to getgroups" >&5
-$as_echo_n "checking type of array argument to getgroups... " >&6; }
-if test "${ac_cv_type_getgroups+set}" = set; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test "$cross_compiling" = yes; then :
-  ac_cv_type_getgroups=cross
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-/* Thanks to Mike Rendell for this test.  */
-$ac_includes_default
-#define NGID 256
-#undef MAX
-#define MAX(x, y) ((x) > (y) ? (x) : (y))
-
-int
-main ()
-{
-  gid_t gidset[NGID];
-  int i, n;
-  union { gid_t gval; long int lval; }  val;
 
-  val.lval = -1;
-  for (i = 0; i < NGID; i++)
-    gidset[i] = val.gval;
-  n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1,
-                gidset);
-  /* Exit non-zero if getgroups seems to require an array of ints.  This
-     happens when gid_t is short int but getgroups modifies an array
-     of ints.  */
-  return n > 0 && gidset[n] != val.gval;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-  ac_cv_type_getgroups=gid_t
-else
-  ac_cv_type_getgroups=int
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
+ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_pid" "ac_cv_member_struct_utmpx_ut_pid" "
+       #include <sys/types.h>
+       #include <utmpx.h>
 
-if test $ac_cv_type_getgroups = cross; then
-        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <unistd.h>
+"
+if test "x$ac_cv_member_struct_utmpx_ut_pid" = x""yes; then :
 
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMPX_UT_PID 1
 _ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "getgroups.*int.*gid_t" >/dev/null 2>&1; then :
-  ac_cv_type_getgroups=gid_t
-else
-  ac_cv_type_getgroups=int
-fi
-rm -f conftest*
+
 
 fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_getgroups" >&5
-$as_echo "$ac_cv_type_getgroups" >&6; }
+ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_tv" "ac_cv_member_struct_utmpx_ut_tv" "
+       #include <sys/types.h>
+       #include <utmpx.h>
+
+"
+if test "x$ac_cv_member_struct_utmpx_ut_tv" = x""yes; then :
 
 cat >>confdefs.h <<_ACEOF
-#define GETGROUPS_T $ac_cv_type_getgroups
+#define HAVE_STRUCT_UTMPX_UT_TV 1
 _ACEOF
 
 
-ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
-if test "x$ac_cv_type_size_t" = x""yes; then :
+fi
+ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_type" "ac_cv_member_struct_utmpx_ut_type" "
+       #include <sys/types.h>
+       #include <utmpx.h>
 
-else
+"
+if test "x$ac_cv_member_struct_utmpx_ut_type" = x""yes; then :
 
 cat >>confdefs.h <<_ACEOF
-#define size_t unsigned int
+#define HAVE_STRUCT_UTMPX_UT_TYPE 1
 _ACEOF
 
+
 fi
 
-ac_fn_c_check_func "$LINENO" "getgroups" "ac_cv_func_getgroups"
+                ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_exit.__e_termination" "ac_cv_member_struct_utmpx_ut_exit___e_termination" "
+       #include <sys/types.h>
+       #include <utmpx.h>
+
+"
+if test "x$ac_cv_member_struct_utmpx_ut_exit___e_termination" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMPX_UT_EXIT___E_TERMINATION 1
+_ACEOF
+
+$as_echo "#define HAVE_STRUCT_UTMPX_UT_EXIT 1" >>confdefs.h
+
+else
+
+       ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_exit.e_termination" "ac_cv_member_struct_utmpx_ut_exit_e_termination" "
+           #include <sys/types.h>
+           #include <utmpx.h>
+
+"
+if test "x$ac_cv_member_struct_utmpx_ut_exit_e_termination" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMPX_UT_EXIT_E_TERMINATION 1
+_ACEOF
+
+$as_echo "#define HAVE_STRUCT_UTMPX_UT_EXIT 1" >>confdefs.h
+
+fi
+
+
+fi
+
+else
+    ac_fn_c_check_member "$LINENO" "struct utmp" "ut_id" "ac_cv_member_struct_utmp_ut_id" "
+       #include <sys/types.h>
+       #include <utmp.h>
+
+"
+if test "x$ac_cv_member_struct_utmp_ut_id" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMP_UT_ID 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "struct utmp" "ut_pid" "ac_cv_member_struct_utmp_ut_pid" "
+       #include <sys/types.h>
+       #include <utmp.h>
+
+"
+if test "x$ac_cv_member_struct_utmp_ut_pid" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMP_UT_PID 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "struct utmp" "ut_tv" "ac_cv_member_struct_utmp_ut_tv" "
+       #include <sys/types.h>
+       #include <utmp.h>
+
+"
+if test "x$ac_cv_member_struct_utmp_ut_tv" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMP_UT_TV 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "struct utmp" "ut_type" "ac_cv_member_struct_utmp_ut_type" "
+       #include <sys/types.h>
+       #include <utmp.h>
+
+"
+if test "x$ac_cv_member_struct_utmp_ut_type" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMP_UT_TYPE 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "struct utmp" "ut_user" "ac_cv_member_struct_utmp_ut_user" "
+       #include <sys/types.h>
+       #include <utmp.h>
+
+"
+if test "x$ac_cv_member_struct_utmp_ut_user" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMP_UT_USER 1
+_ACEOF
+
+
+fi
+
+                ac_fn_c_check_member "$LINENO" "struct utmp" "ut_exit.__e_termination" "ac_cv_member_struct_utmp_ut_exit___e_termination" "
+       #include <sys/types.h>
+       #include <utmp.h>
+
+"
+if test "x$ac_cv_member_struct_utmp_ut_exit___e_termination" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMP_UT_EXIT___E_TERMINATION 1
+_ACEOF
+
+$as_echo "#define HAVE_STRUCT_UTMP_UT_EXIT 1" >>confdefs.h
+
+else
+
+       ac_fn_c_check_member "$LINENO" "struct utmp" "ut_exit.e_termination" "ac_cv_member_struct_utmp_ut_exit_e_termination" "
+           #include <sys/types.h>
+           #include <utmp.h>
+
+"
+if test "x$ac_cv_member_struct_utmp_ut_exit_e_termination" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMP_UT_EXIT_E_TERMINATION 1
+_ACEOF
+
+$as_echo "#define HAVE_STRUCT_UTMP_UT_EXIT 1" >>confdefs.h
+
+fi
+
+
+fi
+
+fi
+CFLAGS="$_CFLAGS"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking type of array argument to getgroups" >&5
+$as_echo_n "checking type of array argument to getgroups... " >&6; }
+if test "${ac_cv_type_getgroups+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ac_cv_type_getgroups=cross
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Thanks to Mike Rendell for this test.  */
+$ac_includes_default
+#define NGID 256
+#undef MAX
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+
+int
+main ()
+{
+  gid_t gidset[NGID];
+  int i, n;
+  union { gid_t gval; long int lval; }  val;
+
+  val.lval = -1;
+  for (i = 0; i < NGID; i++)
+    gidset[i] = val.gval;
+  n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1,
+                gidset);
+  /* Exit non-zero if getgroups seems to require an array of ints.  This
+     happens when gid_t is short int but getgroups modifies an array
+     of ints.  */
+  return n > 0 && gidset[n] != val.gval;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_type_getgroups=gid_t
+else
+  ac_cv_type_getgroups=int
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+if test $ac_cv_type_getgroups = cross; then
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <unistd.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "getgroups.*int.*gid_t" >/dev/null 2>&1; then :
+  ac_cv_type_getgroups=gid_t
+else
+  ac_cv_type_getgroups=int
+fi
+rm -f conftest*
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_getgroups" >&5
+$as_echo "$ac_cv_type_getgroups" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define GETGROUPS_T $ac_cv_type_getgroups
+_ACEOF
+
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+ac_fn_c_check_func "$LINENO" "getgroups" "ac_cv_func_getgroups"
 if test "x$ac_cv_func_getgroups" = x""yes; then :
 
 fi
@@ -15126,10 +15415,9 @@ $as_echo "#define HAVE_GETGROUPS 1" >>confdefs.h
 fi
 LIBS=$ac_save_LIBS
 
-for ac_func in strchr strrchr memchr memcpy memset sysconf tzset \
-              strftime setrlimit initgroups getgroups fstat gettimeofday \
-              regcomp setlocale nl_langinfo getaddrinfo setenv \
-              mbr_check_membership setrlimit64
+for ac_func in strrchr sysconf tzset strftime initgroups getgroups fstat \
+              regcomp setlocale nl_langinfo getaddrinfo mbr_check_membership \
+              setrlimit64 sysctl
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -15173,68 +15461,22 @@ done
 fi
 done
 
-for ac_func in setsid
+utmp_style=LEGACY
+for ac_func in getutxid getutid
 do :
-  ac_fn_c_check_func "$LINENO" "setsid" "ac_cv_func_setsid"
-if test "x$ac_cv_func_setsid" = x""yes; then :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+eval as_val=\$$as_ac_var
+   if test "x$as_val" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
-#define HAVE_SETSID 1
-_ACEOF
-
-else
-
-    case " $LIBOBJS " in
-  *" setsid.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS setsid.$ac_objext"
- ;;
-esac
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether setpgrp takes no argument" >&5
-$as_echo_n "checking whether setpgrp takes no argument... " >&6; }
-if test "${ac_cv_func_setpgrp_void+set}" = set; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test "$cross_compiling" = yes; then :
-  as_fn_error "cannot check setpgrp when cross compiling" "$LINENO" 5
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-/* If this system has a BSD-style setpgrp which takes arguments,
-  setpgrp(1, 1) will fail with ESRCH and return -1, in that case
-  exit successfully. */
-  return setpgrp (1,1) != -1;
-  ;
-  return 0;
-}
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
 _ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-  ac_cv_func_setpgrp_void=no
-else
-  ac_cv_func_setpgrp_void=yes
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-  conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_setpgrp_void" >&5
-$as_echo "$ac_cv_func_setpgrp_void" >&6; }
-if test $ac_cv_func_setpgrp_void = yes; then
-
-$as_echo "#define SETPGRP_VOID 1" >>confdefs.h
-
-fi
-
-
+ utmp_style=POSIX; break
 fi
 done
 
-
-for ac_func in sysctl getutxid getutid
+if test "$utmp_style" = "LEGACY"; then
+    for ac_func in getttyent ttyslot
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -15247,6 +15489,7 @@ _ACEOF
 fi
 done
 
+fi
 
 for ac_func in openpty
 do :
 
 done
 
-       SUDO_LIBS="${SUDO_LIBS} -lutil"
+       case "$SUDO_LIBS" in
+           *-lutil*) ;;
+           *) SUDO_LIBS="${SUDO_LIBS} -lutil";;
+       esac
        $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h
 
 
@@ -15436,41 +15682,15 @@ $as_echo "#define UNSETENV_VOID 1" >>confdefs.h
 
     fi
 
-fi
-done
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether putenv has a const argument" >&5
-$as_echo_n "checking whether putenv has a const argument... " >&6; }
-if test "${sudo_cv_func_putenv_const+set}" = set; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-$ac_includes_default
-int putenv(const char *string) {return 0;}
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  sudo_cv_func_putenv_const=yes
 else
-  sudo_cv_func_putenv_const=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  case " $LIBOBJS " in
+  *" unsetenv.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS unsetenv.$ac_objext"
+ ;;
+esac
 
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv_func_putenv_const" >&5
-$as_echo "$sudo_cv_func_putenv_const" >&6; }
-  if test $sudo_cv_func_putenv_const = yes; then
-
-$as_echo "#define PUTENV_CONST 1" >>confdefs.h
-
-  fi
+done
 
 if test -z "$SKIP_SETRESUID"; then
     for ac_func in setresuid
@@ -15480,7 +15700,20 @@ if test "x$ac_cv_func_setresuid" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_SETRESUID 1
 _ACEOF
- SKIP_SETREUID=yes
+
+       SKIP_SETREUID=yes
+       for ac_func in getresuid
+do :
+  ac_fn_c_check_func "$LINENO" "getresuid" "ac_cv_func_getresuid"
+if test "x$ac_cv_func_getresuid" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GETRESUID 1
+_ACEOF
+
+fi
+done
+
+
 fi
 done
 
@@ -15614,19 +15847,6 @@ _ACEOF
 fi
 done
 
-for ac_func in waitpid wait3
-do :
-  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-eval as_val=\$$as_ac_var
-   if test "x$as_val" = x""yes; then :
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
- break
-fi
-done
-
 for ac_func in innetgr _innetgr
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -15787,7 +16007,7 @@ esac
 
   fi
 
-for ac_func in memrchr strerror strcasecmp sigaction strlcpy strlcat
+for ac_func in memrchr strlcpy strlcat setenv
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -15856,7 +16076,7 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_nanosleep" >&5
 $as_echo "$ac_cv_lib_rt_nanosleep" >&6; }
 if test "x$ac_cv_lib_rt_nanosleep" = x""yes; then :
-  LIBS="${LIBS} -lrt"
+  REPLAY_LIBS="${REPLAY_LIBS} -lrt"
 else
   case " $LIBOBJS " in
   *" nanosleep.$ac_objext "* ) ;;
 fi
 done
 
-for ac_func in mkstemps
+for ac_func in mkstemps mkdtemp
 do :
-  ac_fn_c_check_func "$LINENO" "mkstemps" "ac_cv_func_mkstemps"
-if test "x$ac_cv_func_mkstemps" = x""yes; then :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+eval as_val=\$$as_ac_var
+   if test "x$as_val" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
-#define HAVE_MKSTEMPS 1
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
 _ACEOF
 
 else
-  SUDO_OBJS="${SUDO_OBJS} mkstemps.o"
+
     for ac_func in random lrand48
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -15920,6 +16142,12 @@ _ACEOF
 fi
 done
 
+    case " $LIBOBJS " in
+  *" mktemp.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS mktemp.$ac_objext"
+ ;;
+esac
+
 
 fi
 done
 done
 
 
+case ${enable_zlib-"yes"} in
+    yes)
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gzdopen in -lz" >&5
+$as_echo_n "checking for gzdopen in -lz... " >&6; }
+if test "${ac_cv_lib_z_gzdopen+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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 gzdopen ();
+int
+main ()
+{
+return gzdopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_z_gzdopen=yes
+else
+  ac_cv_lib_z_gzdopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzdopen" >&5
+$as_echo "$ac_cv_lib_z_gzdopen" >&6; }
+if test "x$ac_cv_lib_z_gzdopen" = x""yes; then :
+
+           for ac_header in zlib.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
+if test "x$ac_cv_header_zlib_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_ZLIB_H 1
+_ACEOF
+ ZLIB="-lz"
+else
+  enable_zlib=builtin
+fi
+
+done
+
+
+fi
+
+       ;;
+    no)
+       ;;
+    system)
+       $as_echo "#define HAVE_ZLIB_H 1" >>confdefs.h
+
+       ZLIB="-lz"
+       ;;
+    builtin)
+       # handled below
+       ;;
+    *)
+       $as_echo "#define HAVE_ZLIB_H 1" >>confdefs.h
+
+       CPPFLAGS="${CPPFLAGS} -I${enable_zlib}/include"
+
+    if test X"$with_rpath" = X"yes"; then
+       case "$host" in
+           *-*-hpux*)  ZLIB="${ZLIB} -L$enable_zlib/lib -Wl,+b,$enable_zlib/lib"
+                       ;;
+           *)          ZLIB="${ZLIB} -L$enable_zlib/lib -Wl,-R$enable_zlib/lib"
+                       ;;
+       esac
+    else
+       ZLIB="${ZLIB} -L$enable_zlib/lib"
+    fi
+    if test X"$blibpath" != X"" -a "ZLIB" = "SUDO_LDFLAGS"; then
+       blibpath_add="${blibpath_add}:$enable_zlib/lib"
+    fi
+
+       ZLIB="${ZLIB} -lz"
+       ;;
+esac
+if test X"$enable_zlib" = X"builtin"; then
+    $as_echo "#define HAVE_ZLIB_H 1" >>confdefs.h
+
+    CPPFLAGS="${CPPFLAGS}"' -I$(top_srcdir)/zlib'
+    ZLIB="${ZLIB}"' $(top_builddir)/zlib/libz.la'
+    ZLIB_SRC=zlib
+    ac_config_headers="$ac_config_headers zlib/zconf.h"
+
+    ac_config_files="$ac_config_files zlib/Makefile"
+
+fi
+
 for ac_func in strsignal
 do :
   ac_fn_c_check_func "$LINENO" "strsignal" "ac_cv_func_strsignal"
@@ -16571,48 +16901,8 @@ if test -z "${AUTH_EXCL}${AUTH_REG}" -a -n "$AUTH_EXCL_DEF"; then
 fi
 
 if test ${with_pam-"no"} != "no"; then
-                case "$LIBS" in
-       *-ldl*) SUDO_LIBS="${SUDO_LIBS} -lpam"
-               ;;
-       *)      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -ldl" >&5
-$as_echo_n "checking for main in -ldl... " >&6; }
-if test "${ac_cv_lib_dl_main+set}" = set; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-
-int
-main ()
-{
-return main ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_dl_main=yes
-else
-  ac_cv_lib_dl_main=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_main" >&5
-$as_echo "$ac_cv_lib_dl_main" >&6; }
-if test "x$ac_cv_lib_dl_main" = x""yes; then :
-  SUDO_LIBS="${SUDO_LIBS} -lpam -ldl"
-else
-  SUDO_LIBS="${SUDO_LIBS} -lpam"
-fi
-
-               ac_cv_lib_dl=ac_cv_lib_dl_main
-               ;;
-    esac
+    # Note: we already link the main sudo program with -ldl as needed
+    SUDOERS_LIBS="${SUDOERS_LIBS} -lpam"
 
                     for ac_header in security/pam_appl.h pam/pam_appl.h
 do :
@@ -16631,7 +16921,7 @@ done
     if test "$with_pam" = "yes"; then
        $as_echo "#define HAVE_PAM 1" >>confdefs.h
 
-       AUTH_OBJS="$AUTH_OBJS pam.o";
+       AUTH_OBJS="$AUTH_OBJS pam.lo";
        AUTH_EXCL=PAM
 
 
@@ -16662,8 +16952,7 @@ $as_echo "yes" >&6; }
                        ;;
                no)             { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-
-$as_echo "#define NO_PAM_SESSION /**/" >>confdefs.h
+                           $as_echo "#define NO_PAM_SESSION 1" >>confdefs.h
 
                            ;;
                *)              { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
@@ -16754,8 +17043,8 @@ if test ${with_aixauth-'no'} != "no"; then
 $as_echo "$as_me: using AIX general authentication" >&6;}
        $as_echo "#define HAVE_AIXAUTH 1" >>confdefs.h
 
-       AUTH_OBJS="$AUTH_OBJS aix_auth.o";
-       SUDO_LIBS="${SUDO_LIBS} -ls"
+       AUTH_OBJS="$AUTH_OBJS aix_auth.lo";
+       SUDOERS_LIBS="${SUDOERS_LIBS} -ls"
        AUTH_EXCL=AIX_AUTH
     fi
 fi
@@ -16765,7 +17054,7 @@ if test ${with_bsdauth-'no'} != "no"; then
 if test "x$ac_cv_header_bsd_auth_h" = x""yes; then :
   $as_echo "#define HAVE_BSD_AUTH_H 1" >>confdefs.h
 
-       AUTH_OBJS="$AUTH_OBJS bsdauth.o"
+       AUTH_OBJS="$AUTH_OBJS bsdauth.lo"
        BSDAUTH_USAGE='[-a auth_type] '
        AUTH_EXCL=BSD_AUTH; BAMAN=1
 else
@@ -16791,7 +17080,7 @@ done
 
     if test "$found" = "true"; then
        AUTH_EXCL=SIA
-       AUTH_OBJS="$AUTH_OBJS sia.o"
+       AUTH_OBJS="$AUTH_OBJS sia.lo"
     fi
 fi
 
@@ -16800,23 +17089,23 @@ if test ${with_fwtk-'no'} != "no"; then
 
     if test X"$with_rpath" = X"yes"; then
        case "$host" in
-           *-*-hpux*)  SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_fwtk} -Wl,+b,${with_fwtk}"
+           *-*-hpux*)  SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_fwtk} -Wl,+b,${with_fwtk}"
                        ;;
-           *)          SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_fwtk} -Wl,-R${with_fwtk}"
+           *)          SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_fwtk} -Wl,-R${with_fwtk}"
                        ;;
        esac
     else
-       SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_fwtk}"
+       SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_fwtk}"
     fi
-    if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then
+    if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then
        blibpath_add="${blibpath_add}:${with_fwtk}"
     fi
 
        CPPFLAGS="${CPPFLAGS} -I${with_fwtk}"
        with_fwtk=yes
     fi
-    SUDO_LIBS="${SUDO_LIBS} -lauth -lfwall"
-    AUTH_OBJS="$AUTH_OBJS fwtk.o"
+    SUDOERS_LIBS="${SUDOERS_LIBS} -lauth -lfwall"
+    AUTH_OBJS="$AUTH_OBJS fwtk.lo"
 fi
 
 if test ${with_SecurID-'no'} != "no"; then
 $as_echo "$ac_cv_lib_aceclnt_SD_Init_______lpthread_______" >&6; }
 if test "x$ac_cv_lib_aceclnt_SD_Init_______lpthread_______" = x""yes; then :
 
-           AUTH_OBJS="$AUTH_OBJS securid5.o";
-           SUDO_LIBS="${SUDO_LIBS} -laceclnt -lpthread"
+           AUTH_OBJS="$AUTH_OBJS securid5.lo";
+           SUDOERS_LIBS="${SUDOERS_LIBS} -laceclnt -lpthread"
 
 
 
     if test X"$with_rpath" = X"yes"; then
        case "$host" in
-           *-*-hpux*)  SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_SecurID} -Wl,+b,${with_SecurID}"
+           *-*-hpux*)  SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_SecurID} -Wl,+b,${with_SecurID}"
                        ;;
-           *)          SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_SecurID} -Wl,-R${with_SecurID}"
+           *)          SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_SecurID} -Wl,-R${with_SecurID}"
                        ;;
        esac
     else
-       SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_SecurID}"
+       SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_SecurID}"
     fi
-    if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then
+    if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then
        blibpath_add="${blibpath_add}:${with_SecurID}"
     fi
 
 
 else
 
-           AUTH_OBJS="$AUTH_OBJS securid.o";
-           SUDO_LIBS="${SUDO_LIBS} ${with_SecurID}/sdiclient.a"
+           AUTH_OBJS="$AUTH_OBJS securid.lo";
+           SUDOERS_LIBS="${SUDOERS_LIBS} ${with_SecurID}/sdiclient.a"
 
 fi
 
@@ -16965,15 +17254,15 @@ rm -f conftest.err conftest.$ac_ext
 
     if test X"$with_rpath" = X"yes"; then
        case "$host" in
-           *-*-hpux*)  SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_kerb4}/lib -Wl,+b,${with_kerb4}/lib"
+           *-*-hpux*)  SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_kerb4}/lib -Wl,+b,${with_kerb4}/lib"
                        ;;
-           *)          SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_kerb4}/lib -Wl,-R${with_kerb4}/lib"
+           *)          SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_kerb4}/lib -Wl,-R${with_kerb4}/lib"
                        ;;
        esac
     else
-       SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_kerb4}/lib"
+       SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_kerb4}/lib"
     fi
-    if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then
+    if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then
        blibpath_add="${blibpath_add}:${with_kerb4}/lib"
     fi
 
@@ -17212,8 +17501,8 @@ eval as_val=\$$as_ac_Lib
   K4LIBS="-lkrb4 $K4LIBS"
 else
   K4LIBS="-lkrb $K4LIBS"
-           { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate Kerberos IV libraries, you will have to edit the Makefile and add -L/path/to/krb/libs to SUDO_LDFLAGS and possibly add Kerberos libs to SUDO_LIBS" >&5
-$as_echo "$as_me: WARNING: Unable to locate Kerberos IV libraries, you will have to edit the Makefile and add -L/path/to/krb/libs to SUDO_LDFLAGS and possibly add Kerberos libs to SUDO_LIBS" >&2;}
+           { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate Kerberos IV libraries, you will have to edit the Makefile and add -L/path/to/krb/libs to SUDOERS_LDFLAGS and possibly add Kerberos libs to SUDOERS_LIBS" >&5
+$as_echo "$as_me: WARNING: Unable to locate Kerberos IV libraries, you will have to edit the Makefile and add -L/path/to/krb/libs to SUDOERS_LDFLAGS and possibly add Kerberos libs to SUDOERS_LIBS" >&2;}
 
 fi
 
@@ -17221,8 +17510,8 @@ fi
 fi
 
     LDFLAGS="$O_LDFLAGS"
-    SUDO_LIBS="${SUDO_LIBS} $K4LIBS"
-    AUTH_OBJS="$AUTH_OBJS kerb4.o"
+    SUDOERS_LIBS="${SUDOERS_LIBS} $K4LIBS"
+    AUTH_OBJS="$AUTH_OBJS kerb4.lo"
 fi
 
 if test ${with_kerb5-'no'} != "no"; then
@@ -17267,9 +17556,9 @@ fi
     if test -n "$KRB5CONFIG"; then
        $as_echo "#define HAVE_KERB5 1" >>confdefs.h
 
-       AUTH_OBJS="$AUTH_OBJS kerb5.o"
+       AUTH_OBJS="$AUTH_OBJS kerb5.lo"
        CPPFLAGS="$CPPFLAGS `krb5-config --cflags`"
-       SUDO_LIBS="$SUDO_LIBS `krb5-config --libs`"
+       SUDOERS_LIBS="$SUDOERS_LIBS `krb5-config --libs`"
                                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using Heimdal" >&5
 $as_echo_n "checking whether we are using Heimdal... " >&6; }
        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -17298,17 +17587,15 @@ $as_echo "no" >&6; }
 
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-    fi
-fi
-if test ${with_kerb5-'no'} != "no" -a -z "$KRB5CONFIG"; then
-    $as_echo "#define HAVE_KERB5 1" >>confdefs.h
+    else
+       $as_echo "#define HAVE_KERB5 1" >>confdefs.h
 
-                if test "$with_kerb5" = "yes"; then
-       found=no
-       O_CPPFLAGS="$CPPFLAGS"
-       for dir in "" "kerberosV/" "krb5/" "kerberos5/" "kerberosv5/"; do
-           CPPFLAGS="$O_CPPFLAGS -I/usr/include/${dir}"
-           cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+                               if test "$with_kerb5" = "yes"; then
+           found=no
+           O_CPPFLAGS="$CPPFLAGS"
+           for dir in "" "kerberosV/" "krb5/" "kerberos5/" "kerberosv5/"; do
+               CPPFLAGS="$O_CPPFLAGS -I/usr/include/${dir}"
+               cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <krb5.h>
 _ACEOF
@@ -17316,34 +17603,34 @@ if ac_fn_c_try_cpp "$LINENO"; then :
   found=yes; break
 fi
 rm -f conftest.err conftest.$ac_ext
-       done
-       if test X"$found" = X"no"; then
-           CPPFLAGS="$O_CPPFLAGS"
-           { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate Kerberos V include files, you will have to edit the Makefile and add -I/path/to/krb/includes to CPPFLAGS" >&5
+           done
+           if test X"$found" = X"no"; then
+               CPPFLAGS="$O_CPPFLAGS"
+               { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate Kerberos V include files, you will have to edit the Makefile and add -I/path/to/krb/includes to CPPFLAGS" >&5
 $as_echo "$as_me: WARNING: Unable to locate Kerberos V include files, you will have to edit the Makefile and add -I/path/to/krb/includes to CPPFLAGS" >&2;}
-       fi
-    else
+           fi
+       else
 
     if test X"$with_rpath" = X"yes"; then
        case "$host" in
-           *-*-hpux*)  SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_kerb5}/lib -Wl,+b,${with_kerb5}/lib"
+           *-*-hpux*)  SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_kerb5}/lib -Wl,+b,${with_kerb5}/lib"
                        ;;
-           *)          SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_kerb5}/lib -Wl,-R${with_kerb5}/lib"
+           *)          SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_kerb5}/lib -Wl,-R${with_kerb5}/lib"
                        ;;
        esac
     else
-       SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_kerb5}/lib"
+       SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_kerb5}/lib"
     fi
-    if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then
+    if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then
        blibpath_add="${blibpath_add}:${with_kerb5}/lib"
     fi
 
-       CPPFLAGS="$CPPFLAGS -I${with_kerb5}/include"
-    fi
+           CPPFLAGS="$CPPFLAGS -I${with_kerb5}/include"
+       fi
 
-                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using Heimdal" >&5
+                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using Heimdal" >&5
 $as_echo_n "checking whether we are using Heimdal... " >&6; }
-    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <krb5.h>
 int
@@ -17356,13 +17643,13 @@ const char *tmp = heimdal_version;
 _ACEOF
 if ac_fn_c_try_compile "$LINENO"; then :
 
-           { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-           $as_echo "#define HAVE_HEIMDAL 1" >>confdefs.h
+               $as_echo "#define HAVE_HEIMDAL 1" >>confdefs.h
 
-           # XXX - need to check whether -lcrypo is needed!
-           SUDO_LIBS="${SUDO_LIBS} -lkrb5 -lcrypto -ldes -lcom_err -lasn1"
-           { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lroken" >&5
+               # XXX - need to check whether -lcrypo is needed!
+               SUDOERS_LIBS="${SUDOERS_LIBS} -lkrb5 -lcrypto -ldes -lcom_err -lasn1"
+               { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lroken" >&5
 $as_echo_n "checking for main in -lroken... " >&6; }
 if test "${ac_cv_lib_roken_main+set}" = set; then :
   $as_echo_n "(cached) " >&6
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_roken_main" >&5
 $as_echo "$ac_cv_lib_roken_main" >&6; }
 if test "x$ac_cv_lib_roken_main" = x""yes; then :
-  SUDO_LIBS="${SUDO_LIBS} -lroken"
+  SUDOERS_LIBS="${SUDOERS_LIBS} -lroken"
 fi
 
 
 else
 
-           { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-           SUDO_LIBS="${SUDO_LIBS} -lkrb5 -lk5crypto -lcom_err"
-           { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lkrb5support" >&5
+               SUDOERS_LIBS="${SUDOERS_LIBS} -lkrb5 -lk5crypto -lcom_err"
+               { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lkrb5support" >&5
 $as_echo_n "checking for main in -lkrb5support... " >&6; }
 if test "${ac_cv_lib_krb5support_main+set}" = set; then :
   $as_echo_n "(cached) " >&6
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_krb5support_main" >&5
 $as_echo "$ac_cv_lib_krb5support_main" >&6; }
 if test "x$ac_cv_lib_krb5support_main" = x""yes; then :
-  SUDO_LIBS="${SUDO_LIBS} -lkrb5support"
+  SUDOERS_LIBS="${SUDOERS_LIBS} -lkrb5support"
 fi
 
 
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-    AUTH_OBJS="$AUTH_OBJS kerb5.o"
+       AUTH_OBJS="$AUTH_OBJS kerb5.lo"
+    fi
     _LIBS="$LIBS"
-    LIBS="${LIBS} ${SUDO_LIBS}"
+    LIBS="${LIBS} ${SUDOERS_LIBS}"
     for ac_func in krb5_verify_user krb5_init_secure_context
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -17469,7 +17757,7 @@ if test "${sudo_cv_krb5_get_init_creds_opt_free_two_args+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
 
-              cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+               cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <krb5.h>
 int
@@ -17513,15 +17801,15 @@ if test ${with_AFS-'no'} = "yes"; then
 
     if test X"$with_rpath" = X"yes"; then
        case "$host" in
-           *-*-hpux*)  SUDO_LDFLAGS="${SUDO_LDFLAGS} -L$i -Wl,+b,$i"
+           *-*-hpux*)  SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L$i -Wl,+b,$i"
                        ;;
-           *)          SUDO_LDFLAGS="${SUDO_LDFLAGS} -L$i -Wl,-R$i"
+           *)          SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L$i -Wl,-R$i"
                        ;;
        esac
     else
-       SUDO_LDFLAGS="${SUDO_LDFLAGS} -L$i"
+       SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L$i"
     fi
-    if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then
+    if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then
        blibpath_add="${blibpath_add}:$i"
     fi
 
@@ -17529,8 +17817,8 @@ if test ${with_AFS-'no'} = "yes"; then
        fi
     done
     if test -z "$FOUND_AFSLIBDIR"; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate AFS libraries, you will have to edit the Makefile and add -L/path/to/afs/libs to SUDO_LDFLAGS or rerun configure with the --with-libpath options." >&5
-$as_echo "$as_me: WARNING: Unable to locate AFS libraries, you will have to edit the Makefile and add -L/path/to/afs/libs to SUDO_LDFLAGS or rerun configure with the --with-libpath options." >&2;}
+       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate AFS libraries, you will have to edit the Makefile and add -L/path/to/afs/libs to SUDOERS_LDFLAGS or rerun configure with the --with-libpath options." >&5
+$as_echo "$as_me: WARNING: Unable to locate AFS libraries, you will have to edit the Makefile and add -L/path/to/afs/libs to SUDOERS_LDFLAGS or rerun configure with the --with-libpath options." >&2;}
     fi
 
     # Order is important here.  Note that we build AFS_LIBS from right to left
@@ -17561,13 +17849,13 @@ $as_echo "$as_me: WARNING: Unable to locate AFS libraries, you will have to edit
 $as_echo "$as_me: WARNING: Unable to locate AFS include dir, you may have to edit the Makefile and add -I/path/to/afs/includes to CPPFLAGS or rerun configure with the --with-incpath options." >&2;}
     fi
 
-    AUTH_OBJS="$AUTH_OBJS afs.o"
+    AUTH_OBJS="$AUTH_OBJS afs.lo"
 fi
 
 if test ${with_DCE-'no'} = "yes"; then
     DCE_OBJS="${DCE_OBJS} dce_pwent.o"
-    SUDO_LIBS="${SUDO_LIBS} -ldce"
-    AUTH_OBJS="$AUTH_OBJS dce.o"
+    SUDOERS_LIBS="${SUDOERS_LIBS} -ldce"
+    AUTH_OBJS="$AUTH_OBJS dce.lo"
 fi
 
 if test "${with_skey-'no'}" = "yes"; then
@@ -17592,41 +17880,39 @@ if test "${with_skey-'no'}" = "yes"; then
 
     if test X"$with_rpath" = X"yes"; then
        case "$host" in
-           *-*-hpux*)  SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_skey}/lib -Wl,+b,${with_skey}/lib"
+           *-*-hpux*)  SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_skey}/lib -Wl,+b,${with_skey}/lib"
                        ;;
-           *)          SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_skey}/lib -Wl,-R${with_skey}/lib"
+           *)          SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_skey}/lib -Wl,-R${with_skey}/lib"
                        ;;
        esac
     else
-       SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_skey}/lib"
+       SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_skey}/lib"
     fi
-    if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then
+    if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then
        blibpath_add="${blibpath_add}:${with_skey}/lib"
     fi
 
-       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <skey.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+       ac_fn_c_check_header_compile "$LINENO" "skey.h" "ac_cv_header_skey_h" "#include <stdio.h>
+"
+if test "x$ac_cv_header_skey_h" = x""yes; then :
   found=yes
 else
   found=no
 fi
-rm -f conftest.err conftest.$ac_ext
+
+
     else
        found=no
        O_CPPFLAGS="$CPPFLAGS"
        for dir in "" "/usr/local" "/usr/contrib"; do
            test -n "$dir" && CPPFLAGS="$O_CPPFLAGS -I${dir}/include"
-           cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <skey.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+           ac_fn_c_check_header_compile "$LINENO" "skey.h" "ac_cv_header_skey_h" "#include <stdio.h>
+"
+if test "x$ac_cv_header_skey_h" = x""yes; then :
   found=yes; break
 fi
-rm -f conftest.err conftest.$ac_ext
+
+
        done
        if test "$found" = "no" -o -z "$dir"; then
            CPPFLAGS="$O_CPPFLAGS"
@@ -17649,23 +17935,23 @@ rm -f conftest.err conftest.$ac_ext
 
     if test X"$with_rpath" = X"yes"; then
        case "$host" in
-           *-*-hpux*)  SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${dir}/lib -Wl,+b,${dir}/lib"
+           *-*-hpux*)  SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${dir}/lib -Wl,+b,${dir}/lib"
                        ;;
-           *)          SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${dir}/lib -Wl,-R${dir}/lib"
+           *)          SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${dir}/lib -Wl,-R${dir}/lib"
                        ;;
        esac
     else
-       SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${dir}/lib"
+       SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${dir}/lib"
     fi
-    if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then
+    if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then
        blibpath_add="${blibpath_add}:${dir}/lib"
     fi
 
        fi
-    fi
-    if test "$found" = "no"; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate skey.h, you will have to edit the Makefile and add -I/path/to/skey/includes to CPPFLAGS" >&5
+       if test "$found" = "no"; then
+           { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate skey.h, you will have to edit the Makefile and add -I/path/to/skey/includes to CPPFLAGS" >&5
 $as_echo "$as_me: WARNING: Unable to locate skey.h, you will have to edit the Makefile and add -I/path/to/skey/includes to CPPFLAGS" >&2;}
+       fi
     fi
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lskey" >&5
 $as_echo_n "checking for main in -lskey... " >&6; }
@@ -17700,8 +17986,8 @@ $as_echo "$ac_cv_lib_skey_main" >&6; }
 if test "x$ac_cv_lib_skey_main" = x""yes; then :
   found=yes
 else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate libskey.a, you will have to edit the Makefile and add -L/path/to/skey/lib to SUDO_LDFLAGS" >&5
-$as_echo "$as_me: WARNING: Unable to locate libskey.a, you will have to edit the Makefile and add -L/path/to/skey/lib to SUDO_LDFLAGS" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate libskey.a, you will have to edit the Makefile and add -L/path/to/skey/lib to SUDOERS_LDFLAGS" >&5
+$as_echo "$as_me: WARNING: Unable to locate libskey.a, you will have to edit the Makefile and add -L/path/to/skey/lib to SUDOERS_LDFLAGS" >&2;}
 fi
 
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for skeyaccess in -lskey" >&5
@@ -17745,9 +18031,41 @@ if test "x$ac_cv_lib_skey_skeyaccess" = x""yes; then :
 
 fi
 
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for RFC1938-compliant skeychallenge" >&5
+$as_echo_n "checking for RFC1938-compliant skeychallenge... " >&6; }
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+           #include <skey.h>
+int
+main ()
+{
+skeychallenge(NULL, NULL, NULL, 0);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+           $as_echo "#define HAVE_RFC1938_SKEYCHALLENGE 1" >>confdefs.h
+
+           { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+
+           { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
     LDFLAGS="$O_LDFLAGS"
-    SUDO_LIBS="${SUDO_LIBS} -lskey"
-    AUTH_OBJS="$AUTH_OBJS rfc1938.o"
+    SUDOERS_LIBS="${SUDOERS_LIBS} -lskey"
+    AUTH_OBJS="$AUTH_OBJS rfc1938.lo"
 fi
 
 if test "${with_opie-'no'}" = "yes"; then
@@ -17772,15 +18090,15 @@ if test "${with_opie-'no'}" = "yes"; then
 
     if test X"$with_rpath" = X"yes"; then
        case "$host" in
-           *-*-hpux*)  SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_opie}/lib -Wl,+b,${with_opie}/lib"
+           *-*-hpux*)  SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_opie}/lib -Wl,+b,${with_opie}/lib"
                        ;;
-           *)          SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_opie}/lib -Wl,-R${with_opie}/lib"
+           *)          SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_opie}/lib -Wl,-R${with_opie}/lib"
                        ;;
        esac
     else
-       SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_opie}/lib"
+       SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_opie}/lib"
     fi
-    if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then
+    if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then
        blibpath_add="${blibpath_add}:${with_opie}/lib"
     fi
 
@@ -17829,23 +18147,23 @@ rm -f conftest.err conftest.$ac_ext
 
     if test X"$with_rpath" = X"yes"; then
        case "$host" in
-           *-*-hpux*)  SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${dir}/lib -Wl,+b,${dir}/lib"
+           *-*-hpux*)  SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${dir}/lib -Wl,+b,${dir}/lib"
                        ;;
-           *)          SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${dir}/lib -Wl,-R${dir}/lib"
+           *)          SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${dir}/lib -Wl,-R${dir}/lib"
                        ;;
        esac
     else
-       SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${dir}/lib"
+       SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${dir}/lib"
     fi
-    if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then
+    if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then
        blibpath_add="${blibpath_add}:${dir}/lib"
     fi
 
        fi
-    fi
-    if test "$found" = "no"; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate opie.h, you will have to edit the Makefile and add -I/path/to/opie/includes to CPPFLAGS" >&5
+       if test "$found" = "no"; then
+           { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate opie.h, you will have to edit the Makefile and add -I/path/to/opie/includes to CPPFLAGS" >&5
 $as_echo "$as_me: WARNING: Unable to locate opie.h, you will have to edit the Makefile and add -I/path/to/opie/includes to CPPFLAGS" >&2;}
+       fi
     fi
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lopie" >&5
 $as_echo_n "checking for main in -lopie... " >&6; }
@@ -17880,17 +18198,18 @@ $as_echo "$ac_cv_lib_opie_main" >&6; }
 if test "x$ac_cv_lib_opie_main" = x""yes; then :
   found=yes
 else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate libopie.a, you will have to edit the Makefile and add -L/path/to/opie/lib to SUDO_LDFLAGS" >&5
-$as_echo "$as_me: WARNING: Unable to locate libopie.a, you will have to edit the Makefile and add -L/path/to/opie/lib to SUDO_LDFLAGS" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate libopie.a, you will have to edit the Makefile and add -L/path/to/opie/lib to SUDOERS_LDFLAGS" >&5
+$as_echo "$as_me: WARNING: Unable to locate libopie.a, you will have to edit the Makefile and add -L/path/to/opie/lib to SUDOERS_LDFLAGS" >&2;}
 fi
 
     LDFLAGS="$O_LDFLAGS"
-    SUDO_LIBS="${SUDO_LIBS} -lopie"
-    AUTH_OBJS="$AUTH_OBJS rfc1938.o"
+    SUDOERS_LIBS="${SUDOERS_LIBS} -lopie"
+    AUTH_OBJS="$AUTH_OBJS rfc1938.lo"
 fi
 
 if test ${with_passwd-'no'} != "no"; then
                 if test -z "$LIB_CRYPT"; then
+       _LIBS="$LIBS"
        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing crypt" >&5
 $as_echo_n "checking for library containing crypt... " >&6; }
 if test "${ac_cv_search_crypt+set}" = set; then :
@@ -17944,9 +18263,10 @@ $as_echo "$ac_cv_search_crypt" >&6; }
 ac_res=$ac_cv_search_crypt
 if test "$ac_res" != no; then :
   test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-  test -n "$ac_lib" && SUDO_LIBS="${SUDO_LIBS} $ac_res"
+  test -n "$ac_lib" && SUDOERS_LIBS="${SUDOERS_LIBS} $ac_res"
 fi
 
+       LIBS="$_LIBS"
     fi
 
     if test "$CHECKSHADOW" = "true" -a -n "$shadow_funcs"; then
@@ -17967,7 +18287,7 @@ fi
 done
 
        if test "$found" = "yes"; then
-           SUDO_LIBS="$SUDO_LIBS $shadow_libs"
+           SUDOERS_LIBS="$SUDOERS_LIBS $shadow_libs"
        elif test -n "$shadow_libs_optional"; then
            LIBS="$LIBS $shadow_libs_optional"
            for ac_func in $shadow_funcs
@@ -17984,7 +18304,7 @@ fi
 done
 
            if test "$found" = "yes"; then
-               SUDO_LIBS="$SUDO_LIBS $shadow_libs $shadow_libs_optional"
+               SUDOERS_LIBS="$SUDOERS_LIBS $shadow_libs $shadow_libs_optional"
            fi
        fi
        if test "$found" = "yes"; then
@@ -18052,7 +18372,7 @@ ac_res=$ac_cv_search_getspnam
 if test "$ac_res" != no; then :
   test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
   $as_echo "#define HAVE_GETSPNAM 1" >>confdefs.h
- CHECKSHADOW=false; test -n "$ac_lib" && SUDO_LIBS="${SUDO_LIBS} $ac_res"
+ CHECKSHADOW=false; test -n "$ac_lib" && SUDOERS_LIBS="${SUDOERS_LIBS} $ac_res"
 fi
 
     fi
@@ -18111,7 +18431,7 @@ ac_res=$ac_cv_search_getprpwnam
 if test "$ac_res" != no; then :
   test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
   $as_echo "#define HAVE_GETPRPWNAM 1" >>confdefs.h
- CHECKSHADOW=false; SECUREWARE=1; test -n "$ac_lib" && SUDO_LIBS="${SUDO_LIBS} $ac_res"
+ CHECKSHADOW=false; SECUREWARE=1; test -n "$ac_lib" && SUDOERS_LIBS="${SUDOERS_LIBS} $ac_res"
 fi
 
     fi
@@ -18129,7 +18449,7 @@ _ACEOF
 fi
 done
 
-       AUTH_OBJS="$AUTH_OBJS secureware.o"
+       AUTH_OBJS="$AUTH_OBJS secureware.lo"
     fi
 fi
 
@@ -18139,15 +18459,15 @@ if test ${with_ldap-'no'} != "no"; then
 
     if test X"$with_rpath" = X"yes"; then
        case "$host" in
-           *-*-hpux*)  SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_ldap}/lib -Wl,+b,${with_ldap}/lib"
+           *-*-hpux*)  SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_ldap}/lib -Wl,+b,${with_ldap}/lib"
                        ;;
-           *)          SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_ldap}/lib -Wl,-R${with_ldap}/lib"
+           *)          SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_ldap}/lib -Wl,-R${with_ldap}/lib"
                        ;;
        esac
     else
-       SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_ldap}/lib"
+       SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_ldap}/lib"
     fi
-    if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then
+    if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then
        blibpath_add="${blibpath_add}:${with_ldap}/lib"
     fi
 
@@ -18169,7 +18489,7 @@ if test ${with_ldap-'no'} != "no"; then
        CPPFLAGS="${CPPFLAGS} -I${with_ldap}/include"
        with_ldap=yes
     fi
-    SUDO_OBJS="${SUDO_OBJS} ldap.o"
+    SUDOERS_OBJS="${SUDOERS_OBJS} ldap.lo"
     LDAP=""
 
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LDAP libraries" >&5
@@ -18512,32 +18832,131 @@ $as_echo "$as_me: WARNING: Unable to locate gssapi.h, you will have to edit the
        fi
     fi
 
-    SUDO_LIBS="${SUDO_LIBS} ${LDAP_LIBS}"
+    SUDOERS_LIBS="${SUDOERS_LIBS} ${LDAP_LIBS}"
     LIBS="$_LIBS"
     LDFLAGS="$_LDFLAGS"
 fi
 
-if test X"$LIBVAS_RPATH" != X""; then
-    if test -n "$blibpath"; then
-       blibpath_add="${blibpath_add}:$LIBVAS_RPATH"
-    else
-       case "$host" in
-           *-*-hpux*)  LDFLAGS="$LDFLAGS -Wl,+b,$LIBVAS_RPATH"
-                       ;;
-           *)          LDFLAGS="$LDFLAGS -Wl,-R$LIBVAS_RPATH"
-                       ;;
-       esac
-    fi
+#
+# How to do dynamic object loading.
+# We support dlopen() and sh_load(), else fall back to static loading.
+#
+case "$lt_cv_dlopen" in
+    dlopen)
+       $as_echo "#define HAVE_DLOPEN 1" >>confdefs.h
+
+       SUDOERS_OBJS="$SUDOERS_OBJS plugin_error.lo"
+       LT_STATIC="--tag=disable-static"
+       ;;
+    shl_load)
+       $as_echo "#define HAVE_SHL_LOAD 1" >>confdefs.h
+
+       SUDOERS_OBJS="$SUDOERS_OBJS plugin_error.lo"
+       LT_STATIC="--tag=disable-static"
+       case " $LIBOBJS " in
+  *" dlopen.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS dlopen.$ac_objext"
+ ;;
+esac
+
+       ;;
+    *)
+       # Preload sudoers module symbols
+       SUDO_OBJS="${SUDO_OBJS} preload.o"
+       SUDO_LIBS="${SUDO_LIBS} \$(top_builddir)/plugins/sudoers/sudoers.la"
+       LT_STATIC=""
+       case " $LIBOBJS " in
+  *" dlopen.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS dlopen.$ac_objext"
+ ;;
+esac
+
+       ;;
+esac
+
+#
+# Add library needed for dynamic loading, if any.
+#
+LIBDL="$lt_cv_dlopen_libs"
+if test X"$LIBDL" != X""; then
+    SUDO_LIBS="${SUDO_LIBS} $LIBDL"
+    SUDOERS_LIBS="${SUDOERS_LIBS} $LIBDL"
+fi
+
+# On HP-UX, you cannot dlopen() a shared object that uses pthreads
+# unless the main program is linked against -lpthread.  Since we
+# have no knowledge what libraries a plugin may depend on, we always
+# link against -lpthread on HP-UX if it is available.
+# This check should go after all other libraries tests.
+case "$host" in
+    *-*-hpux*)
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lpthread" >&5
+$as_echo_n "checking for main in -lpthread... " >&6; }
+if test "${ac_cv_lib_pthread_main+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_main=yes
+else
+  ac_cv_lib_pthread_main=no
 fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_main" >&5
+$as_echo "$ac_cv_lib_pthread_main" >&6; }
+if test "x$ac_cv_lib_pthread_main" = x""yes; then :
+  SUDO_LIBS="${SUDO_LIBS} -lpthread"
+fi
+
+       ;;
+esac
 
 if test -n "$blibpath"; then
     if test -n "$blibpath_add"; then
-       SUDO_LDFLAGS="$SUDO_LDFLAGS -Wl,-blibpath:${blibpath}${blibpath_add}"
+       SUDOERS_LDFLAGS="$SUDOERS_LDFLAGS -Wl,-blibpath:${blibpath}${blibpath_add}"
     elif test -n "$with_blibpath" -a "$with_blibpath" != "yes"; then
-       SUDO_LDFLAGS="$SUDO_LDFLAGS -Wl,-blibpath:${blibpath}"
+       SUDOERS_LDFLAGS="$SUDOERS_LDFLAGS -Wl,-blibpath:${blibpath}"
+    fi
+fi
+
+if test "$utmp_style" = "LEGACY"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for utmp file path" >&5
+$as_echo_n "checking for utmp file path... " >&6; }
+found=no
+for p in "/var/run/utmp" "/var/adm/utmp" "/etc/utmp"; do
+    if test -r "$p"; then
+       found=yes
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $p" >&5
+$as_echo "$p" >&6; }
+       cat >>confdefs.h <<EOF
+#define _PATH_UTMP "$p"
+EOF
+
+       break
     fi
+done
+if test X"$found" != X"yes"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
 fi
 
+fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log file location" >&5
 $as_echo_n "checking for log file location... " >&6; }
 if test -n "$with_logpath"; then
@@ -18613,137 +19032,9 @@ EOF
 $as_echo "$iolog_dir" >&6; }
 
 
-if test "${with_iologdir-yes}" != "no"; then
-    # Require POSIX job control for I/O log support
-    for ac_func in tcsetpgrp
-do :
-  ac_fn_c_check_func "$LINENO" "tcsetpgrp" "ac_cv_func_tcsetpgrp"
-if test "x$ac_cv_func_tcsetpgrp" = x""yes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_TCSETPGRP 1
-_ACEOF
-
-       SUDO_OBJS="${SUDO_OBJS} exec_pty.o get_pty.o iolog.o"
-       PROGS="$PROGS sudoreplay"
-       REPLAY=""
-
-       # Check whether --enable-zlib was given.
-if test "${enable_zlib+set}" = set; then :
-  enableval=$enable_zlib;
-fi
-
-       case ${enable_zlib-"yes"} in
-           yes)
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gzdopen in -lz" >&5
-$as_echo_n "checking for gzdopen in -lz... " >&6; }
-if test "${ac_cv_lib_z_gzdopen+set}" = set; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lz  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* 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 gzdopen ();
-int
-main ()
-{
-return gzdopen ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_z_gzdopen=yes
-else
-  ac_cv_lib_z_gzdopen=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzdopen" >&5
-$as_echo "$ac_cv_lib_z_gzdopen" >&6; }
-if test "x$ac_cv_lib_z_gzdopen" = x""yes; then :
-
-                   for ac_header in zlib.h
-do :
-  ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_zlib_h" = x""yes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_ZLIB_H 1
-_ACEOF
- ZLIB="-lz"
-else
-  enable_zlib=builtin
-fi
-
-done
-
-
-fi
-
-               ;;
-           no)
-               ;;
-           system)
-               $as_echo "#define HAVE_ZLIB_H 1" >>confdefs.h
-
-               ZLIB="-lz"
-               ;;
-           builtin)
-               # handled below
-               ;;
-           *)
-               $as_echo "#define HAVE_ZLIB_H 1" >>confdefs.h
-
-               CPPFLAGS="${CPPFLAGS} -I${enable_zlib}/include"
-
-    if test X"$with_rpath" = X"yes"; then
-       case "$host" in
-           *-*-hpux*)  ZLIB="${ZLIB} -L$enable_zlib/lib -Wl,+b,$enable_zlib/lib"
-                       ;;
-           *)          ZLIB="${ZLIB} -L$enable_zlib/lib -Wl,-R$enable_zlib/lib"
-                       ;;
-       esac
-    else
-       ZLIB="${ZLIB} -L$enable_zlib/lib"
-    fi
-    if test X"$blibpath" != X"" -a "ZLIB" = "SUDO_LDFLAGS"; then
-       blibpath_add="${blibpath_add}:$enable_zlib/lib"
-    fi
-
-               ZLIB="${ZLIB} -lz"
-               ;;
-       esac
-       if test X"$enable_zlib" = X"builtin"; then
-           $as_echo "#define HAVE_ZLIB_H 1" >>confdefs.h
-
-           CPPFLAGS="${CPPFLAGS}"' -I$(srcdir)/zlib'
-           ZLIB="${ZLIB} libz.a"
-           ZLIB_DEP=libz.a
-       fi
-
-else
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Disabling I/O log support due to lack of tcsetpgrp function" >&5
-$as_echo "$as_me: WARNING: Disabling I/O log support due to lack of tcsetpgrp function" >&2;}
-       with_iologdir=no
-
-fi
-done
-
-fi
-
 case "$with_passwd" in
 yes|maybe)
-    AUTH_OBJS="$AUTH_OBJS getspwuid.o passwd.o"
+    AUTH_OBJS="$AUTH_OBJS getspwuid.lo passwd.lo"
     ;;
 *)
     $as_echo "#define WITHOUT_PASSWD 1" >>confdefs.h
@@ -18754,7 +19045,7 @@ yes|maybe)
     ;;
 esac
 AUTH_OBJS=${AUTH_OBJS# }
-_AUTH=`echo "$AUTH_OBJS" | sed -e 's/\.o//g' -e 's/getspwuid *//'`
+_AUTH=`echo "$AUTH_OBJS" | sed -e 's/\.lo//g' -e 's/getspwuid *//'`
 { $as_echo "$as_me:${as_lineno-$LINENO}: using the following authentication methods: $_AUTH" >&5
 $as_echo "$as_me: using the following authentication methods: $_AUTH" >&6;}
 
@@ -18763,7 +19054,7 @@ if test -n "$LIBS"; then
     LIBS=
     for l in ${L}; do
        dupe=0
-       for sl in ${SUDO_LIBS} ${NET_LIBS}; do
+       for sl in ${SUDO_LIBS} ${SUDOERS_LIBS} ${NET_LIBS}; do
            test $l = $sl && dupe=1
        done
        test $dupe = 0 && LIBS="${LIBS} $l"
@@ -18798,6 +19089,15 @@ EOF
 EOF
 
     fi
+    eval PLUGINDIR="$with_plugindir"
+    cat >>confdefs.h <<EOF
+#define _PATH_SUDO_PLUGIN_DIR "$PLUGINDIR/"
+EOF
+
+    cat >>confdefs.h <<EOF
+#define SUDOERS_PLUGIN "sudoers${SOEXT}"
+EOF
+
     exec_prefix="$oexec_prefix"
 fi
 
@@ -18814,7 +19114,7 @@ test "$datarootdir" = '${prefix}/share' && datarootdir='$(prefix)/share'
 test "$docdir" = '${datarootdir}/doc/${PACKAGE_TARNAME}' && docdir='$(datarootdir)/doc/$(PACKAGE_TARNAME)'
 test "$sysconfdir" = '${prefix}/etc' -a X"$with_stow" != X"yes" && sysconfdir='/etc'
 
-ac_config_files="$ac_config_files Makefile sudo.man visudo.man sudoers.man sudoers.ldap.man sudoreplay.man sudo_usage.h sudoers"
+ac_config_files="$ac_config_files Makefile common/Makefile compat/Makefile doc/Makefile include/Makefile src/sudo_usage.h src/Makefile plugins/sample/Makefile plugins/sample_group/Makefile plugins/sudoers/Makefile plugins/sudoers/sudoers"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -19321,7 +19621,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=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.7.6p1, which was
+This file was extended by sudo $as_me 1.8.1p2, which was
 generated by GNU Autoconf 2.65.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -19387,7 +19687,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-sudo config.status 1.7.6p1
+sudo config.status 1.8.1p2
 configured by $0, generated by GNU Autoconf 2.65,
   with options \\"\$ac_cs_config\\"
 
@@ -19397,6 +19697,7 @@ gives unlimited permission to copy, distribute and modify it."
 
 ac_pwd='$ac_pwd'
 srcdir='$srcdir'
+AWK='$AWK'
 test -n "\$AWK" || AWK=awk
 _ACEOF
 
@@ -19506,131 +19807,143 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 sed_quote_subst='$sed_quote_subst'
 double_quote_subst='$double_quote_subst'
 delay_variable_subst='$delay_variable_subst'
-macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`'
-macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`'
-enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`'
-enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`'
-pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`'
-enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`'
-host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`'
-host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`'
-host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`'
-build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`'
-build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`'
-build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`'
-SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`'
-Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`'
-GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`'
-EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`'
-FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`'
-LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`'
-NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`'
-LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`'
-max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`'
-ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`'
-exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`'
-lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`'
-lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`'
-lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`'
-reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`'
-reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-OBJDUMP='`$ECHO "X$OBJDUMP" | $Xsed -e "$delay_single_quote_subst"`'
-deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`'
-file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`'
-AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`'
-AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`'
-STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`'
-RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`'
-old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`'
-CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`'
-compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`'
-GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`'
-objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`'
-SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`'
-ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`'
-MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`'
-lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`'
-lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`'
-lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`'
-lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`'
-lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`'
-need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`'
-DSYMUTIL='`$ECHO "X$DSYMUTIL" | $Xsed -e "$delay_single_quote_subst"`'
-NMEDIT='`$ECHO "X$NMEDIT" | $Xsed -e "$delay_single_quote_subst"`'
-LIPO='`$ECHO "X$LIPO" | $Xsed -e "$delay_single_quote_subst"`'
-OTOOL='`$ECHO "X$OTOOL" | $Xsed -e "$delay_single_quote_subst"`'
-OTOOL64='`$ECHO "X$OTOOL64" | $Xsed -e "$delay_single_quote_subst"`'
-libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`'
-shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`'
-enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`'
-export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
-whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
-compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`'
-old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`'
-allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`'
-no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`'
-hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
-hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`'
-hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`'
-hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`'
-hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`'
-hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`'
-hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`'
-hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`'
-inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`'
-link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`'
-fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`'
-always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`'
-export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`'
-include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`'
-prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`'
-variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`'
-need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`'
-need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`'
-version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`'
-runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`'
-shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`'
-shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`'
-libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`'
-library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`'
-soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`'
-postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`'
-finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`'
-hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`'
-sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`'
-sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`'
-hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`'
-enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`'
-enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`'
-enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`'
-old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`'
-striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
 
 LTCC='$LTCC'
 LTCFLAGS='$LTCFLAGS'
 compiler='$compiler_DEFAULT'
 
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
 # Quote evaled strings.
-for var in SED \
+for var in SHELL \
+ECHO \
+SED \
 GREP \
 EGREP \
 FGREP \
@@ -19654,8 +19967,6 @@ lt_cv_sys_global_symbol_pipe \
 lt_cv_sys_global_symbol_to_cdecl \
 lt_cv_sys_global_symbol_to_c_name_address \
 lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
-SHELL \
-ECHO \
 lt_prog_compiler_no_builtin_flag \
 lt_prog_compiler_wl \
 lt_prog_compiler_pic \
@@ -19685,12 +19996,13 @@ variables_saved_for_relink \
 libname_spec \
 library_names_spec \
 soname_spec \
+install_override_mode \
 finish_eval \
 old_striplib \
 striplib; do
-    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
     *[\\\\\\\`\\"\\\$]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
       ;;
     *)
       eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -19717,9 +20029,9 @@ postuninstall_cmds \
 finish_cmds \
 sys_lib_search_path_spec \
 sys_lib_dlsearch_path_spec; do
-    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
     *[\\\\\\\`\\"\\\$]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
       ;;
     *)
       eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -19727,12 +20039,6 @@ sys_lib_dlsearch_path_spec; do
     esac
 done
 
-# Fix-up fallback echo if it was mangled by the above quoting rules.
-case \$lt_ECHO in
-*'\\\$0 --fallback-echo"')  lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\`
-  ;;
-esac
-
 ac_aux_dir='$ac_aux_dir'
 xsi_shell='$xsi_shell'
 lt_shell_append='$lt_shell_append'
   case $ac_config_target in
     "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
     "pathnames.h") CONFIG_HEADERS="$CONFIG_HEADERS pathnames.h" ;;
-    "zlib/zconf.h") CONFIG_HEADERS="$CONFIG_HEADERS zlib/zconf.h" ;;
     "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+    "zlib/zconf.h") CONFIG_HEADERS="$CONFIG_HEADERS zlib/zconf.h" ;;
+    "zlib/Makefile") CONFIG_FILES="$CONFIG_FILES zlib/Makefile" ;;
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
-    "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" ;;
-    "sudoreplay.man") CONFIG_FILES="$CONFIG_FILES sudoreplay.man" ;;
-    "sudo_usage.h") CONFIG_FILES="$CONFIG_FILES sudo_usage.h" ;;
-    "sudoers") CONFIG_FILES="$CONFIG_FILES sudoers" ;;
+    "common/Makefile") CONFIG_FILES="$CONFIG_FILES common/Makefile" ;;
+    "compat/Makefile") CONFIG_FILES="$CONFIG_FILES compat/Makefile" ;;
+    "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+    "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
+    "src/sudo_usage.h") CONFIG_FILES="$CONFIG_FILES src/sudo_usage.h" ;;
+    "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+    "plugins/sample/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/sample/Makefile" ;;
+    "plugins/sample_group/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/sample_group/Makefile" ;;
+    "plugins/sudoers/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/sudoers/Makefile" ;;
+    "plugins/sudoers/sudoers") CONFIG_FILES="$CONFIG_FILES plugins/sudoers/sudoers" ;;
 
   *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
@@ -20333,7 +20643,8 @@ $as_echo "$as_me: executing $ac_file commands" >&6;}
 # NOTE: Changes made to this file will be lost: look at ltmain.sh.
 #
 #   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-#                 2006, 2007, 2008 Free Software Foundation, Inc.
+#                 2006, 2007, 2008, 2009, 2010 Free Software Foundation,
+#                 Inc.
 #   Written by Gordon Matzigkeit, 1996
 #
 #   This file is part of GNU Libtool.
@@ -20381,6 +20692,12 @@ pic_mode=$pic_mode
 # Whether or not to optimize for fast installation.
 fast_install=$enable_fast_install
 
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
 # The host system.
 host_alias=$host_alias
 host=$host
@@ -20430,10 +20747,6 @@ SP2NL=$lt_lt_SP2NL
 # turn newlines into spaces.
 NL2SP=$lt_lt_NL2SP
 
-# How to create reloadable object files.
-reload_flag=$lt_reload_flag
-reload_cmds=$lt_reload_cmds
-
 # An object symbol dumper.
 OBJDUMP=$lt_OBJDUMP
 
@@ -20455,6 +20768,9 @@ RANLIB=$lt_RANLIB
 old_postinstall_cmds=$lt_old_postinstall_cmds
 old_postuninstall_cmds=$lt_old_postuninstall_cmds
 
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
 # A C compiler.
 LTCC=$lt_CC
 
@@ -20476,12 +20792,6 @@ global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name
 # The name of the directory that contains temporary libtool files.
 objdir=$objdir
 
-# Shell to use when invoking shell scripts.
-SHELL=$lt_SHELL
-
-# An echo program that does not interpret backslashes.
-ECHO=$lt_ECHO
-
 # Used to examine libraries when file_magic_cmd begins with "file".
 MAGIC_CMD=$MAGIC_CMD
 
@@ -20544,6 +20854,9 @@ library_names_spec=$lt_library_names_spec
 # The coded name of the library, if different from the real name.
 soname_spec=$lt_soname_spec
 
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
 # Command to use after installation of a shared archive.
 postinstall_cmds=$lt_postinstall_cmds
 
@@ -20583,6 +20896,10 @@ striplib=$lt_striplib
 # The linker used to build libraries.
 LD=$lt_LD
 
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
 # Commands used to build an old-style archive.
 old_archive_cmds=$lt_old_archive_cmds
 
@@ -20842,7 +21159,7 @@ _LT_EOF
 func_dirname ()
 {
   # Extract subdirectory from the argument.
-  func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
+  func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
   if test "X$func_dirname_result" = "X${1}"; then
     func_dirname_result="${3}"
   else
@@ -20853,7 +21170,7 @@ func_dirname ()
 # func_basename file
 func_basename ()
 {
-  func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
+  func_basename_result=`$ECHO "${1}" | $SED "$basename"`
 }
 
 
@@ -20866,10 +21183,8 @@ func_basename ()
 func_stripname ()
 {
   case ${2} in
-    .*) func_stripname_result=`$ECHO "X${3}" \
-           | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;;
-    *)  func_stripname_result=`$ECHO "X${3}" \
-           | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;;
+    .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+    *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
   esac
 }
 
@@ -20880,20 +21195,20 @@ my_sed_long_arg='1s/^-[^=]*=//'
 # func_opt_split
 func_opt_split ()
 {
-  func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"`
-  func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"`
+  func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"`
+  func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"`
 }
 
 # func_lo2o object
 func_lo2o ()
 {
-  func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"`
+  func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
 }
 
 # func_xform libobj-or-source
 func_xform ()
 {
-  func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[^.]*$/.lo/'`
+  func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
 }
 
 # func_arith arithmetic-term...
 
 
 
+
+
+
+
 
 
 
index 29d7f28b223e77c29a765100496d46eb38fc3900..d180df4a64f3cbbc94dfe856d9e641206344529d 100644 (file)
@@ -3,8 +3,8 @@ dnl Process this file with GNU autoconf to produce a configure script.
 dnl
 dnl Copyright (c) 1994-1996,1998-2011 Todd C. Miller <Todd.Miller@courtesan.com>
 dnl
-AC_INIT([sudo], [1.7.6p1], [http://www.sudo.ws/bugs/], [sudo])
-AC_CONFIG_HEADER(config.h pathnames.h zlib/zconf.h)
+AC_INIT([sudo], [1.8.1p2], [http://www.sudo.ws/bugs/], [sudo])
+AC_CONFIG_HEADER([config.h pathnames.h])
 dnl
 dnl Note: this must come after AC_INIT
 dnl
@@ -19,13 +19,17 @@ AC_SUBST([CFLAGS])
 AC_SUBST([PROGS])
 AC_SUBST([CPPFLAGS])
 AC_SUBST([LDFLAGS])
+AC_SUBST([SUDOERS_LDFLAGS])
+AC_SUBST([LTLDFLAGS])
 AC_SUBST([COMMON_OBJS])
-AC_SUBST([SUDO_LDFLAGS])
+AC_SUBST([SUDOERS_OBJS])
 AC_SUBST([SUDO_OBJS])
 AC_SUBST([LIBS])
 AC_SUBST([SUDO_LIBS])
+AC_SUBST([SUDOERS_LIBS])
 AC_SUBST([NET_LIBS])
 AC_SUBST([AFS_LIBS])
+AC_SUBST([REPLAY_LIBS])
 AC_SUBST([GETGROUPS_LIB])
 AC_SUBST([OSDEFS])
 AC_SUBST([AUTH_OBJS])
@@ -44,17 +48,22 @@ AC_SUBST([mansectform])
 AC_SUBST([mansrcdir])
 AC_SUBST([NOEXECFILE])
 AC_SUBST([NOEXECDIR])
+AC_SUBST([PLUGINDIR])
+AC_SUBST([SOEXT])
 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([REPLAY])
 AC_SUBST([LOGINCAP_USAGE])
 AC_SUBST([ZLIB])
-AC_SUBST([ZLIB_DEP])
+AC_SUBST([ZLIB_SRC])
+AC_SUBST([LIBTOOL_DEPS])
+AC_SUBST([ac_config_libobj_dir])
 AC_SUBST([CONFIGURE_ARGS])
+AC_SUBST([LIBDL])
+AC_SUBST([LT_STATIC])
 dnl
 dnl Variables that get substituted in docs (not overridden by environment)
 dnl
@@ -141,7 +150,7 @@ dnl May be overridden by environment variables..
 dnl
 INSTALL_NOEXEC=
 devdir='$(srcdir)'
-PROGS="sudo visudo"
+PROGS="sudo"
 : ${MANTYPE='man'}
 : ${mansrcdir='.'}
 : ${SUDOERS_MODE='0440'}
@@ -149,12 +158,11 @@ PROGS="sudo visudo"
 : ${SUDOERS_GID='0'}
 DEV="#"
 LDAP="#"
-REPLAY="#"
 BAMAN=0
 LCMAN=0
 SEMAN=0
 ZLIB=
-ZLIB_DEP=
+ZLIB_SRC=
 AUTH_OBJS=
 AUTH_REG=
 AUTH_EXCL=
@@ -169,9 +177,13 @@ shadow_defs=
 shadow_funcs=
 shadow_libs=
 shadow_libs_optional=
-
 CONFIGURE_ARGS="$@"
 
+dnl
+dnl libc replacement functions live in compat
+dnl
+AC_CONFIG_LIBOBJ_DIR(compat)
+
 dnl
 dnl Deprecated --with options (these all warn or generate an error)
 dnl
@@ -197,7 +209,6 @@ dnl
 AC_ARG_WITH(devel, [AS_HELP_STRING([--with-devel], [add development options])],
 [case $with_devel in
     yes)       AC_MSG_NOTICE([Setting up for development: -Wall, flex, yacc])
-               PROGS="${PROGS} testsudoers"
                OSDEFS="${OSDEFS} -DSUDO_DEVEL"
                DEV=""
                devdir=.
@@ -237,8 +248,8 @@ dnl
 AC_ARG_WITH(bsm-audit, [AS_HELP_STRING([--with-bsm-audit], [enable BSM audit support])],
 [case $with_bsm_audit in
     yes)       AC_DEFINE(HAVE_BSM_AUDIT)
-               SUDO_LIBS="${SUDO_LIBS} -lbsm"
-               SUDO_OBJS="${SUDO_OBJS} bsm_audit.o"
+               SUDOERS_LIBS="${SUDOERS_LIBS} -lbsm"
+               SUDOERS_OBJS="${SUDOERS_OBJS} bsm_audit.lo"
                ;;
     no)                ;;
     *)         AC_MSG_ERROR(["--with-bsm-audit does not take an argument."])
@@ -253,7 +264,8 @@ AC_ARG_WITH(linux-audit, [AS_HELP_STRING([--with-linux-audit], [enable Linux aud
     yes)       AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <libaudit.h>]], [[int i = AUDIT_USER_CMD; (void)i;]])], [
                    AC_DEFINE(HAVE_LINUX_AUDIT)
                    SUDO_LIBS="${SUDO_LIBS} -laudit"
-                   SUDO_OBJS="${SUDO_OBJS} linux_audit.o"
+                   SUDOERS_LIBS="${SUDO_LIBS} -laudit"
+                   SUDOERS_OBJS="${SUDOERS_OBJS} linux_audit.lo"
                ], [
                    AC_MSG_ERROR([unable to find AUDIT_USER_CMD in libaudit.h for --with-linux-audit])
                ])
@@ -721,8 +733,9 @@ esac])
 
 AC_ARG_WITH(iologdir, [AS_HELP_STRING([--with-iologdir=DIR], [directory to store sudo I/O log files in])],
 [case $with_iologdir in
-    yes)       ;;
-    no)                ;;
+    yes)    ;;
+    no)     AC_MSG_ERROR(["--without-iologdir not supported."])
+           ;;
 esac])
 
 AC_ARG_WITH(sendmail, [AS_HELP_STRING([--with-sendmail], [set path to sendmail])
@@ -1084,32 +1097,12 @@ AC_ARG_WITH(askpass, [AS_HELP_STRING([--with-askpass=PATH], [Fully qualified pat
                ;;
 esac], AC_MSG_RESULT(no))
 
-dnl
-dnl If enabled, set LIBVAS_SO, LIBVAS_RPATH and USING_NONUNIX_GROUPS
-dnl
-AC_ARG_WITH(libvas, [AS_HELP_STRING([--with-libvas=NAME], [Name of the libvas shared library (default=libvas.so)])],
-[case $with_libvas in
-    yes)       with_libvas=libvas.so
-               ;;
-    no)                ;;
-    *)         AC_DEFINE_UNQUOTED([LIBVAS_SO], ["$with_libvas"], [The name of libvas.so])
+AC_ARG_WITH(plugindir, [AS_HELP_STRING([--with-plugindir], [set directory to load plugins from])],
+[case $with_plugindir in
+    no)                AC_MSG_ERROR(["illegal argument: --without-plugindir."])
                ;;
-esac
-if test X"$with_libvas" != X"no"; then
-    AC_DEFINE_UNQUOTED([LIBVAS_SO], ["$with_libvas"], [The name of libvas.so])
-    AC_DEFINE(USING_NONUNIX_GROUPS)
-    COMMON_OBJS="$COMMON_OBJS vasgroups.o"
-    AC_ARG_WITH([libvas-rpath],
-       [AS_HELP_STRING([--with-libvas-rpath=PATH],
-                      [Path to look for libvas in [default=/opt/quest/lib]])],
-       [LIBVAS_RPATH=$withval],
-       [LIBVAS_RPATH=/opt/quest/lib])
-    dnl
-    dnl Some platforms require libdl for dlopen()
-    dnl
-    AC_CHECK_LIB([dl], [main])
-fi
-])
+    *)         ;;
+esac], [with_plugindir="$libexecdir"])
 
 dnl
 dnl Options for --enable
@@ -1269,6 +1262,10 @@ AC_ARG_ENABLE(env_debug,
   esac
 ], AC_MSG_RESULT(no))
 
+AC_ARG_ENABLE(zlib,
+[AS_HELP_STRING([--enable-zlib[[=PATH]]], [Whether to enable or disable zlib])],
+[])
+
 AC_MSG_CHECKING(whether to enable environment resetting by default)
 AC_ARG_ENABLE(env_reset,
 [AS_HELP_STRING([--enable-env-reset], [Whether to enable environment resetting by default.])],
@@ -1348,21 +1345,34 @@ if test X"$AR" = X"false"; then
     AC_MSG_ERROR([the "ar" utility is required to build sudo])
 fi
 
+if test "x$ac_cv_prog_cc_c89" = "xno"; then
+    AC_MSG_ERROR([Sudo version $PACKAGE_VERSION requires an ANSI C compiler to build.])
+fi
+
 dnl
 dnl Libtool setup, we require libtool 2.2.6b or higher
 dnl
 AC_CANONICAL_HOST
 AC_CONFIG_MACRO_DIR([m4])
 LT_PREREQ([2.2.6b])
-LT_INIT
+LT_INIT([dlopen])
 
 dnl
 dnl Defer with_noexec until after libtool magic runs
 dnl
 if test "$enable_shared" = "no"; then
     with_noexec=no
+    enable_dlopen=no
+    lt_cv_dlopen=none
+    lt_cv_dlopen_libs=
 else
     eval _shrext="$shrext_cmds"
+    # Darwin uses .dylib for libraries but .so for modules
+    if test X"$_shrext" = X".dylib"; then
+       SOEXT=".so"
+    else
+       SOEXT="$_shrext"
+    fi
 fi
 AC_MSG_CHECKING(path to sudo_noexec.so)
 AC_ARG_WITH(noexec, [AS_HELP_STRING([--with-noexec[=PATH]], [fully qualified pathname of sudo_noexec.so])],
@@ -1447,11 +1457,12 @@ case "$host" in
                : ${mansectform='4'}
                : ${with_rpath='yes'}
                test -z "$with_pam" && AUTH_EXCL_DEF="PAM"
+               AC_CHECK_FUNCS(priv_set)
                ;;
     *-*-aix*)
                # To get all prototypes (so we pass -Wall)
                OSDEFS="${OSDEFS} -D_ALL_SOURCE -D_LINUX_SOURCE_COMPAT"
-               SUDO_LDFLAGS="${SUDO_LDFLAGS} -Wl,-bI:\$(srcdir)/aixcrypt.exp"
+               SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -Wl,-bI:\$(srcdir)/aixcrypt.exp"
                if test X"$with_blibpath" != X"no"; then
                    AC_MSG_CHECKING([if linker accepts -Wl,-blibpath])
                    O_LDFLAGS="$LDFLAGS"
@@ -1488,7 +1499,7 @@ case "$host" in
 
                # AIX-specific functions
                AC_CHECK_FUNCS(getuserattr setauthdb)
-               COMMON_OBJS="$COMMON_OBJS aix.o"
+               COMMON_OBJS="$COMMON_OBJS aix.lo"
                ;;
     *-*-hiuxmpp*)
                : ${mansectsu='1m'}
@@ -1503,11 +1514,6 @@ case "$host" in
                : ${mansectform='4'}
 
                if test -z "$GCC"; then
-                   # HP-UX bundled compiler can't generate shared objects
-                   if test "x$ac_cv_prog_cc_c89" = "xno"; then
-                       with_noexec=no
-                   fi
-
                    # Use the +DAportable flag on hppa if it is supported
                    case "$host_cpu" in
                    hppa*)
@@ -1532,13 +1538,6 @@ case "$host" in
                case "$host" in
                        *-*-hpux[1-8].*)
                            AC_DEFINE(BROKEN_SYSLOG)
-
-                           # Not sure if setuid binaries are safe in < 9.x
-                           if test -n "$GCC"; then
-                               SUDO_LDFLAGS="${SUDO_LDFLAGS} -static"
-                           else
-                               SUDO_LDFLAGS="${SUDO_LDFLAGS} -Wl,-a,archive"
-                           fi
                        ;;
                        *-*-hpux9.*)
                            AC_DEFINE(BROKEN_SYSLOG)
@@ -1548,7 +1547,7 @@ case "$host" in
                            # DCE support (requires ANSI C compiler)
                            if test "$with_DCE" = "yes"; then
                                # order of libs in 9.X is important. -lc_r must be last
-                               SUDO_LIBS="${SUDO_LIBS} -ldce -lM -lc_r"
+                               SUDOERS_LIBS="${SUDOERS_LIBS} -ldce -lM -lc_r"
                                LIBS="${LIBS} -ldce -lM -lc_r"
                                CPPFLAGS="${CPPFLAGS} -D_REENTRANT -I/usr/include/reentrant"
                            fi
@@ -1568,7 +1567,7 @@ case "$host" in
                ;;
     *-dec-osf*)
                # ignore envariables wrt dynamic lib path
-               SUDO_LDFLAGS="${SUDO_LDFLAGS} -Wl,-no_library_replacement"
+               SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -Wl,-no_library_replacement"
 
                : ${CHECKSIA='true'}
                AC_MSG_CHECKING(whether to disable sia support on Digital UNIX)
@@ -1673,8 +1672,7 @@ case "$host" in
     *-*-isc*)
                OSDEFS="${OSDEFS} -D_ISC"
                LIB_CRYPT=1
-               SUDO_LIBS="${SUDO_LIBS} -lcrypt"
-               LIBS="${LIBS} -lcrypt"
+               SUDOERS_LIBS="${SUDOERS_LIBS} -lcrypt"
 
                shadow_funcs="getspnam"
                shadow_libs="-lsec"
@@ -1702,14 +1700,13 @@ case "$host" in
                : ${with_rpath='yes'}
                ;;
     *-ncr-sysv4*|*-ncr-sysvr4*)
-               AC_CHECK_LIB(c89, strcasecmp, AC_DEFINE(HAVE_STRCASECMP) [LIBS="${LIBS} -lc89"; ac_cv_func_strcasecmp=yes])
+               AC_CHECK_LIB(c89, strcasecmp, [LIBS="${LIBS} -lc89"])
                : ${mansectsu='1m'}
                : ${mansectform='4'}
                : ${with_rpath='yes'}
                ;;
     *-ccur-sysv4*|*-ccur-sysvr4*)
                LIBS="${LIBS} -lgen"
-               SUDO_LIBS="${SUDO_LIBS} -lgen"
                : ${mansectsu='1m'}
                : ${mansectform='4'}
                : ${with_rpath='yes'}
@@ -1739,7 +1736,7 @@ case "$host" in
                    ;;
                esac
                if test "${with_skey-'no'}" = "yes"; then
-                    SUDO_LIBS="${SUDO_LIBS} -lmd"
+                    SUDOERS_LIBS="${SUDOERS_LIBS} -lmd"
                fi
                CHECKSHADOW="false"
                test -z "$with_pam" && AUTH_EXCL_DEF="PAM"
@@ -1775,7 +1772,7 @@ case "$host" in
                ;;
     *-*-dragonfly*)
                if test "${with_skey-'no'}" = "yes"; then
-                    SUDO_LIBS="${SUDO_LIBS} -lmd"
+                    SUDOERS_LIBS="${SUDOERS_LIBS} -lmd"
                fi
                CHECKSHADOW="false"
                test -z "$with_pam" && AUTH_EXCL_DEF="PAM"
@@ -1865,6 +1862,9 @@ dnl
 AC_PROG_GCC_TRADITIONAL
 AC_C_CONST
 AC_C_VOLATILE
+if test X"$with_gnu_ld" != "yes" -a -n "$GCC"; then
+    LTLDFLAGS="$LTLDFLAGS -Wc,-static-libgcc"
+fi
 dnl
 dnl Program checks
 dnl
@@ -1875,9 +1875,7 @@ SUDO_PROG_BSHELL
 if test -z "$with_sendmail"; then
     SUDO_PROG_SENDMAIL
 fi
-if test -z "$with_editor"; then
-    SUDO_PROG_VI
-fi
+SUDO_PROG_VI
 dnl
 dnl Check for authpriv support in syslog
 dnl
@@ -1893,7 +1891,7 @@ dnl
 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 sys/stropts.h sys/sysmacros.h)
+AC_CHECK_HEADERS(malloc.h paths.h utime.h netgroup.h utmpx.h sys/sockio.h sys/bsdtypes.h sys/select.h sys/stropts.h sys/sysmacros.h)
 dnl
 dnl Check for large file support.  HP-UX 11.23 has a broken sys/type.h
 dnl when large files support is enabled so work around it.
@@ -1916,17 +1914,17 @@ case "$host" in
        ;;
 esac
 AC_SYS_POSIX_TERMIOS
-if test "$ac_cv_sys_posix_termios" = "yes"; then
-    AC_DEFINE(HAVE_TERMIOS_H)
-else
-    AC_CHECK_HEADERS(termio.h)
+if test "$ac_cv_sys_posix_termios" != "yes"; then
+    AC_MSG_ERROR([Must have POSIX termios to build sudo])
 fi
 SUDO_MAILDIR
 if test ${with_logincap-'no'} != "no"; then
     AC_CHECK_HEADERS(login_cap.h, [LOGINCAP_USAGE='[[-c class|-]] '; LCMAN=1
        case "$OS" in
-           freebsd|netbsd)     SUDO_LIBS="${SUDO_LIBS} -lutil"
-           ;;
+           freebsd|netbsd)
+               SUDO_LIBS="${SUDO_LIBS} -lutil"
+               SUDOERS_LIBS="${SUDOERS_LIBS} -lutil"
+               ;;
        esac
     ])
 fi
@@ -1960,35 +1958,73 @@ SUDO_TYPE_INO_T
 SUDO_UID_T_LEN
 SUDO_SOCK_SA_LEN
 dnl
-dnl only set RETSIGTYPE if it is not set already
+dnl Check for utmp/utmpx struct members.
+dnl We need to include OSDEFS for glibc which only has __e_termination
+dnl visible when _GNU_SOURCE is *not* defined.
 dnl
-case "$DEFS" in
-    *"RETSIGTYPE"*)    ;;
-    *)                 AC_TYPE_SIGNAL;;
-esac
+_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS $OSDEFS"
+if test $ac_cv_header_utmpx_h = "yes"; then
+    AC_CHECK_MEMBERS([struct utmpx.ut_id, struct utmpx.ut_pid, struct utmpx.ut_tv, struct utmpx.ut_type], [], [], [
+       #include <sys/types.h>
+       #include <utmpx.h>
+    ])
+    dnl
+    dnl Check for ut_exit.__e_termination first, then ut_exit.e_termination
+    dnl
+    AC_CHECK_MEMBERS([struct utmpx.ut_exit.__e_termination], [AC_DEFINE(HAVE_STRUCT_UTMPX_UT_EXIT)], [
+       AC_CHECK_MEMBERS([struct utmpx.ut_exit.e_termination], [AC_DEFINE(HAVE_STRUCT_UTMPX_UT_EXIT)], [], [
+           #include <sys/types.h>
+           #include <utmpx.h>
+       ])
+    ], [
+       #include <sys/types.h>
+       #include <utmpx.h>
+    ])
+else
+    AC_CHECK_MEMBERS([struct utmp.ut_id, struct utmp.ut_pid, struct utmp.ut_tv, struct utmp.ut_type, struct utmp.ut_user], [], [], [
+       #include <sys/types.h>
+       #include <utmp.h>
+    ])
+    dnl
+    dnl Check for ut_exit.__e_termination first, then ut_exit.e_termination
+    dnl
+    AC_CHECK_MEMBERS([struct utmp.ut_exit.__e_termination], [AC_DEFINE(HAVE_STRUCT_UTMP_UT_EXIT)], [
+       AC_CHECK_MEMBERS([struct utmp.ut_exit.e_termination], [AC_DEFINE(HAVE_STRUCT_UTMP_UT_EXIT)], [], [
+           #include <sys/types.h>
+           #include <utmp.h>
+       ])
+    ], [
+       #include <sys/types.h>
+       #include <utmp.h>
+    ])
+fi
+CFLAGS="$_CFLAGS"
+
 dnl
 dnl Function checks
 dnl
 AC_FUNC_GETGROUPS
-AC_CHECK_FUNCS(strchr strrchr memchr memcpy memset sysconf tzset \
-              strftime setrlimit initgroups getgroups fstat gettimeofday \
-              regcomp setlocale nl_langinfo getaddrinfo setenv \
-              mbr_check_membership setrlimit64)
+AC_CHECK_FUNCS(strrchr sysconf tzset strftime initgroups getgroups fstat \
+              regcomp setlocale nl_langinfo getaddrinfo mbr_check_membership \
+              setrlimit64 sysctl)
 AC_CHECK_FUNCS(getline, [], [
     AC_LIBOBJ(getline)
     AC_CHECK_FUNCS(fgetln)
 ])
-AC_CHECK_FUNCS(setsid, [], [
-    AC_LIBOBJ(setsid)
-    AC_FUNC_SETPGRP
-])
-
-AC_CHECK_FUNCS(sysctl getutxid getutid, [break])
+utmp_style=LEGACY
+AC_CHECK_FUNCS(getutxid getutid, [utmp_style=POSIX; break])
+if test "$utmp_style" = "LEGACY"; then
+    AC_CHECK_FUNCS(getttyent ttyslot, [break])
+fi
 
 AC_CHECK_FUNCS(openpty, [AC_CHECK_HEADERS(util.h pty.h, [break])], [
     AC_CHECK_LIB(util, openpty, [
        AC_CHECK_HEADERS(util.h pty.h, [break])
-       SUDO_LIBS="${SUDO_LIBS} -lutil"
+       case "$SUDO_LIBS" in
+           *-lutil*) ;;
+           *) SUDO_LIBS="${SUDO_LIBS} -lutil";;
+       esac
        AC_DEFINE(HAVE_OPENPTY)
     ], [
        AC_CHECK_FUNCS(_getpty, [], [
@@ -2000,10 +2036,12 @@ AC_CHECK_FUNCS(openpty, [AC_CHECK_HEADERS(util.h pty.h, [break])], [
        ])
     ])
 ])
-AC_CHECK_FUNCS(unsetenv, SUDO_FUNC_UNSETENV_VOID)
-SUDO_FUNC_PUTENV_CONST
+AC_CHECK_FUNCS(unsetenv, [SUDO_FUNC_UNSETENV_VOID], [AC_LIBOBJ(unsetenv)])
 if test -z "$SKIP_SETRESUID"; then
-    AC_CHECK_FUNCS(setresuid, [SKIP_SETREUID=yes])
+    AC_CHECK_FUNCS(setresuid, [
+       SKIP_SETREUID=yes
+       AC_CHECK_FUNCS(getresuid)
+    ])
 fi
 if test -z "$SKIP_SETREUID"; then
     AC_CHECK_FUNCS(setreuid, [SKIP_SETEUID=yes])
@@ -2022,24 +2060,24 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <glob.h>]], [[int i = GLOB_BRACE |
     AC_MSG_RESULT(yes)], [AC_LIBOBJ(glob)
     AC_MSG_RESULT(no)])], [AC_LIBOBJ(glob)])
 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(utimes, [AC_CHECK_FUNCS(futimes futimesat, [break])], [AC_CHECK_FUNCS(futime) AC_LIBOBJ(utimes)])
 AC_CHECK_FUNCS(killpg, [], [AC_LIBOBJ(killpg)])
 SUDO_FUNC_FNMATCH([AC_DEFINE(HAVE_FNMATCH)], [AC_LIBOBJ(fnmatch)])
 SUDO_FUNC_ISBLANK
-AC_REPLACE_FUNCS(memrchr strerror strcasecmp sigaction strlcpy strlcat)
+AC_REPLACE_FUNCS(memrchr strlcpy strlcat setenv)
 AC_CHECK_FUNCS(nanosleep, [], [
     # On Solaris, nanosleep is in librt
-    AC_CHECK_LIB(rt, nanosleep, [LIBS="${LIBS} -lrt"], [AC_LIBOBJ(nanosleep)])
+    AC_CHECK_LIB(rt, nanosleep, [REPLAY_LIBS="${REPLAY_LIBS} -lrt"], [AC_LIBOBJ(nanosleep)])
 ])
 AC_CHECK_FUNCS(closefrom, [], [AC_LIBOBJ(closefrom)
     AC_CHECK_DECL(F_CLOSEM, AC_DEFINE(HAVE_FCNTL_CLOSEM), [],
        [ #include <limits.h>
          #include <fcntl.h> ])
 ])
-AC_CHECK_FUNCS(mkstemps, [], [SUDO_OBJS="${SUDO_OBJS} mkstemps.o"
+AC_CHECK_FUNCS(mkstemps mkdtemp, [], [
     AC_CHECK_FUNCS(random lrand48, [break])
+    AC_LIBOBJ(mktemp)
 ])
 AC_CHECK_FUNCS(snprintf vsnprintf asprintf vasprintf, , [NEED_SNPRINTF=1])
 if test X"$ac_cv_type_struct_timespec" != X"no"; then
@@ -2092,6 +2130,41 @@ AC_CHECK_FUNCS(getprogname, , [
     AC_MSG_RESULT($sudo_cv___progname)
 ])
 
+dnl
+dnl Deferred zlib option processing.
+dnl By default we use the system zlib if it is present.
+dnl
+case ${enable_zlib-"yes"} in
+    yes)
+       AC_CHECK_LIB(z, gzdopen, [
+           AC_CHECK_HEADERS(zlib.h, [ZLIB="-lz"], [enable_zlib=builtin])
+       ])
+       ;;
+    no)
+       ;;
+    system)
+       AC_DEFINE(HAVE_ZLIB_H)
+       ZLIB="-lz"
+       ;;
+    builtin)
+       # handled below
+       ;;
+    *)
+       AC_DEFINE(HAVE_ZLIB_H)
+       CPPFLAGS="${CPPFLAGS} -I${enable_zlib}/include"
+       SUDO_APPEND_LIBPATH(ZLIB, [$enable_zlib/lib])
+       ZLIB="${ZLIB} -lz"
+       ;;
+esac
+if test X"$enable_zlib" = X"builtin"; then
+    AC_DEFINE(HAVE_ZLIB_H)
+    CPPFLAGS="${CPPFLAGS}"' -I$(top_srcdir)/zlib'
+    ZLIB="${ZLIB}"' $(top_builddir)/zlib/libz.la'
+    ZLIB_SRC=zlib
+    AC_CONFIG_HEADER([zlib/zconf.h])
+    AC_CONFIG_FILES([zlib/Makefile])
+fi
+
 dnl
 dnl Check for strsignal() or sys_siglist
 dnl
@@ -2146,16 +2219,8 @@ dnl PAM support.  Systems that use PAM by default set with_pam=default
 dnl and we do the actual tests here.
 dnl
 if test ${with_pam-"no"} != "no"; then
-    dnl
-    dnl Some platforms need libdl for dlopen
-    dnl
-    case "$LIBS" in
-       *-ldl*) SUDO_LIBS="${SUDO_LIBS} -lpam"
-               ;;
-       *)      AC_CHECK_LIB([dl], [main], [SUDO_LIBS="${SUDO_LIBS} -lpam -ldl"], [SUDO_LIBS="${SUDO_LIBS} -lpam"])
-               ac_cv_lib_dl=ac_cv_lib_dl_main
-               ;;
-    esac
+    # Note: we already link the main sudo program with -ldl as needed
+    SUDOERS_LIBS="${SUDOERS_LIBS} -lpam"
 
     dnl
     dnl Some PAM implementations (MacOS X for example) put the PAM headers
@@ -2164,7 +2229,7 @@ if test ${with_pam-"no"} != "no"; then
     AC_CHECK_HEADERS([security/pam_appl.h] [pam/pam_appl.h], [with_pam=yes; break])
     if test "$with_pam" = "yes"; then
        AC_DEFINE(HAVE_PAM)
-       AUTH_OBJS="$AUTH_OBJS pam.o";
+       AUTH_OBJS="$AUTH_OBJS pam.lo";
        AUTH_EXCL=PAM
 
        AC_ARG_WITH(pam-login, [AS_HELP_STRING([--with-pam-login], [enable specific PAM session for sudo -i])],
@@ -2185,7 +2250,7 @@ if test ${with_pam-"no"} != "no"; then
                yes)    AC_MSG_RESULT(yes)
                        ;;
                no)             AC_MSG_RESULT(no)
-                           AC_DEFINE([NO_PAM_SESSION], [], [PAM session support disabled])
+                           AC_DEFINE(NO_PAM_SESSION)
                            ;;
                *)              AC_MSG_RESULT(no)
                            AC_MSG_WARN([Ignoring unknown argument to --enable-pam-session: $enableval])
@@ -2215,8 +2280,8 @@ if test ${with_aixauth-'no'} != "no"; then
     if test X"$with_aixauth" != X"maybe" -o X"$AUTH_EXCL" = X""; then
        AC_MSG_NOTICE([using AIX general authentication])
        AC_DEFINE(HAVE_AIXAUTH)
-       AUTH_OBJS="$AUTH_OBJS aix_auth.o";
-       SUDO_LIBS="${SUDO_LIBS} -ls"
+       AUTH_OBJS="$AUTH_OBJS aix_auth.lo";
+       SUDOERS_LIBS="${SUDOERS_LIBS} -ls"
        AUTH_EXCL=AIX_AUTH
     fi
 fi
@@ -2227,7 +2292,7 @@ dnl If set to "maybe" only enable if no other exclusive method in use.
 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"]
+       [AUTH_OBJS="$AUTH_OBJS bsdauth.lo"]
        [BSDAUTH_USAGE='[[-a auth_type]] ']
        [AUTH_EXCL=BSD_AUTH; BAMAN=1],
        [AC_MSG_ERROR([BSD authentication was specified but bsd_auth.h could not be found])])
@@ -2240,7 +2305,7 @@ if test ${CHECKSIA-'false'} = "true"; then
     AC_CHECK_FUNCS(sia_ses_init, [found=true], [found=false])
     if test "$found" = "true"; then
        AUTH_EXCL=SIA
-       AUTH_OBJS="$AUTH_OBJS sia.o"
+       AUTH_OBJS="$AUTH_OBJS sia.lo"
     fi
 fi
 
@@ -2249,12 +2314,12 @@ dnl extra FWTK libs + includes
 dnl
 if test ${with_fwtk-'no'} != "no"; then
     if test "$with_fwtk" != "yes"; then
-       SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_fwtk}])
+       SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${with_fwtk}])
        CPPFLAGS="${CPPFLAGS} -I${with_fwtk}"
        with_fwtk=yes
     fi
-    SUDO_LIBS="${SUDO_LIBS} -lauth -lfwall"
-    AUTH_OBJS="$AUTH_OBJS fwtk.o"
+    SUDOERS_LIBS="${SUDOERS_LIBS} -lauth -lfwall"
+    AUTH_OBJS="$AUTH_OBJS fwtk.lo"
 fi
 
 dnl
@@ -2276,14 +2341,14 @@ if test ${with_SecurID-'no'} != "no"; then
     #
     AC_CHECK_LIB(aceclnt, SD_Init,
        [
-           AUTH_OBJS="$AUTH_OBJS securid5.o";
-           SUDO_LIBS="${SUDO_LIBS} -laceclnt -lpthread"
+           AUTH_OBJS="$AUTH_OBJS securid5.lo";
+           SUDOERS_LIBS="${SUDOERS_LIBS} -laceclnt -lpthread"
        ]
        [
-           SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_SecurID}])
+           SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${with_SecurID}])
        ], [
-           AUTH_OBJS="$AUTH_OBJS securid.o";
-           SUDO_LIBS="${SUDO_LIBS} ${with_SecurID}/sdiclient.a"
+           AUTH_OBJS="$AUTH_OBJS securid.lo";
+           SUDOERS_LIBS="${SUDOERS_LIBS} ${with_SecurID}/sdiclient.a"
        ],
        [
            -lpthread
@@ -2328,7 +2393,7 @@ if test ${with_kerb4-'no'} != "no"; then
        test X"$found" = X"no" && CPPFLAGS="$O_CPPFLAGS"
     else
        SUDO_APPEND_LIBPATH(LDFLAGS, [${with_kerb4}/lib])
-       SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_kerb4}/lib])
+       SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${with_kerb4}/lib])
        CPPFLAGS="$CPPFLAGS -I${with_kerb4}/include"
        AC_CHECK_HEADER([krb.h], [found=yes], [found=no])
     fi
@@ -2360,12 +2425,12 @@ if test ${with_kerb4-'no'} != "no"; then
     AC_CHECK_LIB(krb, main, [K4LIBS="-lkrb $K4LIBS"], [
        AC_CHECK_LIB(krb4, main, [K4LIBS="-lkrb4 $K4LIBS"],
            [K4LIBS="-lkrb $K4LIBS"]
-           [AC_MSG_WARN([Unable to locate Kerberos IV libraries, you will have to edit the Makefile and add -L/path/to/krb/libs to SUDO_LDFLAGS and possibly add Kerberos libs to SUDO_LIBS])]
+           [AC_MSG_WARN([Unable to locate Kerberos IV libraries, you will have to edit the Makefile and add -L/path/to/krb/libs to SUDOERS_LDFLAGS and possibly add Kerberos libs to SUDOERS_LIBS])]
        , [$K4LIBS])
     ], [$K4LIBS])
     LDFLAGS="$O_LDFLAGS"
-    SUDO_LIBS="${SUDO_LIBS} $K4LIBS"
-    AUTH_OBJS="$AUTH_OBJS kerb4.o"
+    SUDOERS_LIBS="${SUDOERS_LIBS} $K4LIBS"
+    AUTH_OBJS="$AUTH_OBJS kerb4.lo"
 fi
 
 dnl
@@ -2376,9 +2441,9 @@ if test ${with_kerb5-'no'} != "no"; then
     AC_CHECK_PROG(KRB5CONFIG, krb5-config, yes, "")
     if test -n "$KRB5CONFIG"; then
        AC_DEFINE(HAVE_KERB5)
-       AUTH_OBJS="$AUTH_OBJS kerb5.o"
+       AUTH_OBJS="$AUTH_OBJS kerb5.lo"
        CPPFLAGS="$CPPFLAGS `krb5-config --cflags`"
-       SUDO_LIBS="$SUDO_LIBS `krb5-config --libs`"
+       SUDOERS_LIBS="$SUDOERS_LIBS `krb5-config --libs`"
        dnl
        dnl Try to determine whether we have Heimdal or MIT Kerberos
        dnl
@@ -2390,57 +2455,56 @@ if test ${with_kerb5-'no'} != "no"; then
                AC_MSG_RESULT(no)
            ]
        )
-    fi
-fi
-if test ${with_kerb5-'no'} != "no" -a -z "$KRB5CONFIG"; then
-    AC_DEFINE(HAVE_KERB5)
-    dnl
-    dnl Use the specified directory, if any, else search for correct inc dir
-    dnl
-    if test "$with_kerb5" = "yes"; then
-       found=no
-       O_CPPFLAGS="$CPPFLAGS"
-       for dir in "" "kerberosV/" "krb5/" "kerberos5/" "kerberosv5/"; do
-           CPPFLAGS="$O_CPPFLAGS -I/usr/include/${dir}"
-           AC_PREPROC_IFELSE([#include <krb5.h>], [found=yes; break])
-       done
-       if test X"$found" = X"no"; then
-           CPPFLAGS="$O_CPPFLAGS"
-           AC_MSG_WARN([Unable to locate Kerberos V include files, you will have to edit the Makefile and add -I/path/to/krb/includes to CPPFLAGS])
-       fi
     else
-       dnl XXX - try to include krb5.h here too
-       SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_kerb5}/lib])
-       CPPFLAGS="$CPPFLAGS -I${with_kerb5}/include"
-    fi
+       AC_DEFINE(HAVE_KERB5)
+       dnl
+       dnl Use the specified directory, if any, else search for correct inc dir
+       dnl
+       if test "$with_kerb5" = "yes"; then
+           found=no
+           O_CPPFLAGS="$CPPFLAGS"
+           for dir in "" "kerberosV/" "krb5/" "kerberos5/" "kerberosv5/"; do
+               CPPFLAGS="$O_CPPFLAGS -I/usr/include/${dir}"
+               AC_PREPROC_IFELSE([#include <krb5.h>], [found=yes; break])
+           done
+           if test X"$found" = X"no"; then
+               CPPFLAGS="$O_CPPFLAGS"
+               AC_MSG_WARN([Unable to locate Kerberos V include files, you will have to edit the Makefile and add -I/path/to/krb/includes to CPPFLAGS])
+           fi
+       else
+           dnl XXX - try to include krb5.h here too
+           SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${with_kerb5}/lib])
+           CPPFLAGS="$CPPFLAGS -I${with_kerb5}/include"
+       fi
 
-    dnl
-    dnl Try to determine whether we have Heimdal or MIT Kerberos
-    dnl
-    AC_MSG_CHECKING(whether we are using Heimdal)
-    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"])
-       ], [
-           AC_MSG_RESULT(no)
-           SUDO_LIBS="${SUDO_LIBS} -lkrb5 -lk5crypto -lcom_err"
-           AC_CHECK_LIB(krb5support, main, [SUDO_LIBS="${SUDO_LIBS} -lkrb5support"])
-    ])
-    AUTH_OBJS="$AUTH_OBJS kerb5.o"
+       dnl
+       dnl Try to determine whether we have Heimdal or MIT Kerberos
+       dnl
+       AC_MSG_CHECKING(whether we are using Heimdal)
+       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!
+               SUDOERS_LIBS="${SUDOERS_LIBS} -lkrb5 -lcrypto -ldes -lcom_err -lasn1"
+               AC_CHECK_LIB(roken, main, [SUDOERS_LIBS="${SUDOERS_LIBS} -lroken"])
+           ], [
+               AC_MSG_RESULT(no)
+               SUDOERS_LIBS="${SUDOERS_LIBS} -lkrb5 -lk5crypto -lcom_err"
+               AC_CHECK_LIB(krb5support, main, [SUDOERS_LIBS="${SUDOERS_LIBS} -lkrb5support"])
+       ])
+       AUTH_OBJS="$AUTH_OBJS kerb5.lo"
+    fi
     _LIBS="$LIBS"
-    LIBS="${LIBS} ${SUDO_LIBS}"
+    LIBS="${LIBS} ${SUDOERS_LIBS}"
     AC_CHECK_FUNCS(krb5_verify_user krb5_init_secure_context)
     AC_CHECK_FUNCS(krb5_get_init_creds_opt_alloc, [
        AC_CACHE_CHECK([whether krb5_get_init_creds_opt_free takes a context],
            sudo_cv_krb5_get_init_creds_opt_free_two_args, [
-              AC_COMPILE_IFELSE(
-                  [AC_LANG_PROGRAM(
-                      [[#include <krb5.h>]],
-                      [[krb5_get_init_creds_opt_free(NULL, NULL);]]
-                   )],
+               AC_COMPILE_IFELSE(
+                   [AC_LANG_PROGRAM(
+                       [[#include <krb5.h>]],
+                       [[krb5_get_init_creds_opt_free(NULL, NULL);]]
+                   )],
                    [sudo_cv_krb5_get_init_creds_opt_free_two_args=yes],
                    [sudo_cv_krb5_get_init_creds_opt_free_two_args=no]
                )
@@ -2462,12 +2526,12 @@ if test ${with_AFS-'no'} = "yes"; then
     AFSLIBDIRS="/usr/lib/afs /usr/afsws/lib /usr/afsws/lib/afs"
     for i in $AFSLIBDIRS; do
        if test -d ${i}; then
-           SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [$i])
+           SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [$i])
            FOUND_AFSLIBDIR=true
        fi
     done
     if test -z "$FOUND_AFSLIBDIR"; then
-       AC_MSG_WARN([Unable to locate AFS libraries, you will have to edit the Makefile and add -L/path/to/afs/libs to SUDO_LDFLAGS or rerun configure with the --with-libpath options.])
+       AC_MSG_WARN([Unable to locate AFS libraries, you will have to edit the Makefile and add -L/path/to/afs/libs to SUDOERS_LDFLAGS or rerun configure with the --with-libpath options.])
     fi
 
     # Order is important here.  Note that we build AFS_LIBS from right to left
@@ -2497,7 +2561,7 @@ if test ${with_AFS-'no'} = "yes"; then
        AC_MSG_WARN([Unable to locate AFS include dir, you may have to edit the Makefile and add -I/path/to/afs/includes to CPPFLAGS or rerun configure with the --with-incpath options.])
     fi
 
-    AUTH_OBJS="$AUTH_OBJS afs.o"
+    AUTH_OBJS="$AUTH_OBJS afs.lo"
 fi
 
 dnl
@@ -2506,8 +2570,8 @@ dnl Order of libs in HP-UX 10.x is important, -ldce must be last.
 dnl
 if test ${with_DCE-'no'} = "yes"; then
     DCE_OBJS="${DCE_OBJS} dce_pwent.o"
-    SUDO_LIBS="${SUDO_LIBS} -ldce"
-    AUTH_OBJS="$AUTH_OBJS dce.o"
+    SUDOERS_LIBS="${SUDOERS_LIBS} -ldce"
+    AUTH_OBJS="$AUTH_OBJS dce.lo"
 fi
 
 dnl
@@ -2518,30 +2582,46 @@ if test "${with_skey-'no'}" = "yes"; then
     if test "$with_skey" != "yes"; then
        CPPFLAGS="${CPPFLAGS} -I${with_skey}/include"
        SUDO_APPEND_LIBPATH(LDFLAGS, [${with_skey}/lib])
-       SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_skey}/lib])
-       AC_PREPROC_IFELSE([#include <skey.h>], [found=yes], [found=no])
+       SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${with_skey}/lib])
+       AC_CHECK_HEADER([skey.h], [found=yes], [found=no], [#include <stdio.h>])
     else
        found=no
        O_CPPFLAGS="$CPPFLAGS"
        for dir in "" "/usr/local" "/usr/contrib"; do
            test -n "$dir" && CPPFLAGS="$O_CPPFLAGS -I${dir}/include"
-           AC_PREPROC_IFELSE([#include <skey.h>], [found=yes; break])
+           AC_CHECK_HEADER([skey.h], [found=yes; break], [],
+               [#include <stdio.h>]) 
        done
        if test "$found" = "no" -o -z "$dir"; then
            CPPFLAGS="$O_CPPFLAGS"
        else
            SUDO_APPEND_LIBPATH(LDFLAGS, [${dir}/lib])
-           SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${dir}/lib])
+           SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${dir}/lib])
+       fi
+       if test "$found" = "no"; then
+           AC_MSG_WARN([Unable to locate skey.h, you will have to edit the Makefile and add -I/path/to/skey/includes to CPPFLAGS])
        fi
     fi
-    if test "$found" = "no"; then
-       AC_MSG_WARN([Unable to locate skey.h, you will have to edit the Makefile and add -I/path/to/skey/includes to CPPFLAGS])
-    fi
-    AC_CHECK_LIB(skey, main, [found=yes], [AC_MSG_WARN([Unable to locate libskey.a, you will have to edit the Makefile and add -L/path/to/skey/lib to SUDO_LDFLAGS])])
+    AC_CHECK_LIB(skey, main, [found=yes], [AC_MSG_WARN([Unable to locate libskey.a, you will have to edit the Makefile and add -L/path/to/skey/lib to SUDOERS_LDFLAGS])])
     AC_CHECK_LIB(skey, skeyaccess, AC_DEFINE(HAVE_SKEYACCESS))
+
+    AC_MSG_CHECKING([for RFC1938-compliant skeychallenge])
+    AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM(
+           [[#include <stdio.h>
+           #include <skey.h>]],
+           [[skeychallenge(NULL, NULL, NULL, 0);]]
+       )], [
+           AC_DEFINE(HAVE_RFC1938_SKEYCHALLENGE)
+           AC_MSG_RESULT([yes])
+       ], [
+           AC_MSG_RESULT([no])
+       ]
+    )
+
     LDFLAGS="$O_LDFLAGS"
-    SUDO_LIBS="${SUDO_LIBS} -lskey"
-    AUTH_OBJS="$AUTH_OBJS rfc1938.o"
+    SUDOERS_LIBS="${SUDOERS_LIBS} -lskey"
+    AUTH_OBJS="$AUTH_OBJS rfc1938.lo"
 fi
 
 dnl
@@ -2552,7 +2632,7 @@ if test "${with_opie-'no'}" = "yes"; then
     if test "$with_opie" != "yes"; then
        CPPFLAGS="${CPPFLAGS} -I${with_opie}/include"
        SUDO_APPEND_LIBPATH(LDFLAGS, [${with_opie}/lib])
-       SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_opie}/lib])
+       SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${with_opie}/lib])
        AC_PREPROC_IFELSE([#include <opie.h>], [found=yes], [found=no])
     else
        found=no
@@ -2565,16 +2645,16 @@ if test "${with_opie-'no'}" = "yes"; then
            CPPFLAGS="$O_CPPFLAGS"
        else
            SUDO_APPEND_LIBPATH(LDFLAGS, [${dir}/lib])
-           SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${dir}/lib])
+           SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${dir}/lib])
+       fi
+       if test "$found" = "no"; then
+           AC_MSG_WARN([Unable to locate opie.h, you will have to edit the Makefile and add -I/path/to/opie/includes to CPPFLAGS])
        fi
     fi
-    if test "$found" = "no"; then
-       AC_MSG_WARN([Unable to locate opie.h, you will have to edit the Makefile and add -I/path/to/opie/includes to CPPFLAGS])
-    fi
-    AC_CHECK_LIB(opie, main, [found=yes], [AC_MSG_WARN([Unable to locate libopie.a, you will have to edit the Makefile and add -L/path/to/opie/lib to SUDO_LDFLAGS])])
+    AC_CHECK_LIB(opie, main, [found=yes], [AC_MSG_WARN([Unable to locate libopie.a, you will have to edit the Makefile and add -L/path/to/opie/lib to SUDOERS_LDFLAGS])])
     LDFLAGS="$O_LDFLAGS"
-    SUDO_LIBS="${SUDO_LIBS} -lopie"
-    AUTH_OBJS="$AUTH_OBJS rfc1938.o"
+    SUDOERS_LIBS="${SUDOERS_LIBS} -lopie"
+    AUTH_OBJS="$AUTH_OBJS rfc1938.lo"
 fi
 
 dnl
@@ -2587,7 +2667,9 @@ if test ${with_passwd-'no'} != "no"; then
     dnl if crypt(3) not in libc, look elsewhere
     dnl
     if test -z "$LIB_CRYPT"; then
-       AC_SEARCH_LIBS([crypt], [crypt crypt_d ufc], [test -n "$ac_lib" && SUDO_LIBS="${SUDO_LIBS} $ac_res"])
+       _LIBS="$LIBS"
+       AC_SEARCH_LIBS([crypt], [crypt crypt_d ufc], [test -n "$ac_lib" && SUDOERS_LIBS="${SUDOERS_LIBS} $ac_res"])
+       LIBS="$_LIBS"
     fi
 
     if test "$CHECKSHADOW" = "true" -a -n "$shadow_funcs"; then
@@ -2596,12 +2678,12 @@ if test ${with_passwd-'no'} != "no"; then
        found=no
        AC_CHECK_FUNCS($shadow_funcs, [found=yes])
        if test "$found" = "yes"; then
-           SUDO_LIBS="$SUDO_LIBS $shadow_libs"
+           SUDOERS_LIBS="$SUDOERS_LIBS $shadow_libs"
        elif test -n "$shadow_libs_optional"; then
            LIBS="$LIBS $shadow_libs_optional"
            AC_CHECK_FUNCS($shadow_funcs, [found=yes])
            if test "$found" = "yes"; then
-               SUDO_LIBS="$SUDO_LIBS $shadow_libs $shadow_libs_optional"
+               SUDOERS_LIBS="$SUDOERS_LIBS $shadow_libs $shadow_libs_optional"
            fi
        fi
        if test "$found" = "yes"; then
@@ -2615,14 +2697,14 @@ if test ${with_passwd-'no'} != "no"; then
        CHECKSHADOW=false
     fi
     if test "$CHECKSHADOW" = "true"; then
-       AC_SEARCH_LIBS([getspnam], [gen], [AC_DEFINE(HAVE_GETSPNAM)] [CHECKSHADOW=false; test -n "$ac_lib" && SUDO_LIBS="${SUDO_LIBS} $ac_res"])
+       AC_SEARCH_LIBS([getspnam], [gen], [AC_DEFINE(HAVE_GETSPNAM)] [CHECKSHADOW=false; test -n "$ac_lib" && SUDOERS_LIBS="${SUDOERS_LIBS} $ac_res"])
     fi
     if test "$CHECKSHADOW" = "true"; then
-       AC_SEARCH_LIBS([getprpwnam], [sec security prot], [AC_DEFINE(HAVE_GETPRPWNAM)] [CHECKSHADOW=false; SECUREWARE=1; test -n "$ac_lib" && SUDO_LIBS="${SUDO_LIBS} $ac_res"])
+       AC_SEARCH_LIBS([getprpwnam], [sec security prot], [AC_DEFINE(HAVE_GETPRPWNAM)] [CHECKSHADOW=false; SECUREWARE=1; test -n "$ac_lib" && SUDOERS_LIBS="${SUDOERS_LIBS} $ac_res"])
     fi
     if test -n "$SECUREWARE"; then
        AC_CHECK_FUNCS(bigcrypt set_auth_parameters initprivs)
-       AUTH_OBJS="$AUTH_OBJS secureware.o"
+       AUTH_OBJS="$AUTH_OBJS secureware.lo"
     fi
 fi
 
@@ -2632,12 +2714,12 @@ dnl
 if test ${with_ldap-'no'} != "no"; then
     _LDFLAGS="$LDFLAGS"
     if test "$with_ldap" != "yes"; then
-       SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_ldap}/lib])
+       SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${with_ldap}/lib])
        SUDO_APPEND_LIBPATH(LDFLAGS, [${with_ldap}/lib])
        CPPFLAGS="${CPPFLAGS} -I${with_ldap}/include"
        with_ldap=yes
     fi
-    SUDO_OBJS="${SUDO_OBJS} ldap.o"
+    SUDOERS_OBJS="${SUDOERS_OBJS} ldap.lo"
     LDAP=""
 
     AC_MSG_CHECKING([for LDAP libraries])
@@ -2704,99 +2786,84 @@ if test ${with_ldap-'no'} != "no"; then
        fi
     fi
 
-    SUDO_LIBS="${SUDO_LIBS} ${LDAP_LIBS}"
+    SUDOERS_LIBS="${SUDOERS_LIBS} ${LDAP_LIBS}"
     LIBS="$_LIBS"
     LDFLAGS="$_LDFLAGS"
 fi
 
-dnl
-dnl Add LIBVAS_RPATH to LDFLAGS
-dnl GNU ld accepts -R/path/ as an alias for -rpath /path/
-dnl
-if test X"$LIBVAS_RPATH" != X""; then
-    if test -n "$blibpath"; then
-       blibpath_add="${blibpath_add}:$LIBVAS_RPATH"
-    else
-       case "$host" in
-           *-*-hpux*)  LDFLAGS="$LDFLAGS -Wl,+b,$LIBVAS_RPATH"
-                       ;;
-           *)          LDFLAGS="$LDFLAGS -Wl,-R$LIBVAS_RPATH"
-                       ;;
-       esac
-    fi
+#
+# How to do dynamic object loading.
+# We support dlopen() and sh_load(), else fall back to static loading.
+#
+case "$lt_cv_dlopen" in
+    dlopen)
+       AC_DEFINE(HAVE_DLOPEN)
+       SUDOERS_OBJS="$SUDOERS_OBJS plugin_error.lo"
+       LT_STATIC="--tag=disable-static"
+       ;;
+    shl_load)
+       AC_DEFINE(HAVE_SHL_LOAD)
+       SUDOERS_OBJS="$SUDOERS_OBJS plugin_error.lo"
+       LT_STATIC="--tag=disable-static"
+       AC_LIBOBJ(dlopen)
+       ;;
+    *)
+       # Preload sudoers module symbols
+       SUDO_OBJS="${SUDO_OBJS} preload.o"
+       SUDO_LIBS="${SUDO_LIBS} \$(top_builddir)/plugins/sudoers/sudoers.la"
+       LT_STATIC=""
+       AC_LIBOBJ(dlopen)
+       ;;
+esac
+
+#
+# Add library needed for dynamic loading, if any.
+#
+LIBDL="$lt_cv_dlopen_libs"
+if test X"$LIBDL" != X""; then
+    SUDO_LIBS="${SUDO_LIBS} $LIBDL"
+    SUDOERS_LIBS="${SUDOERS_LIBS} $LIBDL"
 fi
 
+# On HP-UX, you cannot dlopen() a shared object that uses pthreads
+# unless the main program is linked against -lpthread.  Since we
+# have no knowledge what libraries a plugin may depend on, we always
+# link against -lpthread on HP-UX if it is available.
+# This check should go after all other libraries tests.
+case "$host" in
+    *-*-hpux*)
+       AC_CHECK_LIB(pthread, main, [SUDO_LIBS="${SUDO_LIBS} -lpthread"])
+       ;;
+esac
+
 dnl
-dnl Add $blibpath to SUDO_LDFLAGS if specified by the user or if we
-dnl added -L dirpaths to SUDO_LDFLAGS.
+dnl Add $blibpath to SUDOERS_LDFLAGS if specified by the user or if we
+dnl added -L dirpaths to SUDOERS_LDFLAGS.
 dnl
 if test -n "$blibpath"; then
     if test -n "$blibpath_add"; then
-       SUDO_LDFLAGS="$SUDO_LDFLAGS -Wl,-blibpath:${blibpath}${blibpath_add}"
+       SUDOERS_LDFLAGS="$SUDOERS_LDFLAGS -Wl,-blibpath:${blibpath}${blibpath_add}"
     elif test -n "$with_blibpath" -a "$with_blibpath" != "yes"; then
-       SUDO_LDFLAGS="$SUDO_LDFLAGS -Wl,-blibpath:${blibpath}"
+       SUDOERS_LDFLAGS="$SUDOERS_LDFLAGS -Wl,-blibpath:${blibpath}"
     fi
 fi
 
 dnl
 dnl Check for log file, timestamp and iolog locations
 dnl
+if test "$utmp_style" = "LEGACY"; then
+    SUDO_PATH_UTMP
+fi
 SUDO_LOGFILE
 SUDO_TIMEDIR
 SUDO_IO_LOGDIR
 
-dnl
-dnl If I/O logging is enabled, build sudoreplay and exec_pty get_pty.o iolog.o
-dnl
-if test "${with_iologdir-yes}" != "no"; then
-    # Require POSIX job control for I/O log support
-    AC_CHECK_FUNCS(tcsetpgrp, [
-       SUDO_OBJS="${SUDO_OBJS} exec_pty.o get_pty.o iolog.o"
-       PROGS="$PROGS sudoreplay"
-       REPLAY=""
-
-       AC_ARG_ENABLE(zlib,
-       [AS_HELP_STRING([--enable-zlib[[=PATH]]], [Whether to enable or disable zlib])], [])
-       case ${enable_zlib-"yes"} in
-           yes)
-               AC_CHECK_LIB(z, gzdopen, [
-                   AC_CHECK_HEADERS(zlib.h, [ZLIB="-lz"], [enable_zlib=builtin])
-               ])
-               ;;
-           no)
-               ;;
-           system)
-               AC_DEFINE(HAVE_ZLIB_H)
-               ZLIB="-lz"
-               ;;
-           builtin)
-               # handled below
-               ;;
-           *)
-               AC_DEFINE(HAVE_ZLIB_H)
-               CPPFLAGS="${CPPFLAGS} -I${enable_zlib}/include"
-               SUDO_APPEND_LIBPATH(ZLIB, [$enable_zlib/lib])
-               ZLIB="${ZLIB} -lz"
-               ;;
-       esac
-       if test X"$enable_zlib" = X"builtin"; then
-           AC_DEFINE(HAVE_ZLIB_H)
-           CPPFLAGS="${CPPFLAGS}"' -I$(srcdir)/zlib'
-           ZLIB="${ZLIB} libz.a"
-           ZLIB_DEP=libz.a
-       fi
-    ], [
-       AC_MSG_WARN([Disabling I/O log support due to lack of tcsetpgrp function])
-       with_iologdir=no
-    ])
-fi
-
 dnl
 dnl Use passwd auth module?
 dnl
 case "$with_passwd" in
 yes|maybe)
-    AUTH_OBJS="$AUTH_OBJS getspwuid.o passwd.o"
+    AUTH_OBJS="$AUTH_OBJS getspwuid.lo passwd.lo"
     ;;
 *)
     AC_DEFINE(WITHOUT_PASSWD)
@@ -2806,18 +2873,18 @@ yes|maybe)
     ;;
 esac
 AUTH_OBJS=${AUTH_OBJS# }
-_AUTH=`echo "$AUTH_OBJS" | sed -e 's/\.o//g' -e 's/getspwuid *//'`
+_AUTH=`echo "$AUTH_OBJS" | sed -e 's/\.lo//g' -e 's/getspwuid *//'`
 AC_MSG_NOTICE([using the following authentication methods: $_AUTH])
 
 dnl
-dnl LIBS may contain duplicates from SUDO_LIBS or NET_LIBS so prune it.
+dnl LIBS may contain duplicates from SUDO_LIBS, SUDOERS_LIBS, or NET_LIBS
 dnl
 if test -n "$LIBS"; then
     L="$LIBS"
     LIBS=
     for l in ${L}; do
        dupe=0
-       for sl in ${SUDO_LIBS} ${NET_LIBS}; do
+       for sl in ${SUDO_LIBS} ${SUDOERS_LIBS} ${NET_LIBS}; do
            test $l = $sl && dupe=1
        done
        test $dupe = 0 && LIBS="${LIBS} $l"
@@ -2853,6 +2920,9 @@ if test X"$with_noexec" != X"no" -o X"$with_selinux" != X"no"; then
        eval sesh_file="$libexecdir/sesh"
        SUDO_DEFINE_UNQUOTED(_PATH_SUDO_SESH, "$sesh_file", [The fully qualified pathname of sesh])
     fi
+    eval PLUGINDIR="$with_plugindir"
+    SUDO_DEFINE_UNQUOTED(_PATH_SUDO_PLUGIN_DIR, "$PLUGINDIR/")
+    SUDO_DEFINE_UNQUOTED(SUDOERS_PLUGIN, "sudoers${SOEXT}")
     exec_prefix="$oexec_prefix"
 fi
 
@@ -2875,7 +2945,8 @@ test "$sysconfdir" = '${prefix}/etc' -a X"$with_stow" != X"yes" && sysconfdir='/
 dnl
 dnl Substitute into the Makefile and man pages
 dnl
-AC_CONFIG_FILES([Makefile sudo.man visudo.man sudoers.man sudoers.ldap.man sudoreplay.man sudo_usage.h sudoers])
+dnl AC_CONFIG_FILES([doc/sudo.man doc/visudo.man doc/sudoers.man doc/sudoers.ldap.man doc/sudoreplay.man src/Makefile src/sudo_usage.h])
+AC_CONFIG_FILES([Makefile common/Makefile compat/Makefile doc/Makefile include/Makefile src/sudo_usage.h src/Makefile plugins/sample/Makefile plugins/sample_group/Makefile plugins/sudoers/Makefile plugins/sudoers/sudoers])
 AC_OUTPUT
 
 dnl
@@ -2895,11 +2966,12 @@ dnl
 AH_TEMPLATE(BROKEN_SYSLOG, [Define to 1 if the `syslog' function returns a non-zero int to denote failure.])
 AH_TEMPLATE(CLASSIC_INSULTS, [Define to 1 if you want the insults from the "classic" version sudo.])
 AH_TEMPLATE(CSOPS_INSULTS, [Define to 1 if you want insults culled from the twisted minds of CSOps.])
+AH_TEMPLATE(SUDOERS_PLUGIN, [The name of the sudoers plugin, including extension.])
 AH_TEMPLATE(DONT_LEAK_PATH_INFO, [Define to 1 if you want sudo to display "command not allowed" instead of "command not found" when a command cannot be found.])
-AH_TEMPLATE(ENV_EDITOR, [Define to 1 if you want visudo to honor the EDITOR and VISUAL env variables.])
 AH_TEMPLATE(ENV_DEBUG, [Define to 1 to enable environment function debugging.])
-AH_TEMPLATE(ENV_RESET, [Define to 1 to enable environment resetting by default.])
+AH_TEMPLATE(ENV_EDITOR, [Define to 1 if you want visudo to honor the EDITOR and VISUAL env variables.])
 AH_TEMPLATE(FQDN, [Define to 1 if you want to require fully qualified hosts in sudoers.])
+AH_TEMPLATE(ENV_RESET, [Define to 1 to enable environment resetting by default.])
 AH_TEMPLATE(GOONS_INSULTS, [Define to 1 if you want insults from the "Goon Show".])
 AH_TEMPLATE(HAL_INSULTS, [Define to 1 if you want 2001-like insults.])
 AH_TEMPLATE(HAVE_AFS, [Define to 1 if you use AFS.])
@@ -2911,6 +2983,7 @@ AH_TEMPLATE(HAVE_DD_FD, [Define to 1 if your `DIR' contains dd_fd.])
 AH_TEMPLATE(HAVE_DIRFD, [Define to 1 if you have the `dirfd' function or macro.])
 AH_TEMPLATE(HAVE_DGETTEXT, [Define to 1 if you have the `dgettext' function.])
 AH_TEMPLATE(HAVE_DISPCRYPT, [Define to 1 if you have the `dispcrypt' function.])
+AH_TEMPLATE(HAVE_DLOPEN, [Define to 1 if you have the `dlopen' function.])
 AH_TEMPLATE(HAVE_EXTENDED_GLOB, [Define to 1 if your glob.h defines the GLOB_BRACE and GLOB_TILDE flags.])
 AH_TEMPLATE(HAVE_FCNTL_CLOSEM, [Define to 1 if your system has the F_CLOSEM fcntl.])
 AH_TEMPLATE(HAVE_FNMATCH, [Define to 1 if you have the `fnmatch' function.])
@@ -2941,13 +3014,14 @@ 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_SETKEYCREATECON, [Define to 1 if you have the `setkeycreatecon' function.])
+AH_TEMPLATE(HAVE_SHL_LOAD, [Define to 1 if you have the `shl_load' function.])
 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().])
+AH_TEMPLATE(HAVE_RFC1938_SKEYCHALLENGE, [Define to 1 if the skeychallenge() function is RFC1938-compliant and takes 4 arguments])
 AH_TEMPLATE(HAVE_ST__TIM, [Define to 1 if your struct stat uses an st__tim union])
 AH_TEMPLATE(HAVE_ST_MTIM, [Define to 1 if your struct stat has an st_mtim member])
 AH_TEMPLATE(HAVE_ST_MTIMESPEC, [Define to 1 if your struct stat has an st_mtimespec member])
-AH_TEMPLATE(HAVE_TERMIOS_H, [Define to 1 if you have the <termios.h> header file and the `tcgetattr' function.])
 AH_TEMPLATE(HAVE_TIMESPEC, [Define to 1 if you have struct timespec in sys/time.h])
 AH_TEMPLATE(HAVE___PROGNAME, [Define to 1 if your crt0.o defines the __progname symbol for you.])
 AH_TEMPLATE(HOST_IN_LOG, [Define to 1 if you want the hostname to be entered into the log file.])
@@ -2975,7 +3049,8 @@ AH_TEMPLATE(USE_STOW, [Define to 1 if you use GNU stow packaging.])
 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.])
-AH_TEMPLATE(USING_NONUNIX_GROUPS, [Define to 1 if using a non-Unix group lookup implementation.])
+AH_TEMPLATE(HAVE_STRUCT_UTMP_UT_EXIT, [Define to 1 if `ut_exit' is a member of `struct utmp'.])
+AH_TEMPLATE(HAVE_STRUCT_UTMPX_UT_EXIT, [Define to 1 if `ut_exit' is a member of `struct utmpx'.])
 
 dnl
 dnl Bits to copy verbatim into config.h.in
@@ -3009,17 +3084,6 @@ AH_BOTTOM([/*
 # endif /* HAVE_ST_MTIMESPEC */
 #endif /* HAVE_ST_MTIM */
 
-/*
- * Emulate a subset of waitpid() if we don't have it.
- */
-#ifdef HAVE_WAITPID
-# define sudo_waitpid(p, s, o) waitpid(p, s, o)
-#else
-# ifdef HAVE_WAIT3
-#  define sudo_waitpid(p, s, o)        wait3(s, o, NULL)
-# endif
-#endif
-
 /* GNU stow needs /etc/sudoers to be a symlink. */
 #ifdef USE_STOW
 # define stat_sudoers  stat
diff --git a/def_data.c b/def_data.c
deleted file mode 100644 (file)
index c63d595..0000000
+++ /dev/null
@@ -1,340 +0,0 @@
-static struct def_values def_data_lecture[] = {
-    { "never", never },
-    { "once", once },
-    { "always", always },
-    { NULL, 0 },
-};
-
-static struct def_values def_data_listpw[] = {
-    { "never", never },
-    { "any", any },
-    { "all", all },
-    { "always", always },
-    { NULL, 0 },
-};
-
-static struct def_values def_data_verifypw[] = {
-    { "never", never },
-    { "all", all },
-    { "any", any },
-    { "always", always },
-    { NULL, 0 },
-};
-
-struct sudo_defs_types sudo_defs_table[] = {
-    {
-       "syslog", T_LOGFAC|T_BOOL,
-       "Syslog facility if syslog is being used for logging: %s",
-       NULL,
-    }, {
-       "syslog_goodpri", T_LOGPRI,
-       "Syslog priority to use when user authenticates successfully: %s",
-       NULL,
-    }, {
-       "syslog_badpri", T_LOGPRI,
-       "Syslog priority to use when user authenticates unsuccessfully: %s",
-       NULL,
-    }, {
-       "long_otp_prompt", T_FLAG,
-       "Put OTP prompt on its own line",
-       NULL,
-    }, {
-       "ignore_dot", T_FLAG,
-       "Ignore '.' in $PATH",
-       NULL,
-    }, {
-       "mail_always", T_FLAG,
-       "Always send mail when sudo is run",
-       NULL,
-    }, {
-       "mail_badpass", T_FLAG,
-       "Send mail if user authentication fails",
-       NULL,
-    }, {
-       "mail_no_user", T_FLAG,
-       "Send mail if the user is not in sudoers",
-       NULL,
-    }, {
-       "mail_no_host", T_FLAG,
-       "Send mail if the user is not in sudoers for this host",
-       NULL,
-    }, {
-       "mail_no_perms", T_FLAG,
-       "Send mail if the user is not allowed to run a command",
-       NULL,
-    }, {
-       "tty_tickets", T_FLAG,
-       "Use a separate timestamp for each user/tty combo",
-       NULL,
-    }, {
-       "lecture", T_TUPLE|T_BOOL,
-       "Lecture user the first time they run sudo",
-       def_data_lecture,
-    }, {
-       "lecture_file", T_STR|T_PATH|T_BOOL,
-       "File containing the sudo lecture: %s",
-       NULL,
-    }, {
-       "authenticate", T_FLAG,
-       "Require users to authenticate by default",
-       NULL,
-    }, {
-       "root_sudo", T_FLAG,
-       "Root may run sudo",
-       NULL,
-    }, {
-       "log_host", T_FLAG,
-       "Log the hostname in the (non-syslog) log file",
-       NULL,
-    }, {
-       "log_year", T_FLAG,
-       "Log the year in the (non-syslog) log file",
-       NULL,
-    }, {
-       "shell_noargs", T_FLAG,
-       "If sudo is invoked with no arguments, start a shell",
-       NULL,
-    }, {
-       "set_home", T_FLAG,
-       "Set $HOME to the target user when starting a shell with -s",
-       NULL,
-    }, {
-       "always_set_home", T_FLAG,
-       "Always set $HOME to the target user's home directory",
-       NULL,
-    }, {
-       "path_info", T_FLAG,
-       "Allow some information gathering to give useful error messages",
-       NULL,
-    }, {
-       "fqdn", T_FLAG,
-       "Require fully-qualified hostnames in the sudoers file",
-       NULL,
-    }, {
-       "insults", T_FLAG,
-       "Insult the user when they enter an incorrect password",
-       NULL,
-    }, {
-       "requiretty", T_FLAG,
-       "Only allow the user to run sudo if they have a tty",
-       NULL,
-    }, {
-       "env_editor", T_FLAG,
-       "Visudo will honor the EDITOR environment variable",
-       NULL,
-    }, {
-       "rootpw", T_FLAG,
-       "Prompt for root's password, not the users's",
-       NULL,
-    }, {
-       "runaspw", T_FLAG,
-       "Prompt for the runas_default user's password, not the users's",
-       NULL,
-    }, {
-       "targetpw", T_FLAG,
-       "Prompt for the target user's password, not the users's",
-       NULL,
-    }, {
-       "use_loginclass", T_FLAG,
-       "Apply defaults in the target user's login class if there is one",
-       NULL,
-    }, {
-       "set_logname", T_FLAG,
-       "Set the LOGNAME and USER environment variables",
-       NULL,
-    }, {
-       "stay_setuid", T_FLAG,
-       "Only set the effective uid to the target user, not the real uid",
-       NULL,
-    }, {
-       "preserve_groups", T_FLAG,
-       "Don't initialize the group vector to that of the target user",
-       NULL,
-    }, {
-       "loglinelen", T_UINT|T_BOOL,
-       "Length at which to wrap log file lines (0 for no wrap): %d",
-       NULL,
-    }, {
-       "timestamp_timeout", T_FLOAT|T_BOOL,
-       "Authentication timestamp timeout: %.1f minutes",
-       NULL,
-    }, {
-       "passwd_timeout", T_FLOAT|T_BOOL,
-       "Password prompt timeout: %.1f minutes",
-       NULL,
-    }, {
-       "passwd_tries", T_UINT,
-       "Number of tries to enter a password: %d",
-       NULL,
-    }, {
-       "umask", T_MODE|T_BOOL,
-       "Umask to use or 0777 to use user's: 0%o",
-       NULL,
-    }, {
-       "logfile", T_STR|T_BOOL|T_PATH,
-       "Path to log file: %s",
-       NULL,
-    }, {
-       "mailerpath", T_STR|T_BOOL|T_PATH,
-       "Path to mail program: %s",
-       NULL,
-    }, {
-       "mailerflags", T_STR|T_BOOL,
-       "Flags for mail program: %s",
-       NULL,
-    }, {
-       "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",
-       NULL,
-    }, {
-       "badpass_message", T_STR,
-       "Incorrect password message: %s",
-       NULL,
-    }, {
-       "timestampdir", T_STR|T_PATH,
-       "Path to authentication timestamp dir: %s",
-       NULL,
-    }, {
-       "timestampowner", T_STR,
-       "Owner of the authentication timestamp dir: %s",
-       NULL,
-    }, {
-       "exempt_group", T_STR|T_BOOL,
-       "Users in this group are exempt from password and PATH requirements: %s",
-       NULL,
-    }, {
-       "passprompt", T_STR,
-       "Default password prompt: %s",
-       NULL,
-    }, {
-       "passprompt_override", T_FLAG,
-       "If set, passprompt will override system prompt in all cases.",
-       NULL,
-    }, {
-       "runas_default", T_STR,
-       "Default user to run commands as: %s",
-       NULL,
-    }, {
-       "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",
-       NULL,
-    }, {
-       "listpw", T_TUPLE|T_BOOL,
-       "When to require a password for 'list' pseudocommand: %s",
-       def_data_listpw,
-    }, {
-       "verifypw", T_TUPLE|T_BOOL,
-       "When to require a password for 'verify' pseudocommand: %s",
-       def_data_verifypw,
-    }, {
-       "noexec", T_FLAG,
-       "Preload the dummy exec functions contained in 'noexec_file'",
-       NULL,
-    }, {
-       "noexec_file", T_STR|T_PATH,
-       "File containing dummy exec functions: %s",
-       NULL,
-    }, {
-       "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",
-       NULL,
-    }, {
-       "env_reset", T_FLAG,
-       "Reset the environment to a default set of variables",
-       NULL,
-    }, {
-       "env_check", T_LIST|T_BOOL,
-       "Environment variables to check for sanity:",
-       NULL,
-    }, {
-       "env_delete", T_LIST|T_BOOL,
-       "Environment variables to remove:",
-       NULL,
-    }, {
-       "env_keep", T_LIST|T_BOOL,
-       "Environment variables to preserve:",
-       NULL,
-    }, {
-       "role", T_STR,
-       "SELinux role to use in the new security context: %s",
-       NULL,
-    }, {
-       "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,
-    }, {
-       "pwfeedback", T_FLAG,
-       "Provide visual feedback at the password prompt when there is user input",
-       NULL,
-    }, {
-       "fast_glob", T_FLAG,
-       "Use faster globbing that is less accurate but does not access the filesystem",
-       NULL,
-    }, {
-       "umask_override", T_FLAG,
-       "The umask specified in sudoers will override the user's, even if it is more permissive",
-       NULL,
-    }, {
-       "log_input", T_FLAG,
-       "Log user's input for the command being run",
-       NULL,
-    }, {
-       "log_output", T_FLAG,
-       "Log the output of the command being run",
-       NULL,
-    }, {
-       "compress_io", T_FLAG,
-       "Compress I/O logs using zlib",
-       NULL,
-    }, {
-       "use_pty", T_FLAG,
-       "Always run commands in a pseudo-tty",
-       NULL,
-    }, {
-       "iolog_dir", T_STR|T_PATH,
-       "Directory in which to store input/output logs",
-       NULL,
-    }, {
-       NULL, 0, NULL
-    }
-};
diff --git a/def_data.h b/def_data.h
deleted file mode 100644 (file)
index 0996ec8..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-#define def_syslog              (sudo_defs_table[0].sd_un.ival)
-#define I_SYSLOG                0
-#define def_syslog_goodpri      (sudo_defs_table[1].sd_un.ival)
-#define I_SYSLOG_GOODPRI        1
-#define def_syslog_badpri       (sudo_defs_table[2].sd_un.ival)
-#define I_SYSLOG_BADPRI         2
-#define def_long_otp_prompt     (sudo_defs_table[3].sd_un.flag)
-#define I_LONG_OTP_PROMPT       3
-#define def_ignore_dot          (sudo_defs_table[4].sd_un.flag)
-#define I_IGNORE_DOT            4
-#define def_mail_always         (sudo_defs_table[5].sd_un.flag)
-#define I_MAIL_ALWAYS           5
-#define def_mail_badpass        (sudo_defs_table[6].sd_un.flag)
-#define I_MAIL_BADPASS          6
-#define def_mail_no_user        (sudo_defs_table[7].sd_un.flag)
-#define I_MAIL_NO_USER          7
-#define def_mail_no_host        (sudo_defs_table[8].sd_un.flag)
-#define I_MAIL_NO_HOST          8
-#define def_mail_no_perms       (sudo_defs_table[9].sd_un.flag)
-#define I_MAIL_NO_PERMS         9
-#define def_tty_tickets         (sudo_defs_table[10].sd_un.flag)
-#define I_TTY_TICKETS           10
-#define def_lecture             (sudo_defs_table[11].sd_un.tuple)
-#define I_LECTURE               11
-#define def_lecture_file        (sudo_defs_table[12].sd_un.str)
-#define I_LECTURE_FILE          12
-#define def_authenticate        (sudo_defs_table[13].sd_un.flag)
-#define I_AUTHENTICATE          13
-#define def_root_sudo           (sudo_defs_table[14].sd_un.flag)
-#define I_ROOT_SUDO             14
-#define def_log_host            (sudo_defs_table[15].sd_un.flag)
-#define I_LOG_HOST              15
-#define def_log_year            (sudo_defs_table[16].sd_un.flag)
-#define I_LOG_YEAR              16
-#define def_shell_noargs        (sudo_defs_table[17].sd_un.flag)
-#define I_SHELL_NOARGS          17
-#define def_set_home            (sudo_defs_table[18].sd_un.flag)
-#define I_SET_HOME              18
-#define def_always_set_home     (sudo_defs_table[19].sd_un.flag)
-#define I_ALWAYS_SET_HOME       19
-#define def_path_info           (sudo_defs_table[20].sd_un.flag)
-#define I_PATH_INFO             20
-#define def_fqdn                (sudo_defs_table[21].sd_un.flag)
-#define I_FQDN                  21
-#define def_insults             (sudo_defs_table[22].sd_un.flag)
-#define I_INSULTS               22
-#define def_requiretty          (sudo_defs_table[23].sd_un.flag)
-#define I_REQUIRETTY            23
-#define def_env_editor          (sudo_defs_table[24].sd_un.flag)
-#define I_ENV_EDITOR            24
-#define def_rootpw              (sudo_defs_table[25].sd_un.flag)
-#define I_ROOTPW                25
-#define def_runaspw             (sudo_defs_table[26].sd_un.flag)
-#define I_RUNASPW               26
-#define def_targetpw            (sudo_defs_table[27].sd_un.flag)
-#define I_TARGETPW              27
-#define def_use_loginclass      (sudo_defs_table[28].sd_un.flag)
-#define I_USE_LOGINCLASS        28
-#define def_set_logname         (sudo_defs_table[29].sd_un.flag)
-#define I_SET_LOGNAME           29
-#define def_stay_setuid         (sudo_defs_table[30].sd_un.flag)
-#define I_STAY_SETUID           30
-#define def_preserve_groups     (sudo_defs_table[31].sd_un.flag)
-#define I_PRESERVE_GROUPS       31
-#define def_loglinelen          (sudo_defs_table[32].sd_un.ival)
-#define I_LOGLINELEN            32
-#define def_timestamp_timeout   (sudo_defs_table[33].sd_un.fval)
-#define I_TIMESTAMP_TIMEOUT     33
-#define def_passwd_timeout      (sudo_defs_table[34].sd_un.fval)
-#define I_PASSWD_TIMEOUT        34
-#define def_passwd_tries        (sudo_defs_table[35].sd_un.ival)
-#define I_PASSWD_TRIES          35
-#define def_umask               (sudo_defs_table[36].sd_un.mode)
-#define I_UMASK                 36
-#define def_logfile             (sudo_defs_table[37].sd_un.str)
-#define I_LOGFILE               37
-#define def_mailerpath          (sudo_defs_table[38].sd_un.str)
-#define I_MAILERPATH            38
-#define def_mailerflags         (sudo_defs_table[39].sd_un.str)
-#define I_MAILERFLAGS           39
-#define def_mailto              (sudo_defs_table[40].sd_un.str)
-#define I_MAILTO                40
-#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
-#define def_pwfeedback          (sudo_defs_table[70].sd_un.flag)
-#define I_PWFEEDBACK            70
-#define def_fast_glob           (sudo_defs_table[71].sd_un.flag)
-#define I_FAST_GLOB             71
-#define def_umask_override      (sudo_defs_table[72].sd_un.flag)
-#define I_UMASK_OVERRIDE        72
-#define def_log_input           (sudo_defs_table[73].sd_un.flag)
-#define I_LOG_INPUT             73
-#define def_log_output          (sudo_defs_table[74].sd_un.flag)
-#define I_LOG_OUTPUT            74
-#define def_compress_io         (sudo_defs_table[75].sd_un.flag)
-#define I_COMPRESS_IO           75
-#define def_use_pty             (sudo_defs_table[76].sd_un.flag)
-#define I_USE_PTY               76
-#define def_iolog_dir           (sudo_defs_table[77].sd_un.str)
-#define I_IOLOG_DIR             77
-
-enum def_tupple {
-       never,
-       once,
-       always,
-       any,
-       all
-};
diff --git a/def_data.in b/def_data.in
deleted file mode 100644 (file)
index 4a7ae96..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-#
-# Format:
-#
-# var_name
-#      TYPE
-#      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
-       "Syslog facility if syslog is being used for logging: %s"
-syslog_goodpri
-       T_LOGPRI
-       "Syslog priority to use when user authenticates successfully: %s"
-syslog_badpri
-       T_LOGPRI
-       "Syslog priority to use when user authenticates unsuccessfully: %s"
-long_otp_prompt
-       T_FLAG
-       "Put OTP prompt on its own line"
-ignore_dot
-       T_FLAG
-       "Ignore '.' in $PATH"
-mail_always
-       T_FLAG
-       "Always send mail when sudo is run"
-mail_badpass
-       T_FLAG
-       "Send mail if user authentication fails"
-mail_no_user
-       T_FLAG
-       "Send mail if the user is not in sudoers"
-mail_no_host
-       T_FLAG
-       "Send mail if the user is not in sudoers for this host"
-mail_no_perms
-       T_FLAG
-       "Send mail if the user is not allowed to run a command"
-tty_tickets
-       T_FLAG
-       "Use a separate timestamp for each user/tty combo"
-lecture
-       T_TUPLE|T_BOOL
-       "Lecture user the first time they run sudo"
-       never once always
-lecture_file
-       T_STR|T_PATH|T_BOOL
-       "File containing the sudo lecture: %s"
-authenticate
-       T_FLAG
-       "Require users to authenticate by default"
-root_sudo
-       T_FLAG
-       "Root may run sudo"
-log_host
-       T_FLAG
-       "Log the hostname in the (non-syslog) log file"
-log_year
-       T_FLAG
-       "Log the year in the (non-syslog) log file"
-shell_noargs
-       T_FLAG
-       "If sudo is invoked with no arguments, start a shell"
-set_home
-       T_FLAG
-       "Set $HOME to the target user when starting a shell with -s"
-always_set_home
-       T_FLAG
-       "Always set $HOME to the target user's home directory"
-path_info
-       T_FLAG
-       "Allow some information gathering to give useful error messages"
-fqdn
-       T_FLAG
-       "Require fully-qualified hostnames in the sudoers file"
-insults
-       T_FLAG
-       "Insult the user when they enter an incorrect password"
-requiretty
-       T_FLAG
-       "Only allow the user to run sudo if they have a tty"
-env_editor
-       T_FLAG
-       "Visudo will honor the EDITOR environment variable"
-rootpw
-       T_FLAG
-       "Prompt for root's password, not the users's"
-runaspw
-       T_FLAG
-       "Prompt for the runas_default user's password, not the users's"
-targetpw
-       T_FLAG
-       "Prompt for the target user's password, not the users's"
-use_loginclass
-       T_FLAG
-       "Apply defaults in the target user's login class if there is one"
-set_logname
-       T_FLAG
-       "Set the LOGNAME and USER environment variables"
-stay_setuid
-       T_FLAG
-       "Only set the effective uid to the target user, not the real uid"
-preserve_groups
-       T_FLAG
-       "Don't initialize the group vector to that of the target user"
-loglinelen
-       T_UINT|T_BOOL
-       "Length at which to wrap log file lines (0 for no wrap): %d"
-timestamp_timeout
-       T_FLOAT|T_BOOL
-       "Authentication timestamp timeout: %.1f minutes"
-passwd_timeout
-       T_FLOAT|T_BOOL
-       "Password prompt timeout: %.1f minutes"
-passwd_tries
-       T_UINT
-       "Number of tries to enter a password: %d"
-umask
-       T_MODE|T_BOOL
-       "Umask to use or 0777 to use user's: 0%o"
-logfile
-       T_STR|T_BOOL|T_PATH
-       "Path to log file: %s"
-mailerpath
-       T_STR|T_BOOL|T_PATH
-       "Path to mail program: %s"
-mailerflags
-       T_STR|T_BOOL
-       "Flags for mail program: %s"
-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"
-badpass_message
-       T_STR
-       "Incorrect password message: %s"
-timestampdir
-       T_STR|T_PATH
-       "Path to authentication timestamp dir: %s"
-timestampowner
-       T_STR
-       "Owner of the authentication timestamp dir: %s"
-exempt_group
-       T_STR|T_BOOL
-       "Users in this group are exempt from password and PATH requirements: %s"
-passprompt
-       T_STR
-       "Default password prompt: %s"
-passprompt_override
-       T_FLAG
-       "If set, passprompt will override system prompt in all cases."
-runas_default
-       T_STR
-       "Default user to run commands as: %s"
-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"
-listpw
-       T_TUPLE|T_BOOL
-       "When to require a password for 'list' pseudocommand: %s"
-       never any all always
-verifypw
-       T_TUPLE|T_BOOL
-       "When to require a password for 'verify' pseudocommand: %s"
-       never all any always
-noexec
-       T_FLAG
-       "Preload the dummy exec functions contained in 'noexec_file'"
-noexec_file
-       T_STR|T_PATH
-       "File containing dummy exec functions: %s"
-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"
-env_reset
-       T_FLAG
-       "Reset the environment to a default set of variables"
-env_check
-       T_LIST|T_BOOL
-       "Environment variables to check for sanity:"
-env_delete
-       T_LIST|T_BOOL
-       "Environment variables to remove:"
-env_keep
-       T_LIST|T_BOOL
-       "Environment variables to preserve:"
-role
-       T_STR
-       "SELinux role to use in the new security context: %s"
-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"
-pwfeedback
-       T_FLAG
-       "Provide visual feedback at the password prompt when there is user input"
-fast_glob
-       T_FLAG
-       "Use faster globbing that is less accurate but does not access the filesystem"
-umask_override
-       T_FLAG
-       "The umask specified in sudoers will override the user's, even if it is more permissive"
-log_input
-       T_FLAG
-       "Log user's input for the command being run"
-log_output
-       T_FLAG
-       "Log the output of the command being run"
-compress_io
-       T_FLAG
-       "Compress I/O logs using zlib"
-use_pty
-       T_FLAG
-       "Always run commands in a pseudo-tty"
-iolog_dir
-       T_STR|T_PATH
-       "Directory in which to store input/output logs"
diff --git a/defaults.c b/defaults.c
deleted file mode 100644 (file)
index c1f0afa..0000000
+++ /dev/null
@@ -1,843 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2007-2008, 2010
- *     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/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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-# ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <ctype.h>
-
-#include "sudo.h"
-#include "parse.h"
-#include <gram.h>
-
-/*
- * For converting between syslog numbers and strings.
- */
-struct strmap {
-    char *name;
-    int num;
-};
-
-#ifdef LOG_NFACILITIES
-static struct strmap facilities[] = {
-#ifdef LOG_AUTHPRIV
-       { "authpriv",   LOG_AUTHPRIV },
-#endif
-       { "auth",       LOG_AUTH },
-       { "daemon",     LOG_DAEMON },
-       { "user",       LOG_USER },
-       { "local0",     LOG_LOCAL0 },
-       { "local1",     LOG_LOCAL1 },
-       { "local2",     LOG_LOCAL2 },
-       { "local3",     LOG_LOCAL3 },
-       { "local4",     LOG_LOCAL4 },
-       { "local5",     LOG_LOCAL5 },
-       { "local6",     LOG_LOCAL6 },
-       { "local7",     LOG_LOCAL7 },
-       { NULL,         -1 }
-};
-#endif /* LOG_NFACILITIES */
-
-static struct strmap priorities[] = {
-       { "alert",      LOG_ALERT },
-       { "crit",       LOG_CRIT },
-       { "debug",      LOG_DEBUG },
-       { "emerg",      LOG_EMERG },
-       { "err",        LOG_ERR },
-       { "info",       LOG_INFO },
-       { "notice",     LOG_NOTICE },
-       { "warning",    LOG_WARNING },
-       { NULL,         -1 }
-};
-
-/*
- * Local prototypes.
- */
-static int store_int __P((char *, struct sudo_defs_types *, int));
-static int store_list __P((char *, struct sudo_defs_types *, int));
-static int store_mode __P((char *, struct sudo_defs_types *, int));
-static int store_str __P((char *, struct sudo_defs_types *, int));
-static int store_syslogfac __P((char *, struct sudo_defs_types *, int));
-static int store_syslogpri __P((char *, struct sudo_defs_types *, int));
-static int store_tuple __P((char *, struct sudo_defs_types *, int));
-static int store_uint __P((char *, struct sudo_defs_types *, int));
-static int store_float __P((char *, struct sudo_defs_types *, int));
-static void list_op __P((char *, size_t, struct sudo_defs_types *, enum list_ops));
-static const char *logfac2str __P((int));
-static const char *logpri2str __P((int));
-
-/*
- * Table describing compile-time and run-time options.
- */
-#include <def_data.c>
-
-/*
- * Print version and configure info.
- */
-void
-dump_defaults()
-{
-    struct sudo_defs_types *cur;
-    struct list_member *item;
-    struct def_values *def;
-
-    for (cur = sudo_defs_table; cur->name; cur++) {
-       if (cur->desc) {
-           switch (cur->type & T_MASK) {
-               case T_FLAG:
-                   if (cur->sd_un.flag)
-                       puts(cur->desc);
-                   break;
-               case T_STR:
-                   if (cur->sd_un.str) {
-                       (void) printf(cur->desc, cur->sd_un.str);
-                       putchar('\n');
-                   }
-                   break;
-               case T_LOGFAC:
-                   if (cur->sd_un.ival) {
-                       (void) printf(cur->desc, logfac2str(cur->sd_un.ival));
-                       putchar('\n');
-                   }
-                   break;
-               case T_LOGPRI:
-                   if (cur->sd_un.ival) {
-                       (void) printf(cur->desc, logpri2str(cur->sd_un.ival));
-                       putchar('\n');
-                   }
-                   break;
-               case T_UINT:
-               case T_INT:
-                   (void) printf(cur->desc, cur->sd_un.ival);
-                   putchar('\n');
-                   break;
-               case T_FLOAT:
-                   (void) printf(cur->desc, cur->sd_un.fval);
-                   putchar('\n');
-                   break;
-               case T_MODE:
-                   (void) printf(cur->desc, cur->sd_un.mode);
-                   putchar('\n');
-                   break;
-               case T_LIST:
-                   if (cur->sd_un.list) {
-                       puts(cur->desc);
-                       for (item = cur->sd_un.list; item; item = item->next)
-                           printf("\t%s\n", item->value);
-                   }
-                   break;
-               case T_TUPLE:
-                   for (def = cur->values; def->sval; def++) {
-                       if (cur->sd_un.ival == def->ival) {
-                           (void) printf(cur->desc, def->sval);
-                           break;
-                       }
-                   }
-                   putchar('\n');
-                   break;
-           }
-       }
-    }
-}
-
-/*
- * List each option along with its description.
- */
-void
-list_options()
-{
-    struct sudo_defs_types *cur;
-    char *p;
-
-    (void) puts("Available options in a sudoers ``Defaults'' line:\n");
-    for (cur = sudo_defs_table; cur->name; cur++) {
-       if (cur->name && cur->desc) {
-           switch (cur->type & T_MASK) {
-               case T_FLAG:
-                   (void) printf("%s: %s\n", cur->name, cur->desc);
-                   break;
-               default:
-                   p = strrchr(cur->desc, ':');
-                   if (p)
-                       (void) printf("%s: %.*s\n", cur->name,
-                           (int) (p - cur->desc), cur->desc);
-                   else
-                       (void) printf("%s: %s\n", cur->name, cur->desc);
-                   break;
-           }
-       }
-    }
-}
-
-/*
- * Sets/clears an entry in the defaults structure
- * If a variable that takes a value is used in a boolean
- * context with op == 0, disable that variable.
- * Eg. you may want to turn off logging to a file for some hosts.
- * This is only meaningful for variables that are *optional*.
- */
-int
-set_default(var, val, op)
-    char *var;
-    char *val;
-    int op;     /* TRUE or FALSE */
-{
-    struct sudo_defs_types *cur;
-    int num;
-
-    for (cur = sudo_defs_table, num = 0; cur->name; cur++, num++) {
-       if (strcmp(var, cur->name) == 0)
-           break;
-    }
-    if (!cur->name) {
-       warningx("unknown defaults entry `%s'", var);
-       return FALSE;
-    }
-
-    switch (cur->type & T_MASK) {
-       case T_LOGFAC:
-           if (!store_syslogfac(val, cur, op)) {
-               if (val)
-                   warningx("value `%s' is invalid for option `%s'", val, var);
-               else
-                   warningx("no value specified for `%s'", var);
-               return FALSE;
-           }
-           break;
-       case T_LOGPRI:
-           if (!store_syslogpri(val, cur, op)) {
-               if (val)
-                   warningx("value `%s' is invalid for option `%s'", val, var);
-               else
-                   warningx("no value specified for `%s'", var);
-               return FALSE;
-           }
-           break;
-       case T_STR:
-           if (!val) {
-               /* Check for bogus boolean usage or lack of a value. */
-               if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-                   warningx("no value specified for `%s'", var);
-                   return FALSE;
-               }
-           }
-           if (ISSET(cur->type, T_PATH) && val && *val != '/') {
-               warningx("values for `%s' must start with a '/'", var);
-               return FALSE;
-           }
-           if (!store_str(val, cur, op)) {
-               warningx("value `%s' is invalid for option `%s'", val, var);
-               return FALSE;
-           }
-           break;
-       case T_INT:
-           if (!val) {
-               /* Check for bogus boolean usage or lack of a value. */
-               if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-                   warningx("no value specified for `%s'", var);
-                   return FALSE;
-               }
-           }
-           if (!store_int(val, cur, op)) {
-               warningx("value `%s' is invalid for option `%s'", val, var);
-               return FALSE;
-           }
-           break;
-       case T_UINT:
-           if (!val) {
-               /* Check for bogus boolean usage or lack of a value. */
-               if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-                   warningx("no value specified for `%s'", var);
-                   return FALSE;
-               }
-           }
-           if (!store_uint(val, cur, op)) {
-               warningx("value `%s' is invalid for option `%s'", val, var);
-               return FALSE;
-           }
-           break;
-       case T_FLOAT:
-           if (!val) {
-               /* Check for bogus boolean usage or lack of a value. */
-               if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-                   warningx("no value specified for `%s'", var);
-                   return FALSE;
-               }
-           }
-           if (!store_float(val, cur, op)) {
-               warningx("value `%s' is invalid for option `%s'", val, var);
-               return FALSE;
-           }
-           break;
-       case T_MODE:
-           if (!val) {
-               /* Check for bogus boolean usage or lack of a value. */
-               if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-                   warningx("no value specified for `%s'", var);
-                   return FALSE;
-               }
-           }
-           if (!store_mode(val, cur, op)) {
-               warningx("value `%s' is invalid for option `%s'", val, var);
-               return FALSE;
-           }
-           break;
-       case T_FLAG:
-           if (val) {
-               warningx("option `%s' does not take a value", var);
-               return FALSE;
-           }
-           cur->sd_un.flag = op;
-           break;
-       case T_LIST:
-           if (!val) {
-               /* Check for bogus boolean usage or lack of a value. */
-               if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
-                   warningx("no value specified for `%s'", var);
-                   return FALSE;
-               }
-           }
-           if (!store_list(val, cur, op)) {
-               warningx("value `%s' is invalid for option `%s'", val, var);
-               return FALSE;
-           }
-           break;
-       case T_TUPLE:
-           if (!val && !ISSET(cur->type, T_BOOL)) {
-               warningx("no value specified for `%s'", var);
-               return FALSE;
-           }
-           if (!store_tuple(val, cur, op)) {
-               warningx("value `%s' is invalid for option `%s'", val, var);
-               return FALSE;
-           }
-           break;
-    }
-
-    return TRUE;
-}
-
-/*
- * Set default options to compiled-in values.
- * Any of these may be overridden at runtime by a "Defaults" file.
- */
-void
-init_defaults()
-{
-    static int firsttime = 1;
-    struct sudo_defs_types *def;
-
-    /* Clear any old settings. */
-    if (!firsttime) {
-       for (def = sudo_defs_table; def->name; def++) {
-           switch (def->type & T_MASK) {
-               case T_STR:
-                   efree(def->sd_un.str);
-                   def->sd_un.str = NULL;
-                   break;
-               case T_LIST:
-                   list_op(NULL, 0, def, freeall);
-                   break;
-           }
-           zero_bytes(&def->sd_un, sizeof(def->sd_un));
-       }
-    }
-
-    /* First initialize the flags. */
-#ifdef LONG_OTP_PROMPT
-    def_long_otp_prompt = TRUE;
-#endif
-#ifdef IGNORE_DOT_PATH
-    def_ignore_dot = TRUE;
-#endif
-#ifdef ALWAYS_SEND_MAIL
-    def_mail_always = TRUE;
-#endif
-#ifdef SEND_MAIL_WHEN_NO_USER
-    def_mail_no_user = TRUE;
-#endif
-#ifdef SEND_MAIL_WHEN_NO_HOST
-    def_mail_no_host = TRUE;
-#endif
-#ifdef SEND_MAIL_WHEN_NOT_OK
-    def_mail_no_perms = TRUE;
-#endif
-#ifndef NO_TTY_TICKETS
-    def_tty_tickets = TRUE;
-#endif
-#ifndef NO_LECTURE
-    def_lecture = once;
-#endif
-#ifndef NO_AUTHENTICATION
-    def_authenticate = TRUE;
-#endif
-#ifndef NO_ROOT_SUDO
-    def_root_sudo = TRUE;
-#endif
-#ifdef HOST_IN_LOG
-    def_log_host = TRUE;
-#endif
-#ifdef SHELL_IF_NO_ARGS
-    def_shell_noargs = TRUE;
-#endif
-#ifdef SHELL_SETS_HOME
-    def_set_home = TRUE;
-#endif
-#ifndef DONT_LEAK_PATH_INFO
-    def_path_info = TRUE;
-#endif
-#ifdef FQDN
-    def_fqdn = TRUE;
-#endif
-#ifdef USE_INSULTS
-    def_insults = TRUE;
-#endif
-#ifdef ENV_EDITOR
-    def_env_editor = TRUE;
-#endif
-#ifdef UMASK_OVERRIDE
-    def_umask_override = TRUE;
-#endif
-#ifdef _PATH_SUDO_ASKPASS
-    def_askpass = estrdup(_PATH_SUDO_ASKPASS);
-#endif
-    def_iolog_dir = estrdup(_PATH_SUDO_IO_LOGDIR);
-    def_sudoers_locale = estrdup("C");
-    def_env_reset = ENV_RESET;
-    def_set_logname = TRUE;
-    def_closefrom = STDERR_FILENO + 1;
-
-    /* Syslog options need special care since they both strings and ints */
-#if (LOGGING & SLOG_SYSLOG)
-    (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG], TRUE);
-    (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI],
-       TRUE);
-    (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI],
-       TRUE);
-#endif
-
-    /* Password flags also have a string and integer component. */
-    (void) store_tuple("any", &sudo_defs_table[I_LISTPW], TRUE);
-    (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], TRUE);
-
-    /* Then initialize the int-like things. */
-#ifdef SUDO_UMASK
-    def_umask = SUDO_UMASK;
-#else
-    def_umask = 0777;
-#endif
-    def_loglinelen = MAXLOGFILELEN;
-    def_timestamp_timeout = TIMEOUT;
-    def_passwd_timeout = PASSWORD_TIMEOUT;
-    def_passwd_tries = TRIES_FOR_PASSWORD;
-#ifdef HAVE_ZLIB_H
-    def_compress_io = TRUE;
-#endif
-
-    /* Now do the strings */
-    def_mailto = estrdup(MAILTO);
-    def_mailsub = estrdup(MAILSUBJECT);
-    def_badpass_message = estrdup(INCORRECT_PASSWORD);
-    def_timestampdir = estrdup(_PATH_SUDO_TIMEDIR);
-    def_passprompt = estrdup(PASSPROMPT);
-    def_runas_default = estrdup(RUNAS_DEFAULT);
-#ifdef _PATH_SUDO_SENDMAIL
-    def_mailerpath = estrdup(_PATH_SUDO_SENDMAIL);
-    def_mailerflags = estrdup("-t");
-#endif
-#if (LOGGING & SLOG_FILE)
-    def_logfile = estrdup(_PATH_SUDO_LOGFILE);
-#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
-    def_noexec_file = estrdup(_PATH_SUDO_NOEXEC);
-#endif
-
-    /* Finally do the lists (currently just environment tables). */
-    init_envtables();
-
-    firsttime = 0;
-}
-
-/*
- * Update the defaults based on what was set by sudoers.
- * Pass in an OR'd list of which default types to update.
- */
-int
-update_defaults(what)
-    int what;
-{
-    struct defaults *def;
-    int rc = TRUE;
-
-    tq_foreach_fwd(&defaults, def) {
-       switch (def->type) {
-           case DEFAULTS:
-               if (ISSET(what, SETDEF_GENERIC) &&
-                   !set_default(def->var, def->val, def->op))
-                   rc = 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))
-                   rc = FALSE;
-               break;
-           case DEFAULTS_RUNAS:
-               if (ISSET(what, SETDEF_RUNAS) &&
-                   runaslist_matches(&def->binding, NULL) == ALLOW &&
-                   !set_default(def->var, def->val, def->op))
-                   rc = FALSE;
-               break;
-           case DEFAULTS_HOST:
-               if (ISSET(what, SETDEF_HOST) &&
-                   hostlist_matches(&def->binding) == ALLOW &&
-                   !set_default(def->var, def->val, def->op))
-                   rc = FALSE;
-               break;
-           case DEFAULTS_CMND:
-               if (ISSET(what, SETDEF_CMND) &&
-                   cmndlist_matches(&def->binding) == ALLOW &&
-                   !set_default(def->var, def->val, def->op))
-                   rc = FALSE;
-               break;
-       }
-    }
-    return rc;
-}
-
-static int
-store_int(val, def, op)
-    char *val;
-    struct sudo_defs_types *def;
-    int op;
-{
-    char *endp;
-    long l;
-
-    if (op == FALSE) {
-       def->sd_un.ival = 0;
-    } else {
-       l = strtol(val, &endp, 10);
-       if (*endp != '\0')
-           return FALSE;
-       /* XXX - should check against INT_MAX */
-       def->sd_un.ival = (int)l;
-    }
-    if (def->callback)
-       return def->callback(val);
-    return TRUE;
-}
-
-static int
-store_uint(val, def, op)
-    char *val;
-    struct sudo_defs_types *def;
-    int op;
-{
-    char *endp;
-    long l;
-
-    if (op == FALSE) {
-       def->sd_un.ival = 0;
-    } else {
-       l = strtol(val, &endp, 10);
-       if (*endp != '\0' || l < 0)
-           return FALSE;
-       /* XXX - should check against INT_MAX */
-       def->sd_un.ival = (unsigned int)l;
-    }
-    if (def->callback)
-       return def->callback(val);
-    return TRUE;
-}
-
-static int
-store_float(val, def, op)
-    char *val;
-    struct sudo_defs_types *def;
-    int op;
-{
-    char *endp;
-    double d;
-
-    if (op == FALSE) {
-       def->sd_un.fval = 0.0;
-    } else {
-       d = strtod(val, &endp);
-       if (*endp != '\0')
-           return FALSE;
-       /* XXX - should check against HUGE_VAL */
-       def->sd_un.fval = d;
-    }
-    if (def->callback)
-       return def->callback(val);
-    return TRUE;
-}
-
-static int
-store_tuple(val, def, op)
-    char *val;
-    struct sudo_defs_types *def;
-    int op;
-{
-    struct def_values *v;
-
-    /*
-     * Since enums are really just ints we store the value as an ival.
-     * In the future, there may be multiple enums for different tuple
-     * types we want to avoid and special knowledge of the tuple type.
-     * This does assume that the first entry in the tuple enum will
-     * be the equivalent to a boolean "false".
-     */
-    if (!val) {
-       def->sd_un.ival = (op == FALSE) ? 0 : 1;
-    } else {
-       for (v = def->values; v->sval != NULL; v++) {
-           if (strcmp(v->sval, val) == 0) {
-               def->sd_un.ival = v->ival;
-               break;
-           }
-       }
-       if (v->sval == NULL)
-           return FALSE;
-    }
-    if (def->callback)
-       return def->callback(val);
-    return TRUE;
-}
-
-static int
-store_str(val, def, op)
-    char *val;
-    struct sudo_defs_types *def;
-    int op;
-{
-
-    efree(def->sd_un.str);
-    if (op == FALSE)
-       def->sd_un.str = NULL;
-    else
-       def->sd_un.str = estrdup(val);
-    if (def->callback)
-       return def->callback(val);
-    return TRUE;
-}
-
-static int
-store_list(str, def, op)
-    char *str;
-    struct sudo_defs_types *def;
-    int op;
-{
-    char *start, *end;
-
-    /* Remove all old members. */
-    if (op == FALSE || op == TRUE)
-       list_op(NULL, 0, def, freeall);
-
-    /* Split str into multiple space-separated words and act on each one. */
-    if (op != FALSE) {
-       end = str;
-       do {
-           /* Remove leading blanks, if nothing but blanks we are done. */
-           for (start = end; isblank((unsigned char)*start); start++)
-               ;
-           if (*start == '\0')
-               break;
-
-           /* Find end position and perform operation. */
-           for (end = start; *end && !isblank((unsigned char)*end); end++)
-               ;
-           list_op(start, end - start, def, op == '-' ? delete : add);
-       } while (*end++ != '\0');
-    }
-    return TRUE;
-}
-
-static int
-store_syslogfac(val, def, op)
-    char *val;
-    struct sudo_defs_types *def;
-    int op;
-{
-    struct strmap *fac;
-
-    if (op == FALSE) {
-       def->sd_un.ival = FALSE;
-       return TRUE;
-    }
-#ifdef LOG_NFACILITIES
-    if (!val)
-       return FALSE;
-    for (fac = facilities; fac->name && strcmp(val, fac->name); fac++)
-       ;
-    if (fac->name == NULL)
-       return FALSE;                           /* not found */
-
-    def->sd_un.ival = fac->num;
-#else
-    def->sd_un.ival = -1;
-#endif /* LOG_NFACILITIES */
-    return TRUE;
-}
-
-static const char *
-logfac2str(n)
-    int n;
-{
-#ifdef LOG_NFACILITIES
-    struct strmap *fac;
-
-    for (fac = facilities; fac->name && fac->num != n; fac++)
-       ;
-    return fac->name;
-#else
-    return "default";
-#endif /* LOG_NFACILITIES */
-}
-
-static int
-store_syslogpri(val, def, op)
-    char *val;
-    struct sudo_defs_types *def;
-    int op;
-{
-    struct strmap *pri;
-
-    if (op == FALSE || !val)
-       return FALSE;
-
-    for (pri = priorities; pri->name && strcmp(val, pri->name); pri++)
-       ;
-    if (pri->name == NULL)
-       return FALSE;                           /* not found */
-
-    def->sd_un.ival = pri->num;
-    return TRUE;
-}
-
-static const char *
-logpri2str(n)
-    int n;
-{
-    struct strmap *pri;
-
-    for (pri = priorities; pri->name && pri->num != n; pri++)
-       ;
-    return pri->name;
-}
-
-static int
-store_mode(val, def, op)
-    char *val;
-    struct sudo_defs_types *def;
-    int op;
-{
-    char *endp;
-    long l;
-
-    if (op == FALSE) {
-       def->sd_un.mode = (mode_t)0777;
-    } else {
-       l = strtol(val, &endp, 8);
-       if (*endp != '\0' || l < 0 || l > 0777)
-           return FALSE;
-       def->sd_un.mode = (mode_t)l;
-    }
-    if (def->callback)
-       return def->callback(val);
-    return TRUE;
-}
-
-static void
-list_op(val, len, def, op)
-    char *val;
-    size_t len;
-    struct sudo_defs_types *def;
-    enum list_ops op;
-{
-    struct list_member *cur, *prev, *tmp;
-
-    if (op == freeall) {
-       for (cur = def->sd_un.list; cur; ) {
-           tmp = cur;
-           cur = tmp->next;
-           efree(tmp->value);
-           efree(tmp);
-       }
-       def->sd_un.list = NULL;
-       return;
-    }
-
-    for (cur = def->sd_un.list, prev = NULL; cur; prev = cur, cur = cur->next) {
-       if ((strncmp(cur->value, val, len) == 0 && cur->value[len] == '\0')) {
-
-           if (op == add)
-               return;                 /* already exists */
-
-           /* Delete node */
-           if (prev != NULL)
-               prev->next = cur->next;
-           else
-               def->sd_un.list = cur->next;
-           efree(cur->value);
-           efree(cur);
-           break;
-       }
-    }
-
-    /* Add new node to the head of the list. */
-    if (op == add) {
-       cur = emalloc(sizeof(struct list_member));
-       cur->value = emalloc(len + 1);
-       (void) memcpy(cur->value, val, len);
-       cur->value[len] = '\0';
-       cur->next = def->sd_un.list;
-       def->sd_un.list = cur;
-    }
-}
diff --git a/defaults.h b/defaults.h
deleted file mode 100644 (file)
index eb2188a..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2008, 2010
- *     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.
- */
-
-#ifndef _SUDO_DEFAULTS_H
-#define _SUDO_DEFAULTS_H
-
-#include <def_data.h>
-
-struct list_member {
-    char *value;
-    struct list_member *next;
-};
-
-struct def_values {
-    char *sval;                /* string value */
-    int ival;          /* actually an enum */
-};
-
-enum list_ops {
-    add,
-    delete,
-    freeall
-};
-
-/*
- * Structure describing compile-time and run-time options.
- */
-struct sudo_defs_types {
-    char *name;
-    int type;
-    char *desc;
-    struct def_values *values;
-    int (*callback) __P((char *));
-    union {
-       int flag;
-       int ival;
-       double fval;
-       enum def_tupple tuple;
-       char *str;
-       mode_t mode;
-       struct list_member *list;
-    } sd_un;
-};
-
-/*
- * Four types of defaults: strings, integers, and flags.
- * Also, T_INT, T_FLOAT or T_STR may be ANDed with T_BOOL to indicate that
- * a value is not required.  Flags are boolean by nature...
- */
-#undef T_INT
-#define T_INT          0x001
-#undef T_UINT
-#define T_UINT         0x002
-#undef T_STR
-#define T_STR          0x003
-#undef T_FLAG
-#define T_FLAG         0x004
-#undef T_MODE
-#define T_MODE         0x005
-#undef T_LIST
-#define T_LIST         0x006
-#undef T_LOGFAC
-#define T_LOGFAC       0x007
-#undef T_LOGPRI
-#define T_LOGPRI       0x008
-#undef T_TUPLE
-#define T_TUPLE                0x009
-#undef T_FLOAT
-#define T_FLOAT                0x010
-#undef T_MASK
-#define T_MASK         0x0FF
-#undef T_BOOL
-#define T_BOOL         0x100
-#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
- */
-int set_default                __P((char *, char *, int));
-int update_defaults    __P((int));
-void dump_default      __P((void));
-void dump_defaults     __P((void));
-void init_defaults     __P((void));
-void list_options      __P((void));
-
-extern struct sudo_defs_types sudo_defs_table[];
-
-#endif /* _SUDO_DEFAULTS_H */
diff --git a/doc/HISTORY b/doc/HISTORY
new file mode 100644 (file)
index 0000000..b265144
--- /dev/null
@@ -0,0 +1,74 @@
+A Brief History of Sudo:
+
+The Early Years
+
+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.
+
+Sudo at CU-Boulder
+
+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.
+
+Root Group Sudo
+
+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.
+
+CU Sudo
+
+In 1994, after maintaining sudo informally within CU-Boulder for some time,
+Todd C. 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.
+
+Just Plain Sudo
+
+In 1999, the "CU" prefix was dropped from the name since there had 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).
+
+LDAP Integration
+
+In 2003, Nationwide Mutual Insurance Company contributed code written by
+Aaron Spangler to store the sudoers data in LDAP. These changes were
+incorporated into Sudo 1.6.8.
+
+New Parser
+
+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.
+
+Quest Sponsorship
+
+In 2010, Quest Software began sponsoring Sudo development by hiring Todd to
+work on Sudo as part of his full-time job.
+
+Present Day
+
+Sudo, in its current form, is maintained by:
+
+        Todd C. Miller <Todd.Miller@courtesan.com>
+
+Todd continues to enhance sudo and fix bugs.
+
diff --git a/doc/LICENSE b/doc/LICENSE
new file mode 100644 (file)
index 0000000..f6c411f
--- /dev/null
@@ -0,0 +1,73 @@
+Sudo is distributed under the following ISC-style license:
+
+   Copyright (c) 1994-1996, 1998-2011
+        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.
+
+The files 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.
+
+   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.
+
+The embedded copy of zlib bears the following license:
+
+  Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644 (file)
index 0000000..414d8c0
--- /dev/null
@@ -0,0 +1,196 @@
+#
+# Copyright (c) 2011 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.
+#
+# @configure_input@
+#
+
+#### Start of system configuration section. ####
+
+srcdir = @srcdir@
+docdir = @docdir@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Tools to use
+NROFF = @NROFFPROG@ -Tascii
+
+# Our install program supports extra flags...
+INSTALL = $(SHELL) $(top_srcdir)/install-sh -c
+
+# Where to install things...
+prefix = @prefix@
+datarootdir = @datarootdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+
+# Directory in which to install the man page
+mantype = @MANTYPE@
+mansectsu = @mansectsu@
+mansectform = @mansectform@
+mandirsu = $(mandir)/$(mantype)$(mansectsu)
+mandirform = $(mandir)/$(mantype)$(mansectform)
+
+# User and group ids the installed files should be "owned" by
+install_uid = 0
+install_gid = 0
+
+#### End of system configuration section. ####
+
+SHELL = @SHELL@
+
+DOCS = sudo.man visudo.man sudoers.man sudoers.ldap.man sudoers.man \
+       sudoreplay.man sudo_plugin.man
+
+@DEV@DEVDOCS = $(srcdir)/sudo.man.in $(srcdir)/sudo.cat \
+@DEV@          $(srcdir)/visudo.man.in $(srcdir)/visudo.cat \
+@DEV@          $(srcdir)/sudoers.man.in $(srcdir)/sudoers.cat \
+@DEV@          $(srcdir)/sudoers.ldap.man.in $(srcdir)/sudoers.ldap.cat \
+@DEV@          $(srcdir)/sudoers.man.in $(srcdir)/sudoers.cat \
+@DEV@          $(srcdir)/sudoreplay.man.in $(srcdir)/sudoreplay.cat \
+@DEV@          $(srcdir)/sudo_plugin.man.in $(srcdir)/sudo_plugin.cat \
+@DEV@          $(srcdir)/HISTORY $(srcdir)/LICENSE
+
+OTHER_DOCS= $(top_srcdir)/ChangeLog $(top_srcdir)/README \
+           $(top_srcdir)/NEWS $(srcdir)/HISTORY $(srcdir)/LICENSE \
+           $(srcdir)/TROUBLESHOOTING $(srcdir)/UPGRADE $(srcdir)/sample.*
+
+OTHER_DOCS_LDAP= $(top_srcdir)/README.LDAP $(srcdir)/schema.*
+
+VERSION = @PACKAGE_VERSION@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+
+all: $(DEVDOCS) $(DOCS)
+
+Makefile: $(srcdir)/Makefile.in
+       (cd $(top_builddir) && ./config.status --file doc/Makefile)
+
+.SUFFIXES: .man
+
+@DEV@varsub: $(top_srcdir)/configure.in
+@DEV@  printf 's#@%s@#1#\ns#@%s@#1#\ns#@%s@#1#\ns#@%s@#/etc#g\ns#@%s@#/usr/local#g\ns#@%s@#4#g\ns#@%s@#1m#g\n' SEMAN BAMAN LCMAN sysconfdir prefix mansectform mansectsu > $@; sed -n '/Begin initial values for man page substitution/,/End initial values for man page substitution/{;p;}' $(top_srcdir)/configure.in | sed -e '/^#/d' -e 's/^/s#@/' -e 's/=[\\"]*/@#/' -e 's/[\\"]*$$/#g/' >> $@
+
+@DEV@$(srcdir)/sudo.man.in: $(srcdir)/sudo.pod
+@DEV@  mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudo.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudo.pod | sed -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" | perl -p $(srcdir)/sudo.man.pl >> $@
+
+sudo.man: $(srcdir)/sudo.man.in
+       (cd $(top_builddir) && $(SHELL) config.status --file=doc/$@)
+
+@DEV@$(srcdir)/sudo.cat: varsub $(srcdir)/sudo.man.in
+@DEV@  sed -f varsub $(srcdir)/sudo.man.in | $(NROFF) -man > $@
+
+@DEV@$(srcdir)/visudo.man.in: $(srcdir)/visudo.pod
+@DEV@  mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/visudo.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/visudo.pod | sed -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@
+
+visudo.man: $(srcdir)/visudo.man.in
+       (cd $(top_builddir) && $(SHELL) config.status --file=doc/$@)
+
+@DEV@$(srcdir)/visudo.cat: varsub $(srcdir)/visudo.man.in
+@DEV@  sed -f varsub $(srcdir)/visudo.man.in | $(NROFF) -man > $@
+
+@DEV@$(srcdir)/sudoers.man.in: $(srcdir)/sudoers.pod
+@DEV@  mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudoers.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectform --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudoers.pod | sed -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" | perl -p $(srcdir)/sudoers.man.pl >> $@
+
+sudoers.man: $(srcdir)/sudoers.man.in
+       (cd $(top_builddir) && $(SHELL) config.status --file=doc/$@)
+
+@DEV@$(srcdir)/sudoers.cat: varsub $(srcdir)/sudoers.man.in
+@DEV@  sed -f varsub $(srcdir)/sudoers.man.in | $(NROFF) -man > $@
+
+@DEV@$(srcdir)/sudoers.ldap.man.in: $(srcdir)/sudoers.ldap.pod
+@DEV@  mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudoers.ldap.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectform --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudoers.ldap.pod | sed -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@
+
+sudoers.ldap.man: $(srcdir)/sudoers.ldap.man.in
+       (cd $(top_builddir) && $(SHELL) config.status --file=doc/$@)
+
+@DEV@$(srcdir)/sudoers.ldap.cat: varsub $(srcdir)/sudoers.ldap.man.in
+@DEV@  sed -f varsub $(srcdir)/sudoers.ldap.man.in | $(NROFF) -man > $@
+
+@DEV@$(srcdir)/sudoreplay.man.in: $(srcdir)/sudoreplay.pod
+@DEV@  mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudoreplay.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudoreplay.pod | sed -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@
+
+sudoreplay.man: $(srcdir)/sudoreplay.man.in
+       (cd $(top_builddir) && $(SHELL) config.status --file=doc/$@)
+
+@DEV@$(srcdir)/sudoreplay.cat: varsub $(srcdir)/sudoreplay.man.in
+@DEV@  sed -f varsub $(srcdir)/sudoreplay.man.in | $(NROFF) -man > $@
+
+@DEV@$(srcdir)/sudo_plugin.man.in: $(srcdir)/sudo_plugin.pod
+@DEV@  mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudo_plugin.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudo_plugin.pod | sed -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@
+
+sudo_plugin.man: $(srcdir)/sudo_plugin.man.in
+       (cd $(top_builddir) && $(SHELL) config.status --file=doc/$@)
+
+@DEV@$(srcdir)/sudo_plugin.cat: varsub $(srcdir)/sudo_plugin.man.in
+@DEV@  sed -f varsub $(srcdir)/sudo_plugin.man.in | $(NROFF) -man > $@
+
+HISTORY: $(srcdir)/history.pod
+       pod2text -l -i0 $(srcdir)/history.pod > $@
+
+LICENSE: $(srcdir)/license.pod
+       pod2text -l -i0 $(srcdir)/license.pod | sed '1,2d' > $@
+
+pre-install:
+
+install: install-dirs install-doc
+
+install-dirs:
+       $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(docdir) \
+           $(DESTDIR)$(mandirsu) $(DESTDIR)$(mandirform)
+
+install-binaries:
+
+install-includes:
+
+install-doc: install-dirs
+       for f in $(OTHER_DOCS); do $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 $$f $(DESTDIR)$(docdir); done
+       @LDAP@for f in $(OTHER_DOCS_LDAP); do $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 $$f $(DESTDIR)$(docdir); done
+       $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 @mansrcdir@/sudo.$(mantype) $(DESTDIR)$(mandirsu)/sudo.$(mansectsu)
+       @rm -f $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu)
+       ln $(DESTDIR)$(mandirsu)/sudo.$(mansectsu) $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu)
+       $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 @mansrcdir@/sudo_plugin.$(mantype) $(DESTDIR)$(mandirsu)/sudo_plugin.$(mansectsu)
+       $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 @mansrcdir@/sudoreplay.$(mantype) $(DESTDIR)$(mandirsu)/sudoreplay.$(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@
+
+install-plugin:
+
+uninstall:
+       -rm -rf $(DESTDIR)$(docdir)
+       -rm -f  $(DESTDIR)$(mandirsu)/sudo.$(mansectsu) \
+               $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu) \
+               $(DESTDIR)$(mandirsu)/sudo_plugin.$(mansectsu) \
+               $(DESTDIR)$(mandirsu)/sudoreplay.$(mansectsu) \
+               $(DESTDIR)$(mandirsu)/visudo.$(mansectsu) \
+               $(DESTDIR)$(mandirform)/sudoers.$(mansectform) \
+               $(DESTDIR)$(mandirform)/sudoers.ldap.$(mansectform)
+
+check:
+
+clean:
+       -rm -f varsub
+
+mostlyclean: clean
+
+distclean: clean
+       -rm -rf Makefile config.log *.man
+
+clobber: distclean
+
+realclean: distclean
+
+cleandir: distclean
diff --git a/doc/TROUBLESHOOTING b/doc/TROUBLESHOOTING
new file mode 100644 (file)
index 0000000..9ed1817
--- /dev/null
@@ -0,0 +1,199 @@
+Troubleshooting tips and FAQ for Sudo
+=====================================
+
+Q) When I run configure, it says "C compiler cannot create executables".
+A) This usually means you either don't have a working compiler.  This
+   could be due to the lack of a license or that some component of the
+   compiler suite could not be found.  Check config.log for clues as
+   to why this is happening.  On many systems, compiler components live
+   in /usr/ccs/bin which may not be in your PATH environment variable.
+
+Q) When I run configure, it says "sudo requires the 'ar' utility to build".
+A) As part of the build process, sudo creates a temporary library containing
+   objects that are shared amongst the different sudo executables.
+   On Unix systems, the "ar" utility is used to do this.  This error
+   indicates that "ar" is missing on your system.  On Solaris systems,
+   you may need to install the SUNWbtool package.  On other systems
+   "ar" may be included in the GNU binutils package.
+
+Q) Sudo compiles but when I run it I get "Sorry, sudo must be setuid root."
+   and sudo quits.
+A) Sudo must be setuid root to do its work.  You need to do something like
+   `chmod 4111 /usr/local/bin/sudo'.  Also, the file system sudo resides
+   on must *not* be mounted (or exported) with the nosuid option or sudo
+   will not be able to work.  Another possibility is you may have '.' in
+   your $PATH before the directory containing sudo.  If you are going
+   to have '.' in your path you should make sure it is at the end.
+
+Q) Sudo never gives me a chance to enter a password using PAM, it just
+   says 'Sorry, try again.' three times and exits.
+A) You didn't setup PAM to work with sudo.  On Redhat Linux or Fedora
+   Core this generally means installing sample.pam as /etc/pam.d/sudo.
+   See the sample.pam file for hints on what to use for other Linux
+   systems.
+
+Q) Sudo says 'Account expired or PAM config lacks an "account"
+   section for sudo, contact your system administrator' and exits
+   but I know my account has not expired.
+A) Your PAM config lacks an "account" specification.  On Linux this
+   usually means you are missing a line like:
+       account    required    pam_unix.so
+   in /etc/pam.d/sudo.
+
+Q) Sudo is setup to log via syslog(3) but I'm not getting any log
+   messages.
+A) Make sure you have an entry in your syslog.conf file to save
+   the sudo messages (see the sample.syslog.conf file).  The default
+   log facility is authpriv (changeable via configure or in sudoers).
+   Don't forget to send a SIGHUP to your syslogd so that it re-reads
+   its conf file.  Also, remember that syslogd does *not* create
+   log files, you need to create the file before syslogd will log
+   to it (ie: touch /var/log/sudo).
+   Note:  the facility (e.g. "auth.debug") must be separated from the 
+         destination (e.g. "/var/log/auth" or "@loghost") by
+         tabs, *not* spaces.  This is a common error.
+
+Q) When sudo asks me for my password it never accepts what I enter even
+   though I know I entered my password correctly.
+A) If your system uses shadow passwords, it is possible that sudo
+   didn't detect this.  Take a look at the generated config.h file
+   and verify that the C function used for shadow password lookups
+   was detected.  For instance, for SVR4-style shadow passwords,
+   HAVE_GETSPNAM should be defined (you can search for the string
+   "shadow passwords" in config.h with your editor).  Note that
+   there is no define for 4.4BSD-based shadow passwords since that
+   just uses the standard getpw* routines.
+
+Q) I don't want the sudoers file in /etc, how can I specify where it
+   should go?
+A) Use the --sysconfdir option to configure.  Ie:
+   configure --sysconfdir=/dir/you/want/sudoers/in
+
+Q) Can I put the sudoers file in NIS/NIS+ or do I have to have a
+   copy on each machine?
+A) There is no support for making an NIS/NIS+ map/table out of
+   the sudoers file at this time.  A good way to distribute the
+   sudoers file is via rdist(1).  It is also possible to NFS-mount
+   the sudoers file.
+
+Q) I don't run sendmail on my machine.  Does this mean that I cannot
+   use sudo?
+A) No, you just need to run use the --without-sendmail argument to configure
+   or add "!mailerpath" to the Defaults line in /etc/sudoers.
+
+Q) When I run visudo it uses vi as the editor and I hate vi.  How
+   can I make it use another editor?
+A) Your best bet is to run configure with the --with-env-editor switch.
+   This will make visudo use the editor specified by the user's
+   EDITOR environment variable.  Alternately, you can run configure
+   with the --with-editor=/path/to/another/editor.
+
+Q) Sudo appears to be removing some variables from my environment, why?
+A) Sudo removes the following "dangerous" environment variables
+   to guard against shared library spoofing, shell voodoo, and
+   kerberos server spoofing.
+     IFS
+     LOCALDOMAIN
+     RES_OPTIONS
+     HOSTALIASES
+     NLSPATH
+     PATH_LOCALE
+     TERMINFO
+     TERMINFO_DIRS
+     TERMPATH
+     TERMCAP
+     ENV
+     BASH_ENV
+     LC_ (if it contains a '/' or '%')
+     LANG (if it contains a '/' or '%')
+     LANGUAGE (if it contains a '/' or '%')
+     LD_*
+     _RLD_*
+     SHLIB_PATH (HP-UX only)
+     LIBPATH (AIX only)
+     KRB_CONF (kerb4 only)
+     KRBCONFDIR (kerb4 only)
+     KRBTKFILE (kerb4 only)
+     KRB5_CONFIG (kerb5 only)
+     VAR_ACE (SecurID only)
+     USR_ACE (SecurID only)
+     DLC_ACE (SecurID only)
+
+Q) How can I keep sudo from asking for a password?
+A) To specify this on a per-user (and per-command) basis, use the 'NOPASSWD'
+   tag right before the command list in sudoers.  See the sudoers man page
+   and sample.sudoers for details.  To disable passwords completely,
+   run configure with the --without-passwd option or add "!authenticate"
+   to the Defaults line in /etc/sudoers.  You can also turn off authentication
+   on a per-user or per-host basis using a user or host-specific Defaults
+   entry in sudoers.
+
+Q) When I run configure, it dies with the following error:
+   "no acceptable cc found in $PATH".
+A) /usr/ucb/cc was the only C compiler that configure could find.
+   You need to tell configure the path to the "real" C compiler
+   via the --with-CC option.  On Solaris, the path is probably
+   something like "/opt/SUNWspro/SC4.0/bin/cc".  If you have gcc
+   that will also work.
+
+Q) When I run configure, it dies with the following error:
+   Fatal Error: config.cache exists from another platform!
+   Please remove it and re-run configure.
+A) configure caches the results of its tests in a file called
+   config.cache to make re-running configure speedy.  However,
+   if you are building sudo for a different platform the results
+   in config.cache will be wrong so you need to remove config.cache.
+   You can do this by "rm config.cache" or "make realclean".
+   Note that "make realclean" will also remove any object files
+   and configure temp files that are laying around as well.
+
+Q) I built sudo on a Solaris >= 2.6 machine but the resulting binary
+   doesn't work on Solaris <= 2.5.1.  Why?
+A) Starting with Solaris 2.6, snprintf(3) is included in the standard
+   C library.  To build a version of sudo on a >= 2.6 machine that
+   will run on a <= 2.5.1 machine, edit config.h and comment out the lines:
+       #define HAVE_SNPRINTF 1
+       #define HAVE_VSNPRINTF 1
+   and run make.
+
+Q) When I run "visudo" it says "sudoers file busy, try again later."
+   and doesn't do anything.
+A) Someone else is currently editing the sudoers file with visudo.
+
+Q) When I try to use "cd" with sudo it says "cd: command not found".
+A) "cd" is a shell built-in command, you can't run it as a command
+   since a child process (sudo) cannot affect the current working
+   directory of the parent (your shell).
+
+Q) When I try to use "cd" with sudo the command completes without
+   errors but nothing happens.
+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.
+   My sudoers file entry looks like:
+    bob        ALL=(oracle) ALL
+A) The default user sudo tries to run things as is always root, even if
+   the invoking user can only run commands as a single, specific user.
+   This may change in the future but at the present time you have to
+   work around this using the 'runas_default' option in sudoers.
+   For example:
+    Defaults:bob       runas_default=oracle
+   would achieve the desired result ofr the preceding sudoers fragment.
+
+Q) When I try to run sudo via ssh, I get the error:
+    sudo: no tty present and no askpass program specified
+A) ssh does not allocate a tty by default when running a remote command.
+   Without a tty, sudo cannot disable echo when prompting for a password.
+   You can use ssh's "-t" option to force it to allocate a tty.
+   Alternately, if you do not mind your password being echoed to the
+   screen, you can use the "visiblepw" sudoers option to allow this.
+
+Q) How do you pronounce `sudo'?
+A) The official pronunciation is soo-doo (for su "do").  However, an
+   alternate pronunciation, a homophone of "pseudo", is also common.
diff --git a/doc/UPGRADE b/doc/UPGRADE
new file mode 100644 (file)
index 0000000..35ca9a5
--- /dev/null
@@ -0,0 +1,266 @@
+Notes on upgrading from an older release
+========================================
+
+o Upgrading from a version prior to 1.8.1:
+
+    Changes in the sudoers parser could result in parse errors for
+    existing sudoers file.  These changes cause certain erroneous
+    entries to be flagged as errors where before they allowed.
+    Changes include:
+
+    Combining multiple Defaults entries with a backslash.  E.g.
+
+       Defaults set_path \
+       Defaults syslog
+
+    which should be:
+
+       Defaults set_path
+       Defaults syslog
+
+    Also, double-quoted strings with a missing end-quote are now
+    detected and result in an error.  Previously, text starting a
+    double quote and ending with a newline was ignored.  E.g.
+
+       Defaults set_path"foo
+
+    In previous versions of sudo, the `"foo' portion would have
+    been ignored.
+
+    To avoid problems, sudo 1.8.1's "make install" will not install
+    a new sudo binary if the existing sudoers file has errors.
+
+    In Sudo 1.8.1 the "noexec" functionality has moved out of the
+    sudoers policy plugin and into the sudo front-end.  As a result,
+    the path to the noexec file is now specified in the sudo.conf
+    file instead of the sudoers file.  If you have a sudoers file
+    that uses the "noexec_file" option, you will need to move the
+    definition to the sudo.conf file instead.
+
+    Old style in /etc/sudoers:
+       Defaults noexec_file=/usr/local/libexec/sudo_noexec.so
+
+    New style in /etc/sudo.conf:
+       Path noexec /usr/local/libexec/sudo_noexec.so
+
+o Upgrading from a version prior to 1.8.0:
+
+    Starting with version 1.8.0, sudo uses a modular framework to
+    support policy and I/O logging plugins.  The default policy
+    plugin is "sudoers" which provides the traditional sudoers
+    evaluation and I/O logging.  Plugins are typically located in
+    /usr/libexec or /usr/local/libexec, though this is system-dependent.
+    The sudoers plugin is named "sudoers.so" on most systems.
+
+    The sudo.conf file, usually stored in /etc, is used to configure
+    plugins.  This file is optional--if no plugins are specified
+    in sudo.conf, the "sudoers" plugin is used.  See the sample.sudo.conf
+    file in the doc directory or refer to the updated sudo manual
+    to see how to configure sudo.conf.
+
+    The "askpass" setting has moved from the sudoers file to the
+    sudo.conf file.  If you have a sudoers file that uses the
+    "askpass" option, you will need to move the definition to the
+    sudo.conf file.
+
+    Old style in /etc/sudoers:
+       Defaults askpass=/usr/X11R6/bin/ssh-askpass
+
+    New style in /etc/sudo.conf:
+       Path askpass /usr/X11R6/bin/ssh-askpass
+
+o Upgrading from a version prior to 1.7.5:
+
+    Sudo 1.7.5 includes an updated LDAP schema with support for
+    the sudoNotBefore, sudoNotAfter and sudoOrder attributes.
+
+    The sudoNotBefore and sudoNotAfter attribute support is only
+    used when the SUDOERS_TIMED setting is enabled in ldap.conf.
+    If enabled, those attributes are used directly when constructing
+    an LDAP filter.  As a result, your LDAP server must have the
+    updated schema if you want to use sudoNotBefore and sudoNotAfter.
+
+    The sudoOrder support does not affect the LDAP filter sudo
+    constructs and so there is no need to explicitly enable it in
+    ldap.conf.  If the sudoOrder attribute is not present in an
+    entry, a value of 0 is used.  If no entries contain sudoOrder
+    attributes, the results are in whatever order the LDAP server
+    returns them, as in past versions of sudo.
+
+    Older versions of sudo will simply ignore the new attributes
+    if they are present in an entry.  There are no compatibility
+    problems using the updated schema with older versions of sudo.
+
+o Upgrading from a version prior to 1.7.4:
+
+    Starting with sudo 1.7.4, the time stamp files have moved from
+    /var/run/sudo to either /var/db/sudo, /var/lib/sudo or /var/adm/sudo.
+    The directories are checked for existence in that order.  This
+    prevents users from receiving the sudo lecture every time the
+    system reboots.  Time stamp files older than the boot time are
+    ignored on systems where it is possible to determine this.
+
+    Additionally, the tty_tickets sudoers option is now enabled by
+    default.  To restore the old behavior (single time stamp per user),
+    add a line like:
+       Defaults !tty_tickets
+    to sudoers or use the --without-tty-tickets configure option.
+
+    The HOME and MAIL environment variables are now reset based on the
+    target user's password database entry when the env_reset sudoers option
+    is enabled (which is the case in the default configuration).  Users
+    wishing to preserve the original values should use a sudoers entry like:
+        Defaults env_keep += HOME
+    to preserve the old value of HOME and
+        Defaults env_keep += MAIL
+    to preserve the old value of MAIL.
+
+    NOTE: preserving HOME has security implications since many programs
+    use when searching for configuration files.  Adding HOME to env_keep
+    may enable a user to run unrestricted commands via sudo.
+
+    The default syslog facility has changed from "local2" to "authpriv"
+    (or "auth" if the operating system doesn't have "authpriv").
+    The --with-logfac configure option can be used to change this
+    or it can be changed in the sudoers file.
+
+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 NEWS 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
+    method such as PAM, it will be used by default by configure.
+
+    Environment variable handling has changed significantly in sudo
+    1.6.9.  Prior to version 1.6.9, sudo would preserve the user's
+    environment, pruning out potentially dangerous variables.
+    Beginning with sudo 1.6.9, the envionment is reset to a default
+    set of values with only a small number of "safe" variables
+    preserved.  To preserve specific environment variables, add
+    them to the "env_keep" list in sudoers.  E.g.
+
+       Defaults env_keep += "EDITOR"
+
+    The old behavior can be restored by negating the "env_reset"
+    option in sudoers.  E.g.
+
+       Defaults !env_reset
+
+    There have  also been changes to how the "env_keep" and
+    "env_check" options behave.
+
+    Prior to sudo 1.6.9, the TERM and PATH environment variables
+    would always be preserved even if the env_keep option was
+    redefined.  That is no longer the case.  Consequently, if
+    env_keep is set with "=" and not simply appended to (i.e. using
+    "+="), PATH and TERM must be explicitly included in the list
+    of environment variables to keep.  The LOGNAME, SHELL, USER,
+    and USERNAME environment variables are still always set.
+
+    Additionally, the env_check setting previously had no effect
+    when env_reset was set (which is now on by default).  Starting
+    with sudo 1.6.9, environment variables listed in env_check are
+    also preserved in the env_reset case, provided that they do not
+    contain a '/' or '%' character.  Note that it is not necessary
+    to also list a variable in env_keep--having it in env_check is
+    sufficent.
+
+    The default lists of variables to be preserved and/or checked
+    are displayed when sudo is run by root with the -V flag.
+
+o Upgrading from a version prior to 1.6.8:
+
+    Prior to sudo 1.6.8, if /var/run did not exist, sudo would put
+    the time stamp files in /tmp/.odus.  As of sudo 1.6.8, the
+    time stamp files will be placed in /var/adm/sudo or /usr/adm/sudo
+    if there is no /var/run directory.  This directory will be
+    created if it does not already exist.
+
+    Previously, a sudoers entry that explicitly prohibited running
+    a command as a certain user did not override a previous entry
+    allowing the same command.  This has been fixed in sudo 1.6.8
+    such that the last match is now used (as it is documented).
+    Hopefully no one was depending on the previous (buggy) beghavior.
+
+o Upgrading from a version prior to 1.6:
+
+    As of sudo 1.6, parsing of runas entries and the NOPASSWD tag
+    has changed.  Prior to 1.6, a runas specifier applied only to
+    a single command directly following it.  Likewise, the NOPASSWD
+    tag only allowed the command directly following it to be run
+    without a password.  Starting with sudo 1.6, both the runas
+    specifier and the NOPASSWD tag are "sticky" for an entire
+    command list.  So, given the following line in sudo < 1.6
+
+       millert ALL=(daemon) NOPASSWD:/usr/bin/whoami,/bin/ls
+
+    millert would be able to run /usr/bin/whoami as user daemon
+    without a password and /bin/ls as root with a password.
+
+    As of sudo 1.6, the same line now means that millert is able
+    to run run both /usr/bin/whoami and /bin/ls as user daemon
+    without a password.  To expand on this, take the following
+    example:
+
+       millert ALL=(daemon) NOPASSWD:/usr/bin/whoami, (root) /bin/ls, \
+           /sbin/dump
+
+    millert can run /usr/bin/whoami as daemon and /bin/ls and
+    /sbin/dump as root.  No password need be given for either
+    command.  In other words, the "(root)" sets the default runas
+    user to root for the rest of the list.  If we wanted to require
+    a password for /bin/ls and /sbin/dump the line could be written
+    thusly:
+
+       millert ALL=(daemon) NOPASSWD:/usr/bin/whoami, \
+           (root) PASSWD:/bin/ls, /sbin/dump
+
+    Additionally, sudo now uses a per-user time stamp directory
+    instead of a time stamp file.  This allows tty time stamps to
+    simply be files within the user's time stamp dir.  For the
+    default, non-tty case, the time stamp on the directory itself
+    is used.
+
+    Also, the temporary file used by visudo is now /etc/sudoers.tmp
+    since some versions of vipw on systems with shadow passwords use
+    /etc/stmp for the temporary shadow file.
+
+o Upgrading from a version prior to 1.5:
+
+    By default, sudo expects the sudoers file to be mode 0440 and
+    to be owned by user and group 0.  This differs from version 1.4
+    and below which expected the sudoers file to be mode 0400 and
+    to be owned by root.  Doing a `make install' will set the sudoers
+    file to the new mode and group.  If sudo encounters a sudoers
+    file with the old permissions it will attempt to update it to
+    the new scheme.  You cannot, however, use a sudoers file with
+    the new permissions with an old sudo binary.  It is suggested
+    that if have a means of distributing sudo you distribute the
+    new binaries first, then the new sudoers file (or you can leave
+    sudoers as is and sudo will fix the permissions itself as long
+    as sudoers is on a local file system).
diff --git a/doc/history.pod b/doc/history.pod
new file mode 100644 (file)
index 0000000..506afc0
--- /dev/null
@@ -0,0 +1,79 @@
+=head1 A Brief History of Sudo:
+
+=head3 The Early Years
+
+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.
+
+=head3 Sudo at CU-Boulder
+
+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.
+
+=head3 Root Group Sudo
+
+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.
+
+=head3 CU Sudo
+
+In 1994, after maintaining sudo informally within CU-Boulder for
+some time, Todd C. 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.
+
+=head3 Just Plain Sudo
+
+In 1999, the "CU" prefix was dropped from the name since there had
+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).
+
+=head3 LDAP Integration
+
+In 2003, Nationwide Mutual Insurance Company contributed code written
+by Aaron Spangler to store the sudoers data in LDAP.  These changes
+were incorporated into Sudo 1.6.8.
+
+=head3 New Parser
+
+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.
+
+=head3 Quest Sponsorship
+
+In 2010, Quest Software began sponsoring Sudo development by hiring
+Todd to work on Sudo as part of his full-time job.
+
+=head3 Present Day
+
+Sudo, in its current form, is maintained by:
+
+       Todd C. Miller <Todd.Miller@courtesan.com>
+
+Todd continues to enhance sudo and fix bugs.
diff --git a/doc/license.pod b/doc/license.pod
new file mode 100644 (file)
index 0000000..5786e38
--- /dev/null
@@ -0,0 +1,78 @@
+=head1 Sudo License
+
+=head3
+Sudo is distributed under the following ISC-style license:
+
+   Copyright (c) 1994-1996, 1998-2010
+       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.
+
+=head3
+The files 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.
+
+   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.
+
+=head3
+The embedded copy of zlib bears the following license:
+
+  Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
diff --git a/doc/sample.pam b/doc/sample.pam
new file mode 100644 (file)
index 0000000..d56e712
--- /dev/null
@@ -0,0 +1,30 @@
+#%PAM-1.0
+# Sample /etc/pam.d/sudo file for RedHat 9 / Fedora Core.
+#   For other Linux distributions you may want to
+#   use /etc/pam.d/sshd or /etc/pam.d/su as a guide.
+#
+#   There are two basic ways to configure PAM, either via pam_stack
+#   or by explicitly specifying the various methods to use.
+#
+# Here we use pam_stack
+auth       required    pam_stack.so service=system-auth
+account    required    pam_stack.so service=system-auth
+password   required    pam_stack.so service=system-auth
+session    required    pam_stack.so service=system-auth
+#
+# Alternately, you can specify the authentication method directly.
+# Here we use pam_unix for normal password authentication.
+#auth       required   pam_env.so
+#auth       sufficient pam_unix.so
+#account    required   pam_unix.so
+#password   required   pam_cracklib.so retry=3 type=
+#password   required   pam_unix.so nullok use_authtok md5 shadow
+#session    required   pam_limits.so
+#session    required   pam_unix.so
+#
+# Another option is to use SMB for authentication.
+#auth       required   pam_env.so
+#auth       sufficient pam_smb_auth.so
+#account    required   pam_smb_auth.so
+#password   required   pam_smb_auth.so
+#session    required   pam_limits.so
diff --git a/doc/sample.sudo.conf b/doc/sample.sudo.conf
new file mode 100644 (file)
index 0000000..18baa59
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# Sample /etc/sudo.conf file
+#
+# Format:
+#   Plugin plugin_name plugin_path
+#   Path askpass /path/to/askpass
+#   Path noexec /path/to/noexec.so
+#
+# Sudo plugins:
+#
+# The plugin_path is relative to ${prefix}/libexec unless fully qualified.
+# The plugin_name corresponds to a global symbol in the plugin
+#   that contains the plugin interface structure.
+#
+# The sudoers plugin is used by default if no Plugin lines are present.
+Plugin sudoers_policy sudoers.so
+Plugin sudoers_io sudoers.so
+
+#
+# Sudo askpass:
+#
+# An askpass helper program may be specified to provide a graphical
+# password prompt for "sudo -A" support.  Sudo does not ship with its
+# own passpass program but can use the OpenSSH askpass.
+#
+# Use the OpenSSH askpass
+#Path askpass /usr/X11R6/bin/ssh-askpass
+#
+# Use the Gnome OpenSSH askpass
+#Path askpass /usr/libexec/openssh/gnome-ssh-askpass
+
+#
+# Sudo noexec:
+#
+# Path to a shared library containing dummy versions of the execv(),
+# execve() and fexecve() library functions that just return an error.
+# This is used to implement the "noexec" functionality on systems that
+# support C<LD_PRELOAD> or its equivalent.
+# The compiled-in value is usually sufficient and should only be changed
+# if you rename or move the sudo_noexec.so file.
+#
+#Path noexec /usr/libexec/sudo_noexec.so
diff --git a/doc/sample.sudoers b/doc/sample.sudoers
new file mode 100644 (file)
index 0000000..0ef1579
--- /dev/null
@@ -0,0 +1,131 @@
+#
+# Sample /etc/sudoers file.
+#
+# This file MUST be edited with the 'visudo' command as root.
+#
+# See the sudoers man page for the details on how to write a sudoers file.
+
+##
+# 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
+##
+User_Alias     FULLTIMERS = millert, mikef, dowdy
+User_Alias     PARTTIMERS = bostley, jwfox, crawl
+User_Alias     WEBMASTERS = will, wendy, wim
+
+##
+# Runas alias specification
+##
+Runas_Alias    OP = root, operator
+Runas_Alias    DB = oracle, sybase
+
+##
+# Host alias specification
+##
+Host_Alias     SPARC = bigtime, eclipse, moet, anchor:\
+               SGI = grolsch, dandelion, black:\
+               ALPHA = widget, thalamus, foobar:\
+               HPPA = boa, nag, python
+Host_Alias     CUNETS = 128.138.0.0/255.255.0.0
+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
+
+##
+# Cmnd alias specification
+##
+Cmnd_Alias     DUMPS = /usr/sbin/dump, /usr/sbin/rdump, /usr/sbin/restore, \
+                       /usr/sbin/rrestore, /usr/bin/mt
+Cmnd_Alias     KILL = /usr/bin/kill
+Cmnd_Alias     PRINTING = /usr/sbin/lpc, /usr/bin/lprm
+Cmnd_Alias     SHUTDOWN = /usr/sbin/shutdown
+Cmnd_Alias     HALT = /usr/sbin/halt
+Cmnd_Alias     REBOOT = /usr/sbin/reboot
+Cmnd_Alias     SHELLS = /sbin/sh, /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \
+                        /usr/local/bin/tcsh, /usr/bin/rsh, \
+                        /usr/local/bin/zsh
+Cmnd_Alias     SU = /usr/bin/su
+Cmnd_Alias     VIPW = /usr/sbin/vipw, /usr/bin/passwd, /usr/bin/chsh, \
+                      /usr/bin/chfn
+Cmnd_Alias     PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less
+
+##
+# User specification
+##
+
+# root and users in group wheel can run anything on any machine as any user
+root           ALL = (ALL) ALL
+%wheel         ALL = (ALL) ALL
+
+# full time sysadmins can run anything on any machine without a password
+FULLTIMERS     ALL = NOPASSWD: ALL
+
+# part time sysadmins may run anything but need a password
+PARTTIMERS     ALL = ALL
+
+# jack may run anything on machines in CSNETS
+jack           CSNETS = ALL
+
+# lisa may run any command on any host in CUNETS (a class B network)
+lisa           CUNETS = ALL
+
+# operator may run maintenance commands and anything in /usr/oper/bin/
+operator       ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\
+               sudoedit /etc/printcap, /usr/oper/bin/
+
+# joe may su only to operator
+joe            ALL = /usr/bin/su operator
+
+# pete may change passwords for anyone but root on the hp snakes
+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)
+bob            SPARC = (OP) ALL : SGI = (OP) ALL
+
+# jim may run anything on machines in the biglab netgroup
+jim            +biglab = ALL
+
+# users in the secretaries netgroup need to help manage the printers
+# as well as add and remove users
++secretaries   ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser
+
+# fred can run commands as oracle or sybase without a password
+fred           ALL = (DB) NOPASSWD: ALL
+
+# on the alphas, john may su to anyone but root and flags are not allowed
+john           ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
+
+# jen can run anything on all machines except the ones
+# in the "SERVERS" Host_Alias
+jen            ALL, !SERVERS = ALL
+
+# jill can run any commands in the directory /usr/bin/, except for
+# those in the SU and SHELLS aliases.
+jill           SERVERS = /usr/bin/, !SU, !SHELLS
+
+# steve can run any command in the directory /usr/local/op_commands/
+# as user operator.
+steve          CSNETS = (operator) /usr/local/op_commands/
+
+# matt needs to be able to kill things on his workstation when
+# they get hung.
+matt           valkyrie = KILL
+
+# users in the WEBMASTERS User_Alias (will, wendy, and wim)
+# may run any command as user www (which owns the web pages)
+# or simply su to www.
+WEBMASTERS     www = (www) ALL, (root) /usr/bin/su www
+
+# anyone can mount/unmount a cd-rom on the machines in the CDROM alias
+ALL            CDROM = NOPASSWD: /sbin/umount /CDROM,\
+               /sbin/mount -o nosuid\,nodev /dev/cd0a /CDROM
diff --git a/doc/sample.syslog.conf b/doc/sample.syslog.conf
new file mode 100644 (file)
index 0000000..686cd19
--- /dev/null
@@ -0,0 +1,26 @@
+# This is a sample syslog.conf fragment for use with Sudo.
+#
+# By default, sudo logs to "authpriv" if your system supports it, else it
+# uses "auth".  The facility can be set via the --with-logfac configure
+# option or in the sudoers file.
+# To see what syslog facility a sudo binary uses, run `sudo -V' as *root*.
+#
+# NOTES:
+#      The whitespace in the following line is made up of <TAB>
+#       characters, *not* spaces.  You cannot just cut and paste!
+#
+#      If you edit syslog.conf you need to send syslogd a HUP signal.
+#      Ie: kill -HUP process_id
+#
+#      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'
+
+# This logs successful and failed sudo attempts to the file /var/log/auth
+# If your system has the authpriv syslog facility, use authpriv.debug
+auth.debug                                     /var/log/auth
+
+# To log to a remote machine, use something like the following,
+# where "loghost" is the name of the remote machine.
+# If your system has the authpriv syslog facility, use authpriv.debug
+auth.debug                                     @loghost
diff --git a/doc/schema.ActiveDirectory b/doc/schema.ActiveDirectory
new file mode 100644 (file)
index 0000000..cfdc7cb
--- /dev/null
@@ -0,0 +1,255 @@
+#\r
+# Active Directory Schema for sudo configuration (sudoers)\r
+#\r
+# To extend your Active Directory schema, run one of the following command\r
+# on your Windows DC (default port - Active Directory):\r
+# \r
+#  ldifde -i -f schema.ActiveDirectory -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext\r
+#\r
+# or on your Windows DC if using another port (with Active Directory LightWeight Directory Services / ADAM-Active Directory Application Mode)\r
+# Port 50000 by example (or any other port specified when defining the ADLDS/ADAM instance\r
+#\r
+#  ldifde -i -f schema.ActiveDirectory -t 50000 -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext\r
+#\r
+# or \r
+#\r
+#  ldifde -i -f schema.ActiveDirectory -s server:port -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext\r
+#\r
+# Can add username domain and password\r
+#\r
+# -b username domain password\r
+#\r
+# Can create Log file in current or any directory\r
+#\r
+# -j .\r
+#\r
+\r
+dn: CN=sudoUser,CN=Schema,CN=Configuration,DC=X\r
+changetype: add\r
+objectClass: top\r
+objectClass: attributeSchema\r
+cn: sudoUser\r
+distinguishedName: CN=sudoUser,CN=Schema,CN=Configuration,DC=X\r
+instanceType: 4\r
+attributeID: 1.3.6.1.4.1.15953.9.1.1\r
+attributeSyntax: 2.5.5.5\r
+isSingleValued: FALSE\r
+showInAdvancedViewOnly: TRUE\r
+adminDisplayName: sudoUser\r
+adminDescription: User(s) who may run sudo\r
+oMSyntax: 22\r
+searchFlags: 1\r
+lDAPDisplayName: sudoUser\r
+name: sudoUser\r
+schemaIDGUID:: JrGcaKpnoU+0s+HgeFjAbg==\r
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
+\r
+dn: CN=sudoHost,CN=Schema,CN=Configuration,DC=X\r
+changetype: add\r
+objectClass: top\r
+objectClass: attributeSchema\r
+cn: sudoHost\r
+distinguishedName: CN=sudoHost,CN=Schema,CN=Configuration,DC=X\r
+instanceType: 4\r
+attributeID: 1.3.6.1.4.1.15953.9.1.2\r
+attributeSyntax: 2.5.5.5\r
+isSingleValued: FALSE\r
+showInAdvancedViewOnly: TRUE\r
+adminDisplayName: sudoHost\r
+adminDescription: Host(s) who may run sudo\r
+oMSyntax: 22\r
+lDAPDisplayName: sudoHost\r
+name: sudoHost\r
+schemaIDGUID:: d0TTjg+Y6U28g/Y+ns2k4w==\r
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
+\r
+dn: CN=sudoCommand,CN=Schema,CN=Configuration,DC=X\r
+changetype: add\r
+objectClass: top\r
+objectClass: attributeSchema\r
+cn: sudoCommand\r
+distinguishedName: CN=sudoCommand,CN=Schema,CN=Configuration,DC=X\r
+instanceType: 4\r
+attributeID: 1.3.6.1.4.1.15953.9.1.3\r
+attributeSyntax: 2.5.5.5\r
+isSingleValued: FALSE\r
+showInAdvancedViewOnly: TRUE\r
+adminDisplayName: sudoCommand\r
+adminDescription: Command(s) to be executed by sudo\r
+oMSyntax: 22\r
+lDAPDisplayName: sudoCommand\r
+name: sudoCommand\r
+schemaIDGUID:: D6QR4P5UyUen3RGYJCHCPg==\r
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
+\r
+dn: CN=sudoRunAs,CN=Schema,CN=Configuration,DC=X\r
+changetype: add\r
+objectClass: top\r
+objectClass: attributeSchema\r
+cn: sudoRunAs\r
+distinguishedName: CN=sudoRunAs,CN=Schema,CN=Configuration,DC=X\r
+instanceType: 4\r
+attributeID: 1.3.6.1.4.1.15953.9.1.4\r
+attributeSyntax: 2.5.5.5\r
+isSingleValued: FALSE\r
+showInAdvancedViewOnly: TRUE\r
+adminDisplayName: sudoRunAs\r
+adminDescription: User(s) impersonated by sudo (deprecated)\r
+oMSyntax: 22\r
+lDAPDisplayName: sudoRunAs\r
+name: sudoRunAs\r
+schemaIDGUID:: CP98mCQTyUKKxGrQeM80hQ==\r
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
+\r
+dn: CN=sudoOption,CN=Schema,CN=Configuration,DC=X\r
+changetype: add\r
+objectClass: top\r
+objectClass: attributeSchema\r
+cn: sudoOption\r
+distinguishedName: CN=sudoOption,CN=Schema,CN=Configuration,DC=X\r
+instanceType: 4\r
+attributeID: 1.3.6.1.4.1.15953.9.1.5\r
+attributeSyntax: 2.5.5.5\r
+isSingleValued: FALSE\r
+showInAdvancedViewOnly: TRUE\r
+adminDisplayName: sudoOption\r
+adminDescription: Option(s) followed by sudo\r
+oMSyntax: 22\r
+lDAPDisplayName: sudoOption\r
+name: sudoOption\r
+schemaIDGUID:: ojaPzBBlAEmsvrHxQctLnA==\r
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
+\r
+dn: CN=sudoRunAsUser,CN=Schema,CN=Configuration,DC=X\r
+changetype: add\r
+objectClass: top\r
+objectClass: attributeSchema\r
+cn: sudoRunAsUser\r
+distinguishedName: CN=sudoRunAsUser,CN=Schema,CN=Configuration,DC=X\r
+instanceType: 4\r
+attributeID: 1.3.6.1.4.1.15953.9.1.6\r
+attributeSyntax: 2.5.5.5\r
+isSingleValued: FALSE\r
+showInAdvancedViewOnly: TRUE\r
+adminDisplayName: sudoRunAsUser\r
+adminDescription: User(s) impersonated by sudo\r
+oMSyntax: 22\r
+lDAPDisplayName: sudoRunAsUser\r
+name: sudoRunAsUser\r
+schemaIDGUID:: 9C52yPYd3RG3jMR2VtiVkw==\r
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
+\r
+dn: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,DC=X\r
+changetype: add\r
+objectClass: top\r
+objectClass: attributeSchema\r
+cn: sudoRunAsGroup\r
+distinguishedName: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,DC=X\r
+instanceType: 4\r
+attributeID: 1.3.6.1.4.1.15953.9.1.7\r
+attributeSyntax: 2.5.5.5\r
+isSingleValued: FALSE\r
+showInAdvancedViewOnly: TRUE\r
+adminDisplayName: sudoRunAsGroup\r
+adminDescription: Groups(s) impersonated by sudo\r
+oMSyntax: 22\r
+lDAPDisplayName: sudoRunAsGroup\r
+name: sudoRunAsGroup\r
+schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw==\r
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
+\r
+dn: CN=sudoNotBefore,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoNotBefore
+distinguishedName: CN=sudoNotBefore,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.8
+attributeSyntax: 1.3.6.1.4.1.1466.115.121.1.24
+isSingleValued: TRUE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoNotBefore
+adminDescription: Start of time interval for which the entry is valid
+oMSyntax: 22
+lDAPDisplayName:  sudoNotBefore
+name: sudoNotBefore
+schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoNotAfter,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoNotAfter
+distinguishedName: CN=sudoNotAfter,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.9
+attributeSyntax: 1.3.6.1.4.1.1466.115.121.1.24
+isSingleValued: TRUE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoNotAfter
+adminDescription: End of time interval for which the entry is valid
+oMSyntax: 22
+lDAPDisplayName:  sudoNotAfter
+name: sudoNotAfter
+schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoOrder,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoOrder
+distinguishedName: CN=sudoOrder,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.10
+attributeSyntax: 1.3.6.1.4.1.1466.115.121.1.27
+isSingleValued: TRUE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoOrder
+adminDescription: an integer to order the sudoRole entries
+oMSyntax: 22
+lDAPDisplayName:  sudoOrder
+name: sudoOrder
+schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn:\r
+changetype: modify\r
+add: schemaUpdateNow\r
+schemaUpdateNow: 1\r
+-\r
+\r
+dn: CN=sudoRole,CN=Schema,CN=Configuration,DC=X\r
+changetype: add\r
+objectClass: top\r
+objectClass: classSchema\r
+cn: sudoRole\r
+distinguishedName: CN=sudoRole,CN=Schema,CN=Configuration,DC=X\r
+instanceType: 4\r
+possSuperiors: container\r
+possSuperiors: top\r
+subClassOf: top\r
+governsID: 1.3.6.1.4.1.15953.9.2.1\r
+mayContain: sudoCommand\r
+mayContain: sudoHost\r
+mayContain: sudoOption\r
+mayContain: sudoRunAs\r
+mayContain: sudoRunAsUser\r
+mayContain: sudoRunAsGroup\r
+mayContain: sudoUser\r
+mayContain: sudoNotBefore
+mayContain: sudoNotAfter
+mayContain: sudoOrder
+rDNAttID: cn\r
+showInAdvancedViewOnly: FALSE\r
+adminDisplayName: sudoRole\r
+adminDescription: Sudoer Entries\r
+objectClassCategory: 1\r
+lDAPDisplayName: sudoRole\r
+name: sudoRole\r
+schemaIDGUID:: SQn432lnZ0+ukbdh3+gN3w==\r
+systemOnly: FALSE\r
+objectCategory: CN=Class-Schema,CN=Schema,CN=Configuration,DC=X\r
+defaultObjectCategory: CN=sudoRole,CN=Schema,CN=Configuration,DC=X\r
diff --git a/doc/schema.OpenLDAP b/doc/schema.OpenLDAP
new file mode 100644 (file)
index 0000000..d3e95e0
--- /dev/null
@@ -0,0 +1,76 @@
+#
+# OpenLDAP schema file for Sudo
+# Save as /etc/openldap/schema/sudo.schema
+#
+
+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 (deprecated)'
+    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 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.8
+    NAME 'sudoNotBefore'
+    DESC 'Start of time interval for which the entry is valid'
+    EQUALITY generalizedTimeMatch
+    ORDERING generalizedTimeOrderingMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.9
+    NAME 'sudoNotAfter'
+    DESC 'End of time interval for which the entry is valid'
+    EQUALITY generalizedTimeMatch
+    ORDERING generalizedTimeOrderingMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+attributeTypes ( 1.3.6.1.4.1.15953.9.1.10
+    NAME 'sudoOrder'
+    DESC 'an integer to order the sudoRole entries'
+    EQUALITY integerMatch
+    ORDERING integerOrderingMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+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 $ sudoOrder $ sudoNotBefore $ sudoNotAfter $
+           description )
+    )
diff --git a/doc/schema.iPlanet b/doc/schema.iPlanet
new file mode 100644 (file)
index 0000000..e512864
--- /dev/null
@@ -0,0 +1,12 @@
+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 (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' )
+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' )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.8 NAME 'sudoNotBefore' DESC 'Start of time interval for which the entry is valid' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.9 NAME 'sudoNotAfter' DESC 'End of time interval for which the entry is valid' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.10 NAME 'sudoOrder' DESC 'an integer to order the sudoRole entries' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+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 $ sudoOrder $ sudoNotBefore $ sudoNotAfter $ description ) X-ORIGIN 'SUDO' )
diff --git a/doc/sudo.cat b/doc/sudo.cat
new file mode 100644 (file)
index 0000000..08e1ac8
--- /dev/null
@@ -0,0 +1,547 @@
+SUDO(1m)                     MAINTENANCE COMMANDS                     SUDO(1m)
+
+
+
+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\bo [-\b-D\bD _\bl_\be_\bv_\be_\bl] -\b-h\bh | -\b-K\bK | -\b-k\bk | -\b-V\bV
+
+       s\bsu\bud\bdo\bo -\b-v\bv [-\b-A\bAk\bkn\bnS\bS] [-\b-a\ba _\ba_\bu_\bt_\bh_\b__\bt_\by_\bp_\be] [-\b-D\bD _\bl_\be_\bv_\be_\bl] [-\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]
+
+       s\bsu\bud\bdo\bo -\b-l\bl[\b[l\bl]\b] [-\b-A\bAk\bkn\bnS\bS] [-\b-a\ba _\ba_\bu_\bt_\bh_\b__\bt_\by_\bp_\be] [-\b-D\bD _\bl_\be_\bv_\be_\bl] [-\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-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\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-D\bD _\bl_\be_\bv_\be_\bl] [-\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-r\br _\br_\bo_\bl_\be] [-\b-t\bt _\bt_\by_\bp_\be]
+       [-\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-D\bD _\bl_\be_\bv_\be_\bl]
+       [-\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 by the security policy.  The real and
+       effective uid and gid are set to match those of the target user, as
+       specified in the password database, and the group vector is initialized
+       based on the group database (unless the -\b-P\bP option was specified).
+
+       s\bsu\bud\bdo\bo supports a plugin architecture for security policies and
+       input/output logging.  Third parties can develop and distribute their
+       own policy and I/O logging modules to work seemlessly with the s\bsu\bud\bdo\bo
+       front end.  The default security policy is _\bs_\bu_\bd_\bo_\be_\br_\bs, which is configured
+       via the file _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs, or via LDAP.  See the PLUGINS section for
+       more information.
+
+       The security policy determines what privileges, if any, a user has to
+       run s\bsu\bud\bdo\bo.  The policy may require that users authenticate themselves
+       with a password or another authentication mechanism.  If authentication
+       is required, s\bsu\bud\bdo\bo will exit if the user's password is not entered
+       within a configurable time limit.  This limit is policy-specific; the
+       default password prompt timeout for the _\bs_\bu_\bd_\bo_\be_\br_\bs security policy is 5
+       minutes.
+
+       Security policies may support credential caching to allow the user to
+       run s\bsu\bud\bdo\bo again for a period of time without requiring authentication.
+       The _\bs_\bu_\bd_\bo_\be_\br_\bs policy caches credentials for 5 minutes, unless overridden
+       in _\bs_\bu_\bd_\bo_\be_\br_\bs(4).  By running s\bsu\bud\bdo\bo with the -\b-v\bv option, a user can update
+       the cached credentials without running a _\bc_\bo_\bm_\bm_\ba_\bn_\bd.
+
+       When invoked as s\bsu\bud\bdo\boe\bed\bdi\bit\bt, the -\b-e\be option (described below), is implied.
+
+       Security policies may log successful and failed attempts to use s\bsu\bud\bdo\bo.
+       If an I/O plugin is configured, the running command's input and output
+       may be logged as well.
+
+O\bOP\bPT\bTI\bIO\bON\bNS\bS
+       s\bsu\bud\bdo\bo accepts the following command line options:
+
+       -A          Normally, if s\bsu\bud\bdo\bo requires a password, it will read it from
+                   the user's terminal.  If the -\b-A\bA (_\ba_\bs_\bk_\bp_\ba_\bs_\bs) option is
+                   specified, a (possibly graphical) 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, if _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b._\bc_\bo_\bn_\bf contains a
+                   line specifying the askpass program, that value will be
+                   used.  For example:
+
+                       # Path to askpass helper program
+                       Path askpass /usr/X11R6/bin/ssh-askpass
+
+                   If no askpass program is available, sudo will exit with an
+                   error.
+
+       -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.
+
+       -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.  Most interactive commands will fail to work
+                   properly in background mode.
+
+       -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.  The
+                   security policy may restrict the user's ability to use the
+                   -\b-C\bC option.  The _\bs_\bu_\bd_\bo_\be_\br_\bs policy only permits use of the -\b-C\bC
+                   option when the administrator has enabled the
+                   _\bc_\bl_\bo_\bs_\be_\bf_\br_\bo_\bm_\b__\bo_\bv_\be_\br_\br_\bi_\bd_\be option.
+
+       -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.
+
+       -D _\bl_\be_\bv_\be_\bl    Enable debugging of s\bsu\bud\bdo\bo plugins and s\bsu\bud\bdo\bo itself.  The
+                   _\bl_\be_\bv_\be_\bl may be a value from 1 through 9.
+
+       -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 indicates to the
+                   security policy that the uses wishes to preserve their
+                   existing environment variables.  The security policy may
+                   return an error if the -\b-E\bE option is specified and the user
+                   does not have permission to preserve the environment.
+
+       -e          The -\b-e\be (_\be_\bd_\bi_\bt) option indicates that, instead of running a
+                   command, the user wishes to edit one or more files.  In
+                   lieu of a command, the string "sudoedit" is used when
+                   consulting the security policy.  If the user is authorized
+                   by the policy, the following steps are taken:
+
+                   1.  Temporary copies are made of the files to be edited
+                       with the owner set to the invoking user.
+
+                   2.  The editor specified by the policy is run to edit the
+                       temporary files.  The _\bs_\bu_\bd_\bo_\be_\br_\bs policy uses the
+                       SUDO_EDITOR, VISUAL and EDITOR environment variables
+                       (in that order).  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(4) option is used.
+
+                   3.  If they have been modified, the temporary files are
+                       copied back to their original location and the
+                       temporary versions are removed.
+
+                   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.
+
+       -g _\bg_\br_\bo_\bu_\bp    Normally, s\bsu\bud\bdo\bo runs a command with the primary group set to
+                   the one specified by the password 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 command with the primary
+                   group set to _\bg_\br_\bo_\bu_\bp instead.  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.
+
+       -H          The -\b-H\bH (_\bH_\bO_\bM_\bE) option requests that the security policy set
+                   the HOME environment variable to the home directory of the
+                   target user (root by default) as specified by the password
+                   database.  Depending on the policy, this may be the default
+                   behavior.
+
+       -h          The -\b-h\bh (_\bh_\be_\bl_\bp) option causes s\bsu\bud\bdo\bo to print a short help
+                   message to the standard output and exit.
+
+       -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 by the password database 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 via the shell's -\b-c\bc option.  If no command is
+                   specified, an interactive shell is executed.  s\bsu\bud\bdo\bo attempts
+                   to change to that user's home directory before running the
+                   shell.  The security policy shall initialize the
+                   environment to a minimal set of variables, similar to what
+                   is present when a user logs in.
+
+       -K          The -\b-K\bK (sure _\bk_\bi_\bl_\bl) option is like -\b-k\bk except that it removes
+                   the user's cached credentials entirely and may not be used
+                   in conjunction with a command or other option.  This option
+                   does not require a password.  Not all security policies
+                   support credential caching.
+
+       -k [command]
+                   When used alone, the -\b-k\bk (_\bk_\bi_\bl_\bl) option to s\bsu\bud\bdo\bo invalidates
+                   the user's cached credentials.  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.  Not all security policies
+                   support credential caching.
+
+                   When used in conjunction with a command or an option that
+                   may require a password, the -\b-k\bk option will cause s\bsu\bud\bdo\bo to
+                   ignore the user's cached credentials.  As a result, s\bsu\bud\bdo\bo
+                   will prompt for a password (if one is required by the
+                   security policy) and will not update the user's cached
+                   credentials.
+
+       -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 the
+                   security policy, 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.
+
+       -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.
+
+       -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, the _\bs_\bu_\bd_\bo_\be_\br_\bs policy 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.
+
+       -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 by the _\bs_\bu_\bd_\bo_\be_\br_\bs policy:
+
+                   %H  expanded to the host name including the domain name (on
+                       if the machine's host name is fully qualified or the
+                       _\bf_\bq_\bd_\bn option is set in _\bs_\bu_\bd_\bo_\be_\br_\bs(4))
+
+                   %h  expanded to the local host name without the domain name
+
+                   %p  expanded to the name of the user whose password is
+                       being requested (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(4))
+
+                   %U  expanded to the login name of the user the command will
+                       be run as (defaults to root unless the -u option is
+                       also specified)
+
+                   %u  expanded to the invoking user's login name
+
+                   %%  two consecutive % characters are collapsed into a
+                       single % character
+
+                   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 _\br_\bo_\bl_\be     The -\b-r\br (_\br_\bo_\bl_\be) option causes the new (SELinux) security
+                   context to have the role specified by _\br_\bo_\bl_\be.
+
+       -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.  The
+                   password must be followed by a newline character.
+
+       -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 the password database.  If a command is specified, it is
+                   passed to the shell for execution via the shell's -\b-c\bc
+                   option.  If no command is specified, an interactive shell
+                   is executed.
+
+       -t _\bt_\by_\bp_\be     The -\b-t\bt (_\bt_\by_\bp_\be) option causes the new (SELinux) security
+                   context to have the type specified by _\bt_\by_\bp_\be.  If no type is
+                   specified, the default type is derived from the specified
+                   role.
+
+       -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.  The security policy may restrict listing other
+                   users' privileges.  The _\bs_\bu_\bd_\bo_\be_\br_\bs policy only allows root or
+                   a user with the ALL privilege on the current host to use
+                   this option.
+
+       -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 ('\').  Security policies may restrict _\bu_\bi_\bds to
+                   those listed in the password database.  The _\bs_\bu_\bd_\bo_\be_\br_\bs policy
+                   allows _\bu_\bi_\bds that are not in the password database as long
+                   as the _\bt_\ba_\br_\bg_\be_\bt_\bp_\bw option is not set.  Other security policies
+                   may not support this.
+
+       -V          The -\b-V\bV (_\bv_\be_\br_\bs_\bi_\bo_\bn) option causes s\bsu\bud\bdo\bo to print its version
+                   string and the version string of the security policy plugin
+                   and any I/O plugins.  If the invoking user is already root
+                   the -\b-V\bV option will display the arguments passed to
+                   configure when _\bs_\bu_\bd_\bo was built and plugins may display more
+                   verbose information such as default options.
+
+       -v          When given the -\b-v\bv (_\bv_\ba_\bl_\bi_\bd_\ba_\bt_\be) option, s\bsu\bud\bdo\bo will update the
+                   user's cached credentials, authenticating the user's
+                   password if necessary.  For the _\bs_\bu_\bd_\bo_\be_\br_\bs plugin, 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.  Not all security policies support cached
+                   credentials.
+
+       --          The -\b--\b- option indicates that s\bsu\bud\bdo\bo should stop processing
+                   command line arguments.
+
+       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_\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.
+
+P\bPL\bLU\bUG\bGI\bIN\bNS\bS
+       Plugins are dynamically loaded based on the contents of the
+       _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b._\bc_\bo_\bn_\bf file.  If no _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b._\bc_\bo_\bn_\bf file is present, or it
+       contains no Plugin lines, s\bsu\bud\bdo\bo will use the traditional _\bs_\bu_\bd_\bo_\be_\br_\bs
+       security policy and I/O logging, which corresponds to the following
+       _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b._\bc_\bo_\bn_\bf file.
+
+        #
+        # Default /etc/sudo.conf file
+        #
+        # Format:
+        #   Plugin plugin_name plugin_path
+        #   Path askpass /path/to/askpass
+        #   Path noexec /path/to/noexec.so
+        #
+        # The plugin_path is relative to /usr/local/libexec unless
+        #   fully qualified.
+        # The plugin_name corresponds to a global symbol in the plugin
+        #   that contains the plugin interface structure.
+        #
+        Plugin policy_plugin sudoers.so
+        Plugin io_plugin sudoers.so
+
+       A Plugin line consists of the Plugin keyword, followed by the
+       _\bs_\by_\bm_\bb_\bo_\bl_\b__\bn_\ba_\bm_\be and the _\bp_\ba_\bt_\bh to the shared object containing the plugin.
+       The _\bs_\by_\bm_\bb_\bo_\bl_\b__\bn_\ba_\bm_\be is the name of the struct policy_plugin or struct
+       io_plugin in the plugin shared object.  The _\bp_\ba_\bt_\bh may be fully qualified
+       or relative.  If not fully qualified it is relative to the
+       _\b/_\bu_\bs_\br_\b/_\bl_\bo_\bc_\ba_\bl_\b/_\bl_\bi_\bb_\be_\bx_\be_\bc directory.  Any additional parameters after the _\bp_\ba_\bt_\bh
+       are ignored.  Lines that don't begin with Plugin or Path are silently
+       ignored
+
+       For more information, see the _\bs_\bu_\bd_\bo_\b__\bp_\bl_\bu_\bg_\bi_\bn(1m) manual.
+
+P\bPA\bAT\bTH\bHS\bS
+       A Path line consists of the Path keyword, followed by the name of the
+       path to set and its value.  E.g.
+
+        Path noexec /usr/local/libexec/sudo_noexec.so
+        Path askpass /usr/X11R6/bin/ssh-askpass
+
+       The following plugin-agnostic paths may be set in the _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b._\bc_\bo_\bn_\bf
+       file.
+
+       askpass         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.
+
+       noexec          The fully-qualified 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.
+
+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 exits with a 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 the
+       standard error.  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.
+
+       To prevent command spoofing, s\bsu\bud\bdo\bo checks "." and "" (both denoting
+       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.
+
+       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 are not subject to s\bsu\bud\bdo\bo's security policy.
+       The same is true for commands that offer shell escapes (including most
+       editors).  If I/O logging is enabled, subsequent commands will have
+       their input and/or output logged, but there will not be traditional
+       logs for those commands.  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.  The security policy
+       has control over the content of the command's environment.
+
+       EDITOR          Default editor to use in -\b-e\be (sudoedit) mode if neither
+                       SUDO_EDITOR nor VISUAL is set
+
+       MAIL            In -\b-i\bi mode or when _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt is enabled in _\bs_\bu_\bd_\bo_\be_\br_\bs, set
+                       to the mail spool of the target user
+
+       HOME            Set to the home directory of the target user if -\b-i\bi or
+                       -\b-H\bH are specified, _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt or _\ba_\bl_\bw_\ba_\by_\bs_\b__\bs_\be_\bt_\b__\bh_\bo_\bm_\be are set
+                       in _\bs_\bu_\bd_\bo_\be_\br_\bs, or when the -\b-s\bs option is specified and
+                       _\bs_\be_\bt_\b__\bh_\bo_\bm_\be is set in _\bs_\bu_\bd_\bo_\be_\br_\bs
+
+       PATH            May be overridden by the security policy.
+
+       SHELL           Used to determine shell to run with -s option
+
+       SUDO_ASKPASS    Specifies the path to a helper program used to read the
+                       password if no terminal is available or if the -A
+                       option is specified.
+
+       SUDO_COMMAND    Set to the command run by sudo
+
+       SUDO_EDITOR     Default editor to use in -\b-e\be (sudoedit) mode
+
+       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
+
+       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_\b._\bc_\bo_\bn_\bf          s\bsu\bud\bdo\bo plugin and path configuration
+
+E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
+       Note: the following examples assume a properly configured security
+       policy.
+
+       To get a file listing of an unreadable directory:
+
+        $ sudo ls /usr/local/protected
+
+       To list the home directory of user yaz on a machine where the file
+       system holding ~yaz is not exported as root:
+
+        $ sudo -u yaz ls ~yaz
+
+       To edit the _\bi_\bn_\bd_\be_\bx_\b._\bh_\bt_\bm_\bl file as user www:
+
+        $ sudo -u www vi ~www/htdocs/index.html
+
+       To view system logs only accessible to root and users in the adm group:
+
+        $ sudo -g adm view /var/log/syslog
+
+       To run an editor as jim with a different primary group:
+
+        $ sudo -u jim -g audio vi ~jim/sound.txt
+
+       To shutdown a machine:
+
+        $ 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.
+
+        $ 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(4),
+       _\bs_\bu_\bd_\bo_\b__\bp_\bl_\bu_\bg_\bi_\bn(1m), _\bs_\bu_\bd_\bo_\br_\be_\bp_\bl_\ba_\by(1m), _\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.
+
+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 the _\bs_\bu_\bd_\bo_\be_\br_\bs(4) module's _\bn_\bo_\be_\bx_\be_\bc
+       functionality.
+
+       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.
+
+       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/
+
+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.
+
+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.8.1p2                          May 16, 2011                         SUDO(1m)
diff --git a/doc/sudo.man.in b/doc/sudo.man.in
new file mode 100644 (file)
index 0000000..1d5ca05
--- /dev/null
@@ -0,0 +1,800 @@
+.\" Copyright (c) 1994-1996, 1998-2005, 2007-2011
+.\"    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.
+.\" 
+.\" 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.
+.\" 
+.nr SL @SEMAN@
+.nr BA @BAMAN@
+.nr LC @LCMAN@
+.nr PT @password_timeout@
+.\"
+.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.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 (.SS), 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 "SUDO @mansectsu@"
+.TH SUDO @mansectsu@ "May 16, 2011" "1.8.1p2" "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\-D\fR\ \fIlevel\fR] \fB\-h\fR | \fB\-K\fR | \fB\-k\fR | \fB\-V\fR
+.PP
+\&\fBsudo\fR \fB\-v\fR [\fB\-AknS\fR]
+.if \n(BA [\fB\-a\fR\ \fIauth_type\fR]
+[\fB\-D\fR\ \fIlevel\fR]
+[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR]
+[\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR]
+.PP
+\&\fBsudo\fR \fB\-l[l]\fR [\fB\-AknS\fR]
+.if \n(BA [\fB\-a\fR\ \fIauth_type\fR]
+[\fB\-D\fR\ \fIlevel\fR]
+[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR]
+[\fB\-U\fR\ \fIuser\ name\fR] [\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR] [\fIcommand\fR]
+.PP
+\&\fBsudo\fR [\fB\-AbEHnPS\fR]
+.if \n(BA [\fB\-a\fR\ \fIauth_type\fR]
+[\fB\-C\fR\ \fIfd\fR]
+[\fB\-D\fR\ \fIlevel\fR]
+.if \n(LC [\fB\-c\fR\ \fIclass\fR|\fI\-\fR]
+[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR]
+.if \n(SL [\fB\-r\fR\ \fIrole\fR] [\fB\-t\fR\ \fItype\fR]
+[\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR]
+[\fB\s-1VAR\s0\fR=\fIvalue\fR] [\fB\-i\fR\ |\ \fB\-s\fR] [\fIcommand\fR]
+.PP
+\&\fBsudoedit\fR [\fB\-AnS\fR]
+.if \n(BA [\fB\-a\fR\ \fIauth_type\fR]
+[\fB\-C\fR\ \fIfd\fR]
+.if \n(LC [\fB\-c\fR\ \fIclass\fR|\fI\-\fR]
+[\fB\-D\fR\ \fIlevel\fR]
+[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR]
+[\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR] file ...
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+\&\fBsudo\fR allows a permitted user to execute a \fIcommand\fR as the
+superuser or another user, as specified by the security policy.
+The real and effective uid and gid are set to match those of the
+target user, as specified in the password database, and the group
+vector is initialized based on the group database (unless the \fB\-P\fR
+option was specified).
+.PP
+\&\fBsudo\fR supports a plugin architecture for security policies and
+input/output logging.  Third parties can develop and distribute
+their own policy and I/O logging modules to work seemlessly with
+the \fBsudo\fR front end.  The default security policy is \fIsudoers\fR,
+which is configured via the file \fI@sysconfdir@/sudoers\fR, or via
+\&\s-1LDAP\s0.  See the \s-1PLUGINS\s0 section for more information.
+.PP
+The security policy determines what privileges, if any, a user has
+to run \fBsudo\fR.  The policy may require that users authenticate
+themselves with a password or another authentication mechanism.  If
+authentication is required, \fBsudo\fR will exit if the user's password
+is not entered within a configurable time limit.  This limit is
+policy-specific; the default password prompt timeout for the
+\&\fIsudoers\fR security policy is 
+.ie \n(PT \f(CW\*(C`@password_timeout@\*(C'\fR minutes.
+.el unlimited.
+.PP
+Security policies may support credential caching to allow the user
+to run \fBsudo\fR again for a period of time without requiring
+authentication.  The \fIsudoers\fR policy caches credentials for
+\&\f(CW\*(C`@timeout@\*(C'\fR minutes, unless overridden in \fIsudoers\fR\|(@mansectform@).  By
+running \fBsudo\fR with the \fB\-v\fR option, a user can update the cached
+credentials without running a \fIcommand\fR.
+.PP
+When invoked as \fBsudoedit\fR, the \fB\-e\fR option (described below),
+is implied.
+.PP
+Security policies may log successful and failed attempts to use
+\&\fBsudo\fR.  If an I/O plugin is configured, the running command's
+input and output may be logged as well.
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+\&\fBsudo\fR accepts the following command line options:
+.IP "\-A" 12
+.IX Item "-A"
+Normally, if \fBsudo\fR requires a password, it will read it from the
+user's terminal.  If the \fB\-A\fR (\fIaskpass\fR) option is specified,
+a (possibly graphical) 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, if \fI@sysconfdir@/sudo.conf\fR
+contains a line specifying the askpass program, that value will be
+used.  For example:
+.Sp
+.Vb 2
+\&    # Path to askpass helper program
+\&    Path askpass /usr/X11R6/bin/ssh\-askpass
+.Ve
+.Sp
+If no askpass program is available, sudo will exit with an error.
+.if \n(BA \{\
+.IP "\-a \fItype\fR" 12
+.IX Item "-a type"
+The \fB\-a\fR (\fIauthentication type\fR) option causes \fBsudo\fR to use the
+specified authentication type when validating the user, as allowed
+by \fI/etc/login.conf\fR.  The system administrator may specify a list
+of sudo-specific authentication methods by adding an \*(L"auth-sudo\*(R"
+entry in \fI/etc/login.conf\fR.  This option is only available on systems
+that support \s-1BSD\s0 authentication.
+\}
+.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.
+Most interactive commands will fail to work properly in background
+mode.
+.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.  The security policy may restrict the
+user's ability to use the \fB\-C\fR option.  The \fIsudoers\fR policy only
+permits use of the \fB\-C\fR option when the administrator has enabled
+the \fIclosefrom_override\fR option.
+.if \n(LC \{\
+.IP "\-c \fIclass\fR" 12
+.IX Item "-c class"
+The \fB\-c\fR (\fIclass\fR) option causes \fBsudo\fR to run the specified command
+with resources limited by the specified login class.  The \fIclass\fR
+argument can be either a class name as defined in \fI/etc/login.conf\fR,
+or a single '\-' character.  Specifying a \fIclass\fR of \f(CW\*(C`\-\*(C'\fR indicates
+that the command should be run restricted by the default login
+capabilities for the user the command is run as.  If the \fIclass\fR
+argument specifies an existing user class, the command must be run
+as root, or the \fBsudo\fR command must be run from a shell that is already
+root.  This option is only available on systems with \s-1BSD\s0 login classes.
+\}
+.IP "\-D \fIlevel\fR" 12
+.IX Item "-D level"
+Enable debugging of \fBsudo\fR plugins and \fBsudo\fR itself.  The \fIlevel\fR
+may be a value from 1 through 9.
+.IP "\-E" 12
+.IX Item "-E"
+The \fB\-E\fR (\fIpreserve\fR \fIenvironment\fR) option indicates to the
+security policy that the uses wishes to preserve their existing
+environment variables.  The security policy may return an error if
+the \fB\-E\fR option is specified and the user does not have permission
+to preserve the environment.
+.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 security
+policy.  If the user is authorized by the policy, the following
+steps are taken:
+.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 policy is run to edit the temporary files.
+The \fIsudoers\fR policy uses the \f(CW\*(C`SUDO_EDITOR\*(C'\fR, \f(CW\*(C`VISUAL\*(C'\fR and \f(CW\*(C`EDITOR\*(C'\fR
+environment variables (in that order).  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\|(@mansectform@) option 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 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
+the invoking user's environment unmodified.  If, for some reason,
+\&\fBsudo\fR 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.
+.RE
+.IP "\-g \fIgroup\fR" 12
+.IX Item "-g group"
+Normally, \fBsudo\fR runs a command with the primary group set to the
+one specified by the password 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 command with the primary group set to \fIgroup\fR
+instead.  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 requests that the security policy set
+the \f(CW\*(C`HOME\*(C'\fR environment variable to the home directory of the target
+user (root by default) as specified by the password database.
+Depending on the policy, this may be the default behavior.
+.IP "\-h" 12
+.IX Item "-h"
+The \fB\-h\fR (\fIhelp\fR) option causes \fBsudo\fR to print a short help message
+to the standard output and exit.
+.IP "\-i [command]" 12
+.IX Item "-i [command]"
+The \fB\-i\fR (\fIsimulate initial login\fR) option runs the shell specified
+by the password database 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 via the shell's \fB\-c\fR option.
+If no command is specified, an interactive shell is executed.
+\&\fBsudo\fR attempts to change to that user's home directory before
+running the shell.  The security policy shall initialize the
+environment to a minimal set of variables, similar to what is present
+when a user logs in.
+.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 cached credentials entirely and may not be used in
+conjunction with a command or other option.  This option does not
+require a password.  Not all security policies support credential
+caching.
+.IP "\-k [command]" 12
+.IX Item "-k [command]"
+When used alone, the \fB\-k\fR (\fIkill\fR) option to \fBsudo\fR invalidates
+the user's cached credentials.  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.  Not all security policies support credential
+caching.
+.Sp
+When used in conjunction with a command or an option that may require
+a password, the \fB\-k\fR option will cause \fBsudo\fR to ignore the user's
+cached credentials.  As a result, \fBsudo\fR will prompt for a password
+(if one is required by the security policy) and will not update the
+user's cached credentials.
+.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 the security policy,
+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,
+the \fIsudoers\fR policy 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 \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 by the \fIsudoers\fR policy:
+.RS 12
+.ie n .IP "%H" 4
+.el .IP "\f(CW%H\fR" 4
+.IX Item "%H"
+expanded to the host name including the domain name (on if
+the machine's host name is fully qualified or the \fIfqdn\fR option
+is set in \fIsudoers\fR\|(@mansectform@))
+.ie n .IP "%h" 4
+.el .IP "\f(CW%h\fR" 4
+.IX Item "%h"
+expanded to the local host name without the domain name
+.ie n .IP "%p" 4
+.el .IP "\f(CW%p\fR" 4
+.IX Item "%p"
+expanded to the name of the user whose password is being requested
+(respects the \fIrootpw\fR, \fItargetpw\fR and \fIrunaspw\fR flags in
+\&\fIsudoers\fR\|(@mansectform@))
+.ie n .IP "%U" 4
+.el .IP "\f(CW%U\fR" 4
+.IX Item "%U"
+expanded to the login name of the user the command will be run as
+(defaults to root unless the \f(CW\*(C`\-u\*(C'\fR option is also specified)
+.ie n .IP "%u" 4
+.el .IP "\f(CW%u\fR" 4
+.IX Item "%u"
+expanded to the invoking user's login name
+.ie n .IP "\*(C`%%\*(C'" 4
+.el .IP "\f(CW\*(C`%%\*(C'\fR" 4
+.IX Item "%%"
+two consecutive \f(CW\*(C`%\*(C'\fR characters are collapsed into a single \f(CW\*(C`%\*(C'\fR character
+.RE
+.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
+.if \n(SL \{\
+.IP "\-r \fIrole\fR" 12
+.IX Item "-r role"
+The \fB\-r\fR (\fIrole\fR) option causes the new (SELinux) security context to 
+have the role specified by \fIrole\fR.
+\}
+.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.  The password must
+be followed by a newline character.
+.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 the
+password database.  If a command is specified, it is passed to the
+shell for execution via the shell's \fB\-c\fR option.  If no command
+is specified, an interactive shell is executed.
+.if \n(SL \{\
+.IP "\-t \fItype\fR" 12
+.IX Item "-t type"
+The \fB\-t\fR (\fItype\fR) option causes the new (SELinux) security context to 
+have the type specified by \fItype\fR.  If no type is specified, the default
+type is derived from the specified role.
+\}
+.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.
+The security policy may restrict listing other users' privileges.
+The \fIsudoers\fR policy only allows root or a user with the \f(CW\*(C`ALL\*(C'\fR
+privilege on the current host to 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 \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').
+Security policies may restrict \fIuid\fRs to those listed in the
+password database.  The \fIsudoers\fR policy allows \fIuid\fRs that are
+not in the password database as long as the \fItargetpw\fR option is
+not set.  Other security policies may not support this.
+.IP "\-V" 12
+.IX Item "-V"
+The \fB\-V\fR (\fIversion\fR) option causes \fBsudo\fR to print its version
+string and the version string of the security policy plugin and any
+I/O plugins.  If the invoking user is already root the \fB\-V\fR option
+will display the arguments passed to configure when \fIsudo\fR was
+built and plugins may display more verbose information such as
+default options.
+.IP "\-v" 12
+.IX Item "-v"
+When given the \fB\-v\fR (\fIvalidate\fR) option, \fBsudo\fR will update the
+user's cached credentials, authenticating the user's password if
+necessary.  For the \fIsudoers\fR plugin, 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.  Not all
+security policies support cached credentials.
+.IP "\-\-" 12
+The \fB\-\-\fR option indicates that \fBsudo\fR should stop processing command
+line arguments.
+.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.
+\&\fB\s-1LD_LIBRARY_PATH\s0\fR=\fI/usr/local/pkg/lib\fR.  Variables passed on the
+command line are subject to the same restrictions as normal environment
+variables with one important exception.  If the \fIsetenv\fR option
+is set in \fIsudoers\fR, the command to be run has the \f(CW\*(C`SETENV\*(C'\fR tag
+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 "PLUGINS"
+.IX Header "PLUGINS"
+Plugins are dynamically loaded based on the contents of the
+\&\fI@sysconfdir@/sudo.conf\fR file.  If no \fI@sysconfdir@/sudo.conf\fR
+file is present, or it contains no \f(CW\*(C`Plugin\*(C'\fR lines, \fBsudo\fR
+will use the traditional \fIsudoers\fR security policy and I/O logging,
+which corresponds to the following \fI@sysconfdir@/sudo.conf\fR file.
+.PP
+.Vb 10
+\& #
+\& # Default @sysconfdir@/sudo.conf file
+\& #
+\& # Format:
+\& #   Plugin plugin_name plugin_path
+\& #   Path askpass /path/to/askpass
+\& #   Path noexec /path/to/noexec.so
+\& #
+\& # The plugin_path is relative to @prefix@/libexec unless
+\& #   fully qualified.
+\& # The plugin_name corresponds to a global symbol in the plugin
+\& #   that contains the plugin interface structure.
+\& #
+\& Plugin policy_plugin sudoers.so
+\& Plugin io_plugin sudoers.so
+.Ve
+.PP
+A \f(CW\*(C`Plugin\*(C'\fR line consists of the \f(CW\*(C`Plugin\*(C'\fR keyword, followed by the
+\&\fIsymbol_name\fR and the \fIpath\fR to the shared object containing the
+plugin.  The \fIsymbol_name\fR is the name of the \f(CW\*(C`struct policy_plugin\*(C'\fR
+or \f(CW\*(C`struct io_plugin\*(C'\fR in the plugin shared object.  The \fIpath\fR
+may be fully qualified or relative.  If not fully qualified it is
+relative to the \fI@prefix@/libexec\fR directory.  Any additional
+parameters after the \fIpath\fR are ignored.  Lines that don't begin
+with \f(CW\*(C`Plugin\*(C'\fR or \f(CW\*(C`Path\*(C'\fR are silently ignored
+.PP
+For more information, see the \fIsudo_plugin\fR\|(@mansectsu@) manual.
+.SH "PATHS"
+.IX Header "PATHS"
+A \f(CW\*(C`Path\*(C'\fR line consists of the \f(CW\*(C`Path\*(C'\fR keyword, followed by the
+name of the path to set and its value.  E.g.
+.PP
+.Vb 2
+\& Path noexec @noexec_file@
+\& Path askpass /usr/X11R6/bin/ssh\-askpass
+.Ve
+.PP
+The following plugin-agnostic paths may be set in the
+\&\fI@sysconfdir@/sudo.conf\fR file.
+.IP "askpass" 16
+.IX Item "askpass"
+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 "noexec" 16
+.IX Item "noexec"
+The fully-qualified path to a shared library containing dummy
+versions of the \fIexecv()\fR, \fIexecve()\fR and \fIfexecve()\fR library functions
+that just return an error.  This is used to implement the \fInoexec\fR
+functionality on systems that support \f(CW\*(C`LD_PRELOAD\*(C'\fR or its equivalent.
+Defaults to \fI@noexec_file@\fR.
+.SH "RETURN VALUES"
+.IX Header "RETURN VALUES"
+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 exits with a value of 1 if there is a
+configuration/permission problem or if \fBsudo\fR cannot execute the
+given command.  In the latter case the error string is printed to
+the standard error.  If \fBsudo\fR cannot \fIstat\fR\|(2) one or more entries
+in the user's \f(CW\*(C`PATH\*(C'\fR, 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 \fIstat\fR\|(2)
+to return \*(L"permission denied\*(R" is if you are running an automounter
+and one of the directories in your \f(CW\*(C`PATH\*(C'\fR is on a machine that is
+currently unreachable.
+.SH "SECURITY NOTES"
+.IX Header "SECURITY NOTES"
+\&\fBsudo\fR tries to be safe when executing external commands.
+.PP
+To prevent command spoofing, \fBsudo\fR checks \*(L".\*(R" and "" (both denoting
+current directory) last when searching for a command in the user's
+\&\s-1PATH\s0 (if one or both are in the \s-1PATH\s0).  Note, however, that the
+actual \f(CW\*(C`PATH\*(C'\fR environment variable is \fInot\fR modified and is passed
+unchanged to the program that \fBsudo\fR executes.
+.PP
+Please note that \fBsudo\fR will normally only log the command it
+explicitly runs.  If a user runs a command such as \f(CW\*(C`sudo su\*(C'\fR or
+\&\f(CW\*(C`sudo sh\*(C'\fR, subsequent commands run from that shell are not subject
+to \fBsudo\fR's security policy.  The same is true for commands that
+offer shell escapes (including most editors).  If I/O logging is
+enabled, subsequent commands will have their input and/or output
+logged, but there will not be traditional logs for those commands.
+Because of this, care must be taken when giving users access to
+commands via \fBsudo\fR to verify that the command does not inadvertently
+give the user an effective root shell.  For more information, please
+see the \f(CW\*(C`PREVENTING SHELL ESCAPES\*(C'\fR section in \fIsudoers\fR\|(@mansectform@).
+.SH "ENVIRONMENT"
+.IX Header "ENVIRONMENT"
+\&\fBsudo\fR utilizes the following environment variables.  The security
+policy has control over the content of the command's environment.
+.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 neither \f(CW\*(C`SUDO_EDITOR\*(C'\fR
+nor \f(CW\*(C`VISUAL\*(C'\fR is set
+.ie n .IP "\*(C`MAIL\*(C'" 16
+.el .IP "\f(CW\*(C`MAIL\*(C'\fR" 16
+.IX Item "MAIL"
+In \fB\-i\fR mode or when \fIenv_reset\fR is enabled in \fIsudoers\fR, set
+to the mail spool of the target user
+.ie n .IP "\*(C`HOME\*(C'" 16
+.el .IP "\f(CW\*(C`HOME\*(C'\fR" 16
+.IX Item "HOME"
+Set to the home directory of the target user if \fB\-i\fR or \fB\-H\fR are
+specified, \fIenv_reset\fR or \fIalways_set_home\fR are set in \fIsudoers\fR,
+or when the \fB\-s\fR option is specified and \fIset_home\fR is set in
+\&\fIsudoers\fR
+.ie n .IP "\*(C`PATH\*(C'" 16
+.el .IP "\f(CW\*(C`PATH\*(C'\fR" 16
+.IX Item "PATH"
+May be overridden by the security policy.
+.ie n .IP "\*(C`SHELL\*(C'" 16
+.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_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_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 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 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"
+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 if \f(CW\*(C`SUDO_EDITOR\*(C'\fR
+is not set
+.SH "FILES"
+.IX Header "FILES"
+.ie n .IP "\fI@sysconfdir@/sudo.conf\fR" 24
+.el .IP "\fI@sysconfdir@/sudo.conf\fR" 24
+.IX Item "@sysconfdir@/sudo.conf"
+\&\fBsudo\fR plugin and path configuration
+.SH "EXAMPLES"
+.IX Header "EXAMPLES"
+Note: the following examples assume a properly configured security policy.
+.PP
+To get a file listing of an unreadable directory:
+.PP
+.Vb 1
+\& $ sudo ls /usr/local/protected
+.Ve
+.PP
+To list the home directory of user yaz on a machine where the
+file system holding ~yaz is not exported as root:
+.PP
+.Vb 1
+\& $ sudo \-u yaz ls ~yaz
+.Ve
+.PP
+To edit the \fIindex.html\fR file as user www:
+.PP
+.Vb 1
+\& $ sudo \-u www vi ~www/htdocs/index.html
+.Ve
+.PP
+To view system logs only accessible to root and users in the adm group:
+.PP
+.Vb 1
+\& $ sudo \-g adm view /var/log/syslog
+.Ve
+.PP
+To run an editor as jim with a different primary group:
+.PP
+.Vb 1
+\& $ sudo \-u jim \-g audio vi ~jim/sound.txt
+.Ve
+.PP
+To shutdown a machine:
+.PP
+.Vb 1
+\& $ sudo shutdown \-r +15 "quick reboot"
+.Ve
+.PP
+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 \f(CW\*(C`cd\*(C'\fR and file redirection work.
+.PP
+.Vb 1
+\& $ sudo sh \-c "cd /home ; du \-s * | sort \-rn > USAGE"
+.Ve
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fIgrep\fR\|(1), \fIsu\fR\|(1), \fIstat\fR\|(2),
+.if \n(LC \&\fIlogin_cap\fR\|(3),
+\&\fIpasswd\fR\|(@mansectform@), \fIsudoers\fR\|(@mansectform@), \fIsudo_plugin\fR\|(@mansectsu@), \fIsudoreplay\fR\|(@mansectsu@), \fIvisudo\fR\|(@mansectsu@)
+.SH "AUTHORS"
+.IX Header "AUTHORS"
+Many people have worked on \fBsudo\fR over the years; this
+version consists of code written primarily by:
+.PP
+.Vb 1
+\&        Todd C. Miller
+.Ve
+.PP
+See the \s-1HISTORY\s0 file in the \fBsudo\fR distribution or visit
+http://www.sudo.ws/sudo/history.html for a short history
+of \fBsudo\fR.
+.SH "CAVEATS"
+.IX Header "CAVEATS"
+There is no easy way to prevent a user from gaining a root shell
+if that user is allowed to run arbitrary commands via \fBsudo\fR.
+Also, many programs (such as editors) allow the user to run commands
+via shell escapes, thus avoiding \fBsudo\fR's checks.  However, on
+most systems it is possible to prevent shell escapes with the
+\&\fIsudoers\fR\|(@mansectform@) module's \fInoexec\fR functionality.
+.PP
+It is not meaningful to run the \f(CW\*(C`cd\*(C'\fR command directly via sudo, e.g.,
+.PP
+.Vb 1
+\& $ sudo cd /usr/local/protected
+.Ve
+.PP
+since when the command exits the parent process (your shell) will
+still be the same.  Please see the \s-1EXAMPLES\s0 section for more information.
+.PP
+Running shell scripts via \fBsudo\fR can expose the same kernel bugs that
+make setuid shell scripts unsafe on some operating systems (if your \s-1OS\s0
+has a /dev/fd/ directory, setuid shell scripts are generally safe).
+.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/doc/sudo.man.pl b/doc/sudo.man.pl
new file mode 100644 (file)
index 0000000..e8e6125
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/perl -p
+
+BEGIN {
+    %tags = ( 'a', 'BA', 'c', 'LC', 'r', 'SL', 't', 'SL');
+    $cond = -1;
+}
+
+# Initialize the numeric register we use for conditionals
+if ($cond == -1) {
+    $_ = ".nr SL \@SEMAN\@\n.nr BA \@BAMAN\@\n.nr LC \@LCMAN\@\n.nr PT \@password_timeout\@\n.\\\"\n$_";
+    $cond = 0;
+}
+
+# Add conditionals
+if (/^\.IP.*-([acrt])/) {
+    $_ = ".if \\n($tags{$1} \\{\\\n$_";
+    $cond = 1;
+} elsif ($cond && /^\.(Sh|SS|IP|PP)/) {
+    $_ = "\\}\n$_";
+    $cond = 0;
+}
+
+if (/-a.*auth_type/) {
+    $_ = ".if \\n($tags{'a'} $_";
+} elsif (/(-c.*class.*\||login_cap)/) {
+    $_ = ".if \\n($tags{'c'} $_";
+} elsif (/-r.*role.*-t.*type/) {
+    $_ = ".if \\n($tags{'r'} $_";
+}
+
+# Fix up broken pod2man formatting of F<@foo@/bar>
+s/\\fI\\f(\(C)?I\@([^\@]*)\\fI\@/\\fI\@$2\@/g;
+
+# Try to deal sensibly with password_timeout being set to 0 by default
+s/([^ ]*\@password_timeout\@[^ ]* minutes.$)/\n.ie \\n(PT $1\n.el unlimited./;
diff --git a/doc/sudo.pod b/doc/sudo.pod
new file mode 100644 (file)
index 0000000..cdc5832
--- /dev/null
@@ -0,0 +1,700 @@
+Copyright (c) 1994-1996, 1998-2005, 2007-2011
+       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.
+
+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.
+
+=pod
+
+=head1 NAME
+
+sudo, sudoedit - execute a command as another user
+
+=head1 SYNOPSIS
+
+B<sudo> S<[B<-D> I<level>]> B<-h> | B<-K> | B<-k> | B<-V>
+
+B<sudo> B<-v> [B<-AknS>]
+S<[B<-a> I<auth_type>]>
+S<[B<-D> I<level>]>
+S<[B<-g> I<group name>|I<#gid>]> S<[B<-p> I<prompt>]>
+S<[B<-u> I<user name>|I<#uid>]>
+
+B<sudo> B<-l[l]> [B<-AknS>]
+S<[B<-a> I<auth_type>]>
+S<[B<-D> I<level>]>
+S<[B<-g> I<group name>|I<#gid>]> S<[B<-p> I<prompt>]>
+S<[B<-U> I<user name>]> S<[B<-u> I<user name>|I<#uid>]> [I<command>]
+
+B<sudo> [B<-AbEHnPS>]
+S<[B<-a> I<auth_type>]>
+S<[B<-C> I<fd>]>
+S<[B<-D> I<level>]>
+S<[B<-c> I<class>|I<->]>
+S<[B<-g> I<group name>|I<#gid>]> S<[B<-p> I<prompt>]>
+S<[B<-r> I<role>]> S<[B<-t> I<type>]>
+S<[B<-u> I<user name>|I<#uid>]>
+S<[B<VAR>=I<value>]> S<[B<-i> | B<-s>]> [I<command>]
+
+B<sudoedit> [B<-AnS>]
+S<[B<-a> I<auth_type>]>
+S<[B<-C> I<fd>]>
+S<[B<-c> I<class>|I<->]>
+S<[B<-D> I<level>]>
+S<[B<-g> I<group name>|I<#gid>]> S<[B<-p> I<prompt>]>
+S<[B<-u> I<user name>|I<#uid>]> file ...
+
+=head1 DESCRIPTION
+
+B<sudo> allows a permitted user to execute a I<command> as the
+superuser or another user, as specified by the security policy.
+The real and effective uid and gid are set to match those of the
+target user, as specified in the password database, and the group
+vector is initialized based on the group database (unless the B<-P>
+option was specified).
+
+B<sudo> supports a plugin architecture for security policies and
+input/output logging.  Third parties can develop and distribute
+their own policy and I/O logging modules to work seemlessly with
+the B<sudo> front end.  The default security policy is I<sudoers>,
+which is configured via the file F<@sysconfdir@/sudoers>, or via
+LDAP.  See the L<PLUGINS> section for more information.
+
+The security policy determines what privileges, if any, a user has
+to run B<sudo>.  The policy may require that users authenticate
+themselves with a password or another authentication mechanism.  If
+authentication is required, B<sudo> will exit if the user's password
+is not entered within a configurable time limit.  This limit is
+policy-specific; the default password prompt timeout for the
+I<sudoers> security policy is C<@password_timeout@> minutes.
+
+Security policies may support credential caching to allow the user
+to run B<sudo> again for a period of time without requiring
+authentication.  The I<sudoers> policy caches credentials for
+C<@timeout@> minutes, unless overridden in L<sudoers(5)>.  By
+running B<sudo> with the B<-v> option, a user can update the cached
+credentials without running a I<command>.
+
+When invoked as B<sudoedit>, the B<-e> option (described below),
+is implied.
+
+Security policies may log successful and failed attempts to use
+B<sudo>.  If an I/O plugin is configured, the running command's
+input and output may be logged as well.
+
+=head1 OPTIONS
+
+B<sudo> accepts the following command line options:
+
+=over 12
+
+=item -A
+
+Normally, if B<sudo> requires a password, it will read it from the
+user's terminal.  If the B<-A> (I<askpass>) option is specified,
+a (possibly graphical) 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, if F<@sysconfdir@/sudo.conf>
+contains a line specifying the askpass program, that value will be
+used.  For example:
+
+    # Path to askpass helper program
+    Path askpass /usr/X11R6/bin/ssh-askpass
+
+If no askpass program is available, sudo will exit with an error.
+
+=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
+by F</etc/login.conf>.  The system administrator may specify a list
+of sudo-specific authentication methods by adding an "auth-sudo"
+entry in F</etc/login.conf>.  This option is only available on systems
+that support BSD authentication.
+
+=item -b
+
+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.
+Most interactive commands will fail to work properly in background
+mode.
+
+=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.  The security policy may restrict the
+user's ability to use the B<-C> option.  The I<sudoers> policy only
+permits use of the B<-C> option when the administrator has enabled
+the I<closefrom_override> option.
+
+=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 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>
+argument specifies an existing user class, the command must be run
+as root, or the B<sudo> command must be run from a shell that is already
+root.  This option is only available on systems with BSD login classes.
+
+=item -D I<level>
+
+Enable debugging of B<sudo> plugins and B<sudo> itself.  The I<level>
+may be a value from 1 through 9.
+
+=item -E
+
+The B<-E> (I<preserve> I<environment>) option indicates to the
+security policy that the uses wishes to preserve their existing
+environment variables.  The security policy may return an error if
+the B<-E> option is specified and the user does not have permission
+to preserve the environment.
+
+=item -e
+
+The B<-e> (I<edit>) option indicates that, instead of running a
+command, the user wishes to edit one or more files.  In lieu of a
+command, the string "sudoedit" is used when consulting the security
+policy.  If the user is authorized by the policy, the following
+steps are taken:
+
+=over 4
+
+=item 1.
+
+Temporary copies are made of the files to be edited with the owner
+set to the invoking user.
+
+=item 2.
+
+The editor specified by the policy is run to edit the temporary files.
+The I<sudoers> policy uses the C<SUDO_EDITOR>, C<VISUAL> and C<EDITOR>
+environment variables (in that order).  If none of C<SUDO_EDITOR>,
+C<VISUAL> or C<EDITOR> are set, the first program listed in the
+I<editor> L<sudoers(5)> option is used.
+
+=item 3.
+
+If they have been modified, the temporary files are copied back to
+their original location and the temporary versions are removed.
+
+=back
+
+If the specified file does not exist, it will be created.  Note
+that unlike most commands run by B<sudo>, the editor is run with
+the invoking user's environment unmodified.  If, for some reason,
+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> runs a command with the primary group set to the
+one specified by the password 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 command with the primary group set to I<group>
+instead.  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 requests that the security policy set
+the C<HOME> environment variable to the home directory of the target
+user (root by default) as specified by the password database.
+Depending on the policy, this may be the default behavior.
+
+=item -h
+
+The B<-h> (I<help>) option causes B<sudo> to print a short help message
+to the standard output and exit.
+
+=item -i [command]
+
+The B<-i> (I<simulate initial login>) option runs the shell specified
+by the password database 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 via the shell's B<-c> option.
+If no command is specified, an interactive shell is executed.
+B<sudo> attempts to change to that user's home directory before
+running the shell.  The security policy shall initialize the
+environment to a minimal set of variables, similar to what is present
+when a user logs in.
+
+=item -K
+
+The B<-K> (sure I<kill>) option is like B<-k> except that it removes
+the user's cached credentials entirely and may not be used in
+conjunction with a command or other option.  This option does not
+require a password.  Not all security policies support credential
+caching.
+
+=item -k [command]
+
+When used alone, the B<-k> (I<kill>) option to B<sudo> invalidates
+the user's cached credentials.  The next time B<sudo> is run a
+password will be required.  This option does not require a password
+and was added to allow a user to revoke B<sudo> permissions from a
+.logout file.  Not all security policies support credential
+caching.
+
+When used in conjunction with a command or an option that may require
+a password, the B<-k> option will cause B<sudo> to ignore the user's
+cached credentials.  As a result, B<sudo> will prompt for a password
+(if one is required by the security policy) and will not update the
+user's cached credentials.
+
+=item -l[l] [I<command>]
+
+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 the security policy,
+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
+
+The B<-P> (I<preserve> I<group vector>) option causes B<sudo> to
+preserve the invoking user's group vector unaltered.  By default,
+the I<sudoers> policy 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 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<%>')
+escapes are supported by the I<sudoers> policy:
+
+=over 4
+
+=item C<%H>
+
+expanded to the host name including the domain name (on if
+the machine's host name is fully qualified or the I<fqdn> option
+is set in L<sudoers(5)>)
+
+=item C<%h>
+
+expanded to the local host name without the domain name
+
+=item C<%p>
+
+expanded to the name of the user whose password is being requested
+(respects the I<rootpw>, I<targetpw> and I<runaspw> flags in
+L<sudoers(5)>)
+
+=item C<%U>
+
+expanded to the login name of the user the command will be run as
+(defaults to root unless the C<-u> option is also specified)
+
+=item C<%u>
+
+expanded to the invoking user's login name
+
+=item C<%%>
+
+two consecutive C<%> characters are collapsed into a single C<%> character
+
+=back
+
+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>.
+
+=item -S
+
+The B<-S> (I<stdin>) option causes B<sudo> to read the password from
+the standard input instead of the terminal device.  The password must
+be followed by a newline character.
+
+=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 the
+password database.  If a command is specified, it is passed to the
+shell for execution via the shell's B<-c> option.  If no command
+is specified, an interactive shell is executed.
+
+=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 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.
+The security policy may restrict listing other users' privileges.
+The I<sudoers> policy only allows root or a user with the C<ALL>
+privilege on the current host to 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<user name>, use I<#uid>.  When running commands as a I<uid>,
+many shells require that the '#' be escaped with a backslash ('\').
+Security policies may restrict I<uid>s to those listed in the
+password database.  The I<sudoers> policy allows I<uid>s that are
+not in the password database as long as the I<targetpw> option is
+not set.  Other security policies may not support this.
+
+=item -V
+
+The B<-V> (I<version>) option causes B<sudo> to print its version
+string and the version string of the security policy plugin and any
+I/O plugins.  If the invoking user is already root the B<-V> option
+will display the arguments passed to configure when I<sudo> was
+built and plugins may display more verbose information such as
+default options.
+
+=item -v
+
+When given the B<-v> (I<validate>) option, B<sudo> will update the
+user's cached credentials, authenticating the user's password if
+necessary.  For the I<sudoers> plugin, this extends the B<sudo>
+timeout for another C<@timeout@> minutes (or whatever the timeout
+is set to in I<sudoers>) but does not run a command.  Not all
+security policies support cached credentials.
+
+=item --
+
+The B<--> option indicates that B<sudo> should stop processing command
+line arguments.
+
+=back
+
+Environment variables to be set for the command may also be passed
+on the command line in the form of B<VAR>=I<value>, e.g.
+B<LD_LIBRARY_PATH>=I</usr/local/pkg/lib>.  Variables passed on the
+command line are subject to the same restrictions as normal environment
+variables with one important exception.  If the I<setenv> option
+is set in I<sudoers>, the command to be run has the C<SETENV> tag
+set or the command matched is C<ALL>, the user may set variables
+that would overwise be forbidden.  See L<sudoers(5)> for more information.
+
+=head1 PLUGINS
+
+Plugins are dynamically loaded based on the contents of the
+F<@sysconfdir@/sudo.conf> file.  If no F<@sysconfdir@/sudo.conf>
+file is present, or it contains no C<Plugin> lines, B<sudo>
+will use the traditional I<sudoers> security policy and I/O logging,
+which corresponds to the following F<@sysconfdir@/sudo.conf> file.
+
+ #
+ # Default @sysconfdir@/sudo.conf file
+ #
+ # Format:
+ #   Plugin plugin_name plugin_path
+ #   Path askpass /path/to/askpass
+ #   Path noexec /path/to/noexec.so
+ #
+ # The plugin_path is relative to @prefix@/libexec unless
+ #   fully qualified.
+ # The plugin_name corresponds to a global symbol in the plugin
+ #   that contains the plugin interface structure.
+ #
+ Plugin policy_plugin sudoers.so
+ Plugin io_plugin sudoers.so 
+
+A C<Plugin> line consists of the C<Plugin> keyword, followed by the
+I<symbol_name> and the I<path> to the shared object containing the
+plugin.  The I<symbol_name> is the name of the C<struct policy_plugin>
+or C<struct io_plugin> in the plugin shared object.  The I<path>
+may be fully qualified or relative.  If not fully qualified it is
+relative to the F<@prefix@/libexec> directory.  Any additional
+parameters after the I<path> are ignored.  Lines that don't begin
+with C<Plugin> or C<Path> are silently ignored
+
+For more information, see the L<sudo_plugin(8)> manual.
+
+=head1 PATHS
+
+A C<Path> line consists of the C<Path> keyword, followed by the
+name of the path to set and its value.  E.g.
+
+ Path noexec @noexec_file@
+ Path askpass /usr/X11R6/bin/ssh-askpass
+
+The following plugin-agnostic paths may be set in the
+F<@sysconfdir@/sudo.conf> file.
+
+=over 16
+
+=item askpass
+
+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 noexec
+
+The fully-qualified path to a shared library containing dummy
+versions of the execv(), execve() and fexecve() library functions
+that just return an error.  This is used to implement the I<noexec>
+functionality on systems that support C<LD_PRELOAD> or its equivalent.
+Defaults to F<@noexec_file@>.
+
+=back
+
+=head1 RETURN VALUES
+
+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> exits with a value of 1 if there is a
+configuration/permission problem or if B<sudo> cannot execute the
+given command.  In the latter case the error string is printed to
+the standard error.  If B<sudo> cannot L<stat(2)> one or more entries
+in the user's C<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 L<stat(2)>
+to return "permission denied" is if you are running an automounter
+and one of the directories in your C<PATH> is on a machine that is
+currently unreachable.
+
+=head1 SECURITY NOTES
+
+B<sudo> tries to be safe when executing external commands.
+
+To prevent command spoofing, B<sudo> checks "." and "" (both denoting
+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 C<PATH> environment variable is I<not> modified and is passed
+unchanged to the program that B<sudo> executes.
+
+Please note that B<sudo> will normally only log the command it
+explicitly runs.  If a user runs a command such as C<sudo su> or
+C<sudo sh>, subsequent commands run from that shell are not subject
+to B<sudo>'s security policy.  The same is true for commands that
+offer shell escapes (including most editors).  If I/O logging is
+enabled, subsequent commands will have their input and/or output
+logged, but there will not be traditional logs for those commands.
+Because of this, care must be taken when giving users access to
+commands via B<sudo> to verify that the command does not inadvertently
+give the user an effective root shell.  For more information, please
+see the C<PREVENTING SHELL ESCAPES> section in L<sudoers(5)>.
+
+=head1 ENVIRONMENT
+
+B<sudo> utilizes the following environment variables.  The security
+policy has control over the content of the command's environment.
+
+=over 16
+
+=item C<EDITOR>
+
+Default editor to use in B<-e> (sudoedit) mode if neither C<SUDO_EDITOR>
+nor C<VISUAL> is set
+
+=item C<MAIL>
+
+In B<-i> mode or when I<env_reset> is enabled in I<sudoers>, set
+to the mail spool of the target user
+
+=item C<HOME>
+
+Set to the home directory of the target user if B<-i> or B<-H> are
+specified, I<env_reset> or I<always_set_home> are set in I<sudoers>,
+or when the B<-s> option is specified and I<set_home> is set in
+I<sudoers>
+
+=item C<PATH>
+
+May be overridden by the security policy.
+
+=item C<SHELL>
+
+Used to determine shell to run with C<-s> option
+
+=item C<SUDO_ASKPASS>
+
+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_EDITOR>
+
+Default editor to use in B<-e> (sudoedit) mode
+
+=item C<SUDO_GID>
+
+Set to the group ID of the user who invoked sudo
+
+=item C<SUDO_PROMPT>
+
+Used as the default password prompt
+
+=item C<SUDO_PS1>
+
+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>
+
+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 if C<SUDO_EDITOR>
+is not set
+
+=back
+
+=head1 FILES
+
+=over 24
+
+=item F<@sysconfdir@/sudo.conf>
+
+B<sudo> plugin and path configuration
+
+=back
+
+=head1 EXAMPLES
+
+Note: the following examples assume a properly configured security policy.
+
+To get a file listing of an unreadable directory:
+
+ $ sudo ls /usr/local/protected
+
+To list the home directory of user yaz on a machine where the
+file system holding ~yaz is not exported as root:
+
+ $ sudo -u yaz ls ~yaz
+
+To edit the F<index.html> file as user www:
+
+ $ sudo -u www vi ~www/htdocs/index.html
+
+To view system logs only accessible to root and users in the adm group:
+
+ $ sudo -g adm view /var/log/syslog
+
+To run an editor as jim with a different primary group:
+
+ $ sudo -u jim -g audio vi ~jim/sound.txt
+
+To shutdown a machine:
+
+ $ 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 C<cd> and file redirection work.
+
+ $ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE"
+
+=head1 SEE ALSO
+
+L<grep(1)>, L<su(1)>, L<stat(2)>,
+L<login_cap(3)>,
+L<passwd(5)>, L<sudoers(5)>, L<sudo_plugin(8)>, L<sudoreplay(8)>, L<visudo(8)>
+
+=head1 AUTHORS
+
+Many people have worked on B<sudo> over the years; this
+version consists of code written primarily by:
+
+       Todd C. Miller
+
+See the HISTORY file in the B<sudo> distribution or visit
+http://www.sudo.ws/sudo/history.html for a short history
+of B<sudo>.
+
+=head1 CAVEATS
+
+There is no easy way to prevent a user from gaining a root shell
+if that user is allowed to run arbitrary commands via B<sudo>.
+Also, many programs (such as editors) allow the user to run commands
+via shell escapes, thus avoiding B<sudo>'s checks.  However, on
+most systems it is possible to prevent shell escapes with the
+L<sudoers(5)> module's I<noexec> functionality.
+
+It is not meaningful to run the C<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.
+
+Running shell scripts via B<sudo> 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).
+
+=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.
diff --git a/doc/sudo_plugin.cat b/doc/sudo_plugin.cat
new file mode 100644 (file)
index 0000000..a486f02
--- /dev/null
@@ -0,0 +1,1033 @@
+SUDO_PLUGIN(1m)              MAINTENANCE COMMANDS              SUDO_PLUGIN(1m)
+
+
+
+N\bNA\bAM\bME\bE
+       sudo_plugin - Sudo Plugin API
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+       Starting with version 1.8, s\bsu\bud\bdo\bo supports a plugin API for policy and
+       session logging.  By default, the _\bs_\bu_\bd_\bo_\be_\br_\bs policy plugin and an
+       associated I/O logging plugin are used.  Via the plugin API, s\bsu\bud\bdo\bo can
+       be configured to use alternate policy and/or I/O logging plugins
+       provided by third parties.  The plugins to be used are specified via
+       the _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b._\bc_\bo_\bn_\bf file.
+
+       The API is versioned with a major and minor number.  The minor version
+       number is incremented when additions are made.  The major number is
+       incremented when incompatible changes are made.  A plugin should be
+       check the version passed to it and make sure that the major version
+       matches.
+
+       The plugin API is defined by the sudo_plugin.h header file.
+
+   T\bTh\bhe\be s\bsu\bud\bdo\bo.\b.c\bco\bon\bnf\bf F\bFi\bil\ble\be
+       The _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b._\bc_\bo_\bn_\bf file contains plugin configuration directives.
+       Currently, the only supported keyword is the Plugin directive, which
+       causes a plugin plugin to be loaded.
+
+       A Plugin line consists of the Plugin keyword, followed by the
+       _\bs_\by_\bm_\bb_\bo_\bl_\b__\bn_\ba_\bm_\be and the _\bp_\ba_\bt_\bh to the shared object containing the plugin.
+       The _\bs_\by_\bm_\bb_\bo_\bl_\b__\bn_\ba_\bm_\be is the name of the struct policy_plugin or struct
+       io_plugin in the plugin shared object.  The _\bp_\ba_\bt_\bh may be fully qualified
+       or relative.  If not fully qualified it is relative to the
+       _\b/_\bu_\bs_\br_\b/_\bl_\bo_\bc_\ba_\bl_\b/_\bl_\bi_\bb_\be_\bx_\be_\bc directory.  Any additional parameters after the _\bp_\ba_\bt_\bh
+       are ignored.  Lines that don't begin with Plugin or Path are silently
+       ignored.
+
+       The same shared object may contain multiple plugins, each with a
+       different symbol name.  The shared object file must be owned by uid 0
+       and only writable by its owner.  Because of ambiguities that arise from
+       composite policies, only a single policy plugin may be specified.  This
+       limitation does not apply to I/O plugins.
+
+        #
+        # Default /etc/sudo.conf file
+        #
+        # Format:
+        #   Plugin plugin_name plugin_path
+        #   Path askpass /path/to/askpass
+        #
+        # The plugin_path is relative to /usr/local/libexec unless
+        #   fully qualified.
+        # The plugin_name corresponds to a global symbol in the plugin
+        #   that contains the plugin interface structure.
+        #
+        Plugin sudoers_policy sudoers.so
+        Plugin sudoers_io sudoers.so
+
+   P\bPo\bol\bli\bic\bcy\by P\bPl\blu\bug\bgi\bin\bn A\bAP\bPI\bI
+       A policy plugin must declare and populate a policy_plugin struct in the
+       global scope.  This structure contains pointers to the functions that
+       implement the s\bsu\bud\bdo\bo policy checks.  The name of the symbol should be
+       specified in _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b._\bc_\bo_\bn_\bf along with a path to the plugin so that
+       s\bsu\bud\bdo\bo can load it.
+
+        struct policy_plugin {
+        #define SUDO_POLICY_PLUGIN     1
+            unsigned int type; /* always SUDO_POLICY_PLUGIN */
+            unsigned int version; /* always SUDO_API_VERSION */
+            int (*open)(unsigned int version, sudo_conv_t conversation,
+                        sudo_printf_t plugin_printf, char * const settings[],
+                        char * const user_info[], char * const user_env[]);
+            void (*close)(int exit_status, int error);
+            int (*show_version)(int verbose);
+            int (*check_policy)(int argc, char * const argv[],
+                                char *env_add[], char **command_info[],
+                                char **argv_out[], char **user_env_out[]);
+            int (*list)(int argc, char * const argv[], int verbose,
+                        const char *list_user);
+            int (*validate)(void);
+            void (*invalidate)(int remove);
+            int (*init_session)(struct passwd *pwd);
+        };
+
+       The policy_plugin struct has the following fields:
+
+       type
+           The type field should always be set to SUDO_POLICY_PLUGIN.
+
+       version
+           The version field should be set to SUDO_API_VERSION.
+
+           This allows s\bsu\bud\bdo\bo to determine the API version the plugin was built
+           against.
+
+       open
+            int (*open)(unsigned int version, sudo_conv_t conversation,
+                        sudo_printf_t plugin_printf, char * const settings[],
+                        char * const user_info[], char * const user_env[]);
+
+           Returns 1 on success, 0 on failure, -1 if a general error occurred,
+           or -2 if there was a usage error.  In the latter case, s\bsu\bud\bdo\bo will
+           print a usage message before it exits.  If an error occurs, the
+           plugin may optionally call the conversation or plugin_printf
+           function with SUDO_CONF_ERROR_MSG to present additional error
+           information to the user.
+
+           The function arguments are as follows:
+
+           version
+               The version passed in by s\bsu\bud\bdo\bo allows the plugin to determine
+               the major and minor version number of the plugin API supported
+               by s\bsu\bud\bdo\bo.
+
+           conversation
+               A pointer to the conversation function that can be used by the
+               plugin to interact with the user (see below).  Returns 0 on
+               success and -1 on failure.
+
+           plugin_printf
+               A pointer to a printf-style function that may be used to
+               display informational or error messages (see below).  Returns
+               the number of characters printed on success and -1 on failure.
+
+           settings
+               A vector of user-supplied s\bsu\bud\bdo\bo settings in the form of
+               "name=value" strings.  The vector is terminated by a NULL
+               pointer.  These settings correspond to flags the user specified
+               when running s\bsu\bud\bdo\bo.  As such, they will only be present when the
+               corresponding flag has been specified on the command line.
+
+               When parsing _\bs_\be_\bt_\bt_\bi_\bn_\bg_\bs, the plugin should split on the f\bfi\bir\brs\bst\bt
+               equal sign ('=') since the _\bn_\ba_\bm_\be field will never include one
+               itself but the _\bv_\ba_\bl_\bu_\be might.
+
+               debug_level=number
+                   A numeric debug level, from 1-9, if specified via the -D
+                   flag.
+
+               runas_user=string
+                   The user name or uid to to run the command as, if specified
+                   via the -u flag.
+
+               runas_group=string
+                   The group name or gid to to run the command as, if
+                   specified via the -g flag.
+
+               prompt=string
+                   The prompt to use when requesting a password, if specified
+                   via the -p flag.
+
+               set_home=bool
+                   Set to true if the user specified the -H flag.  If true,
+                   set the HOME environment variable to the target user's home
+                   directory.
+
+               preserve_environment=bool
+                   Set to true if the user specified the -E flag, indicating
+                   that the user wishes to preserve the environment.
+
+               run_shell=bool
+                   Set to true if the user specified the -s flag, indicating
+                   that the user wishes to run a shell.
+
+               login_shell=bool
+                   Set to true if the user specified the -i flag, indicating
+                   that the user wishes to run a login shell.
+
+               implied_shell=bool
+                   If the user does not specify a program on the command line,
+                   s\bsu\bud\bdo\bo will pass the plugin the path to the user's shell and
+                   set _\bi_\bm_\bp_\bl_\bi_\be_\bd_\b__\bs_\bh_\be_\bl_\bl to true.  This allows s\bsu\bud\bdo\bo with no
+                   arguments to be used similarly to _\bs_\bu(1).  If the plugin
+                   does not to support this usage, it may return a value of -2
+                   from the check_policy function, which will cause s\bsu\bud\bdo\bo to
+                   print a usage message and exit.
+
+               preserve_groups=bool
+                   Set to true if the user specified the -P flag, indicating
+                   that the user wishes to preserve the group vector instead
+                   of setting it based on the runas user.
+
+               ignore_ticket=bool
+                   Set to true if the user specified the -k flag along with a
+                   command, indicating that the user wishes to ignore any
+                   cached authentication credentials.
+
+               noninteractive=bool
+                   Set to true if the user specified the -n flag, indicating
+                   that s\bsu\bud\bdo\bo should operate in non-interactive mode.  The
+                   plugin may reject a command run in non-interactive mode if
+                   user interaction is required.
+
+               login_class=string
+                   BSD login class to use when setting resource limits and
+                   nice value, if specified by the -c flag.
+
+               selinux_role=string
+                   SELinux role to use when executing the command, if
+                   specified by the -r flag.
+
+               selinux_type=string
+                   SELinux type to use when executing the command, if
+                   specified by the -t flag.
+
+               bsdauth_type=string
+                   Authentication type, if specified by the -a flag, to use on
+                   systems where BSD authentication is supported.
+
+               network_addrs=list
+                   A space-separated list of IP network addresses and netmasks
+                   in the form "addr/netmask", e.g.
+                   "192.168.1.2/255.255.255.0".  The address and netmask pairs
+                   may be either IPv4 or IPv6, depending on what the operating
+                   system supports.  If the address contains a colon (':'), it
+                   is an IPv6 address, else it is IPv4.
+
+               progname=string
+                   The command name that sudo was run as, typically "sudo" or
+                   "sudoedit".
+
+               sudoedit=bool
+                   Set to true when the -e flag is is specified or if invoked
+                   as s\bsu\bud\bdo\boe\bed\bdi\bit\bt.  The plugin shall substitute an editor into
+                   _\ba_\br_\bg_\bv in the _\bc_\bh_\be_\bc_\bk_\b__\bp_\bo_\bl_\bi_\bc_\by function or return -2 with a usage
+                   error if the plugin does not support _\bs_\bu_\bd_\bo_\be_\bd_\bi_\bt.  For more
+                   information, see the _\bc_\bh_\be_\bc_\bk_\b__\bp_\bo_\bl_\bi_\bc_\by section.
+
+               closefrom=number
+                   If specified, the user has requested via the -C flag that
+                   s\bsu\bud\bdo\bo close all files descriptors with a value of _\bn_\bu_\bm_\bb_\be_\br or
+                   higher.  The plugin may optionally pass this, or another
+                   value, back in the _\bc_\bo_\bm_\bm_\ba_\bn_\bd_\b__\bi_\bn_\bf_\bo list.
+
+               Additional settings may be added in the future so the plugin
+               should silently ignore settings that it does not recognize.
+
+           user_info
+               A vector of information about the user running the command in
+               the form of "name=value" strings.  The vector is terminated by
+               a NULL pointer.
+
+               When parsing _\bu_\bs_\be_\br_\b__\bi_\bn_\bf_\bo, the plugin should split on the f\bfi\bir\brs\bst\bt
+               equal sign ('=') since the _\bn_\ba_\bm_\be field will never include one
+               itself but the _\bv_\ba_\bl_\bu_\be might.
+
+               user=string
+                   The name of the user invoking s\bsu\bud\bdo\bo.
+
+               uid=uid_t
+                   The real user ID of the user invoking s\bsu\bud\bdo\bo.
+
+               gid=gid_t
+                   The real group ID of the user invoking s\bsu\bud\bdo\bo.
+
+               groups=list
+                   The user's supplementary group list formatted as a string
+                   of comma-separated group IDs.
+
+               cwd=string
+                   The user's current working directory.
+
+               tty=string
+                   The path to the user's terminal device.  If the user has no
+                   terminal device associated with the session, the value will
+                   be empty, as in tty=.
+
+               host=string
+                   The local machine's hostname as returned by the
+                   gethostname() system call.
+
+               lines=int
+                   The number of lines the user's terminal supports.  If there
+                   is no terminal device available, a default value of 24 is
+                   used.
+
+               cols=int
+                   The number of columns the user's terminal supports.  If
+                   there is no terminal device available, a default value of
+                   80 is used.
+
+           user_env
+               The user's environment in the form of a NULL-terminated vector
+               of "name=value" strings.
+
+               When parsing _\bu_\bs_\be_\br_\b__\be_\bn_\bv, the plugin should split on the f\bfi\bir\brs\bst\bt
+               equal sign ('=') since the _\bn_\ba_\bm_\be field will never include one
+               itself but the _\bv_\ba_\bl_\bu_\be might.
+
+       close
+            void (*close)(int exit_status, int error);
+
+           The close function is called when the command being run by s\bsu\bud\bdo\bo
+           finishes.
+
+           The function arguments are as follows:
+
+           exit_status
+               The command's exit status, as returned by the _\bw_\ba_\bi_\bt(2) system
+               call.  The value of exit_status is undefined if error is non-
+               zero.
+
+           error
+               If the command could not be executed, this is set to the value
+               of errno set by the _\be_\bx_\be_\bc_\bv_\be(2) system call.  The plugin is
+               responsible for displaying error information via the
+               conversation or plugin_printf function.  If the command was
+               successfully executed, the value of error is 0.
+
+       show_version
+            int (*show_version)(int verbose);
+
+           The show_version function is called by s\bsu\bud\bdo\bo when the user specifies
+           the -V option.  The plugin may display its version information to
+           the user via the conversation or plugin_printf function using
+           SUDO_CONV_INFO_MSG.  If the user requests detailed version
+           information, the verbose flag will be set.
+
+       check_policy
+            int (*check_policy)(int argc, char * const argv[]
+                                char *env_add[], char **command_info[],
+                                char **argv_out[], char **user_env_out[]);
+
+           The _\bc_\bh_\be_\bc_\bk_\b__\bp_\bo_\bl_\bi_\bc_\by function is called by s\bsu\bud\bdo\bo to determine whether
+           the user is allowed to run the specified commands.
+
+           If the _\bs_\bu_\bd_\bo_\be_\bd_\bi_\bt option was enabled in the _\bs_\be_\bt_\bt_\bi_\bn_\bg_\bs array passed to
+           the _\bo_\bp_\be_\bn function, the user has requested _\bs_\bu_\bd_\bo_\be_\bd_\bi_\bt mode.  _\bs_\bu_\bd_\bo_\be_\bd_\bi_\bt
+           is a mechanism for editing one or more files where an editor is run
+           with the user's credentials instead of with elevated privileges.
+           s\bsu\bud\bdo\bo achieves this by creating user-writable temporary copies of
+           the files to be edited and then overwriting the originals with the
+           temporary copies after editing is complete.  If the plugin supports
+           s\bsu\bud\bdo\boe\bed\bdi\bit\bt, it should choose the editor to be used, potentially from
+           a variable in the user's environment, such as EDITOR, and include
+           it in _\ba_\br_\bg_\bv_\b__\bo_\bu_\bt (note that environment variables may include command
+           line flags).  The files to be edited should be copied from _\ba_\br_\bg_\bv
+           into _\ba_\br_\bg_\bv_\b__\bo_\bu_\bt, separated from the editor and its arguments by a
+           "--" element.  The "--" will be removed by s\bsu\bud\bdo\bo before the editor
+           is executed.  The plugin should also set _\bs_\bu_\bd_\bo_\be_\bd_\bi_\bt_\b=_\bt_\br_\bu_\be in the
+           _\bc_\bo_\bm_\bm_\ba_\bn_\bd_\b__\bi_\bn_\bf_\bo list.
+
+           The _\bc_\bh_\be_\bc_\bk_\b__\bp_\bo_\bl_\bi_\bc_\by function returns 1 if the command is allowed, 0 if
+           not allowed, -1 for a general error, or -2 for a usage error or if
+           s\bsu\bud\bdo\boe\bed\bdi\bit\bt was specified but is unsupported by the plugin.  In the
+           latter case, s\bsu\bud\bdo\bo will print a usage message before it exits.  If
+           an error occurs, the plugin may optionally call the conversation or
+           plugin_printf function with SUDO_CONF_ERROR_MSG to present
+           additional error information to the user.
+
+           The function arguments are as follows:
+
+           argc
+               The number of elements in _\ba_\br_\bg_\bv, not counting the final NULL
+               pointer.
+
+           argv
+               The argument vector describing the command the user wishes to
+               run, in the same form as what would be passed to the _\be_\bx_\be_\bc_\bv_\be_\b(_\b)
+               system call.  The vector is terminated by a NULL pointer.
+
+           env_add
+               Additional environment variables specified by the user on the
+               command line in the form of a NULL-terminated vector of
+               "name=value" strings.  The plugin may reject the command if one
+               or more variables are not allowed to be set, or it may silently
+               ignore such variables.
+
+               When parsing _\be_\bn_\bv_\b__\ba_\bd_\bd, the plugin should split on the f\bfi\bir\brs\bst\bt
+               equal sign ('=') since the _\bn_\ba_\bm_\be field will never include one
+               itself but the _\bv_\ba_\bl_\bu_\be might.
+
+           command_info
+               Information about the command being run in the form of
+               "name=value" strings.  These values are used by s\bsu\bud\bdo\bo to set the
+               execution environment when running a command.  The plugin is
+               responsible for creating and populating the vector, which must
+               be terminated with a NULL pointer.  The following values are
+               recognized by s\bsu\bud\bdo\bo:
+
+               command=string
+                   Fully qualified path to the command to be executed.
+
+               runas_uid=uid
+                   User ID to run the command as.
+
+               runas_euid=uid
+                   Effective user ID to run the command as.  If not specified,
+                   the value of _\br_\bu_\bn_\ba_\bs_\b__\bu_\bi_\bd is used.
+
+               runas_gid=gid
+                   Group ID to run the command as.
+
+               runas_egid=gid
+                   Effective group ID to run the command as.  If not
+                   specified, the value of _\br_\bu_\bn_\ba_\bs_\b__\bg_\bi_\bd is used.
+
+               runas_groups=list
+                   The supplementary group vector to use for the command in
+                   the form of a comma-separated list of group IDs.  If
+                   _\bp_\br_\be_\bs_\be_\br_\bv_\be_\b__\bg_\br_\bo_\bu_\bp_\bs is set, this option is ignored.
+
+               login_class=string
+                   BSD login class to use when setting resource limits and
+                   nice value (optional).  This option is only set on systems
+                   that support login classes.
+
+               preserve_groups=bool
+                   If set, s\bsu\bud\bdo\bo will preserve the user's group vector instead
+                   of initializing the group vector based on runas_user.
+
+               cwd=string
+                   The current working directory to change to when executing
+                   the command.
+
+               noexec=bool
+                   If set, prevent the command from executing other programs.
+
+               chroot=string
+                   The root directory to use when running the command.
+
+               nice=int
+                   Nice value (priority) to use when executing the command.
+                   The nice value, if specified, overrides the priority
+                   associated with the _\bl_\bo_\bg_\bi_\bn_\b__\bc_\bl_\ba_\bs_\bs on BSD systems.
+
+               umask=octal
+                   The file creation mask to use when executing the command.
+
+               selinux_role=string
+                   SELinux role to use when executing the command.
+
+               selinux_type=string
+                   SELinux type to use when executing the command.
+
+               timeout=int
+                   Command timeout.  If non-zero then when the timeout expires
+                   the command will be killed.
+
+               sudoedit=bool
+                   Set to true when in _\bs_\bu_\bd_\bo_\be_\bd_\bi_\bt mode.  The plugin may enable
+                   _\bs_\bu_\bd_\bo_\be_\bd_\bi_\bt mode even if s\bsu\bud\bdo\bo was not invoked as s\bsu\bud\bdo\boe\bed\bdi\bit\bt.
+                   This allows the plugin to perform command substitution and
+                   transparently enable _\bs_\bu_\bd_\bo_\be_\bd_\bi_\bt when the user attempts to run
+                   an editor.
+
+               closefrom=number
+                   If specified, s\bsu\bud\bdo\bo will close all files descriptors with a
+                   value of _\bn_\bu_\bm_\bb_\be_\br or higher.
+
+               iolog_compress=bool
+                   Set to true if the I/O logging plugins, if any, should
+                   compress the log data.  This is a hint to the I/O logging
+                   plugin which may choose to ignore it.
+
+               iolog_path=string
+                   Fully qualified path to the file or directory in which I/O
+                   log is to be stored.  This is a hint to the I/O logging
+                   plugin which may choose to ignore it.  If no I/O logging
+                   plugin is loaded, this setting has no effect.
+
+               iolog_stdin=bool
+                   Set to true if the I/O logging plugins, if any, should log
+                   the standard input if it is not connected to a terminal
+                   device.  This is a hint to the I/O logging plugin which may
+                   choose to ignore it.
+
+               iolog_stdout=bool
+                   Set to true if the I/O logging plugins, if any, should log
+                   the standard output if it is not connected to a terminal
+                   device.  This is a hint to the I/O logging plugin which may
+                   choose to ignore it.
+
+               iolog_stderr=bool
+                   Set to true if the I/O logging plugins, if any, should log
+                   the standard error if it is not connected to a terminal
+                   device.  This is a hint to the I/O logging plugin which may
+                   choose to ignore it.
+
+               iolog_ttyin=bool
+                   Set to true if the I/O logging plugins, if any, should log
+                   all terminal input.  This only includes input typed by the
+                   user and not from a pipe or redirected from a file.  This
+                   is a hint to the I/O logging plugin which may choose to
+                   ignore it.
+
+               iolog_ttyout=bool
+                   Set to true if the I/O logging plugins, if any, should log
+                   all terminal output.  This only includes output to the
+                   screen, not output to a pipe or file.  This is a hint to
+                   the I/O logging plugin which may choose to ignore it.
+
+               use_pty=bool
+                   Allocate a pseudo-tty to run the command in, regardless of
+                   whether or not I/O logging is in use.  By default, s\bsu\bud\bdo\bo
+                   will only run the command in a pty when an I/O log plugin
+                   is loaded.
+
+               set_utmp=bool
+                   Create a utmp (or utmpx) entry when a pseudo-tty is
+                   allocated.  By default, the new entry will be a copy of the
+                   user's existing utmp entry (if any), with the tty, time,
+                   type and pid fields updated.
+
+               utmp_user=string
+                   User name to use when constructing a new utmp (or utmpx)
+                   entry when _\bs_\be_\bt_\b__\bu_\bt_\bm_\bp is enabled.  This option can be used to
+                   set the user field in the utmp entry to the user the
+                   command runs as rather than the invoking user.  If not set,
+                   s\bsu\bud\bdo\bo will base the new entry on the invoking user's
+                   existing entry.
+
+               Unsupported values will be ignored.
+
+           argv_out
+               The NULL-terminated argument vector to pass to the _\be_\bx_\be_\bc_\bv_\be_\b(_\b)
+               system call when executing the command.  The plugin is
+               responsible for allocating and populating the vector.
+
+           user_env_out
+               The NULL-terminated environment vector to use when executing
+               the command.  The plugin is responsible for allocating and
+               populating the vector.
+
+       list
+            int (*list)(int verbose, const char *list_user,
+                        int argc, char * const argv[]);
+
+           List available privileges for the invoking user.  Returns 1 on
+           success, 0 on failure and -1 on error.  On error, the plugin may
+           optionally call the conversation or plugin_printf function with
+           SUDO_CONF_ERROR_MSG to present additional error information to the
+           user.
+
+           Privileges should be output via the conversation or plugin_printf
+           function using SUDO_CONV_INFO_MSG.
+
+           verbose
+               Flag indicating whether to list in verbose mode or not.
+
+           list_user
+               The name of a different user to list privileges for if the
+               policy allows it.  If NULL, the plugin should list the
+               privileges of the invoking user.
+
+           argc
+               The number of elements in _\ba_\br_\bg_\bv, not counting the final NULL
+               pointer.
+
+           argv
+               If non-NULL, an argument vector describing a command the user
+               wishes to check against the policy in the same form as what
+               would be passed to the _\be_\bx_\be_\bc_\bv_\be_\b(_\b) system call.  If the command is
+               permitted by the policy, the fully-qualified path to the
+               command should be displayed along with any command line
+               arguments.
+
+       validate
+            int (*validate)(void);
+
+           The validate function is called when s\bsu\bud\bdo\bo is run with the -v flag.
+           For policy plugins such as _\bs_\bu_\bd_\bo_\be_\br_\bs that cache authentication
+           credentials, this function will validate and cache the credentials.
+
+           The validate function should be NULL if the plugin does not support
+           credential caching.
+
+           Returns 1 on success, 0 on failure and -1 on error.  On error, the
+           plugin may optionally call the conversation or plugin_printf
+           function with SUDO_CONF_ERROR_MSG to present additional error
+           information to the user.
+
+       invalidate
+            void (*invalidate)(int remove);
+
+           The invalidate function is called when s\bsu\bud\bdo\bo is called with the -k
+           or -K flag.  For policy plugins such as _\bs_\bu_\bd_\bo_\be_\br_\bs that cache
+           authentication credentials, this function will invalidate the
+           credentials.  If the _\br_\be_\bm_\bo_\bv_\be flag is set, the plugin may remove the
+           credentials instead of simply invalidating them.
+
+           The invalidate function should be NULL if the plugin does not
+           support credential caching.
+
+       init_session
+            int (*init_session)(struct passwd *pwd);
+
+           The init_session function is called when s\bsu\bud\bdo\bo sets up the execution
+           environment for the command, immediately before the contents of the
+           _\bc_\bo_\bm_\bm_\ba_\bn_\bd_\b__\bi_\bn_\bf_\bo list are applied (before the uid changes).  This can
+           be used to do session setup that is not supported by _\bc_\bo_\bm_\bm_\ba_\bn_\bd_\b__\bi_\bn_\bf_\bo,
+           such as opening the PAM session.
+
+           The _\bp_\bw_\bd argument points to a passwd struct for the user the command
+           will be run as if the uid the command will run as was found in the
+           password database, otherwise it will be NULL.
+
+           Returns 1 on success, 0 on failure and -1 on error.  On error, the
+           plugin may optionally call the conversation or plugin_printf
+           function with SUDO_CONF_ERROR_MSG to present additional error
+           information to the user.
+
+       _\bV_\be_\br_\bs_\bi_\bo_\bn _\bm_\ba_\bc_\br_\bo_\bs
+
+        #define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16)
+        #define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
+        #define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \
+            *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \
+        } while(0)
+        #define SUDO_VERSION_SET_MINOR(vp, n) do { \
+            *(vp) = (*(vp) & 0xffff0000) | (n); \
+        } while(0)
+
+        #define SUDO_API_VERSION_MAJOR 1
+        #define SUDO_API_VERSION_MINOR 0
+        #define SUDO_API_VERSION ((SUDO_API_VERSION_MAJOR << 16) | \
+                                  SUDO_API_VERSION_MINOR)
+
+   I\bI/\b/O\bO P\bPl\blu\bug\bgi\bin\bn A\bAP\bPI\bI
+        struct io_plugin {
+        #define SUDO_IO_PLUGIN         2
+            unsigned int type; /* always SUDO_IO_PLUGIN */
+            unsigned int version; /* always SUDO_API_VERSION */
+            int (*open)(unsigned int version, sudo_conv_t conversation
+                        sudo_printf_t plugin_printf, char * const settings[],
+                        char * const user_info[], int argc, char * const argv[],
+                        char * const user_env[]);
+            void (*close)(int exit_status, int error); /* wait status or error */
+            int (*show_version)(int verbose);
+            int (*log_ttyin)(const char *buf, unsigned int len);
+            int (*log_ttyout)(const char *buf, unsigned int len);
+            int (*log_stdin)(const char *buf, unsigned int len);
+            int (*log_stdout)(const char *buf, unsigned int len);
+            int (*log_stderr)(const char *buf, unsigned int len);
+        };
+
+       When an I/O plugin is loaded, s\bsu\bud\bdo\bo runs the command in a pseudo-tty.
+       This makes it possible to log the input and output from the user's
+       session.  If any of the standard input, standard output or standard
+       error do not correspond to a tty, s\bsu\bud\bdo\bo will open a pipe to capture the
+       I/O for logging before passing it on.
+
+       The log_ttyin function receives the raw user input from the terminal
+       device (note that this will include input even when echo is disabled,
+       such as when a password is read). The log_ttyout function receives
+       output from the pseudo-tty that is suitable for replaying the user's
+       session at a later time.  The log_stdin, log_stdout and log_stderr
+       functions are only called if the standard input, standard output or
+       standard error respectively correspond to something other than a tty.
+
+       Any of the logging functions may be set to the NULL pointer if no
+       logging is to be performed.  If the open function returns 0, no I/O
+       will be sent to the plugin.
+
+       The io_plugin struct has the following fields:
+
+       type
+           The type field should always be set to SUDO_IO_PLUGIN
+
+       version
+           The version field should be set to SUDO_API_VERSION.
+
+           This allows s\bsu\bud\bdo\bo to determine the API version the plugin was built
+           against.
+
+       open
+            int (*open)(unsigned int version, sudo_conv_t conversation
+                        sudo_printf_t plugin_printf, char * const settings[],
+                        char * const user_info[], int argc, char * const argv[],
+                        char * const user_env[]);
+
+           The _\bo_\bp_\be_\bn function is run before the _\bl_\bo_\bg_\b__\bi_\bn_\bp_\bu_\bt, _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt or
+           _\bs_\bh_\bo_\bw_\b__\bv_\be_\br_\bs_\bi_\bo_\bn functions are called.  It is only called if the
+           version is being requested or the _\bc_\bh_\be_\bc_\bk_\b__\bp_\bo_\bl_\bi_\bc_\by function has
+           returned successfully.  It returns 1 on success, 0 on failure, -1
+           if a general error occurred, or -2 if there was a usage error.  In
+           the latter case, s\bsu\bud\bdo\bo will print a usage message before it exits.
+           If an error occurs, the plugin may optionally call the conversation
+           or plugin_printf function with SUDO_CONF_ERROR_MSG to present
+           additional error information to the user.
+
+           The function arguments are as follows:
+
+           version
+               The version passed in by s\bsu\bud\bdo\bo allows the plugin to determine
+               the major and minor version number of the plugin API supported
+               by s\bsu\bud\bdo\bo.
+
+           conversation
+               A pointer to the conversation function that may be used by the
+               _\bs_\bh_\bo_\bw_\b__\bv_\be_\br_\bs_\bi_\bo_\bn function to display version information (see
+               show_version below).  The conversation function may also be
+               used to display additional error message to the user.  The
+               conversation function returns 0 on success and -1 on failure.
+
+           plugin_printf
+               A pointer to a printf-style function that may be used by the
+               _\bs_\bh_\bo_\bw_\b__\bv_\be_\br_\bs_\bi_\bo_\bn function to display version information (see
+               show_version below).  The plugin_printf function may also be
+               used to display additional error message to the user.  The
+               plugin_printf function returns number of characters printed on
+               success and -1 on failure.
+
+           settings
+               A vector of user-supplied s\bsu\bud\bdo\bo settings in the form of
+               "name=value" strings.  The vector is terminated by a NULL
+               pointer.  These settings correspond to flags the user specified
+               when running s\bsu\bud\bdo\bo.  As such, they will only be present when the
+               corresponding flag has been specified on the command line.
+
+               When parsing _\bs_\be_\bt_\bt_\bi_\bn_\bg_\bs, the plugin should split on the f\bfi\bir\brs\bst\bt
+               equal sign ('=') since the _\bn_\ba_\bm_\be field will never include one
+               itself but the _\bv_\ba_\bl_\bu_\be might.
+
+               See the "Policy Plugin API" section for a list of all possible
+               settings.
+
+           user_info
+               A vector of information about the user running the command in
+               the form of "name=value" strings.  The vector is terminated by
+               a NULL pointer.
+
+               When parsing _\bu_\bs_\be_\br_\b__\bi_\bn_\bf_\bo, the plugin should split on the f\bfi\bir\brs\bst\bt
+               equal sign ('=') since the _\bn_\ba_\bm_\be field will never include one
+               itself but the _\bv_\ba_\bl_\bu_\be might.
+
+               See the "Policy Plugin API" section for a list of all possible
+               strings.
+
+           argc
+               The number of elements in _\ba_\br_\bg_\bv, not counting the final NULL
+               pointer.
+
+           argv
+               If non-NULL, an argument vector describing a command the user
+               wishes to run in the same form as what would be passed to the
+               _\be_\bx_\be_\bc_\bv_\be_\b(_\b) system call.
+
+           user_env
+               The user's environment in the form of a NULL-terminated vector
+               of "name=value" strings.
+
+               When parsing _\bu_\bs_\be_\br_\b__\be_\bn_\bv, the plugin should split on the f\bfi\bir\brs\bst\bt
+               equal sign ('=') since the _\bn_\ba_\bm_\be field will never include one
+               itself but the _\bv_\ba_\bl_\bu_\be might.
+
+       close
+            void (*close)(int exit_status, int error);
+
+           The close function is called when the command being run by s\bsu\bud\bdo\bo
+           finishes.
+
+           The function arguments are as follows:
+
+           exit_status
+               The command's exit status, as returned by the _\bw_\ba_\bi_\bt(2) system
+               call.  The value of exit_status is undefined if error is non-
+               zero.
+
+           error
+               If the command could not be executed, this is set to the value
+               of errno set by the _\be_\bx_\be_\bc_\bv_\be(2) system call.  If the command was
+               successfully executed, the value of error is 0.
+
+       show_version
+            int (*show_version)(int verbose);
+
+           The show_version function is called by s\bsu\bud\bdo\bo when the user specifies
+           the -V option.  The plugin may display its version information to
+           the user via the conversation or plugin_printf function using
+           SUDO_CONV_INFO_MSG.  If the user requests detailed version
+           information, the verbose flag will be set.
+
+       log_ttyin
+            int (*log_ttyin)(const char *buf, unsigned int len);
+
+           The _\bl_\bo_\bg_\b__\bt_\bt_\by_\bi_\bn function is called whenever data can be read from the
+           user but before it is passed to the running command.  This allows
+           the plugin to reject data if it chooses to (for instance if the
+           input contains banned content).  Returns 1 if the data should be
+           passed to the command, 0 if the data is rejected (which will
+           terminate the command) or -1 if an error occurred.
+
+           The function arguments are as follows:
+
+           buf The buffer containing user input.
+
+           len The length of _\bb_\bu_\bf in bytes.
+
+       log_ttyout
+            int (*log_ttyout)(const char *buf, unsigned int len);
+
+           The _\bl_\bo_\bg_\b__\bt_\bt_\by_\bo_\bu_\bt function is called whenever data can be read from
+           the command but before it is written to the user's terminal.  This
+           allows the plugin to reject data if it chooses to (for instance if
+           the output contains banned content).  Returns 1 if the data should
+           be passed to the user, 0 if the data is rejected (which will
+           terminate the command) or -1 if an error occurred.
+
+           The function arguments are as follows:
+
+           buf The buffer containing command output.
+
+           len The length of _\bb_\bu_\bf in bytes.
+
+       log_stdin
+            int (*log_stdin)(const char *buf, unsigned int len);
+
+           The _\bl_\bo_\bg_\b__\bs_\bt_\bd_\bi_\bn function is only used if the standard input does not
+           correspond to a tty device.  It is called whenever data can be read
+           from the standard input but before it is passed to the running
+           command.  This allows the plugin to reject data if it chooses to
+           (for instance if the input contains banned content).  Returns 1 if
+           the data should be passed to the command, 0 if the data is rejected
+           (which will terminate the command) or -1 if an error occurred.
+
+           The function arguments are as follows:
+
+           buf The buffer containing user input.
+
+           len The length of _\bb_\bu_\bf in bytes.
+
+       log_stdout
+            int (*log_stdout)(const char *buf, unsigned int len);
+
+           The _\bl_\bo_\bg_\b__\bs_\bt_\bd_\bo_\bu_\bt function is only used if the standard output does
+           not correspond to a tty device.  It is called whenever data can be
+           read from the command but before it is written to the standard
+           output.  This allows the plugin to reject data if it chooses to
+           (for instance if the output contains banned content).  Returns 1 if
+           the data should be passed to the user, 0 if the data is rejected
+           (which will terminate the command) or -1 if an error occurred.
+
+           The function arguments are as follows:
+
+           buf The buffer containing command output.
+
+           len The length of _\bb_\bu_\bf in bytes.
+
+       log_stderr
+            int (*log_stderr)(const char *buf, unsigned int len);
+
+           The _\bl_\bo_\bg_\b__\bs_\bt_\bd_\be_\br_\br function is only used if the standard error does not
+           correspond to a tty device.  It is called whenever data can be read
+           from the command but before it is written to the standard error.
+           This allows the plugin to reject data if it chooses to (for
+           instance if the output contains banned content).  Returns 1 if the
+           data should be passed to the user, 0 if the data is rejected (which
+           will terminate the command) or -1 if an error occurred.
+
+           The function arguments are as follows:
+
+           buf The buffer containing command output.
+
+           len The length of _\bb_\bu_\bf in bytes.
+
+       _\bV_\be_\br_\bs_\bi_\bo_\bn _\bm_\ba_\bc_\br_\bo_\bs
+
+       Same as for the "Policy Plugin API".
+
+   C\bCo\bon\bnv\bve\ber\brs\bsa\bat\bti\bio\bon\bn A\bAP\bPI\bI
+       If the plugin needs to interact with the user, it may do so via the
+       conversation function.  A plugin should not attempt to read directly
+       from the standard input or the user's tty (neither of which are
+       guaranteed to exist).  The caller must include a trailing newline in
+       msg if one is to be printed.
+
+       A printf-style function is also available that can be used to display
+       informational or error messages to the user, which is usually more
+       convenient for simple messages where no use input is required.
+
+        struct sudo_conv_message {
+        #define SUDO_CONV_PROMPT_ECHO_OFF  0x0001 /* do not echo user input */
+        #define SUDO_CONV_PROMPT_ECHO_ON   0x0002 /* echo user input */
+        #define SUDO_CONV_ERROR_MSG        0x0003 /* error message */
+        #define SUDO_CONV_INFO_MSG         0x0004 /* informational message */
+        #define SUDO_CONV_PROMPT_MASK      0x0005 /* mask user input */
+        #define SUDO_CONV_PROMPT_ECHO_OK   0x1000 /* flag: allow echo if no tty */
+            int msg_type;
+            int timeout;
+            const char *msg;
+        };
+
+        struct sudo_conv_reply {
+            char *reply;
+        };
+
+        typedef int (*sudo_conv_t)(int num_msgs,
+                     const struct sudo_conv_message msgs[],
+                     struct sudo_conv_reply replies[]);
+
+        typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...);
+
+       Pointers to the conversation and printf-style functions are passed in
+       to the plugin's open function when the plugin is initialized.
+
+       To use the conversation function, the plugin must pass an array of
+       sudo_conv_message and sudo_conv_reply structures.  There must be a
+       struct sudo_conv_message and struct sudo_conv_reply for each message in
+       the conversation.  The plugin is responsible for freeing the reply
+       buffer filled in to the struct sudo_conv_reply, if any.
+
+       The printf-style function uses the same underlying mechanism as the
+       conversation function but only supports SUDO_CONV_INFO_MSG and
+       SUDO_CONV_ERROR_MSG for the _\bm_\bs_\bg_\b__\bt_\by_\bp_\be parameter.  It can be more
+       convenient than using the conversation function if no user reply is
+       needed and supports standard _\bp_\br_\bi_\bn_\bt_\bf_\b(_\b) escape sequences.
+
+       See the sample plugin for an example of the conversation function
+       usage.
+
+   S\bSu\bud\bdo\boe\ber\brs\bs G\bGr\bro\bou\bup\bp P\bPl\blu\bug\bgi\bin\bn A\bAP\bPI\bI
+       The _\bs_\bu_\bd_\bo_\be_\br_\bs module supports a plugin interface to allow non-Unix group
+       lookups.  This can be used to query a group source other than the
+       standard Unix group database.  A sample group plugin is bundled with
+       s\bsu\bud\bdo\bo that implements file-based lookups.  Third party group plugins
+       include a QAS AD plugin available from Quest Software.
+
+       A group plugin must declare and populate a sudoers_group_plugin struct
+       in the global scope.  This structure contains pointers to the functions
+       that implement plugin initialization, cleanup and group lookup.
+
+        struct sudoers_group_plugin {
+           unsigned int version;
+           int (*init)(int version, sudo_printf_t sudo_printf,
+                       char *const argv[]);
+           void (*cleanup)(void);
+           int (*query)(const char *user, const char *group,
+                        const struct passwd *pwd);
+       };
+
+       The sudoers_group_plugin struct has the following fields:
+
+       version
+           The version field should be set to GROUP_API_VERSION.
+
+           This allows _\bs_\bu_\bd_\bo_\be_\br_\bs to determine the API version the group plugin
+           was built against.
+
+       init
+            int (*init)(int version, sudo_printf_t plugin_printf,
+                        char *const argv[]);
+
+           The _\bi_\bn_\bi_\bt function is called after _\bs_\bu_\bd_\bo_\be_\br_\bs has been parsed but
+           before any policy checks.  It returns 1 on success, 0 on failure
+           (or if the plugin is not configured), and -1 if a error occurred.
+           If an error occurs, the plugin may call the plugin_printf function
+           with SUDO_CONF_ERROR_MSG to present additional error information to
+           the user.
+
+           The function arguments are as follows:
+
+           version
+               The version passed in by _\bs_\bu_\bd_\bo_\be_\br_\bs allows the plugin to determine
+               the major and minor version number of the group plugin API
+               supported by _\bs_\bu_\bd_\bo_\be_\br_\bs.
+
+           plugin_printf
+               A pointer to a printf-style function that may be used to
+               display informational or error message to the user.  Returns
+               the number of characters printed on success and -1 on failure.
+
+           argv
+               A NULL-terminated array of arguments generated from the
+               _\bg_\br_\bo_\bu_\bp_\b__\bp_\bl_\bu_\bg_\bi_\bn option in _\bs_\bu_\bd_\bo_\be_\br_\bs.  If no arguments were given,
+               _\ba_\br_\bg_\bv will be NULL.
+
+       cleanup
+            void (*cleanup)();
+
+           The _\bc_\bl_\be_\ba_\bn_\bu_\bp function is called when _\bs_\bu_\bd_\bo_\be_\br_\bs has finished its group
+           checks.  The plugin should free any memory it has allocated and
+           close open file handles.
+
+       query
+            int (*query)(const char *user, const char *group,
+                         const struct passwd *pwd);
+
+           The _\bq_\bu_\be_\br_\by function is used to ask the group plugin whether _\bu_\bs_\be_\br is
+           a member of _\bg_\br_\bo_\bu_\bp.
+
+           The function arguments are as follows:
+
+           user
+               The name of the user being looked up in the external group
+               database.
+
+           group
+               The name of the group being queried.
+
+           pwd The password database entry for _\bu_\bs_\be_\br, if any.  If _\bu_\bs_\be_\br is not
+               present in the password database, _\bp_\bw_\bd will be NULL.
+
+       _\bV_\be_\br_\bs_\bi_\bo_\bn _\bM_\ba_\bc_\br_\bo_\bs
+
+        /* Sudoers group plugin version major/minor */
+        #define GROUP_API_VERSION_MAJOR 1
+        #define GROUP_API_VERSION_MINOR 0
+        #define GROUP_API_VERSION ((GROUP_API_VERSION_MAJOR << 16) | \
+                                   GROUP_API_VERSION_MINOR)
+
+        /* Getters and setters for group version */
+        #define GROUP_API_VERSION_GET_MAJOR(v) ((v) >> 16)
+        #define GROUP_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
+        #define GROUP_API_VERSION_SET_MAJOR(vp, n) do { \
+            *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \
+        } while(0)
+        #define GROUP_API_VERSION_SET_MINOR(vp, n) do { \
+            *(vp) = (*(vp) & 0xffff0000) | (n); \
+        } while(0)
+
+S\bSE\bEE\bE A\bAL\bLS\bSO\bO
+       _\bs_\bu_\bd_\bo_\be_\br_\bs(4), _\bs_\bu_\bd_\bo(1m)
+
+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-workers mailing list,
+       see http://www.sudo.ws/mailman/listinfo/sudo-workers 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 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.8.1p2                          May 16, 2011                  SUDO_PLUGIN(1m)
diff --git a/doc/sudo_plugin.man.in b/doc/sudo_plugin.man.in
new file mode 100644 (file)
index 0000000..9f26bfc
--- /dev/null
@@ -0,0 +1,1282 @@
+.\" Copyright (c) 2009-2011 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.
+.\" 
+.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.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 (.SS), 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 "SUDO_PLUGIN @mansectsu@"
+.TH SUDO_PLUGIN @mansectsu@ "May 16, 2011" "1.8.1p2" "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_plugin \- Sudo Plugin API
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+Starting with version 1.8, \fBsudo\fR supports a plugin \s-1API\s0
+for policy and session logging.  By default, the \fIsudoers\fR policy
+plugin and an associated I/O logging plugin are used.  Via the plugin
+\&\s-1API\s0, \fBsudo\fR can be configured to use alternate policy and/or I/O
+logging plugins provided by third parties.  The plugins to be used
+are specified via the \fI@sysconfdir@/sudo.conf\fR file.
+.PP
+The \s-1API\s0 is versioned with a major and minor number.  The minor
+version number is incremented when additions are made.  The major
+number is incremented when incompatible changes are made.  A plugin
+should be check the version passed to it and make sure that the
+major version matches.
+.PP
+The plugin \s-1API\s0 is defined by the \f(CW\*(C`sudo_plugin.h\*(C'\fR header file.
+.SS "The sudo.conf File"
+.IX Subsection "The sudo.conf File"
+The \fI@sysconfdir@/sudo.conf\fR file contains plugin configuration directives.
+Currently, the only supported keyword is the \f(CW\*(C`Plugin\*(C'\fR directive,
+which causes a plugin plugin to be loaded.
+.PP
+A \f(CW\*(C`Plugin\*(C'\fR line consists of the \f(CW\*(C`Plugin\*(C'\fR keyword, followed by the
+\&\fIsymbol_name\fR and the \fIpath\fR to the shared object containing the
+plugin.  The \fIsymbol_name\fR is the name of the \f(CW\*(C`struct policy_plugin\*(C'\fR
+or \f(CW\*(C`struct io_plugin\*(C'\fR in the plugin shared object.  The \fIpath\fR
+may be fully qualified or relative.  If not fully qualified it is
+relative to the \fI@prefix@/libexec\fR directory.  Any additional
+parameters after the \fIpath\fR are ignored.  Lines that don't begin
+with \f(CW\*(C`Plugin\*(C'\fR or \f(CW\*(C`Path\*(C'\fR are silently ignored.
+.PP
+The same shared object may contain multiple plugins, each with a
+different symbol name.  The shared object file must be owned by uid
+0 and only writable by its owner.  Because of ambiguities that arise
+from composite policies, only a single policy plugin may be specified.
+This limitation does not apply to I/O plugins.
+.PP
+.Vb 10
+\& #
+\& # Default @sysconfdir@/sudo.conf file
+\& #
+\& # Format:
+\& #   Plugin plugin_name plugin_path
+\& #   Path askpass /path/to/askpass
+\& #
+\& # The plugin_path is relative to @prefix@/libexec unless
+\& #   fully qualified.
+\& # The plugin_name corresponds to a global symbol in the plugin
+\& #   that contains the plugin interface structure.
+\& #
+\& Plugin sudoers_policy sudoers.so
+\& Plugin sudoers_io sudoers.so
+.Ve
+.SS "Policy Plugin \s-1API\s0"
+.IX Subsection "Policy Plugin API"
+A policy plugin must declare and populate a \f(CW\*(C`policy_plugin\*(C'\fR struct
+in the global scope.  This structure contains pointers to the functions
+that implement the \fBsudo\fR policy checks.  The name of the symbol should
+be specified in \fI@sysconfdir@/sudo.conf\fR along with a path to the plugin
+so that \fBsudo\fR can load it.
+.PP
+.Vb 10
+\& struct policy_plugin {
+\& #define SUDO_POLICY_PLUGIN     1
+\&     unsigned int type; /* always SUDO_POLICY_PLUGIN */
+\&     unsigned int version; /* always SUDO_API_VERSION */
+\&     int (*open)(unsigned int version, sudo_conv_t conversation,
+\&                 sudo_printf_t plugin_printf, char * const settings[],
+\&                 char * const user_info[], char * const user_env[]);
+\&     void (*close)(int exit_status, int error);
+\&     int (*show_version)(int verbose);
+\&     int (*check_policy)(int argc, char * const argv[],
+\&                         char *env_add[], char **command_info[],
+\&                         char **argv_out[], char **user_env_out[]);
+\&     int (*list)(int argc, char * const argv[], int verbose,
+\&                 const char *list_user);
+\&     int (*validate)(void);
+\&     void (*invalidate)(int remove);
+\&     int (*init_session)(struct passwd *pwd);
+\& };
+.Ve
+.PP
+The policy_plugin struct has the following fields:
+.IP "type" 4
+.IX Item "type"
+The \f(CW\*(C`type\*(C'\fR field should always be set to \s-1SUDO_POLICY_PLUGIN\s0.
+.IP "version" 4
+.IX Item "version"
+The \f(CW\*(C`version\*(C'\fR field should be set to \s-1SUDO_API_VERSION\s0.
+.Sp
+This allows \fBsudo\fR to determine the \s-1API\s0 version the plugin was
+built against.
+.IP "open" 4
+.IX Item "open"
+.Vb 3
+\& int (*open)(unsigned int version, sudo_conv_t conversation,
+\&             sudo_printf_t plugin_printf, char * const settings[],
+\&             char * const user_info[], char * const user_env[]);
+.Ve
+.Sp
+Returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error.  In the latter case, \fBsudo\fR will
+print a usage message before it exits.  If an error occurs, the
+plugin may optionally call the conversation or plugin_printf function
+with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present additional error information
+to the user.
+.Sp
+The function arguments are as follows:
+.RS 4
+.IP "version" 4
+.IX Item "version"
+The version passed in by \fBsudo\fR allows the plugin to determine the
+major and minor version number of the plugin \s-1API\s0 supported by
+\&\fBsudo\fR.
+.IP "conversation" 4
+.IX Item "conversation"
+A pointer to the conversation function that can be used by the
+plugin to interact with the user (see below).
+Returns 0 on success and \-1 on failure.
+.IP "plugin_printf" 4
+.IX Item "plugin_printf"
+A pointer to a printf-style function that may be used to display
+informational or error messages (see below).
+Returns the number of characters printed on success and \-1 on failure.
+.IP "settings" 4
+.IX Item "settings"
+A vector of user-supplied \fBsudo\fR settings in the form of \*(L"name=value\*(R"
+strings.  The vector is terminated by a \f(CW\*(C`NULL\*(C'\fR pointer.  These
+settings correspond to flags the user specified when running \fBsudo\fR.
+As such, they will only be present when the corresponding flag has
+been specified on the command line.
+.Sp
+When parsing \fIsettings\fR, the plugin should split on the \fBfirst\fR
+equal sign ('=') since the \fIname\fR field will never include one
+itself but the \fIvalue\fR might.
+.RS 4
+.IP "debug_level=number" 4
+.IX Item "debug_level=number"
+A numeric debug level, from 1\-9, if specified via the \f(CW\*(C`\-D\*(C'\fR flag.
+.IP "runas_user=string" 4
+.IX Item "runas_user=string"
+The user name or uid to to run the command as, if specified via the
+\&\f(CW\*(C`\-u\*(C'\fR flag.
+.IP "runas_group=string" 4
+.IX Item "runas_group=string"
+The group name or gid to to run the command as, if specified via
+the \f(CW\*(C`\-g\*(C'\fR flag.
+.IP "prompt=string" 4
+.IX Item "prompt=string"
+The prompt to use when requesting a password, if specified via
+the \f(CW\*(C`\-p\*(C'\fR flag.
+.IP "set_home=bool" 4
+.IX Item "set_home=bool"
+Set to true if the user specified the \f(CW\*(C`\-H\*(C'\fR flag.  If true, set the
+\&\f(CW\*(C`HOME\*(C'\fR environment variable to the target user's home directory.
+.IP "preserve_environment=bool" 4
+.IX Item "preserve_environment=bool"
+Set to true if the user specified the \f(CW\*(C`\-E\*(C'\fR flag, indicating that
+the user wishes to preserve the environment.
+.IP "run_shell=bool" 4
+.IX Item "run_shell=bool"
+Set to true if the user specified the \f(CW\*(C`\-s\*(C'\fR flag, indicating that
+the user wishes to run a shell.
+.IP "login_shell=bool" 4
+.IX Item "login_shell=bool"
+Set to true if the user specified the \f(CW\*(C`\-i\*(C'\fR flag, indicating that
+the user wishes to run a login shell.
+.IP "implied_shell=bool" 4
+.IX Item "implied_shell=bool"
+If the user does not specify a program on the command line, \fBsudo\fR
+will pass the plugin the path to the user's shell and set
+\&\fIimplied_shell\fR to true.  This allows \fBsudo\fR with no arguments
+to be used similarly to \fIsu\fR\|(1).  If the plugin does not to support
+this usage, it may return a value of \-2 from the \f(CW\*(C`check_policy\*(C'\fR
+function, which will cause \fBsudo\fR to print a usage message and
+exit.
+.IP "preserve_groups=bool" 4
+.IX Item "preserve_groups=bool"
+Set to true if the user specified the \f(CW\*(C`\-P\*(C'\fR flag, indicating that
+the user wishes to preserve the group vector instead of setting it
+based on the runas user.
+.IP "ignore_ticket=bool" 4
+.IX Item "ignore_ticket=bool"
+Set to true if the user specified the \f(CW\*(C`\-k\*(C'\fR flag along with a
+command, indicating that the user wishes to ignore any cached
+authentication credentials.
+.IP "noninteractive=bool" 4
+.IX Item "noninteractive=bool"
+Set to true if the user specified the \f(CW\*(C`\-n\*(C'\fR flag, indicating that
+\&\fBsudo\fR should operate in non-interactive mode.  The plugin may
+reject a command run in non-interactive mode if user interaction
+is required.
+.IP "login_class=string" 4
+.IX Item "login_class=string"
+\&\s-1BSD\s0 login class to use when setting resource limits and nice value,
+if specified by the \f(CW\*(C`\-c\*(C'\fR flag.
+.IP "selinux_role=string" 4
+.IX Item "selinux_role=string"
+SELinux role to use when executing the command, if specified by
+the \f(CW\*(C`\-r\*(C'\fR flag.
+.IP "selinux_type=string" 4
+.IX Item "selinux_type=string"
+SELinux type to use when executing the command, if specified by
+the \f(CW\*(C`\-t\*(C'\fR flag.
+.IP "bsdauth_type=string" 4
+.IX Item "bsdauth_type=string"
+Authentication type, if specified by the \f(CW\*(C`\-a\*(C'\fR flag, to use on
+systems where \s-1BSD\s0 authentication is supported.
+.IP "network_addrs=list" 4
+.IX Item "network_addrs=list"
+A space-separated list of \s-1IP\s0 network addresses and netmasks in the
+form \*(L"addr/netmask\*(R", e.g. \*(L"192.168.1.2/255.255.255.0\*(R".  The address
+and netmask pairs may be either IPv4 or IPv6, depending on what the
+operating system supports.  If the address contains a colon (':'),
+it is an IPv6 address, else it is IPv4.
+.IP "progname=string" 4
+.IX Item "progname=string"
+The command name that sudo was run as, typically \*(L"sudo\*(R" or \*(L"sudoedit\*(R".
+.IP "sudoedit=bool" 4
+.IX Item "sudoedit=bool"
+Set to true when the \f(CW\*(C`\-e\*(C'\fR flag is is specified or if invoked as
+\&\fBsudoedit\fR.  The plugin shall substitute an editor into \fIargv\fR
+in the \fIcheck_policy\fR function or return \f(CW\*(C`\-2\*(C'\fR with a usage error
+if the plugin does not support \fIsudoedit\fR.  For more information,
+see the \fIcheck_policy\fR section.
+.IP "closefrom=number" 4
+.IX Item "closefrom=number"
+If specified, the user has requested via the \f(CW\*(C`\-C\*(C'\fR flag that \fBsudo\fR
+close all files descriptors with a value of \fInumber\fR or higher.
+The plugin may optionally pass this, or another value, back in the
+\&\fIcommand_info\fR list.
+.RE
+.RS 4
+.Sp
+Additional settings may be added in the future so the plugin should
+silently ignore settings that it does not recognize.
+.RE
+.IP "user_info" 4
+.IX Item "user_info"
+A vector of information about the user running the command in the form of
+\&\*(L"name=value\*(R" strings.  The vector is terminated by a \f(CW\*(C`NULL\*(C'\fR pointer.
+.Sp
+When parsing \fIuser_info\fR, the plugin should split on the \fBfirst\fR
+equal sign ('=') since the \fIname\fR field will never include one
+itself but the \fIvalue\fR might.
+.RS 4
+.IP "user=string" 4
+.IX Item "user=string"
+The name of the user invoking \fBsudo\fR.
+.IP "uid=uid_t" 4
+.IX Item "uid=uid_t"
+The real user \s-1ID\s0 of the user invoking \fBsudo\fR.
+.IP "gid=gid_t" 4
+.IX Item "gid=gid_t"
+The real group \s-1ID\s0 of the user invoking \fBsudo\fR.
+.IP "groups=list" 4
+.IX Item "groups=list"
+The user's supplementary group list formatted as a string of
+comma-separated group IDs.
+.IP "cwd=string" 4
+.IX Item "cwd=string"
+The user's current working directory.
+.IP "tty=string" 4
+.IX Item "tty=string"
+The path to the user's terminal device.  If the user has no terminal
+device associated with the session, the value will be empty, as in
+\&\f(CW\*(C`tty=\*(C'\fR.
+.IP "host=string" 4
+.IX Item "host=string"
+The local machine's hostname as returned by the \f(CW\*(C`gethostname()\*(C'\fR
+system call.
+.IP "lines=int" 4
+.IX Item "lines=int"
+The number of lines the user's terminal supports.  If there is
+no terminal device available, a default value of 24 is used.
+.IP "cols=int" 4
+.IX Item "cols=int"
+The number of columns the user's terminal supports.  If there is
+no terminal device available, a default value of 80 is used.
+.RE
+.RS 4
+.RE
+.IP "user_env" 4
+.IX Item "user_env"
+The user's environment in the form of a \f(CW\*(C`NULL\*(C'\fR\-terminated vector of
+\&\*(L"name=value\*(R" strings.
+.Sp
+When parsing \fIuser_env\fR, the plugin should split on the \fBfirst\fR
+equal sign ('=') since the \fIname\fR field will never include one
+itself but the \fIvalue\fR might.
+.RE
+.RS 4
+.RE
+.IP "close" 4
+.IX Item "close"
+.Vb 1
+\& void (*close)(int exit_status, int error);
+.Ve
+.Sp
+The \f(CW\*(C`close\*(C'\fR function is called when the command being run by \fBsudo\fR
+finishes.
+.Sp
+The function arguments are as follows:
+.RS 4
+.IP "exit_status" 4
+.IX Item "exit_status"
+The command's exit status, as returned by the \fIwait\fR\|(2) system call.
+The value of \f(CW\*(C`exit_status\*(C'\fR is undefined if \f(CW\*(C`error\*(C'\fR is non-zero.
+.IP "error" 4
+.IX Item "error"
+If the command could not be executed, this is set to the value of
+\&\f(CW\*(C`errno\*(C'\fR set by the \fIexecve\fR\|(2) system call.  The plugin is responsible
+for displaying error information via the conversation or plugin_printf
+function.  If the command was successfully executed, the value of
+\&\f(CW\*(C`error\*(C'\fR is 0.
+.RE
+.RS 4
+.RE
+.IP "show_version" 4
+.IX Item "show_version"
+.Vb 1
+\& int (*show_version)(int verbose);
+.Ve
+.Sp
+The \f(CW\*(C`show_version\*(C'\fR function is called by \fBsudo\fR when the user specifies
+the \f(CW\*(C`\-V\*(C'\fR option.  The plugin may display its version information
+to the user via the conversation or plugin_printf function using
+\&\f(CW\*(C`SUDO_CONV_INFO_MSG\*(C'\fR.  If the user requests detailed version
+information, the verbose flag will be set.
+.IP "check_policy" 4
+.IX Item "check_policy"
+.Vb 3
+\& int (*check_policy)(int argc, char * const argv[]
+\&                     char *env_add[], char **command_info[],
+\&                     char **argv_out[], char **user_env_out[]);
+.Ve
+.Sp
+The \fIcheck_policy\fR function is called by \fBsudo\fR to determine
+whether the user is allowed to run the specified commands.
+.Sp
+If the \fIsudoedit\fR option was enabled in the \fIsettings\fR array
+passed to the \fIopen\fR function, the user has requested \fIsudoedit\fR
+mode.  \fIsudoedit\fR is a mechanism for editing one or more files
+where an editor is run with the user's credentials instead of with
+elevated privileges.  \fBsudo\fR achieves this by creating user-writable
+temporary copies of the files to be edited and then overwriting the
+originals with the temporary copies after editing is complete.  If
+the plugin supports \fBsudoedit\fR, it should choose the editor to be
+used, potentially from a variable in the user's environment, such
+as \f(CW\*(C`EDITOR\*(C'\fR, and include it in \fIargv_out\fR (note that environment
+variables may include command line flags).  The files to be edited
+should be copied from \fIargv\fR into \fIargv_out\fR, separated from the
+editor and its arguments by a \f(CW"\-\-"\fR element.  The \f(CW"\-\-"\fR will
+be removed by \fBsudo\fR before the editor is executed.  The plugin
+should also set \fIsudoedit=true\fR in the \fIcommand_info\fR list.
+.Sp
+The \fIcheck_policy\fR function returns 1 if the command is allowed,
+0 if not allowed, \-1 for a general error, or \-2 for a usage error
+or if \fBsudoedit\fR was specified but is unsupported by the plugin.
+In the latter case, \fBsudo\fR will print a usage message before it
+exits.  If an error occurs, the plugin may optionally call the
+conversation or plugin_printf function with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR
+to present additional error information to the user.
+.Sp
+The function arguments are as follows:
+.RS 4
+.IP "argc" 4
+.IX Item "argc"
+The number of elements in \fIargv\fR, not counting the final \f(CW\*(C`NULL\*(C'\fR
+pointer.
+.IP "argv" 4
+.IX Item "argv"
+The argument vector describing the command the user wishes to run,
+in the same form as what would be passed to the \fIexecve()\fR system
+call.  The vector is terminated by a \f(CW\*(C`NULL\*(C'\fR pointer.
+.IP "env_add" 4
+.IX Item "env_add"
+Additional environment variables specified by the user on the command
+line in the form of a \f(CW\*(C`NULL\*(C'\fR\-terminated vector of \*(L"name=value\*(R"
+strings.  The plugin may reject the command if one or more variables
+are not allowed to be set, or it may silently ignore such variables.
+.Sp
+When parsing \fIenv_add\fR, the plugin should split on the \fBfirst\fR
+equal sign ('=') since the \fIname\fR field will never include one
+itself but the \fIvalue\fR might.
+.IP "command_info" 4
+.IX Item "command_info"
+Information about the command being run in the form of \*(L"name=value\*(R"
+strings.  These values are used by \fBsudo\fR to set the execution
+environment when running a command.  The plugin is responsible for
+creating and populating the vector, which must be terminated with
+a \f(CW\*(C`NULL\*(C'\fR pointer.  The following values are recognized by \fBsudo\fR:
+.RS 4
+.IP "command=string" 4
+.IX Item "command=string"
+Fully qualified path to the command to be executed.
+.IP "runas_uid=uid" 4
+.IX Item "runas_uid=uid"
+User \s-1ID\s0 to run the command as.
+.IP "runas_euid=uid" 4
+.IX Item "runas_euid=uid"
+Effective user \s-1ID\s0 to run the command as.
+If not specified, the value of \fIrunas_uid\fR is used.
+.IP "runas_gid=gid" 4
+.IX Item "runas_gid=gid"
+Group \s-1ID\s0 to run the command as.
+.IP "runas_egid=gid" 4
+.IX Item "runas_egid=gid"
+Effective group \s-1ID\s0 to run the command as.
+If not specified, the value of \fIrunas_gid\fR is used.
+.IP "runas_groups=list" 4
+.IX Item "runas_groups=list"
+The supplementary group vector to use for the command in the form
+of a comma-separated list of group IDs.  If \fIpreserve_groups\fR
+is set, this option is ignored.
+.IP "login_class=string" 4
+.IX Item "login_class=string"
+\&\s-1BSD\s0 login class to use when setting resource limits and nice value
+(optional).  This option is only set on systems that support login
+classes.
+.IP "preserve_groups=bool" 4
+.IX Item "preserve_groups=bool"
+If set, \fBsudo\fR will preserve the user's group vector instead of
+initializing the group vector based on \f(CW\*(C`runas_user\*(C'\fR.
+.IP "cwd=string" 4
+.IX Item "cwd=string"
+The current working directory to change to when executing the command.
+.IP "noexec=bool" 4
+.IX Item "noexec=bool"
+If set, prevent the command from executing other programs.
+.IP "chroot=string" 4
+.IX Item "chroot=string"
+The root directory to use when running the command.
+.IP "nice=int" 4
+.IX Item "nice=int"
+Nice value (priority) to use when executing the command.  The nice
+value, if specified, overrides the priority associated with the
+\&\fIlogin_class\fR on \s-1BSD\s0 systems.
+.IP "umask=octal" 4
+.IX Item "umask=octal"
+The file creation mask to use when executing the command.
+.IP "selinux_role=string" 4
+.IX Item "selinux_role=string"
+SELinux role to use when executing the command.
+.IP "selinux_type=string" 4
+.IX Item "selinux_type=string"
+SELinux type to use when executing the command.
+.IP "timeout=int" 4
+.IX Item "timeout=int"
+Command timeout.  If non-zero then when the timeout expires the
+command will be killed.
+.IP "sudoedit=bool" 4
+.IX Item "sudoedit=bool"
+Set to true when in \fIsudoedit\fR mode.  The plugin may enable
+\&\fIsudoedit\fR mode even if \fBsudo\fR was not invoked as \fBsudoedit\fR.
+This allows the plugin to perform command substitution and transparently
+enable \fIsudoedit\fR when the user attempts to run an editor.
+.IP "closefrom=number" 4
+.IX Item "closefrom=number"
+If specified, \fBsudo\fR will close all files descriptors with a value
+of \fInumber\fR or higher.
+.IP "iolog_compress=bool" 4
+.IX Item "iolog_compress=bool"
+Set to true if the I/O logging plugins, if any, should compress the
+log data.  This is a hint to the I/O logging plugin which may choose
+to ignore it.
+.IP "iolog_path=string" 4
+.IX Item "iolog_path=string"
+Fully qualified path to the file or directory in which I/O log is
+to be stored.  This is a hint to the I/O logging plugin which may
+choose to ignore it.  If no I/O logging plugin is loaded, this
+setting has no effect.
+.IP "iolog_stdin=bool" 4
+.IX Item "iolog_stdin=bool"
+Set to true if the I/O logging plugins, if any, should log the
+standard input if it is not connected to a terminal device.  This
+is a hint to the I/O logging plugin which may choose to ignore it.
+.IP "iolog_stdout=bool" 4
+.IX Item "iolog_stdout=bool"
+Set to true if the I/O logging plugins, if any, should log the
+standard output if it is not connected to a terminal device.  This
+is a hint to the I/O logging plugin which may choose to ignore it.
+.IP "iolog_stderr=bool" 4
+.IX Item "iolog_stderr=bool"
+Set to true if the I/O logging plugins, if any, should log the
+standard error if it is not connected to a terminal device.  This
+is a hint to the I/O logging plugin which may choose to ignore it.
+.IP "iolog_ttyin=bool" 4
+.IX Item "iolog_ttyin=bool"
+Set to true if the I/O logging plugins, if any, should log all
+terminal input.  This only includes input typed by the user and not
+from a pipe or redirected from a file.  This is a hint to the I/O
+logging plugin which may choose to ignore it.
+.IP "iolog_ttyout=bool" 4
+.IX Item "iolog_ttyout=bool"
+Set to true if the I/O logging plugins, if any, should log all
+terminal output.  This only includes output to the screen, not
+output to a pipe or file.  This is a hint to the I/O logging plugin
+which may choose to ignore it.
+.IP "use_pty=bool" 4
+.IX Item "use_pty=bool"
+Allocate a pseudo-tty to run the command in, regardless of whether
+or not I/O logging is in use.  By default, \fBsudo\fR will only run
+the command in a pty when an I/O log plugin is loaded.
+.IP "set_utmp=bool" 4
+.IX Item "set_utmp=bool"
+Create a utmp (or utmpx) entry when a pseudo-tty is allocated.  By
+default, the new entry will be a copy of the user's existing utmp
+entry (if any), with the tty, time, type and pid fields updated.
+.IP "utmp_user=string" 4
+.IX Item "utmp_user=string"
+User name to use when constructing a new utmp (or utmpx) entry when
+\&\fIset_utmp\fR is enabled.  This option can be used to set the user
+field in the utmp entry to the user the command runs as rather than
+the invoking user.  If not set, \fBsudo\fR will base the new entry on
+the invoking user's existing entry.
+.RE
+.RS 4
+.Sp
+Unsupported values will be ignored.
+.RE
+.IP "argv_out" 4
+.IX Item "argv_out"
+The \f(CW\*(C`NULL\*(C'\fR\-terminated argument vector to pass to the \fIexecve()\fR
+system call when executing the command.  The plugin is responsible
+for allocating and populating the vector.
+.IP "user_env_out" 4
+.IX Item "user_env_out"
+The \f(CW\*(C`NULL\*(C'\fR\-terminated environment vector to use when executing the
+command.  The plugin is responsible for allocating and populating
+the vector.
+.RE
+.RS 4
+.RE
+.IP "list" 4
+.IX Item "list"
+.Vb 2
+\& int (*list)(int verbose, const char *list_user,
+\&             int argc, char * const argv[]);
+.Ve
+.Sp
+List available privileges for the invoking user.  Returns 1 on
+success, 0 on failure and \-1 on error.  On error, the plugin may
+optionally call the conversation or plugin_printf function with
+\&\f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present additional error information to
+the user.
+.Sp
+Privileges should be output via the conversation or plugin_printf
+function using \f(CW\*(C`SUDO_CONV_INFO_MSG\*(C'\fR.
+.RS 4
+.IP "verbose" 4
+.IX Item "verbose"
+Flag indicating whether to list in verbose mode or not.
+.IP "list_user" 4
+.IX Item "list_user"
+The name of a different user to list privileges for if the policy
+allows it.  If \f(CW\*(C`NULL\*(C'\fR, the plugin should list the privileges of
+the invoking user.
+.IP "argc" 4
+.IX Item "argc"
+The number of elements in \fIargv\fR, not counting the final \f(CW\*(C`NULL\*(C'\fR
+pointer.
+.IP "argv" 4
+.IX Item "argv"
+If non\-\f(CW\*(C`NULL\*(C'\fR, an argument vector describing a command the user
+wishes to check against the policy in the same form as what would
+be passed to the \fIexecve()\fR system call.  If the command is permitted
+by the policy, the fully-qualified path to the command should be
+displayed along with any command line arguments.
+.RE
+.RS 4
+.RE
+.IP "validate" 4
+.IX Item "validate"
+.Vb 1
+\& int (*validate)(void);
+.Ve
+.Sp
+The \f(CW\*(C`validate\*(C'\fR function is called when \fBsudo\fR is run with the
+\&\f(CW\*(C`\-v\*(C'\fR flag.  For policy plugins such as \fIsudoers\fR that cache
+authentication credentials, this function will validate and cache
+the credentials.
+.Sp
+The \f(CW\*(C`validate\*(C'\fR function should be \f(CW\*(C`NULL\*(C'\fR if the plugin does not
+support credential caching.
+.Sp
+Returns 1 on success, 0 on failure and \-1 on error.
+On error, the plugin may optionally call the conversation or plugin_printf
+function with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present additional
+error information to the user.
+.IP "invalidate" 4
+.IX Item "invalidate"
+.Vb 1
+\& void (*invalidate)(int remove);
+.Ve
+.Sp
+The \f(CW\*(C`invalidate\*(C'\fR function is called when \fBsudo\fR is called with
+the \f(CW\*(C`\-k\*(C'\fR or \f(CW\*(C`\-K\*(C'\fR flag.  For policy plugins such as \fIsudoers\fR that
+cache authentication credentials, this function will invalidate the
+credentials.  If the \fIremove\fR flag is set, the plugin may remove
+the credentials instead of simply invalidating them.
+.Sp
+The \f(CW\*(C`invalidate\*(C'\fR function should be \f(CW\*(C`NULL\*(C'\fR if the plugin does not
+support credential caching.
+.IP "init_session" 4
+.IX Item "init_session"
+.Vb 1
+\& int (*init_session)(struct passwd *pwd);
+.Ve
+.Sp
+The \f(CW\*(C`init_session\*(C'\fR function is called when \fBsudo\fR sets up the
+execution environment for the command, immediately before the
+contents of the \fIcommand_info\fR list are applied (before the uid
+changes).  This can be used to do session setup that is not supported
+by \fIcommand_info\fR, such as opening the \s-1PAM\s0 session.
+.Sp
+The \fIpwd\fR argument points to a passwd struct for the user the
+command will be run as if the uid the command will run as was found
+in the password database, otherwise it will be \s-1NULL\s0.
+.Sp
+Returns 1 on success, 0 on failure and \-1 on error.
+On error, the plugin may optionally call the conversation or plugin_printf
+function with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present additional
+error information to the user.
+.PP
+\fIVersion macros\fR
+.IX Subsection "Version macros"
+.PP
+.Vb 8
+\& #define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16)
+\& #define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
+\& #define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \e
+\&     *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \e
+\& } while(0)
+\& #define SUDO_VERSION_SET_MINOR(vp, n) do { \e
+\&     *(vp) = (*(vp) & 0xffff0000) | (n); \e
+\& } while(0)
+\&
+\& #define SUDO_API_VERSION_MAJOR 1
+\& #define SUDO_API_VERSION_MINOR 0
+\& #define SUDO_API_VERSION ((SUDO_API_VERSION_MAJOR << 16) | \e
+\&                           SUDO_API_VERSION_MINOR)
+.Ve
+.SS "I/O Plugin \s-1API\s0"
+.IX Subsection "I/O Plugin API"
+.Vb 10
+\& struct io_plugin {
+\& #define SUDO_IO_PLUGIN         2
+\&     unsigned int type; /* always SUDO_IO_PLUGIN */
+\&     unsigned int version; /* always SUDO_API_VERSION */
+\&     int (*open)(unsigned int version, sudo_conv_t conversation
+\&                 sudo_printf_t plugin_printf, char * const settings[],
+\&                 char * const user_info[], int argc, char * const argv[],
+\&                 char * const user_env[]);
+\&     void (*close)(int exit_status, int error); /* wait status or error */
+\&     int (*show_version)(int verbose);
+\&     int (*log_ttyin)(const char *buf, unsigned int len);
+\&     int (*log_ttyout)(const char *buf, unsigned int len);
+\&     int (*log_stdin)(const char *buf, unsigned int len);
+\&     int (*log_stdout)(const char *buf, unsigned int len);
+\&     int (*log_stderr)(const char *buf, unsigned int len);
+\& };
+.Ve
+.PP
+When an I/O plugin is loaded, \fBsudo\fR runs the command in a pseudo-tty.
+This makes it possible to log the input and output from the user's
+session.  If any of the standard input, standard output or standard
+error do not correspond to a tty, \fBsudo\fR will open a pipe to capture
+the I/O for logging before passing it on.
+.PP
+The log_ttyin function receives the raw user input from the terminal
+device (note that this will include input even when echo is disabled,
+such as when a password is read). The log_ttyout function receives
+output from the pseudo-tty that is suitable for replaying the user's
+session at a later time.  The log_stdin, log_stdout and log_stderr
+functions are only called if the standard input, standard output
+or standard error respectively correspond to something other than
+a tty.
+.PP
+Any of the logging functions may be set to the \s-1NULL\s0
+pointer if no logging is to be performed.  If the open function
+returns \f(CW0\fR, no I/O will be sent to the plugin.
+.PP
+The io_plugin struct has the following fields:
+.IP "type" 4
+.IX Item "type"
+The \f(CW\*(C`type\*(C'\fR field should always be set to \s-1SUDO_IO_PLUGIN\s0
+.IP "version" 4
+.IX Item "version"
+The \f(CW\*(C`version\*(C'\fR field should be set to \s-1SUDO_API_VERSION\s0.
+.Sp
+This allows \fBsudo\fR to determine the \s-1API\s0 version the plugin was
+built against.
+.IP "open" 4
+.IX Item "open"
+.Vb 4
+\& int (*open)(unsigned int version, sudo_conv_t conversation
+\&             sudo_printf_t plugin_printf, char * const settings[],
+\&             char * const user_info[], int argc, char * const argv[],
+\&             char * const user_env[]);
+.Ve
+.Sp
+The \fIopen\fR function is run before the \fIlog_input\fR, \fIlog_output\fR
+or \fIshow_version\fR functions are called.  It is only called if the
+version is being requested or the \fIcheck_policy\fR function has
+returned successfully.  It returns 1 on success, 0 on failure, \-1
+if a general error occurred, or \-2 if there was a usage error.  In
+the latter case, \fBsudo\fR will print a usage message before it exits.
+If an error occurs, the plugin may optionally call the conversation
+or plugin_printf function with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present
+additional error information to the user.
+.Sp
+The function arguments are as follows:
+.RS 4
+.IP "version" 4
+.IX Item "version"
+The version passed in by \fBsudo\fR allows the plugin to determine the
+major and minor version number of the plugin \s-1API\s0 supported by
+\&\fBsudo\fR.
+.IP "conversation" 4
+.IX Item "conversation"
+A pointer to the conversation function that may be used by the
+\&\fIshow_version\fR function to display version information (see
+show_version below).  The conversation function may also be used
+to display additional error message to the user.
+The conversation function returns 0 on success and \-1 on failure.
+.IP "plugin_printf" 4
+.IX Item "plugin_printf"
+A pointer to a printf-style function that may be used by the
+\&\fIshow_version\fR function to display version information (see
+show_version below).  The plugin_printf function may also be used
+to display additional error message to the user.
+The plugin_printf function returns number of characters printed on
+success and \-1 on failure.
+.IP "settings" 4
+.IX Item "settings"
+A vector of user-supplied \fBsudo\fR settings in the form of \*(L"name=value\*(R"
+strings.  The vector is terminated by a \f(CW\*(C`NULL\*(C'\fR pointer.  These
+settings correspond to flags the user specified when running \fBsudo\fR.
+As such, they will only be present when the corresponding flag has
+been specified on the command line.
+.Sp
+When parsing \fIsettings\fR, the plugin should split on the \fBfirst\fR
+equal sign ('=') since the \fIname\fR field will never include one
+itself but the \fIvalue\fR might.
+.Sp
+See the \*(L"Policy Plugin \s-1API\s0\*(R" section for a list of all possible settings.
+.IP "user_info" 4
+.IX Item "user_info"
+A vector of information about the user running the command in the form of
+\&\*(L"name=value\*(R" strings.  The vector is terminated by a \f(CW\*(C`NULL\*(C'\fR pointer.
+.Sp
+When parsing \fIuser_info\fR, the plugin should split on the \fBfirst\fR
+equal sign ('=') since the \fIname\fR field will never include one
+itself but the \fIvalue\fR might.
+.Sp
+See the \*(L"Policy Plugin \s-1API\s0\*(R" section for a list of all possible strings.
+.IP "argc" 4
+.IX Item "argc"
+The number of elements in \fIargv\fR, not counting the final \f(CW\*(C`NULL\*(C'\fR
+pointer.
+.IP "argv" 4
+.IX Item "argv"
+If non\-\f(CW\*(C`NULL\*(C'\fR, an argument vector describing a command the user
+wishes to run in the same form as what would be passed to the
+\&\fIexecve()\fR system call.
+.IP "user_env" 4
+.IX Item "user_env"
+The user's environment in the form of a \f(CW\*(C`NULL\*(C'\fR\-terminated vector of
+\&\*(L"name=value\*(R" strings.
+.Sp
+When parsing \fIuser_env\fR, the plugin should split on the \fBfirst\fR
+equal sign ('=') since the \fIname\fR field will never include one
+itself but the \fIvalue\fR might.
+.RE
+.RS 4
+.RE
+.IP "close" 4
+.IX Item "close"
+.Vb 1
+\& void (*close)(int exit_status, int error);
+.Ve
+.Sp
+The \f(CW\*(C`close\*(C'\fR function is called when the command being run by \fBsudo\fR
+finishes.
+.Sp
+The function arguments are as follows:
+.RS 4
+.IP "exit_status" 4
+.IX Item "exit_status"
+The command's exit status, as returned by the \fIwait\fR\|(2) system call.
+The value of \f(CW\*(C`exit_status\*(C'\fR is undefined if \f(CW\*(C`error\*(C'\fR is non-zero.
+.IP "error" 4
+.IX Item "error"
+If the command could not be executed, this is set to the value of
+\&\f(CW\*(C`errno\*(C'\fR set by the \fIexecve\fR\|(2) system call.  If the command was
+successfully executed, the value of \f(CW\*(C`error\*(C'\fR is 0.
+.RE
+.RS 4
+.RE
+.IP "show_version" 4
+.IX Item "show_version"
+.Vb 1
+\& int (*show_version)(int verbose);
+.Ve
+.Sp
+The \f(CW\*(C`show_version\*(C'\fR function is called by \fBsudo\fR when the user specifies
+the \f(CW\*(C`\-V\*(C'\fR option.  The plugin may display its version information
+to the user via the conversation or plugin_printf function using
+\&\f(CW\*(C`SUDO_CONV_INFO_MSG\*(C'\fR.  If the user requests detailed version
+information, the verbose flag will be set.
+.IP "log_ttyin" 4
+.IX Item "log_ttyin"
+.Vb 1
+\& int (*log_ttyin)(const char *buf, unsigned int len);
+.Ve
+.Sp
+The \fIlog_ttyin\fR function is called whenever data can be read from
+the user but before it is passed to the running command.  This
+allows the plugin to reject data if it chooses to (for instance
+if the input contains banned content).  Returns \f(CW1\fR if the data
+should be passed to the command, \f(CW0\fR if the data is rejected
+(which will terminate the command) or \f(CW\*(C`\-1\*(C'\fR if an error occurred.
+.Sp
+The function arguments are as follows:
+.RS 4
+.IP "buf" 4
+.IX Item "buf"
+The buffer containing user input.
+.IP "len" 4
+.IX Item "len"
+The length of \fIbuf\fR in bytes.
+.RE
+.RS 4
+.RE
+.IP "log_ttyout" 4
+.IX Item "log_ttyout"
+.Vb 1
+\& int (*log_ttyout)(const char *buf, unsigned int len);
+.Ve
+.Sp
+The \fIlog_ttyout\fR function is called whenever data can be read from
+the command but before it is written to the user's terminal.  This
+allows the plugin to reject data if it chooses to (for instance
+if the output contains banned content).  Returns \f(CW1\fR if the data
+should be passed to the user, \f(CW0\fR if the data is rejected
+(which will terminate the command) or \f(CW\*(C`\-1\*(C'\fR if an error occurred.
+.Sp
+The function arguments are as follows:
+.RS 4
+.IP "buf" 4
+.IX Item "buf"
+The buffer containing command output.
+.IP "len" 4
+.IX Item "len"
+The length of \fIbuf\fR in bytes.
+.RE
+.RS 4
+.RE
+.IP "log_stdin" 4
+.IX Item "log_stdin"
+.Vb 1
+\& int (*log_stdin)(const char *buf, unsigned int len);
+.Ve
+.Sp
+The \fIlog_stdin\fR function is only used if the standard input does
+not correspond to a tty device.  It is called whenever data can be
+read from the standard input but before it is passed to the running
+command.  This allows the plugin to reject data if it chooses to
+(for instance if the input contains banned content).  Returns \f(CW1\fR
+if the data should be passed to the command, \f(CW0\fR if the data is
+rejected (which will terminate the command) or \f(CW\*(C`\-1\*(C'\fR if an error
+occurred.
+.Sp
+The function arguments are as follows:
+.RS 4
+.IP "buf" 4
+.IX Item "buf"
+The buffer containing user input.
+.IP "len" 4
+.IX Item "len"
+The length of \fIbuf\fR in bytes.
+.RE
+.RS 4
+.RE
+.IP "log_stdout" 4
+.IX Item "log_stdout"
+.Vb 1
+\& int (*log_stdout)(const char *buf, unsigned int len);
+.Ve
+.Sp
+The \fIlog_stdout\fR function is only used if the standard output does
+not correspond to a tty device.  It is called whenever data can be
+read from the command but before it is written to the standard
+output.  This allows the plugin to reject data if it chooses to
+(for instance if the output contains banned content).  Returns \f(CW1\fR
+if the data should be passed to the user, \f(CW0\fR if the data is
+rejected (which will terminate the command) or \f(CW\*(C`\-1\*(C'\fR if an error
+occurred.
+.Sp
+The function arguments are as follows:
+.RS 4
+.IP "buf" 4
+.IX Item "buf"
+The buffer containing command output.
+.IP "len" 4
+.IX Item "len"
+The length of \fIbuf\fR in bytes.
+.RE
+.RS 4
+.RE
+.IP "log_stderr" 4
+.IX Item "log_stderr"
+.Vb 1
+\& int (*log_stderr)(const char *buf, unsigned int len);
+.Ve
+.Sp
+The \fIlog_stderr\fR function is only used if the standard error does
+not correspond to a tty device.  It is called whenever data can be
+read from the command but before it is written to the standard
+error.  This allows the plugin to reject data if it chooses to
+(for instance if the output contains banned content).  Returns \f(CW1\fR
+if the data should be passed to the user, \f(CW0\fR if the data is
+rejected (which will terminate the command) or \f(CW\*(C`\-1\*(C'\fR if an error
+occurred.
+.Sp
+The function arguments are as follows:
+.RS 4
+.IP "buf" 4
+.IX Item "buf"
+The buffer containing command output.
+.IP "len" 4
+.IX Item "len"
+The length of \fIbuf\fR in bytes.
+.RE
+.RS 4
+.RE
+.PP
+\fIVersion macros\fR
+.IX Subsection "Version macros"
+.PP
+Same as for the \*(L"Policy Plugin \s-1API\s0\*(R".
+.SS "Conversation \s-1API\s0"
+.IX Subsection "Conversation API"
+If the plugin needs to interact with the user, it may do so via the
+conversation function.  A plugin should not attempt to read directly
+from the standard input or the user's tty (neither of which are
+guaranteed to exist).  The caller must include a trailing newline
+in \f(CW\*(C`msg\*(C'\fR if one is to be printed.
+.PP
+A printf-style function is also available that can be used to display
+informational or error messages to the user, which is usually more
+convenient for simple messages where no use input is required.
+.PP
+.Vb 11
+\& struct sudo_conv_message {
+\& #define SUDO_CONV_PROMPT_ECHO_OFF  0x0001 /* do not echo user input */
+\& #define SUDO_CONV_PROMPT_ECHO_ON   0x0002 /* echo user input */
+\& #define SUDO_CONV_ERROR_MSG        0x0003 /* error message */
+\& #define SUDO_CONV_INFO_MSG         0x0004 /* informational message */
+\& #define SUDO_CONV_PROMPT_MASK      0x0005 /* mask user input */
+\& #define SUDO_CONV_PROMPT_ECHO_OK   0x1000 /* flag: allow echo if no tty */
+\&     int msg_type;
+\&     int timeout;
+\&     const char *msg;
+\& };
+\&
+\& struct sudo_conv_reply {
+\&     char *reply;
+\& };
+\&
+\& typedef int (*sudo_conv_t)(int num_msgs,
+\&              const struct sudo_conv_message msgs[],
+\&              struct sudo_conv_reply replies[]);
+\&
+\& typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...);
+.Ve
+.PP
+Pointers to the conversation and printf-style functions are passed
+in to the plugin's \f(CW\*(C`open\*(C'\fR function when the plugin is initialized.
+.PP
+To use the conversation function, the plugin must pass an array of
+\&\f(CW\*(C`sudo_conv_message\*(C'\fR and \f(CW\*(C`sudo_conv_reply\*(C'\fR structures.  There must
+be a \f(CW\*(C`struct sudo_conv_message\*(C'\fR and \f(CW\*(C`struct sudo_conv_reply\*(C'\fR for
+each message in the conversation.  The plugin is responsible for
+freeing the reply buffer filled in to the \f(CW\*(C`struct sudo_conv_reply\*(C'\fR,
+if any.
+.PP
+The printf-style function uses the same underlying mechanism as the
+conversation function but only supports \f(CW\*(C`SUDO_CONV_INFO_MSG\*(C'\fR and
+\&\f(CW\*(C`SUDO_CONV_ERROR_MSG\*(C'\fR for the \fImsg_type\fR parameter.  It can be
+more convenient than using the conversation function if no user
+reply is needed and supports standard \fIprintf()\fR escape sequences.
+.PP
+See the sample plugin for an example of the conversation function usage.
+.SS "Sudoers Group Plugin \s-1API\s0"
+.IX Subsection "Sudoers Group Plugin API"
+The \fIsudoers\fR module supports a plugin interface to allow non-Unix
+group lookups.  This can be used to query a group source other than
+the standard Unix group database.  A sample group plugin is bundled
+with \fBsudo\fR that implements file-based lookups.  Third party group
+plugins include a \s-1QAS\s0 \s-1AD\s0 plugin available from Quest Software.
+.PP
+A group plugin must declare and populate a \f(CW\*(C`sudoers_group_plugin\*(C'\fR
+struct in the global scope.  This structure contains pointers to
+the functions that implement plugin initialization, cleanup and
+group lookup.
+.PP
+.Vb 8
+\& struct sudoers_group_plugin {
+\&    unsigned int version;
+\&    int (*init)(int version, sudo_printf_t sudo_printf,
+\&                char *const argv[]);
+\&    void (*cleanup)(void);
+\&    int (*query)(const char *user, const char *group,
+\&                 const struct passwd *pwd);
+\&};
+.Ve
+.PP
+The \f(CW\*(C`sudoers_group_plugin\*(C'\fR struct has the following fields:
+.IP "version" 4
+.IX Item "version"
+The \f(CW\*(C`version\*(C'\fR field should be set to \s-1GROUP_API_VERSION\s0.
+.Sp
+This allows \fIsudoers\fR to determine the \s-1API\s0 version the group plugin
+was built against.
+.IP "init" 4
+.IX Item "init"
+.Vb 2
+\& int (*init)(int version, sudo_printf_t plugin_printf,
+\&             char *const argv[]);
+.Ve
+.Sp
+The \fIinit\fR function is called after \fIsudoers\fR has been parsed but
+before any policy checks.  It returns 1 on success, 0 on failure
+(or if the plugin is not configured), and \-1 if a error occurred.
+If an error occurs, the plugin may call the plugin_printf function
+with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present additional error information
+to the user.
+.Sp
+The function arguments are as follows:
+.RS 4
+.IP "version" 4
+.IX Item "version"
+The version passed in by \fIsudoers\fR allows the plugin to determine the
+major and minor version number of the group plugin \s-1API\s0 supported by
+\&\fIsudoers\fR.
+.IP "plugin_printf" 4
+.IX Item "plugin_printf"
+A pointer to a printf-style function that may be used to display
+informational or error message to the user.
+Returns the number of characters printed on success and \-1 on failure.
+.IP "argv" 4
+.IX Item "argv"
+A NULL-terminated array of arguments generated from the \fIgroup_plugin\fR
+option in \fIsudoers\fR.  If no arguments were given, \fIargv\fR will be
+\&\s-1NULL\s0.
+.RE
+.RS 4
+.RE
+.IP "cleanup" 4
+.IX Item "cleanup"
+.Vb 1
+\& void (*cleanup)();
+.Ve
+.Sp
+The \fIcleanup\fR function is called when \fIsudoers\fR has finished its
+group checks.  The plugin should free any memory it has allocated
+and close open file handles.
+.IP "query" 4
+.IX Item "query"
+.Vb 2
+\& int (*query)(const char *user, const char *group,
+\&              const struct passwd *pwd);
+.Ve
+.Sp
+The \fIquery\fR function is used to ask the group plugin whether \fIuser\fR
+is a member of \fIgroup\fR.
+.Sp
+The function arguments are as follows:
+.RS 4
+.IP "user" 4
+.IX Item "user"
+The name of the user being looked up in the external group database.
+.IP "group" 4
+.IX Item "group"
+The name of the group being queried.
+.IP "pwd" 4
+.IX Item "pwd"
+The password database entry for \fIuser\fR, if any.  If \fIuser\fR is not
+present in the password database, \fIpwd\fR will be \f(CW\*(C`NULL\*(C'\fR.
+.RE
+.RS 4
+.RE
+.PP
+\fIVersion Macros\fR
+.IX Subsection "Version Macros"
+.PP
+.Vb 5
+\& /* Sudoers group plugin version major/minor */
+\& #define GROUP_API_VERSION_MAJOR 1
+\& #define GROUP_API_VERSION_MINOR 0
+\& #define GROUP_API_VERSION ((GROUP_API_VERSION_MAJOR << 16) | \e
+\&                            GROUP_API_VERSION_MINOR)
+\&
+\& /* Getters and setters for group version */
+\& #define GROUP_API_VERSION_GET_MAJOR(v) ((v) >> 16)
+\& #define GROUP_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
+\& #define GROUP_API_VERSION_SET_MAJOR(vp, n) do { \e
+\&     *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \e
+\& } while(0)
+\& #define GROUP_API_VERSION_SET_MINOR(vp, n) do { \e
+\&     *(vp) = (*(vp) & 0xffff0000) | (n); \e
+\& } while(0)
+.Ve
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fIsudoers\fR\|(@mansectform@), \fIsudo\fR\|(@mansectsu@)
+.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-workers mailing list,
+see http://www.sudo.ws/mailman/listinfo/sudo\-workers 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/doc/sudo_plugin.pod b/doc/sudo_plugin.pod
new file mode 100644 (file)
index 0000000..5702180
--- /dev/null
@@ -0,0 +1,1246 @@
+Copyright (c) 2009-2011 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.
+
+=pod
+
+=head1 NAME
+
+sudo_plugin - Sudo Plugin API
+
+=head1 DESCRIPTION
+
+Starting with version 1.8, B<sudo> supports a plugin API
+for policy and session logging.  By default, the I<sudoers> policy
+plugin and an associated I/O logging plugin are used.  Via the plugin
+API, B<sudo> can be configured to use alternate policy and/or I/O
+logging plugins provided by third parties.  The plugins to be used
+are specified via the F<@sysconfdir@/sudo.conf> file.
+
+The API is versioned with a major and minor number.  The minor
+version number is incremented when additions are made.  The major
+number is incremented when incompatible changes are made.  A plugin
+should be check the version passed to it and make sure that the
+major version matches.
+
+The plugin API is defined by the C<sudo_plugin.h> header file.
+
+=head2 The sudo.conf File
+
+The F<@sysconfdir@/sudo.conf> file contains plugin configuration directives.
+Currently, the only supported keyword is the C<Plugin> directive,
+which causes a plugin plugin to be loaded.
+
+A C<Plugin> line consists of the C<Plugin> keyword, followed by the
+I<symbol_name> and the I<path> to the shared object containing the
+plugin.  The I<symbol_name> is the name of the C<struct policy_plugin>
+or C<struct io_plugin> in the plugin shared object.  The I<path>
+may be fully qualified or relative.  If not fully qualified it is
+relative to the F<@prefix@/libexec> directory.  Any additional
+parameters after the I<path> are ignored.  Lines that don't begin
+with C<Plugin> or C<Path> are silently ignored.
+
+The same shared object may contain multiple plugins, each with a
+different symbol name.  The shared object file must be owned by uid
+0 and only writable by its owner.  Because of ambiguities that arise
+from composite policies, only a single policy plugin may be specified.
+This limitation does not apply to I/O plugins.
+
+ #
+ # Default @sysconfdir@/sudo.conf file
+ #
+ # Format:
+ #   Plugin plugin_name plugin_path
+ #   Path askpass /path/to/askpass
+ #
+ # The plugin_path is relative to @prefix@/libexec unless
+ #   fully qualified.
+ # The plugin_name corresponds to a global symbol in the plugin
+ #   that contains the plugin interface structure.
+ #
+ Plugin sudoers_policy sudoers.so
+ Plugin sudoers_io sudoers.so
+
+=head2 Policy Plugin API
+
+A policy plugin must declare and populate a C<policy_plugin> struct
+in the global scope.  This structure contains pointers to the functions
+that implement the B<sudo> policy checks.  The name of the symbol should
+be specified in F<@sysconfdir@/sudo.conf> along with a path to the plugin
+so that B<sudo> can load it.
+
+ struct policy_plugin {
+ #define SUDO_POLICY_PLUGIN    1
+     unsigned int type; /* always SUDO_POLICY_PLUGIN */
+     unsigned int version; /* always SUDO_API_VERSION */
+     int (*open)(unsigned int version, sudo_conv_t conversation,
+                sudo_printf_t plugin_printf, char * const settings[],
+                char * const user_info[], char * const user_env[]);
+     void (*close)(int exit_status, int error);
+     int (*show_version)(int verbose);
+     int (*check_policy)(int argc, char * const argv[],
+                         char *env_add[], char **command_info[],
+                         char **argv_out[], char **user_env_out[]);
+     int (*list)(int argc, char * const argv[], int verbose,
+                 const char *list_user);
+     int (*validate)(void);
+     void (*invalidate)(int remove);
+     int (*init_session)(struct passwd *pwd);
+ };
+
+The policy_plugin struct has the following fields:
+
+=over 4
+
+=item type
+
+The C<type> field should always be set to SUDO_POLICY_PLUGIN.
+
+=item version
+
+The C<version> field should be set to SUDO_API_VERSION.
+
+This allows B<sudo> to determine the API version the plugin was
+built against.
+
+=item open
+
+ int (*open)(unsigned int version, sudo_conv_t conversation,
+             sudo_printf_t plugin_printf, char * const settings[],
+             char * const user_info[], char * const user_env[]);
+
+Returns 1 on success, 0 on failure, -1 if a general error occurred,
+or -2 if there was a usage error.  In the latter case, B<sudo> will
+print a usage message before it exits.  If an error occurs, the
+plugin may optionally call the conversation or plugin_printf function
+with C<SUDO_CONF_ERROR_MSG> to present additional error information
+to the user.
+
+The function arguments are as follows:
+
+=over 4
+
+=item version
+
+The version passed in by B<sudo> allows the plugin to determine the
+major and minor version number of the plugin API supported by
+B<sudo>.
+
+=item conversation
+
+A pointer to the conversation function that can be used by the
+plugin to interact with the user (see below).
+Returns 0 on success and -1 on failure.
+
+=item plugin_printf
+
+A pointer to a printf-style function that may be used to display
+informational or error messages (see below).
+Returns the number of characters printed on success and -1 on failure.
+
+=item settings
+
+A vector of user-supplied B<sudo> settings in the form of "name=value"
+strings.  The vector is terminated by a C<NULL> pointer.  These
+settings correspond to flags the user specified when running B<sudo>.
+As such, they will only be present when the corresponding flag has
+been specified on the command line.
+
+When parsing I<settings>, the plugin should split on the B<first>
+equal sign ('=') since the I<name> field will never include one
+itself but the I<value> might.
+
+=over 4
+
+=item debug_level=number
+
+A numeric debug level, from 1-9, if specified via the C<-D> flag.
+
+=item runas_user=string
+
+The user name or uid to to run the command as, if specified via the
+C<-u> flag.
+
+=item runas_group=string
+
+The group name or gid to to run the command as, if specified via
+the C<-g> flag.
+
+=item prompt=string
+
+The prompt to use when requesting a password, if specified via
+the C<-p> flag.
+
+=item set_home=bool
+
+Set to true if the user specified the C<-H> flag.  If true, set the
+C<HOME> environment variable to the target user's home directory.
+
+=item preserve_environment=bool
+
+Set to true if the user specified the C<-E> flag, indicating that
+the user wishes to preserve the environment.
+
+=item run_shell=bool
+
+Set to true if the user specified the C<-s> flag, indicating that
+the user wishes to run a shell.
+
+=item login_shell=bool
+
+Set to true if the user specified the C<-i> flag, indicating that
+the user wishes to run a login shell.
+
+=item implied_shell=bool
+
+If the user does not specify a program on the command line, B<sudo>
+will pass the plugin the path to the user's shell and set
+I<implied_shell> to true.  This allows B<sudo> with no arguments
+to be used similarly to L<su(1)>.  If the plugin does not to support
+this usage, it may return a value of -2 from the C<check_policy>
+function, which will cause B<sudo> to print a usage message and
+exit.
+
+=item preserve_groups=bool
+
+Set to true if the user specified the C<-P> flag, indicating that
+the user wishes to preserve the group vector instead of setting it
+based on the runas user.
+
+=item ignore_ticket=bool
+
+Set to true if the user specified the C<-k> flag along with a
+command, indicating that the user wishes to ignore any cached
+authentication credentials.
+
+=item noninteractive=bool
+
+Set to true if the user specified the C<-n> flag, indicating that
+B<sudo> should operate in non-interactive mode.  The plugin may
+reject a command run in non-interactive mode if user interaction
+is required.
+
+=item login_class=string
+
+BSD login class to use when setting resource limits and nice value,
+if specified by the C<-c> flag.
+
+=item selinux_role=string
+
+SELinux role to use when executing the command, if specified by
+the C<-r> flag.
+
+=item selinux_type=string
+
+SELinux type to use when executing the command, if specified by
+the C<-t> flag.
+
+=item bsdauth_type=string
+
+Authentication type, if specified by the C<-a> flag, to use on
+systems where BSD authentication is supported.
+
+=item network_addrs=list
+
+A space-separated list of IP network addresses and netmasks in the
+form "addr/netmask", e.g. "192.168.1.2/255.255.255.0".  The address
+and netmask pairs may be either IPv4 or IPv6, depending on what the
+operating system supports.  If the address contains a colon (':'),
+it is an IPv6 address, else it is IPv4.
+
+=item progname=string
+
+The command name that sudo was run as, typically "sudo" or "sudoedit".
+
+=item sudoedit=bool
+
+Set to true when the C<-e> flag is is specified or if invoked as
+B<sudoedit>.  The plugin shall substitute an editor into I<argv>
+in the I<check_policy> function or return C<-2> with a usage error
+if the plugin does not support I<sudoedit>.  For more information,
+see the I<check_policy> section.
+
+=item closefrom=number
+
+If specified, the user has requested via the C<-C> flag that B<sudo>
+close all files descriptors with a value of I<number> or higher.
+The plugin may optionally pass this, or another value, back in the
+I<command_info> list.
+
+=back
+
+Additional settings may be added in the future so the plugin should
+silently ignore settings that it does not recognize.
+
+=item user_info
+
+A vector of information about the user running the command in the form of
+"name=value" strings.  The vector is terminated by a C<NULL> pointer.
+
+When parsing I<user_info>, the plugin should split on the B<first>
+equal sign ('=') since the I<name> field will never include one
+itself but the I<value> might.
+
+=over 4
+
+=item user=string
+
+The name of the user invoking B<sudo>.
+
+=item uid=uid_t
+
+The real user ID of the user invoking B<sudo>.
+
+=item gid=gid_t
+
+The real group ID of the user invoking B<sudo>.
+
+=item groups=list
+
+The user's supplementary group list formatted as a string of
+comma-separated group IDs.
+
+=item cwd=string
+
+The user's current working directory.
+
+=item tty=string
+
+The path to the user's terminal device.  If the user has no terminal
+device associated with the session, the value will be empty, as in
+C<tty=>.
+
+=item host=string
+
+The local machine's hostname as returned by the C<gethostname()>
+system call.
+
+=item lines=int
+
+The number of lines the user's terminal supports.  If there is
+no terminal device available, a default value of 24 is used.
+
+=item cols=int
+
+The number of columns the user's terminal supports.  If there is
+no terminal device available, a default value of 80 is used.
+
+=back
+
+=item user_env
+
+The user's environment in the form of a C<NULL>-terminated vector of
+"name=value" strings.
+
+When parsing I<user_env>, the plugin should split on the B<first>
+equal sign ('=') since the I<name> field will never include one
+itself but the I<value> might.
+
+=back
+
+=item close
+
+ void (*close)(int exit_status, int error);
+
+The C<close> function is called when the command being run by B<sudo>
+finishes.
+
+The function arguments are as follows:
+
+=over 4
+
+=item exit_status
+
+The command's exit status, as returned by the wait(2) system call.
+The value of C<exit_status> is undefined if C<error> is non-zero.
+
+=item error
+
+If the command could not be executed, this is set to the value of
+C<errno> set by the execve(2) system call.  The plugin is responsible
+for displaying error information via the conversation or plugin_printf
+function.  If the command was successfully executed, the value of
+C<error> is 0.
+
+=back
+
+=item show_version
+
+ int (*show_version)(int verbose);
+
+The C<show_version> function is called by B<sudo> when the user specifies
+the C<-V> option.  The plugin may display its version information
+to the user via the conversation or plugin_printf function using
+C<SUDO_CONV_INFO_MSG>.  If the user requests detailed version
+information, the verbose flag will be set.
+
+=item check_policy
+
+ int (*check_policy)(int argc, char * const argv[]
+                     char *env_add[], char **command_info[],
+                     char **argv_out[], char **user_env_out[]);
+
+The I<check_policy> function is called by B<sudo> to determine
+whether the user is allowed to run the specified commands.
+
+If the I<sudoedit> option was enabled in the I<settings> array
+passed to the I<open> function, the user has requested I<sudoedit>
+mode.  I<sudoedit> is a mechanism for editing one or more files
+where an editor is run with the user's credentials instead of with
+elevated privileges.  B<sudo> achieves this by creating user-writable
+temporary copies of the files to be edited and then overwriting the
+originals with the temporary copies after editing is complete.  If
+the plugin supports B<sudoedit>, it should choose the editor to be
+used, potentially from a variable in the user's environment, such
+as C<EDITOR>, and include it in I<argv_out> (note that environment
+variables may include command line flags).  The files to be edited
+should be copied from I<argv> into I<argv_out>, separated from the
+editor and its arguments by a C<"--"> element.  The C<"--"> will
+be removed by B<sudo> before the editor is executed.  The plugin
+should also set I<sudoedit=true> in the I<command_info> list.
+
+The I<check_policy> function returns 1 if the command is allowed,
+0 if not allowed, -1 for a general error, or -2 for a usage error
+or if B<sudoedit> was specified but is unsupported by the plugin.
+In the latter case, B<sudo> will print a usage message before it
+exits.  If an error occurs, the plugin may optionally call the
+conversation or plugin_printf function with C<SUDO_CONF_ERROR_MSG>
+to present additional error information to the user.
+
+The function arguments are as follows:
+
+=over 4
+
+=item argc
+
+The number of elements in I<argv>, not counting the final C<NULL>
+pointer.
+
+=item argv
+
+The argument vector describing the command the user wishes to run,
+in the same form as what would be passed to the execve() system
+call.  The vector is terminated by a C<NULL> pointer.
+
+=item env_add
+
+Additional environment variables specified by the user on the command
+line in the form of a C<NULL>-terminated vector of "name=value"
+strings.  The plugin may reject the command if one or more variables
+are not allowed to be set, or it may silently ignore such variables.
+
+When parsing I<env_add>, the plugin should split on the B<first>
+equal sign ('=') since the I<name> field will never include one
+itself but the I<value> might.
+
+=item command_info
+
+Information about the command being run in the form of "name=value"
+strings.  These values are used by B<sudo> to set the execution
+environment when running a command.  The plugin is responsible for
+creating and populating the vector, which must be terminated with
+a C<NULL> pointer.  The following values are recognized by B<sudo>:
+
+=over 4
+
+=item command=string
+
+Fully qualified path to the command to be executed.
+
+=item runas_uid=uid
+
+User ID to run the command as.
+
+=item runas_euid=uid
+
+Effective user ID to run the command as.
+If not specified, the value of I<runas_uid> is used.
+
+=item runas_gid=gid
+
+Group ID to run the command as.
+
+=item runas_egid=gid
+
+Effective group ID to run the command as.
+If not specified, the value of I<runas_gid> is used.
+
+=item runas_groups=list
+
+The supplementary group vector to use for the command in the form
+of a comma-separated list of group IDs.  If I<preserve_groups>
+is set, this option is ignored.
+
+=item login_class=string
+
+BSD login class to use when setting resource limits and nice value
+(optional).  This option is only set on systems that support login
+classes.
+
+=item preserve_groups=bool
+
+If set, B<sudo> will preserve the user's group vector instead of
+initializing the group vector based on C<runas_user>.
+
+=item cwd=string
+
+The current working directory to change to when executing the command.
+
+=item noexec=bool
+
+If set, prevent the command from executing other programs.
+
+=item chroot=string
+
+The root directory to use when running the command.
+
+=item nice=int
+
+Nice value (priority) to use when executing the command.  The nice
+value, if specified, overrides the priority associated with the
+I<login_class> on BSD systems.
+
+=item umask=octal
+
+The file creation mask to use when executing the command.
+
+=item selinux_role=string
+
+SELinux role to use when executing the command.
+
+=item selinux_type=string
+
+SELinux type to use when executing the command.
+
+=item timeout=int
+
+Command timeout.  If non-zero then when the timeout expires the
+command will be killed.
+
+=item sudoedit=bool
+
+Set to true when in I<sudoedit> mode.  The plugin may enable
+I<sudoedit> mode even if B<sudo> was not invoked as B<sudoedit>.
+This allows the plugin to perform command substitution and transparently
+enable I<sudoedit> when the user attempts to run an editor.
+
+=item closefrom=number
+
+If specified, B<sudo> will close all files descriptors with a value
+of I<number> or higher.
+
+=item iolog_compress=bool
+
+Set to true if the I/O logging plugins, if any, should compress the
+log data.  This is a hint to the I/O logging plugin which may choose
+to ignore it.
+
+=item iolog_path=string
+
+Fully qualified path to the file or directory in which I/O log is
+to be stored.  This is a hint to the I/O logging plugin which may
+choose to ignore it.  If no I/O logging plugin is loaded, this
+setting has no effect.
+
+=item iolog_stdin=bool
+
+Set to true if the I/O logging plugins, if any, should log the
+standard input if it is not connected to a terminal device.  This
+is a hint to the I/O logging plugin which may choose to ignore it.
+
+=item iolog_stdout=bool
+
+Set to true if the I/O logging plugins, if any, should log the
+standard output if it is not connected to a terminal device.  This
+is a hint to the I/O logging plugin which may choose to ignore it.
+
+=item iolog_stderr=bool
+
+Set to true if the I/O logging plugins, if any, should log the
+standard error if it is not connected to a terminal device.  This
+is a hint to the I/O logging plugin which may choose to ignore it.
+
+=item iolog_ttyin=bool
+
+Set to true if the I/O logging plugins, if any, should log all
+terminal input.  This only includes input typed by the user and not
+from a pipe or redirected from a file.  This is a hint to the I/O
+logging plugin which may choose to ignore it.
+
+=item iolog_ttyout=bool
+
+Set to true if the I/O logging plugins, if any, should log all
+terminal output.  This only includes output to the screen, not
+output to a pipe or file.  This is a hint to the I/O logging plugin
+which may choose to ignore it.
+
+=item use_pty=bool
+
+Allocate a pseudo-tty to run the command in, regardless of whether
+or not I/O logging is in use.  By default, B<sudo> will only run
+the command in a pty when an I/O log plugin is loaded.
+
+=item set_utmp=bool
+
+Create a utmp (or utmpx) entry when a pseudo-tty is allocated.  By
+default, the new entry will be a copy of the user's existing utmp
+entry (if any), with the tty, time, type and pid fields updated.
+
+=item utmp_user=string
+
+User name to use when constructing a new utmp (or utmpx) entry when
+I<set_utmp> is enabled.  This option can be used to set the user
+field in the utmp entry to the user the command runs as rather than
+the invoking user.  If not set, B<sudo> will base the new entry on
+the invoking user's existing entry.
+
+=back
+
+Unsupported values will be ignored.
+
+=item argv_out
+
+The C<NULL>-terminated argument vector to pass to the execve()
+system call when executing the command.  The plugin is responsible
+for allocating and populating the vector.
+
+=item user_env_out
+
+The C<NULL>-terminated environment vector to use when executing the
+command.  The plugin is responsible for allocating and populating
+the vector.
+
+=back
+
+=item list
+
+ int (*list)(int verbose, const char *list_user,
+             int argc, char * const argv[]);
+
+List available privileges for the invoking user.  Returns 1 on
+success, 0 on failure and -1 on error.  On error, the plugin may
+optionally call the conversation or plugin_printf function with
+C<SUDO_CONF_ERROR_MSG> to present additional error information to
+the user.
+
+Privileges should be output via the conversation or plugin_printf
+function using C<SUDO_CONV_INFO_MSG>.
+
+=over 4
+
+=item verbose
+
+Flag indicating whether to list in verbose mode or not.
+
+=item list_user
+
+The name of a different user to list privileges for if the policy
+allows it.  If C<NULL>, the plugin should list the privileges of
+the invoking user.
+
+=item argc
+
+The number of elements in I<argv>, not counting the final C<NULL>
+pointer.
+
+=item argv
+
+If non-C<NULL>, an argument vector describing a command the user
+wishes to check against the policy in the same form as what would
+be passed to the execve() system call.  If the command is permitted
+by the policy, the fully-qualified path to the command should be
+displayed along with any command line arguments.
+
+=back
+
+=item validate
+
+ int (*validate)(void);
+
+The C<validate> function is called when B<sudo> is run with the
+C<-v> flag.  For policy plugins such as I<sudoers> that cache
+authentication credentials, this function will validate and cache
+the credentials.
+
+The C<validate> function should be C<NULL> if the plugin does not
+support credential caching.
+
+Returns 1 on success, 0 on failure and -1 on error.
+On error, the plugin may optionally call the conversation or plugin_printf
+function with C<SUDO_CONF_ERROR_MSG> to present additional
+error information to the user.
+
+=item invalidate
+
+ void (*invalidate)(int remove);
+
+The C<invalidate> function is called when B<sudo> is called with
+the C<-k> or C<-K> flag.  For policy plugins such as I<sudoers> that
+cache authentication credentials, this function will invalidate the
+credentials.  If the I<remove> flag is set, the plugin may remove
+the credentials instead of simply invalidating them.
+
+The C<invalidate> function should be C<NULL> if the plugin does not
+support credential caching.
+
+=item init_session
+
+ int (*init_session)(struct passwd *pwd);
+
+The C<init_session> function is called when B<sudo> sets up the
+execution environment for the command, immediately before the
+contents of the I<command_info> list are applied (before the uid
+changes).  This can be used to do session setup that is not supported
+by I<command_info>, such as opening the PAM session.
+
+The I<pwd> argument points to a passwd struct for the user the
+command will be run as if the uid the command will run as was found
+in the password database, otherwise it will be NULL.
+
+Returns 1 on success, 0 on failure and -1 on error.
+On error, the plugin may optionally call the conversation or plugin_printf
+function with C<SUDO_CONF_ERROR_MSG> to present additional
+error information to the user.
+
+=back
+
+=head3 Version macros
+
+ #define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16)
+ #define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
+ #define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \
+     *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \
+ } while(0)
+ #define SUDO_VERSION_SET_MINOR(vp, n) do { \
+     *(vp) = (*(vp) & 0xffff0000) | (n); \
+ } while(0)
+
+ #define SUDO_API_VERSION_MAJOR 1
+ #define SUDO_API_VERSION_MINOR 0
+ #define SUDO_API_VERSION ((SUDO_API_VERSION_MAJOR << 16) | \
+                           SUDO_API_VERSION_MINOR)
+
+=head2 I/O Plugin API
+
+ struct io_plugin {
+ #define SUDO_IO_PLUGIN                2
+     unsigned int type; /* always SUDO_IO_PLUGIN */
+     unsigned int version; /* always SUDO_API_VERSION */
+     int (*open)(unsigned int version, sudo_conv_t conversation
+                 sudo_printf_t plugin_printf, char * const settings[],
+                 char * const user_info[], int argc, char * const argv[],
+                 char * const user_env[]);
+     void (*close)(int exit_status, int error); /* wait status or error */
+     int (*show_version)(int verbose);
+     int (*log_ttyin)(const char *buf, unsigned int len);
+     int (*log_ttyout)(const char *buf, unsigned int len);
+     int (*log_stdin)(const char *buf, unsigned int len);
+     int (*log_stdout)(const char *buf, unsigned int len);
+     int (*log_stderr)(const char *buf, unsigned int len);
+ };
+
+When an I/O plugin is loaded, B<sudo> runs the command in a pseudo-tty.
+This makes it possible to log the input and output from the user's
+session.  If any of the standard input, standard output or standard
+error do not correspond to a tty, B<sudo> will open a pipe to capture
+the I/O for logging before passing it on.
+
+The log_ttyin function receives the raw user input from the terminal
+device (note that this will include input even when echo is disabled,
+such as when a password is read). The log_ttyout function receives
+output from the pseudo-tty that is suitable for replaying the user's
+session at a later time.  The log_stdin, log_stdout and log_stderr
+functions are only called if the standard input, standard output
+or standard error respectively correspond to something other than
+a tty.
+
+Any of the logging functions may be set to the NULL
+pointer if no logging is to be performed.  If the open function
+returns C<0>, no I/O will be sent to the plugin.
+
+The io_plugin struct has the following fields:
+
+=over 4
+
+=item type
+
+The C<type> field should always be set to SUDO_IO_PLUGIN
+
+=item version
+
+The C<version> field should be set to SUDO_API_VERSION.
+
+This allows B<sudo> to determine the API version the plugin was
+built against.
+
+=item open
+
+ int (*open)(unsigned int version, sudo_conv_t conversation
+             sudo_printf_t plugin_printf, char * const settings[],
+             char * const user_info[], int argc, char * const argv[],
+             char * const user_env[]);
+
+The I<open> function is run before the I<log_input>, I<log_output>
+or I<show_version> functions are called.  It is only called if the
+version is being requested or the I<check_policy> function has
+returned successfully.  It returns 1 on success, 0 on failure, -1
+if a general error occurred, or -2 if there was a usage error.  In
+the latter case, B<sudo> will print a usage message before it exits.
+If an error occurs, the plugin may optionally call the conversation
+or plugin_printf function with C<SUDO_CONF_ERROR_MSG> to present
+additional error information to the user.
+
+The function arguments are as follows:
+
+=over 4
+
+=item version
+
+The version passed in by B<sudo> allows the plugin to determine the
+major and minor version number of the plugin API supported by
+B<sudo>.
+
+=item conversation
+
+A pointer to the conversation function that may be used by the
+I<show_version> function to display version information (see
+show_version below).  The conversation function may also be used
+to display additional error message to the user.
+The conversation function returns 0 on success and -1 on failure.
+
+=item plugin_printf
+
+A pointer to a printf-style function that may be used by the
+I<show_version> function to display version information (see
+show_version below).  The plugin_printf function may also be used
+to display additional error message to the user.
+The plugin_printf function returns number of characters printed on
+success and -1 on failure.
+
+=item settings
+
+A vector of user-supplied B<sudo> settings in the form of "name=value"
+strings.  The vector is terminated by a C<NULL> pointer.  These
+settings correspond to flags the user specified when running B<sudo>.
+As such, they will only be present when the corresponding flag has
+been specified on the command line.
+
+When parsing I<settings>, the plugin should split on the B<first>
+equal sign ('=') since the I<name> field will never include one
+itself but the I<value> might.
+
+See the L<Policy Plugin API> section for a list of all possible settings.
+
+=item user_info
+
+A vector of information about the user running the command in the form of
+"name=value" strings.  The vector is terminated by a C<NULL> pointer.
+
+When parsing I<user_info>, the plugin should split on the B<first>
+equal sign ('=') since the I<name> field will never include one
+itself but the I<value> might.
+
+See the L<Policy Plugin API> section for a list of all possible strings.
+
+=item argc
+
+The number of elements in I<argv>, not counting the final C<NULL>
+pointer.
+
+=item argv
+
+If non-C<NULL>, an argument vector describing a command the user
+wishes to run in the same form as what would be passed to the
+execve() system call.
+
+=item user_env
+
+The user's environment in the form of a C<NULL>-terminated vector of
+"name=value" strings.
+
+When parsing I<user_env>, the plugin should split on the B<first>
+equal sign ('=') since the I<name> field will never include one
+itself but the I<value> might.
+
+=back
+
+=item close
+
+ void (*close)(int exit_status, int error);
+
+The C<close> function is called when the command being run by B<sudo>
+finishes.
+
+The function arguments are as follows:
+
+=over 4
+
+=item exit_status
+
+The command's exit status, as returned by the wait(2) system call.
+The value of C<exit_status> is undefined if C<error> is non-zero.
+
+=item error
+
+If the command could not be executed, this is set to the value of
+C<errno> set by the execve(2) system call.  If the command was
+successfully executed, the value of C<error> is 0.
+
+=back
+
+=item show_version
+
+ int (*show_version)(int verbose);
+
+The C<show_version> function is called by B<sudo> when the user specifies
+the C<-V> option.  The plugin may display its version information
+to the user via the conversation or plugin_printf function using
+C<SUDO_CONV_INFO_MSG>.  If the user requests detailed version
+information, the verbose flag will be set.
+
+=item log_ttyin
+
+ int (*log_ttyin)(const char *buf, unsigned int len);
+
+The I<log_ttyin> function is called whenever data can be read from
+the user but before it is passed to the running command.  This
+allows the plugin to reject data if it chooses to (for instance
+if the input contains banned content).  Returns C<1> if the data
+should be passed to the command, C<0> if the data is rejected
+(which will terminate the command) or C<-1> if an error occurred.
+
+The function arguments are as follows:
+
+=over 4
+
+=item buf
+
+The buffer containing user input.
+
+=item len
+
+The length of I<buf> in bytes.
+
+=back
+
+=item log_ttyout
+
+ int (*log_ttyout)(const char *buf, unsigned int len);
+
+The I<log_ttyout> function is called whenever data can be read from
+the command but before it is written to the user's terminal.  This
+allows the plugin to reject data if it chooses to (for instance
+if the output contains banned content).  Returns C<1> if the data
+should be passed to the user, C<0> if the data is rejected
+(which will terminate the command) or C<-1> if an error occurred.
+
+The function arguments are as follows:
+
+=over 4
+
+=item buf
+
+The buffer containing command output.
+
+=item len
+
+The length of I<buf> in bytes.
+
+=back
+
+=item log_stdin
+
+ int (*log_stdin)(const char *buf, unsigned int len);
+
+The I<log_stdin> function is only used if the standard input does
+not correspond to a tty device.  It is called whenever data can be
+read from the standard input but before it is passed to the running
+command.  This allows the plugin to reject data if it chooses to
+(for instance if the input contains banned content).  Returns C<1>
+if the data should be passed to the command, C<0> if the data is
+rejected (which will terminate the command) or C<-1> if an error
+occurred.
+
+The function arguments are as follows:
+
+=over 4
+
+=item buf
+
+The buffer containing user input.
+
+=item len
+
+The length of I<buf> in bytes.
+
+=back
+
+=item log_stdout
+
+ int (*log_stdout)(const char *buf, unsigned int len);
+
+The I<log_stdout> function is only used if the standard output does
+not correspond to a tty device.  It is called whenever data can be
+read from the command but before it is written to the standard
+output.  This allows the plugin to reject data if it chooses to
+(for instance if the output contains banned content).  Returns C<1>
+if the data should be passed to the user, C<0> if the data is
+rejected (which will terminate the command) or C<-1> if an error
+occurred.
+
+The function arguments are as follows:
+
+=over 4
+
+=item buf
+
+The buffer containing command output.
+
+=item len
+
+The length of I<buf> in bytes.
+
+=back
+
+=item log_stderr
+
+ int (*log_stderr)(const char *buf, unsigned int len);
+
+The I<log_stderr> function is only used if the standard error does
+not correspond to a tty device.  It is called whenever data can be
+read from the command but before it is written to the standard
+error.  This allows the plugin to reject data if it chooses to
+(for instance if the output contains banned content).  Returns C<1>
+if the data should be passed to the user, C<0> if the data is
+rejected (which will terminate the command) or C<-1> if an error
+occurred.
+
+The function arguments are as follows:
+
+=over 4
+
+=item buf
+
+The buffer containing command output.
+
+=item len
+
+The length of I<buf> in bytes.
+
+=back
+
+=back
+
+=head3 Version macros
+
+Same as for the L<Policy Plugin API>.
+
+=head2 Conversation API
+
+If the plugin needs to interact with the user, it may do so via the
+conversation function.  A plugin should not attempt to read directly
+from the standard input or the user's tty (neither of which are
+guaranteed to exist).  The caller must include a trailing newline
+in C<msg> if one is to be printed.
+
+A printf-style function is also available that can be used to display
+informational or error messages to the user, which is usually more
+convenient for simple messages where no use input is required.
+
+ struct sudo_conv_message {
+ #define SUDO_CONV_PROMPT_ECHO_OFF  0x0001 /* do not echo user input */
+ #define SUDO_CONV_PROMPT_ECHO_ON   0x0002 /* echo user input */
+ #define SUDO_CONV_ERROR_MSG       0x0003 /* error message */
+ #define SUDO_CONV_INFO_MSG        0x0004 /* informational message */
+ #define SUDO_CONV_PROMPT_MASK     0x0005 /* mask user input */
+ #define SUDO_CONV_PROMPT_ECHO_OK   0x1000 /* flag: allow echo if no tty */
+     int msg_type;
+     int timeout;
+     const char *msg;
+ };
+
+ struct sudo_conv_reply {
+     char *reply;
+ };
+
+ typedef int (*sudo_conv_t)(int num_msgs,
+             const struct sudo_conv_message msgs[],
+              struct sudo_conv_reply replies[]);
+
+ typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...);
+
+Pointers to the conversation and printf-style functions are passed
+in to the plugin's C<open> function when the plugin is initialized.
+
+To use the conversation function, the plugin must pass an array of
+C<sudo_conv_message> and C<sudo_conv_reply> structures.  There must
+be a C<struct sudo_conv_message> and C<struct sudo_conv_reply> for
+each message in the conversation.  The plugin is responsible for
+freeing the reply buffer filled in to the C<struct sudo_conv_reply>,
+if any.
+
+The printf-style function uses the same underlying mechanism as the
+conversation function but only supports C<SUDO_CONV_INFO_MSG> and
+C<SUDO_CONV_ERROR_MSG> for the I<msg_type> parameter.  It can be
+more convenient than using the conversation function if no user
+reply is needed and supports standard printf() escape sequences.
+
+See the sample plugin for an example of the conversation function usage.
+
+=head2 Sudoers Group Plugin API
+
+The I<sudoers> module supports a plugin interface to allow non-Unix
+group lookups.  This can be used to query a group source other than
+the standard Unix group database.  A sample group plugin is bundled
+with B<sudo> that implements file-based lookups.  Third party group
+plugins include a QAS AD plugin available from Quest Software.
+
+A group plugin must declare and populate a C<sudoers_group_plugin>
+struct in the global scope.  This structure contains pointers to
+the functions that implement plugin initialization, cleanup and
+group lookup.
+
+ struct sudoers_group_plugin {
+    unsigned int version;
+    int (*init)(int version, sudo_printf_t sudo_printf,
+                char *const argv[]);
+    void (*cleanup)(void);
+    int (*query)(const char *user, const char *group,
+                 const struct passwd *pwd);
+};
+
+The C<sudoers_group_plugin> struct has the following fields:
+
+=over 4
+
+=item version
+
+The C<version> field should be set to GROUP_API_VERSION.
+
+This allows I<sudoers> to determine the API version the group plugin
+was built against.
+
+=item init
+
+ int (*init)(int version, sudo_printf_t plugin_printf,
+             char *const argv[]);
+
+The I<init> function is called after I<sudoers> has been parsed but
+before any policy checks.  It returns 1 on success, 0 on failure
+(or if the plugin is not configured), and -1 if a error occurred.
+If an error occurs, the plugin may call the plugin_printf function
+with C<SUDO_CONF_ERROR_MSG> to present additional error information
+to the user.
+
+The function arguments are as follows:
+
+=over 4
+
+=item version
+
+The version passed in by I<sudoers> allows the plugin to determine the
+major and minor version number of the group plugin API supported by
+I<sudoers>.
+
+=item plugin_printf
+
+A pointer to a printf-style function that may be used to display
+informational or error message to the user.
+Returns the number of characters printed on success and -1 on failure.
+
+=item argv
+
+A NULL-terminated array of arguments generated from the I<group_plugin>
+option in I<sudoers>.  If no arguments were given, I<argv> will be
+NULL.
+
+=back
+
+=item cleanup
+
+ void (*cleanup)();
+
+The I<cleanup> function is called when I<sudoers> has finished its
+group checks.  The plugin should free any memory it has allocated
+and close open file handles.
+
+=item query
+
+ int (*query)(const char *user, const char *group,
+              const struct passwd *pwd);
+
+The I<query> function is used to ask the group plugin whether I<user>
+is a member of I<group>.
+
+The function arguments are as follows:
+
+=over 4
+
+=item user
+
+The name of the user being looked up in the external group database.
+
+=item group
+
+The name of the group being queried.
+
+=item pwd
+
+The password database entry for I<user>, if any.  If I<user> is not
+present in the password database, I<pwd> will be C<NULL>.
+
+=back
+
+=back
+
+=head3 Version Macros
+
+ /* Sudoers group plugin version major/minor */
+ #define GROUP_API_VERSION_MAJOR 1
+ #define GROUP_API_VERSION_MINOR 0
+ #define GROUP_API_VERSION ((GROUP_API_VERSION_MAJOR << 16) | \
+                            GROUP_API_VERSION_MINOR)
+
+ /* Getters and setters for group version */
+ #define GROUP_API_VERSION_GET_MAJOR(v) ((v) >> 16)
+ #define GROUP_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
+ #define GROUP_API_VERSION_SET_MAJOR(vp, n) do { \
+     *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \
+ } while(0)
+ #define GROUP_API_VERSION_SET_MINOR(vp, n) do { \
+     *(vp) = (*(vp) & 0xffff0000) | (n); \
+ } while(0)
+
+=head1 SEE ALSO
+
+L<sudoers(5)>, L<sudo(8)>
+
+=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-workers mailing list,
+see http://www.sudo.ws/mailman/listinfo/sudo-workers 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.
diff --git a/doc/sudoers.cat b/doc/sudoers.cat
new file mode 100644 (file)
index 0000000..a30ffc7
--- /dev/null
@@ -0,0 +1,1684 @@
+SUDOERS(4)                   MAINTENANCE COMMANDS                   SUDOERS(4)
+
+
+
+N\bNA\bAM\bME\bE
+       sudoers - default sudo security policy module
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+       The _\bs_\bu_\bd_\bo_\be_\br_\bs policy module determines a user's s\bsu\bud\bdo\bo privileges.  It is
+       the default s\bsu\bud\bdo\bo policy plugin.  The policy is driven by the
+       _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs file or, optionally in LDAP.  The policy format is
+       described in detail in the "SUDOERS FILE FORMAT" section.  For
+       information on storing _\bs_\bu_\bd_\bo_\be_\br_\bs policy information in LDAP, please see
+       _\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bl_\bd_\ba_\bp(4).
+
+   A\bAu\but\bth\bhe\ben\bnt\bti\bic\bca\bat\bti\bio\bon\bn a\ban\bnd\bd L\bLo\bog\bgg\bgi\bin\bng\bg
+       The _\bs_\bu_\bd_\bo_\be_\br_\bs security policy requires that most users authenticate
+       themselves before they can use s\bsu\bud\bdo\bo.  A password is not required if the
+       invoking user is root, if the target user is the same as the invoking
+       user, or if the policy has disabled authentication for the user or
+       command.  Unlike _\bs_\bu(1), when _\bs_\bu_\bd_\bo_\be_\br_\bs requires authentication, it
+       validates the invoking user's credentials, not the target user's (or
+       root's) credentials.  This can be changed via the _\br_\bo_\bo_\bt_\bp_\bw, _\bt_\ba_\br_\bg_\be_\bt_\bp_\bw and
+       _\br_\bu_\bn_\ba_\bs_\bp_\bw flags, described later.
+
+       If a user who is not listed in the policy tries to run a command via
+       s\bsu\bud\bdo\bo, mail is sent to the proper authorities.  The address used for
+       such mail is configurable via the _\bm_\ba_\bi_\bl_\bt_\bo Defaults entry (described
+       later) and defaults to root.
+
+       Note that mail will not be sent if an unauthorized user tries to run
+       s\bsu\bud\bdo\bo 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 s\bsu\bud\bdo\bo is run by root and the SUDO_USER environment variable is set,
+       the _\bs_\bu_\bd_\bo_\be_\br_\bs policy 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 invoked via a sudo-run script or program.  Note,
+       however, that the _\bs_\bu_\bd_\bo_\be_\br_\bs lookup is still done for root, not the user
+       specified by SUDO_USER.
+
+       _\bs_\bu_\bd_\bo_\be_\br_\bs uses time stamp files for credential caching.  Once a user has
+       been authenticated, a time stamp is updated and the user may then use
+       sudo without a password for a short period of time (5 minutes unless
+       overridden by the _\bt_\bi_\bm_\be_\bo_\bu_\bt option.  By default, _\bs_\bu_\bd_\bo_\be_\br_\bs uses a tty-based
+       time stamp which means that there is a separate time stamp for each of
+       a user's login sessions.  The _\bt_\bt_\by_\b__\bt_\bi_\bc_\bk_\be_\bt_\bs option can be disabled to
+       force the use of a single time stamp for all of a user's sessions.
+
+       _\bs_\bu_\bd_\bo_\be_\br_\bs 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, _\bs_\bu_\bd_\bo_\be_\br_\bs will
+       log via _\bs_\by_\bs_\bl_\bo_\bg(3) but this is changeable via the _\bs_\by_\bs_\bl_\bo_\bg and _\bl_\bo_\bg_\bf_\bi_\bl_\be
+       Defaults settings.
+
+       _\bs_\bu_\bd_\bo_\be_\br_\bs also supports logging a command's input and output streams.
+       I/O logging is not on by default but can be enabled using the _\bl_\bo_\bg_\b__\bi_\bn_\bp_\bu_\bt
+       and _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt Defaults flags as well as the LOG_INPUT and LOG_OUTPUT
+       command tags.
+
+   C\bCo\bom\bmm\bma\ban\bnd\bd E\bEn\bnv\bvi\bir\bro\bon\bnm\bme\ben\bnt\bt
+       Since environment variables can influence program behavior, _\bs_\bu_\bd_\bo_\be_\br_\bs
+       provides a means to restrict which variables from the user's
+       environment are inherited by the command to be run.  There are two
+       distinct ways _\bs_\bu_\bd_\bo_\be_\br_\bs can deal with environment variables.
+
+       By default, the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is enabled.  This causes commands to
+       be executed with a minimal environment containing TERM, PATH, HOME,
+       MAIL, 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 options.
+       This is effectively a whitelist for environment variables.
+
+       If, however, the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is disabled, 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.
+
+       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.
+
+       As a special case, If s\bsu\bud\bdo\bo's -\b-i\bi option (initial login) is specified,
+       _\bs_\bu_\bd_\bo_\be_\br_\bs will initialize the environment regardless of the value of
+       _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt.  The _\bD_\bI_\bS_\bP_\bL_\bA_\bY, _\bP_\bA_\bT_\bH and _\bT_\bE_\bR_\bM variables remain unchanged;
+       _\bH_\bO_\bM_\bE, _\bM_\bA_\bI_\bL, _\bS_\bH_\bE_\bL_\bL, _\bU_\bS_\bE_\bR, and _\bL_\bO_\bG_\bN_\bA_\bM_\bE are set based on the target user.
+       On Linux and AIX systems the contents of _\b/_\be_\bt_\bc_\b/_\be_\bn_\bv_\bi_\br_\bo_\bn_\bm_\be_\bn_\bt are also
+       included.  All other environment variables are removed.
+
+S\bSU\bUD\bDO\bOE\bER\bRS\bS F\bFI\bIL\bLE\bE F\bFO\bOR\bRM\bMA\bAT\bT
+       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).
+
+       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_\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 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) may appear
+           zero 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).
+
+   A\bAl\bli\bia\bas\bse\bes\bs
+       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
+
+        Host_Alias ::= NAME '=' Host_List
+
+        Cmnd_Alias ::= NAME '=' Cmnd_List
+
+        NAME ::= [A-Z]([A-Z][0-9]_)*
+
+       Each _\ba_\bl_\bi_\ba_\bs definition is of the form
+
+        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 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.
+
+        User_List ::= User |
+                      User ',' User_List
+
+        User ::= '!'* user name |
+                 '!'* #uid |
+                 '!'* %group |
+                 '!'* %#gid |
+                 '!'* +netgroup |
+                 '!'* %:nonunix_group |
+                 '!'* %:#nonunix_gid |
+                 '!'* User_Alias
+
+       A User_List is made up of one or more user names, user ids (prefixed
+       with '#'), system group names and ids (prefixed with '%' and '%#'
+       respectively), netgroups (prefixed with '+'), non-Unix group names and
+       IDs (prefixed with '%:' and '%:#' respectively) 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.
+
+       A user name, uid, group, gid, netgroup, nonunix_group or nonunix_gid
+       may be enclosed in double quotes to avoid the need for escaping special
+       characters.  Alternately, special characters may be specified in
+       escaped hex mode, e.g. \x20 for space.  When using double quotes, any
+       prefix characters must be included inside the quotes.
+
+       The actual nonunix_group and nonunix_gid syntax depends on the
+       underlying group provider plugin (see the _\bg_\br_\bo_\bu_\bp_\b__\bp_\bl_\bu_\bg_\bi_\bn description
+       below).  For instance, the QAS AD plugin supports the following
+       formats:
+
+       +\bo   Group in the same domain: "Group Name"
+
+       +\bo   Group in any domain: "Group Name@FULLY.QUALIFIED.DOMAIN"
+
+       +\bo   Group SID: "S-1-2-34-5678901234-5678901234-5678901234-567"
+
+       Note that quotes around group names are optional.  Unquoted strings
+       must use a backslash (\) to escape spaces and special characters.  See
+       "Other special characters and reserved words" for a list of characters
+       that need to be escaped.
+
+        Runas_List ::= Runas_Member |
+                       Runas_Member ',' Runas_List
+
+        Runas_Member ::= '!'* user name |
+                         '!'* #uid |
+                         '!'* %group |
+                         '!'* %#gid |
+                         '!'* %:nonunix_group |
+                         '!'* %:#nonunix_gid |
+                         '!'* +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 user names 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 user names 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
+
+        Host ::= '!'* host name |
+                 '!'* ip_addr |
+                 '!'* network(/netmask)? |
+                 '!'* +netgroup |
+                 '!'* Host_Alias
+
+       A Host_List is made up of one or more host names, 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 host name may include
+       shell-style wildcards (see the Wildcards section below), but unless the
+       host name command on your machine returns the fully qualified host
+       name, you'll need to use the _\bf_\bq_\bd_\bn option for wildcards to be useful.
+       Note s\bsu\bud\bdo\bo only inspects actual network interfaces; this means that IP
+       address 127.0.0.1 (localhost) will never match.  Also, the host name
+       "localhost" will only match if that is the actual host name, which is
+       usually only the case for non-networked systems.
+
+        Cmnd_List ::= Cmnd |
+                      Cmnd ',' Cmnd_List
+
+        commandname ::= file name |
+                        file name args |
+                        file name '""'
+
+        Cmnd ::= '!'* commandname |
+                 '!'* directory |
+                 '!'* "sudoedit" |
+                 '!'* Cmnd_Alias
+
+       A Cmnd_List is a list of one or more commandnames, directories, and
+       other aliases.  A commandname is a fully qualified file name which may
+       include shell-style wildcards (see the Wildcards section below).  A
+       simple file name 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 path name 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.
+
+   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, 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
+
+        Parameter_List ::= Parameter |
+                           Parameter ',' Parameter_List
+
+        Parameter ::= Parameter '=' Value |
+                      Parameter '+=' Value |
+                      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 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.
+
+       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
+        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? SELinux_Spec? Tag_Spec* Cmnd
+
+        Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
+
+        SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
+
+        Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' |
+                      'SETENV:' | 'NOSETENV:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' |
+                      'LOG_OUTPUT:' | 'NOLOG_OUTPUT:')
+
+       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.
+
+       The basic structure of a user specification is `who where = (as_whom)
+       what'.  Let's break that down into its constituent parts:
+
+   R\bRu\bun\bna\bas\bs_\b_S\bSp\bpe\bec\bc
+       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.,
+
+        $ 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:
+
+        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_\bl
+       and _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bl_\bp_\br_\bm as r\bro\boo\bot\bt.
+
+       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
+
+       Note that while the group portion of the Runas_Spec permits the user to
+       run as command with that group, it does not force the user to do so.
+       If no group is specified on the command line, the command will run with
+       the group listed in the target user's password database entry.  The
+       following would all be permitted by the sudoers entry above:
+
+        $ sudo -u operator /bin/ls
+        $ sudo -u operator -g operator /bin/ls
+        $ sudo -g operator /bin/ls
+
+       In the following example, user t\btc\bcm\bm may run commands that access a modem
+       device file with the dialer group.
+
+        tcm    boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \
+               /usr/local/bin/minicom
+
+       Note that in this example only the group will be set, the command still
+       runs as user t\btc\bcm\bm.  E.g.
+
+        $ sudo -g dialer /usr/bin/cu
+
+       Multiple users and groups may be present in a Runas_Spec, in which case
+       the user may select any combination of users and groups via the -\b-u\bu and
+       -\b-g\bg options.  In this example:
+
+        alan   ALL = (root, bin : operator, system) ALL
+
+       user a\bal\bla\ban\bn may run any command as either user root or bin, optionally
+       setting the group to operator or system.
+
+   S\bSE\bEL\bLi\bin\bnu\bux\bx_\b_S\bSp\bpe\bec\bc
+       On systems with SELinux support, _\bs_\bu_\bd_\bo_\be_\br_\bs entries may optionally have an
+       SELinux role and/or type associated with a command.  If a role or type
+       is specified with the command it will override any default values
+       specified in _\bs_\bu_\bd_\bo_\be_\br_\bs.  A role or type specified on the command line,
+       however, will supercede the values in _\bs_\bu_\bd_\bo_\be_\br_\bs.
+
+   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,
+       NOSETENV, LOG_INPUT, NOLOG_INPUT, LOG_OUTPUT and NOLOG_OUTPUT.  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:
+
+        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 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.
+
+       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.
+
+       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.
+
+       _\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, the user may
+       disable the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option from the command line via the -\b-E\bE option.
+       Additionally, environment variables set on 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.  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 NOSETENV tag.
+
+       _\bL_\bO_\bG_\b__\bI_\bN_\bP_\bU_\bT _\ba_\bn_\bd _\bN_\bO_\bL_\bO_\bG_\b__\bI_\bN_\bP_\bU_\bT
+
+       These tags override the value of the _\bl_\bo_\bg_\b__\bi_\bn_\bp_\bu_\bt option on a per-command
+       basis.  For more information, see the description of _\bl_\bo_\bg_\b__\bi_\bn_\bp_\bu_\bt in the
+       "SUDOERS OPTIONS" section below.
+
+       _\bL_\bO_\bG_\b__\bO_\bU_\bT_\bP_\bU_\bT _\ba_\bn_\bd _\bN_\bO_\bL_\bO_\bG_\b__\bO_\bU_\bT_\bP_\bU_\bT
+
+       These tags override the value of the _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt option on a per-command
+       basis.  For more information, see the description of _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt in the
+       "SUDOERS OPTIONS" section below.
+
+   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 characters) to be
+       used in host names, path names 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 _\bg_\bl_\bo_\bb(3) and
+       _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3) routines.  Note that these are _\bn_\bo_\bt regular expressions.
+
+       *       Matches any set of zero or more characters.
+
+       ?       Matches any single character.
+
+       [...]   Matches any character in the specified range.
+
+       [!...]  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 "}".
+
+       POSIX character classes may also be used if your system's _\bg_\bl_\bo_\bb(3) and
+       _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3) functions support 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\:]]*
+
+       Would match any file name beginning with a letter.
+
+       Note that a forward slash ('/') will n\bno\bot\bt be matched by wildcards used
+       in the path name.  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/*
+
+       match _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bw_\bh_\bo but not _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bX_\b1_\b1_\b/_\bx_\bt_\be_\br_\bm.
+
+   E\bEx\bxc\bce\bep\bpt\bti\bio\bon\bns\bs t\bto\bo w\bwi\bil\bld\bdc\bca\bar\brd\bd r\bru\bul\ble\bes\bs
+       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 command is not allowed to be run
+               with a\ban\bny\by arguments.
+
+   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
+       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 and #includedir
+       directives.
+
+       This can be used, for example, to keep a site-wide _\bs_\bu_\bd_\bo_\be_\br_\bs file in
+       addition to a local, per-machine file.  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 within
+       _\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:
+
+           #include /etc/sudoers.local
+
+       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.
+
+       The file name may include the %h escape, signifying the short form of
+       the host name.  I.e., if the machine's host name is "xerxes", then
+
+       #include /etc/sudoers.%h
+
+       will cause s\bsu\bud\bdo\bo to include the file _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bx_\be_\br_\bx_\be_\bs.
+
+       The #includedir directive can be used to create a _\bs_\bu_\bd_\bo_\b._\bd directory that
+       the system package manager can drop _\bs_\bu_\bd_\bo_\be_\br_\bs rules into as part of
+       package installation.  For example, given:
+
+       #includedir /etc/sudoers.d
+
+       s\bsu\bud\bdo\bo will read each file in _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bd, skipping file names that
+       end in ~ or contain a . character to avoid causing problems with
+       package manager or editor temporary/backup files.  Files are parsed in
+       sorted lexical order.  That is, _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bd_\b/_\b0_\b1_\b__\bf_\bi_\br_\bs_\bt will be parsed
+       before _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bd_\b/_\b1_\b0_\b__\bs_\be_\bc_\bo_\bn_\bd.  Be aware that because the sorting is
+       lexical, not numeric, _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bd_\b/_\b1_\b__\bw_\bh_\bo_\bo_\bp_\bs would be loaded a\baf\bft\bte\ber\br
+       _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bd_\b/_\b1_\b0_\b__\bs_\be_\bc_\bo_\bn_\bd.  Using a consistent number of leading zeroes
+       in the file names can be used to avoid such problems.
+
+       Note that unlike files included via #include, v\bvi\bis\bsu\bud\bdo\bo will not edit the
+       files in a #includedir directory unless one of them contains a syntax
+       error.  It is still possible to run v\bvi\bis\bsu\bud\bdo\bo with the -f flag to edit the
+       files directly.
+
+   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 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).
+
+       Long lines can be continued with a backslash ('\') as the last
+       character on the line.
+
+       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.
+
+       The following characters must be escaped with a backslash ('\') when
+       used as part of a word (e.g. a user name or host name): '!', '=', ':',
+       ',', '(', ')', '\'.
+
+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.
+
+       B\bBo\boo\bol\ble\bea\ban\bn F\bFl\bla\bag\bgs\bs:
+
+       always_set_home If enabled, 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.  Note that HOME
+                       is already set when the the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is
+                       enabled, so _\ba_\bl_\bw_\ba_\by_\bs_\b__\bs_\be_\bt_\b__\bh_\bo_\bm_\be is only effective for
+                       configurations where either _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt is disabled or
+                       HOME is present in the _\be_\bn_\bv_\b__\bk_\be_\be_\bp list.  This flag is _\bo_\bf_\bf
+                       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.
+
+       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.
+
+       compress_io     If set, and s\bsu\bud\bdo\bo is configured to log a command's input
+                       or output, the I/O logs will be compressed using z\bzl\bli\bib\bb.
+                       This flag is _\bo_\bn by default when s\bsu\bud\bdo\bo is compiled with
+                       z\bzl\bli\bib\bb support.
+
+       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, MAIL, 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.
+
+       fast_glob       Normally, s\bsu\bud\bdo\bo uses the _\bg_\bl_\bo_\bb(3) function to do shell-
+                       style globbing when matching path names.  However,
+                       since it accesses the file system, _\bg_\bl_\bo_\bb(3) can take a
+                       long time to complete for some patterns, especially
+                       when the pattern references a network file system that
+                       is mounted on demand (automounted).  The _\bf_\ba_\bs_\bt_\b__\bg_\bl_\bo_\bb
+                       option causes s\bsu\bud\bdo\bo to use the _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3) function,
+                       which does not access the file system to do its
+                       matching.  The disadvantage of _\bf_\ba_\bs_\bt_\b__\bg_\bl_\bo_\bb is that it is
+                       unable to match relative path names such as _\b._\b/_\bl_\bs or
+                       _\b._\b._\b/_\bb_\bi_\bn_\b/_\bl_\bs.  This has security implications when path
+                       names that include globbing characters are used with
+                       the negation operator, '!', as such rules can be
+                       trivially bypassed.  As such, this option should not be
+                       used when _\bs_\bu_\bd_\bo_\be_\br_\bs contains rules that contain negated
+                       path names which include globbing characters.  This
+                       flag is _\bo_\bf_\bf by default.
+
+       fqdn            Set this flag if you want to put fully qualified host
+                       names 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 host name (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_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.
+
+       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.
+
+       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 host name will be logged in the (non-
+                       syslog) s\bsu\bud\bdo\bo log file.  This flag is _\bo_\bf_\bf by default.
+
+       log_input       If set, s\bsu\bud\bdo\bo will run the command in a _\bp_\bs_\be_\bu_\bd_\bo _\bt_\bt_\by and
+                       log all user input.  If the standard input is not
+                       connected to the user's tty, due to I/O redirection or
+                       because the command is part of a pipeline, that input
+                       is also captured and stored in a separate log file.
+
+                       Input is logged to the directory specified by the
+                       _\bi_\bo_\bl_\bo_\bg_\b__\bd_\bi_\br option (_\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo by default) using a
+                       unique session ID that is included in the normal s\bsu\bud\bdo\bo
+                       log line, prefixed with _\bT_\bS_\bI_\bD_\b=.  The _\bi_\bo_\bl_\bo_\bg_\b__\bf_\bi_\bl_\be option
+                       may be used to control the format of the session ID.
+
+                       Note that user input may contain sensitive information
+                       such as passwords (even if they are not echoed to the
+                       screen), which will be stored in the log file
+                       unencrypted.  In most cases, logging the command output
+                       via _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt is all that is required.
+
+       log_output      If set, s\bsu\bud\bdo\bo will run the command in a _\bp_\bs_\be_\bu_\bd_\bo _\bt_\bt_\by and
+                       log all output that is sent to the screen, similar to
+                       the _\bs_\bc_\br_\bi_\bp_\bt(1) command.  If the standard output or
+                       standard error is not connected to the user's tty, due
+                       to I/O redirection or because the command is part of a
+                       pipeline, that output is also captured and stored in
+                       separate log files.
+
+                       Output is logged to the directory specified by the
+                       _\bi_\bo_\bl_\bo_\bg_\b__\bd_\bi_\br option (_\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo by default) using a
+                       unique session ID that is included in the normal s\bsu\bud\bdo\bo
+                       log line, prefixed with _\bT_\bS_\bI_\bD_\b=.  The _\bi_\bo_\bl_\bo_\bg_\b__\bf_\bi_\bl_\be option
+                       may be used to control the format of the session ID.
+
+                       Output logs may be viewed with the _\bs_\bu_\bd_\bo_\br_\be_\bp_\bl_\ba_\by(1m)
+                       utility, which can also be used to list or search the
+                       available logs.
+
+       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.
+
+       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_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_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_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_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.
+
+       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 password 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.
+
+       pwfeedback      By default, s\bsu\bud\bdo\bo reads the password like most other
+                       Unix programs, by turning off echo until the user hits
+                       the return (or enter) key.  Some users become confused
+                       by this as it appears to them that s\bsu\bud\bdo\bo has hung at
+                       this point.  When _\bp_\bw_\bf_\be_\be_\bd_\bb_\ba_\bc_\bk is set, s\bsu\bud\bdo\bo will provide
+                       visual feedback when the user presses a key.  Note that
+                       this does have a security impact as an onlooker may be
+                       able to determine the length of the password being
+                       entered.  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.  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 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.
+
+       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.
+
+       set_home        If enabled 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.  Note that HOME is already set when
+                       the the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is enabled, so _\bs_\be_\bt_\b__\bh_\bo_\bm_\be is
+                       only effective for configurations where either
+                       _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt is disabled or HOME is present in the
+                       _\be_\bn_\bv_\b__\bk_\be_\be_\bp list.  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_\bn by default.
+
+       set_utmp        When enabled, s\bsu\bud\bdo\bo will create an entry in the utmp (or
+                       utmpx) file when a pseudo-tty is allocated.  A pseudo-
+                       tty is allocated by s\bsu\bud\bdo\bo when the _\bl_\bo_\bg_\b__\bi_\bn_\bp_\bu_\bt, _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt
+                       or _\bu_\bs_\be_\b__\bp_\bt_\by flags are enabled.  By default, the new
+                       entry will be a copy of the user's existing utmp entry
+                       (if any), with the tty, time, type and pid fields
+                       updated.  This flag is _\bo_\bn by default.
+
+       setenv          Allow the user to disable the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option from the
+                       command line via the -\b-E\bE option.  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.
+
+       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.  In addition, the
+                       timestamp file name will include the target user's
+                       name.  Note that this flag 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.
+
+       tty_tickets     If set, users must authenticate on a per-tty basis.
+                       With this flag enabled, s\bsu\bud\bdo\bo will use a file named for
+                       the tty the user is logged in on in the user's time
+                       stamp directory.  If disabled, the time stamp of the
+                       directory is used instead.  This flag is _\bo_\bn by default.
+
+       umask_override  If set, s\bsu\bud\bdo\bo will set the umask as specified by _\bs_\bu_\bd_\bo_\be_\br_\bs
+                       without modification.  This makes it possible to
+                       specify a more permissive umask in _\bs_\bu_\bd_\bo_\be_\br_\bs than the
+                       user's own umask and matches historical behavior.  If
+                       _\bu_\bm_\ba_\bs_\bk_\b__\bo_\bv_\be_\br_\br_\bi_\bd_\be is not set, s\bsu\bud\bdo\bo will set the umask to
+                       be the union of the user's umask and what is specified
+                       in _\bs_\bu_\bd_\bo_\be_\br_\bs.  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.
+
+       use_pty         If set, s\bsu\bud\bdo\bo will run the command in a pseudo-pty even
+                       if no I/O logging is being gone.  A malicious program
+                       run under s\bsu\bud\bdo\bo could conceivably fork a background
+                       process that retains to the user's terminal device
+                       after the main program has finished executing.  Use of
+                       this option will make that impossible.  This flag is
+                       _\bo_\bf_\bf by default.
+
+       utmp_runas      If set, s\bsu\bud\bdo\bo will store the name of the runas user when
+                       updating the utmp (or utmpx) file.  By default, s\bsu\bud\bdo\bo
+                       stores the name of the invoking user.  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:
+
+       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).
+
+       passwd_timeout  Number of minutes before the s\bsu\bud\bdo\bo password prompt times
+                       out, or 0 for no timeout.  The timeout may include a
+                       fractional component if minute granularity is
+                       insufficient, for example 2.5.  The default is 5.
+
+       timestamp_timeout
+                       Number of minutes that can elapse before s\bsu\bud\bdo\bo will ask
+                       for a passwd again.  The timeout may include a
+                       fractional component if minute granularity is
+                       insufficient, for example 2.5.  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 the value of the _\bu_\bm_\ba_\bs_\bk option, which
+                       defaults to 0022.  This guarantees that s\bsu\bud\bdo\bo 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 _\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
+                       possible, or the first editor in the list that exists
+                       and is executable.  The default is "vi".
+
+       iolog_dir       The top-level directory to use when constructing the
+                       path name for the input/output log directory.  Only
+                       used if the _\bl_\bo_\bg_\b__\bi_\bn_\bp_\bu_\bt or _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt options are enabled
+                       or when the LOG_INPUT or LOG_OUTPUT tags are present
+                       for a command.  The session sequence number, if any, is
+                       stored in the directory.  The default is
+                       "/var/log/sudo-io".
+
+                       The following percent (`%') escape sequences are
+                       supported:
+
+                       %{seq}
+                           expanded to a monotonically increasing base-36
+                           sequence number, such as 0100A5, where every two
+                           digits are used to form a new directory, e.g.
+                           _\b0_\b1_\b/_\b0_\b0_\b/_\bA_\b5
+
+                       %{user}
+                           expanded to the invoking user's login name
+
+                       %{group}
+                           expanded to the name of the invoking user's real
+                           group ID
+
+                       %{runas_user}
+                           expanded to the login name of the user the command
+                           will be run as (e.g. root)
+
+                       %{runas_group}
+                           expanded to the group name of the user the command
+                           will be run as (e.g. wheel)
+
+                       %{hostname}
+                           expanded to the local host name without the domain
+                           name
+
+                       %{command}
+                           expanded to the base name of the command being run
+
+                       In addition, any escape sequences supported by the
+                       system's _\bs_\bt_\br_\bf_\bt_\bi_\bm_\be_\b(_\b) function will be expanded.
+
+                       To include a literal `%' character, the string `%%'
+                       should be used.
+
+                       Path names that end in six or more Xs will have the Xs
+                       replaced with a unique combination of digits and
+                       letters, similar to the _\bm_\bk_\bt_\be_\bm_\bp_\b(_\b) function.
+
+       iolog_file      The path name, relative to _\bi_\bo_\bl_\bo_\bg_\b__\bd_\bi_\br, in which to store
+                       input/output logs when the _\bl_\bo_\bg_\b__\bi_\bn_\bp_\bu_\bt or _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt
+                       options are enabled or when the LOG_INPUT or LOG_OUTPUT
+                       tags are present for a command.  Note that _\bi_\bo_\bl_\bo_\bg_\b__\bf_\bi_\bl_\be
+                       may contain directory components.  The default is
+                       "%{seq}".
+
+                       See the _\bi_\bo_\bl_\bo_\bg_\b__\bd_\bi_\br option above for a list of supported
+                       percent (`%') escape sequences.
+
+       mailsub         Subject of the mail sent to the _\bm_\ba_\bi_\bl_\bt_\bo user. The escape
+                       %h will expand to the host name of the machine.
+                       Default is *** SECURITY information for %h ***.
+
+       noexec_file     This option is deprecated and will be removed in a
+                       future release of s\bsu\bud\bdo\bo.  The path to the noexec file
+                       should now be set in the _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b._\bc_\bo_\bn_\bf file.
+
+       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 (`%')
+                       escape sequences are supported:
+
+                       %H  expanded to the local host name including the
+                           domain name (on if the machine's host name is fully
+                           qualified or the _\bf_\bq_\bd_\bn option is set)
+
+                       %h  expanded to the local host name 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 collapsed into a
+                           single % character
+
+                       The default value is Password:.
+
+       role            The default SELinux role to use when constructing a new
+                       security context to run the command.  The default role
+                       may be overridden on a per-command basis in _\bs_\bu_\bd_\bo_\be_\br_\bs or
+                       via command line options.  This option is only
+                       available whe s\bsu\bud\bdo\bo is built with SELinux support.
+
+       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.
+
+       syslog_badpri   Syslog priority to use when user authenticates
+                       unsuccessfully.  Defaults to alert.
+
+                       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.
+
+       syslog_goodpri  Syslog priority to use when user authenticates
+                       successfully.  Defaults to notice.
+
+                       See syslog_badpri for the list of supported syslog
+                       priorities.
+
+       sudoers_locale  Locale to use when parsing the sudoers file, logging
+                       commands, and sending email.  Note that changing the
+                       locale may affect how sudoers is interpreted.  Defaults
+                       to "C".
+
+       timestampdir    The directory in which s\bsu\bud\bdo\bo stores its timestamp files.
+                       The default is _\b/_\bv_\ba_\br_\b/_\ba_\bd_\bm_\b/_\bs_\bu_\bd_\bo.
+
+       timestampowner  The owner of the timestamp directory and the timestamps
+                       stored therein.  The default is root.
+
+       type            The default SELinux type to use when constructing a new
+                       security context to run the command.  The default type
+                       may be overridden on a per-command basis in _\bs_\bu_\bd_\bo_\be_\br_\bs or
+                       via command line options.  This option is only
+                       available whe s\bsu\bud\bdo\bo is built with SELinux support.
+
+       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:
+
+       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 either
+                   be of the form VARIABLE=value or export VARIABLE=value.
+                   The value may optionally be surrounded by single or double
+                   quotes.  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.
+
+       group_plugin
+                   A string containing a _\bs_\bu_\bd_\bo_\be_\br_\bs group plugin with optional
+                   arguments.  This can be used to implement support for the
+                   nonunix_group syntax described earlier.  The string should
+                   consist of the plugin path, either fully-qualified or
+                   relative to the _\b/_\bu_\bs_\br_\b/_\bl_\bo_\bc_\ba_\bl_\b/_\bl_\bi_\bb_\be_\bx_\be_\bc directory, followed by
+                   any configuration arguments the plugin requires.  These
+                   arguments (if any) will be passed to the plugin's
+                   initialization function.  If arguments are present, the
+                   string must be enclosed in double quotes (").
+
+                   For example, given _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b-_\bg_\br_\bo_\bu_\bp, a group file in Unix
+                   group format, the sample group plugin can be used:
+
+                       Defaults sudo_plugin="sample_group.so /etc/sudo-group"
+
+                   For more information see _\bs_\bu_\bd_\bo_\b__\bp_\bl_\bu_\bg_\bi_\bn(4).
+
+       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.
+
+                   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.
+
+       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:
+
+                   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.
+
+                   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-l\bl
+                           option.
+
+                   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.
+
+       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.
+
+       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 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
+                   _\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
+                   option is not set by default.
+
+       syslog      Syslog facility if syslog is being used for logging (negate
+                   to disable syslog logging).  Defaults to auth.
+
+                   The following syslog facilities are supported: 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.
+
+       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.
+
+                   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 entering a password.
+
+                   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.
+
+       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 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 when the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is not in effect.
+                       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 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.
+
+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/_\be_\bt_\bc_\b/_\bg_\br_\bo_\bu_\bp              Local groups file
+
+       _\b/_\be_\bt_\bc_\b/_\bn_\be_\bt_\bg_\br_\bo_\bu_\bp           List of network groups
+
+       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo        I/O log files
+
+       _\b/_\bv_\ba_\br_\b/_\ba_\bd_\bm_\b/_\bs_\bu_\bd_\bo           Directory containing time stamps for the
+                               _\bs_\bu_\bd_\bo_\be_\br_\bs security policy
+
+       _\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
+       Below are example _\bs_\bu_\bd_\bo_\be_\br_\bs entries.  Admittedly, some of these are a bit
+       contrived.  First, we allow a few environment variables to pass and
+       then define our _\ba_\bl_\bi_\ba_\bs_\be_\bs:
+
+        # Run X applications through sudo; HOME is used to find the
+        # .Xauthority file.  Note that other programs use HOME to find
+        # configuration files and this may lead to privilege escalation!
+        Defaults env_keep += "DISPLAY HOME"
+
+        # User alias specification
+        User_Alias     FULLTIMERS = millert, mikef, dowdy
+        User_Alias     PARTTIMERS = bostley, jwfox, crawl
+        User_Alias     WEBMASTERS = will, wendy, wim
+
+        # Runas alias specification
+        Runas_Alias    OP = root, operator
+        Runas_Alias    DB = oracle, sybase
+        Runas_Alias    ADMINGRP = adm, oper
+
+        # Host alias specification
+        Host_Alias     SPARC = bigtime, eclipse, moet, anchor :\
+                       SGI = grolsch, dandelion, black :\
+                       ALPHA = widget, thalamus, foobar :\
+                       HPPA = boa, nag, python
+        Host_Alias     CUNETS = 128.138.0.0/255.255.0.0
+        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
+
+        # Cmnd alias specification
+        Cmnd_Alias     DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\
+                               /usr/sbin/restore, /usr/sbin/rrestore
+        Cmnd_Alias     KILL = /usr/bin/kill
+        Cmnd_Alias     PRINTING = /usr/sbin/lpc, /usr/bin/lprm
+        Cmnd_Alias     SHUTDOWN = /usr/sbin/shutdown
+        Cmnd_Alias     HALT = /usr/sbin/halt
+        Cmnd_Alias     REBOOT = /usr/sbin/reboot
+        Cmnd_Alias     SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \
+                                /usr/local/bin/tcsh, /usr/bin/rsh, \
+                                /usr/local/bin/zsh
+        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
+       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
+        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
+
+       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.
+
+        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
+
+       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.
+
+        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).
+
+        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 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-Za-z]*, !/usr/bin/passwd root
+
+        %opers         ALL = (: ADMINGRP) /usr/sbin/
+
+       Users in the o\bop\bpe\ber\brs\bs group may run commands in _\b/_\bu_\bs_\br_\b/_\bs_\bb_\bi_\bn_\b/ as themselves
+       with any group in the _\bA_\bD_\bM_\bI_\bN_\bG_\bR_\bP Runas_Alias (the a\bad\bdm\bm and o\bop\bpe\ber\br groups).
+
+       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 user names 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
+
+       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.
+
+        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.
+
+        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).
+
+        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_\bU
+       and _\bS_\bH_\bE_\bL_\bL_\bS Cmnd_Aliases.
+
+        steve          CSNETS = (operator) /usr/local/op_commands/
+
+       The user s\bst\bte\bev\bve\be may run any command in the directory
+       /usr/local/op_commands/ but only as user operator.
+
+        matt           valkyrie = KILL
+
+       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.
+
+        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.
+
+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 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 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).
+
+       Furthermore, if the _\bf_\ba_\bs_\bt_\b__\bg_\bl_\bo_\bb option is in use, it is not possible to
+       reliably negate commands where the path name includes globbing (aka
+       wildcard) characters.  This is because the C library's _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3)
+       function cannot resolve relative paths.  While this is typically only
+       an inconvenience for rules that grant privileges, it can result in a
+       security issue for rules that subtract or revoke privileges.
+
+       For example, given the following _\bs_\bu_\bd_\bo_\be_\br_\bs entry:
+
+        john   ALL = /usr/bin/passwd [a-zA-Z0-9]*, /usr/bin/chsh [a-zA-Z0-9]*,
+             /usr/bin/chfn [a-zA-Z0-9]*, !/usr/bin/* root
+
+       User j\bjo\boh\bhn\bn can still run /usr/bin/passwd root if _\bf_\ba_\bs_\bt_\b__\bg_\bl_\bo_\bb is enabled by
+       changing to _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn and running ./passwd root instead.
+
+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,
+       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 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 is 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.
+
+                 The _\bn_\bo_\be_\bx_\be_\bc feature is known to work on SunOS, Solaris, *BSD,
+                 Linux, IRIX, Tru64 UNIX, MacOS X, HP-UX 11.x and AIX 5.3 and
+                 above.  It should be supported 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.
+
+                 On Solaris 10 and higher, _\bn_\bo_\be_\bx_\be_\bc uses Solaris privileges
+                 instead of the LD_PRELOAD environment variable.
+
+                 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 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 check whether shell
+                 escapes work when _\bn_\bo_\be_\bx_\be_\bc is enabled.
+
+       Note that restricting shell escapes is not a panacea.  Programs running
+       as root are still capable of many potentially hazardous operations
+       (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\bEC\bCU\bUR\bRI\bIT\bTY\bY N\bNO\bOT\bTE\bES\bS
+       _\bs_\bu_\bd_\bo_\be_\br_\bs will check the ownership of its time stamp directory
+       (_\b/_\bv_\ba_\br_\b/_\ba_\bd_\bm_\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 time stamp directory is located in a world-writable directory
+       (e.g., _\b/_\bt_\bm_\bp), it is possible for a user to create the time stamp
+       directory before s\bsu\bud\bdo\bo is run.  However, because _\bs_\bu_\bd_\bo_\be_\br_\bs 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 time stamp
+       dir.  This is unlikely to happen since once the time stamp dir is owned
+       by root and inaccessible by any other user, the user placing files
+       there would be unable to get them back out.
+
+       _\bs_\bu_\bd_\bo_\be_\br_\bs will not honor time stamps set far in the future.  Time stamps
+       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 time stamp with a bogus date on systems that allow users to
+       give away files if the time stamp directory is located in a world-
+       writable directory.
+
+       On systems where the boot time is available, _\bs_\bu_\bd_\bo_\be_\br_\bs will ignore time
+       stamps that date from before the machine booted.
+
+       Since time stamp files live in the file system, they can outlive a
+       user's login session.  As a result, a user may be able to login, run a
+       command with s\bsu\bud\bdo\bo after authenticating, logout, login again, and run
+       s\bsu\bud\bdo\bo without authenticating so long as the time stamp file's
+       modification time is within 5 minutes (or whatever the timeout is set
+       to in _\bs_\bu_\bd_\bo_\be_\br_\bs).  When the _\bt_\bt_\by_\b__\bt_\bi_\bc_\bk_\be_\bt_\bs option is enabled, the time stamp
+       has per-tty granularity but still may outlive the user's session.  On
+       Linux systems where the devpts filesystem is used, Solaris systems with
+       the devices filesystem, as well as other systems that utilize a devfs
+       filesystem that monotonically increase the inode number of devices as
+       they are created (such as Mac OS X), _\bs_\bu_\bd_\bo_\be_\br_\bs is able to determine when
+       a tty-based time stamp file is stale and will ignore it.
+       Administrators should not rely on this feature as it is not universally
+       available.
+
+       If users have sudo ALL there is nothing to prevent them from creating
+       their own program that gives them a root shell (or making their own
+       copy of a shell) regardless of any '!' elements in the user
+       specification.
+
+S\bSE\bEE\bE A\bAL\bLS\bSO\bO
+       _\br_\bs_\bh(1), _\bs_\bu(1), _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3), _\bg_\bl_\bo_\bb(3), _\bm_\bk_\bt_\be_\bm_\bp(3), _\bs_\bt_\br_\bf_\bt_\bi_\bm_\be(3),
+       _\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bl_\bd_\ba_\bp(4), _\bs_\bu_\bd_\bo_\b__\bp_\bl_\bu_\bg_\bi_\bn(1m), _\bs_\bu_\bd_\bo(1m), _\bv_\bi_\bs_\bu_\bd_\bo(1m)
+
+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 host name in the netgroup (as is usually the case), you
+       either need to have the machine's host name 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/
+
+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.
+
+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.8.1p2                          May 16, 2011                       SUDOERS(4)
diff --git a/doc/sudoers.ldap.cat b/doc/sudoers.ldap.cat
new file mode 100644 (file)
index 0000000..19f3294
--- /dev/null
@@ -0,0 +1,741 @@
+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
+       LDAP.  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/_\be_\bt_\bc_\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/_\be_\bt_\bc_\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
+       Runas_Aliases.  Host netgroups can be used in place of Host_Aliases.
+       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
+       found, the multi-valued sudoOption attribute is parsed in the same
+       manner as a global Defaults line in _\b/_\be_\bt_\bc_\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 attributes:
+
+       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.
+
+           The sudoRunAsUser attribute is only available in s\bsu\bud\bdo\bo versions
+           1.7.0 and higher.  Older versions of s\bsu\bud\bdo\bo use the sudoRunAs
+           attribute instead.
+
+       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.
+
+           The sudoRunAsGroup attribute is only available in s\bsu\bud\bdo\bo versions
+           1.7.0 and higher.
+
+       s\bsu\bud\bdo\boN\bNo\bot\btB\bBe\bef\bfo\bor\bre\be
+           A timestamp in the form yyyymmddHHMMZ that can be used to provide a
+           start date/time for when the sudoRole will be valid.  If multiple
+           sudoNotBefore entries are present, the earliest is used.  Note that
+           timestamps must be in Coordinated Universal Time (UTC), not the
+           local timezone.
+
+           The sudoNotBefore attribute is only available in s\bsu\bud\bdo\bo versions
+           1.7.5 and higher and must be explicitly enabled via the
+           S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_T\bTI\bIM\bME\bED\bD option in _\b/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf.
+
+       s\bsu\bud\bdo\boN\bNo\bot\btA\bAf\bft\bte\ber\br
+           A timestamp in the form yyyymmddHHMMZ that indicates an expiration
+           date/time, after which the sudoRole will no longer be valid.  If
+           multiple sudoNotBefore entries are present, the last one is used.
+           Note that timestamps must be in Coordinated Universal Time (UTC),
+           not the local timezone.
+
+           The sudoNotAfter attribute is only available in s\bsu\bud\bdo\bo versions 1.7.5
+           and higher and must be explicitly enabled via the S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_T\bTI\bIM\bME\bED\bD
+           option in _\b/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf.
+
+       s\bsu\bud\bdo\boO\bOr\brd\bde\ber\br
+           The sudoRole entries retrieved from the LDAP directory have no
+           inherent order.  The sudoOrder attribute is an integer (or floating
+           point value for LDAP servers that support it) that is used to sort
+           the matching entries.  This allows LDAP-based sudoers entries to
+           more closely mimic the behaviour of the sudoers file, where the of
+           the entries influences the result.  If multiple entries match, the
+           entry with the highest sudoOrder attribute is chosen.  This
+           corresponds to the "last match" behavior of the sudoers file.  If
+           the sudoOrder attribute is not present, a value of 0 is assumed.
+
+           The sudoOrder attribute is only available in s\bsu\bud\bdo\bo versions 1.7.5
+           and higher.
+
+       Each attribute listed above should contain a single value, but there
+       may be multiple instances of each attribute 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:
+
+           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.
+
+       If timed entries are enabled with the S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_T\bTI\bIM\bME\bED\bD configuration
+       directive, the LDAP queries include a subfilter that limits retrieval
+       to entries that satisfy the time constraints, if any.
+
+   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.
+
+       The order in which different entries are applied can be controlled
+       using the sudoOrder attribute, but there is no way to guarantee the
+       order of attributes within a specific entry.  If there are conflicting
+       command rules in 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 ignored.  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/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf 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/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf 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/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf as being
+       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
+           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.  Multiple U\bUR\bRI\bI lines are treated
+           identically to a U\bUR\bRI\bI line containing multiple entries.  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.
+
+       N\bNE\bET\bTW\bWO\bOR\bRK\bK_\b_T\bTI\bIM\bME\bEO\bOU\bUT\bT seconds
+           An alias for B\bBI\bIN\bND\bD_\b_T\bTI\bIM\bME\bEL\bLI\bIM\bMI\bIT\bT for OpenLDAP compatibility.
+
+       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.
+
+       T\bTI\bIM\bME\bEO\bOU\bUT\bT seconds
+           The T\bTI\bIM\bME\bEO\bOU\bUT\bT parameter specifies the amount of time, in seconds, to
+           wait for a response from the various LDAP APIs.
+
+       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.  Multiple S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_B\bBA\bAS\bSE\bE lines may be specified, in
+           which case they are queried in the order specified.
+
+       S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_S\bSE\bEA\bAR\bRC\bCH\bH_\b_F\bFI\bIL\bLT\bTE\bER\bR ldap_filter
+           An LDAP filter which is used to restrict the set of records
+           returned when performing a s\bsu\bud\bdo\bo LDAP query.  Typically, this is of
+           the form attribute=value or
+           (&(attribute=value)(attribute2=value2)).
+
+       S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_T\bTI\bIM\bME\bED\bD on/true/yes/off/false/no
+           Whether or not to evaluate the sudoNotBefore and sudoNotAfter
+           attributes that implement time-dependent sudoers entries.
+
+       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.
+
+       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/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bs_\be_\bc_\br_\be_\bt.  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.  Note that disabling
+           the check creates an opportunity for man-in-the-middle attacks
+           since the server's identity will not be authenticated.  If
+           possible, the CA's certificate should be installed locally so it
+           can be verified.
+
+       T\bTL\bLS\bS_\b_C\bCA\bAC\bCE\bER\bRT\bT file name
+           An alias for T\bTL\bLS\bS_\b_C\bCA\bAC\bCE\bER\bRT\bTF\bFI\bIL\bLE\bE for OpenLDAP compatibility.
+
+       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.  Netscape-derived LDAP
+           libraries use the same certificate database for CA and client
+           certificates (see T\bTL\bLS\bS_\b_C\bCE\bER\bRT\bT).
+
+       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.
+
+           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.
+
+       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/_\be_\bt_\bc_\b/_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b._\bc_\bo_\bn_\bf, 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/_\be_\bt_\bc_\b/_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b._\bc_\bo_\bn_\bf file is not present or there is no sudoers
+       line, the following default is assumed:
+
+           sudoers: files
+
+       Note that _\b/_\be_\bt_\bc_\b/_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b._\bc_\bo_\bn_\bf is supported even when the underlying
+       operating system does not use an nsswitch.conf file.
+
+   C\bCo\bon\bnf\bfi\big\bgu\bur\bri\bin\bng\bg n\bne\bet\bts\bsv\bvc\bc.\b.c\bco\bon\bnf\bf
+       On AIX systems, the _\b/_\be_\bt_\bc_\b/_\bn_\be_\bt_\bs_\bv_\bc_\b._\bc_\bo_\bn_\bf file is consulted instead of
+       _\b/_\be_\bt_\bc_\b/_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b._\bc_\bo_\bn_\bf.  s\bsu\bud\bdo\bo simply treats _\bn_\be_\bt_\bs_\bv_\bc_\b._\bc_\bo_\bn_\bf as a variant of
+       _\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b._\bc_\bo_\bn_\bf; information in the previous section unrelated to the
+       file format itself still applies.
+
+       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
+
+       To treat LDAP as authoratative and only use the local sudoers file if
+       the user is not present in LDAP, use:
+
+           sudoers = ldap = auth, files
+
+       Note that in the above example, the auth qualfier only affects user
+       lookups; both LDAP and _\bs_\bu_\bd_\bo_\be_\br_\bs will be queried for Defaults entries.
+
+       If the _\b/_\be_\bt_\bc_\b/_\bn_\be_\bt_\bs_\bv_\bc_\b._\bc_\bo_\bn_\bf file is not present or there is no sudoers
+       line, the following default is assumed:
+
+           sudoers = files
+
+F\bFI\bIL\bLE\bES\bS
+       _\b/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf          LDAP configuration file
+
+       _\b/_\be_\bt_\bc_\b/_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b._\bc_\bo_\bn_\bf      determines sudoers source order
+
+       _\b/_\be_\bt_\bc_\b/_\bn_\be_\bt_\bs_\bv_\bc_\b._\bc_\bo_\bn_\bf        determines sudoers source order on AIX
+
+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.
+         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; may be specified multiple times.
+         sudoers_base   ou=SUDOers,dc=example,dc=com
+         #
+         # verbose sudoers matching from ldap
+         #sudoers_debug 2
+         #
+         # Enable support for time-based entries in sudoers.
+         #sudoers_timed yes
+         #
+         # 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, tls_cert and tls_key may specify either
+         # a directory, in which case the files in the directory must have the
+         # default names (e.g. cert8.db and key4.db), or the path to the cert
+         # and key files themselves.  However, a bug in version 5.0 of the LDAP
+         # SDK will prevent specific file names from working.  For this reason
+         # it is suggested that tls_cert and tls_key be set to a directory,
+         # not a file name.
+         #
+         # The certificate database 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
+         #tls_key /var/ldap
+         #
+         # If using SASL authentication for LDAP (OpenSSL)
+         # use_sasl yes
+         # sasl_auth_id <SASL user name>
+         # rootuse_sasl yes
+         # rootsasl_auth_id <SASL user name 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, in OpenLDAP format, is included with s\bsu\bud\bdo\bo source
+       and binary distributions as _\bs_\bc_\bh_\be_\bm_\ba_\b._\bO_\bp_\be_\bn_\bL_\bD_\bA_\bP.  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'
+           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 )
+
+        attributetype ( 1.3.6.1.4.1.15953.9.1.8
+           NAME 'sudoNotBefore'
+           DESC 'Start of time interval for which the entry is valid'
+           EQUALITY generalizedTimeMatch
+           ORDERING generalizedTimeOrderingMatch
+           SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+        attributetype ( 1.3.6.1.4.1.15953.9.1.9
+           NAME 'sudoNotAfter'
+           DESC 'End of time interval for which the entry is valid'
+           EQUALITY generalizedTimeMatch
+           ORDERING generalizedTimeOrderingMatch
+           SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+        attributeTypes ( 1.3.6.1.4.1.15953.9.1.10
+            NAME 'sudoOrder'
+            DESC 'an integer to order the sudoRole entries'
+            EQUALITY integerMatch
+            ORDERING integerOrderingMatch
+            SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+        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 $ sudoNotBefore $ sudoNotAfter $
+                 sudoOrder $ description )
+           )
+
+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(4)
+
+C\bCA\bAV\bVE\bEA\bAT\bTS\bS
+       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.
+
+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.8.1p2                          May 16, 2011                  SUDOERS.LDAP(4)
diff --git a/doc/sudoers.ldap.man.in b/doc/sudoers.ldap.man.in
new file mode 100644 (file)
index 0000000..4ad1a47
--- /dev/null
@@ -0,0 +1,918 @@
+.\" Copyright (c) 2003-2011
+.\"    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.
+.\" 
+.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.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 (.SS), 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@ "May 16, 2011" "1.8.1p2" "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-1LDAP\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@sysconfdir@/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@sysconfdir@/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 Runas_Aliases.  Host netgroups can be used in place
+of Host_Aliases.  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 \f(CW\*(C`sudoRole\*(C'\fR.  Instead of defining
+a Cmnd_Alias that is referenced by multiple users, one can create
+a \f(CW\*(C`sudoRole\*(C'\fR that contains the commands and assign multiple users
+to it.
+.SS "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@sysconfdir@/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 attributes:
+.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.
+.Sp
+The \f(CW\*(C`sudoRunAsUser\*(C'\fR attribute is only available in \fBsudo\fR versions
+1.7.0 and higher.  Older versions of \fBsudo\fR use the \f(CW\*(C`sudoRunAs\*(C'\fR
+attribute instead.
+.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.
+.Sp
+The \f(CW\*(C`sudoRunAsGroup\*(C'\fR attribute is only available in \fBsudo\fR versions
+1.7.0 and higher.
+.IP "\fBsudoNotBefore\fR" 4
+.IX Item "sudoNotBefore"
+A timestamp in the form \f(CW\*(C`yyyymmddHHMMZ\*(C'\fR that can be used to provide
+a start date/time for when the \f(CW\*(C`sudoRole\*(C'\fR will be valid.  If
+multiple \f(CW\*(C`sudoNotBefore\*(C'\fR entries are present, the earliest is used.
+Note that timestamps must be in Coordinated Universal Time (\s-1UTC\s0),
+not the local timezone.
+.Sp
+The \f(CW\*(C`sudoNotBefore\*(C'\fR attribute is only available in \fBsudo\fR versions
+1.7.5 and higher and must be explicitly enabled via the \fB\s-1SUDOERS_TIMED\s0\fR
+option in \fI@ldap_conf@\fR.
+.IP "\fBsudoNotAfter\fR" 4
+.IX Item "sudoNotAfter"
+A timestamp in the form \f(CW\*(C`yyyymmddHHMMZ\*(C'\fR that indicates an expiration
+date/time, after which the \f(CW\*(C`sudoRole\*(C'\fR will no longer be valid.  If
+multiple \f(CW\*(C`sudoNotBefore\*(C'\fR entries are present, the last one is used.
+Note that timestamps must be in Coordinated Universal Time (\s-1UTC\s0),
+not the local timezone.
+.Sp
+The \f(CW\*(C`sudoNotAfter\*(C'\fR attribute is only available in \fBsudo\fR versions
+1.7.5 and higher and must be explicitly enabled via the \fB\s-1SUDOERS_TIMED\s0\fR
+option in \fI@ldap_conf@\fR.
+.IP "\fBsudoOrder\fR" 4
+.IX Item "sudoOrder"
+The \f(CW\*(C`sudoRole\*(C'\fR entries retrieved from the \s-1LDAP\s0 directory have no
+inherent order.  The \f(CW\*(C`sudoOrder\*(C'\fR attribute is an integer (or
+floating point value for \s-1LDAP\s0 servers that support it) that is used
+to sort the matching entries.  This allows LDAP-based sudoers entries
+to more closely mimic the behaviour of the sudoers file, where the
+of the entries influences the result.  If multiple entries match,
+the entry with the highest \f(CW\*(C`sudoOrder\*(C'\fR attribute is chosen.  This
+corresponds to the \*(L"last match\*(R" behavior of the sudoers file.  If
+the \f(CW\*(C`sudoOrder\*(C'\fR attribute is not present, a value of 0 is assumed.
+.Sp
+The \f(CW\*(C`sudoOrder\*(C'\fR attribute is only available in \fBsudo\fR versions
+1.7.5 and higher.
+.PP
+Each attribute listed above should contain a single value, but there
+may be multiple instances of each attribute type.  A \f(CW\*(C`sudoRole\*(C'\fR 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
+.SS "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.
+.PP
+If timed entries are enabled with the \fB\s-1SUDOERS_TIMED\s0\fR configuration
+directive, the \s-1LDAP\s0 queries include a subfilter that limits retrieval
+to entries that satisfy the time constraints, if any.
+.SS "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.
+.PP
+The order in which different entries are applied can be controlled
+using the \f(CW\*(C`sudoOrder\*(C'\fR attribute, but there is no way to guarantee
+the order of attributes within a specific entry.  If there are
+conflicting command rules in 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 ignored.  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
+.SS "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.
+.SS "Configuring ldap.conf"
+.IX Subsection "Configuring ldap.conf"
+Sudo reads the \fI@ldap_conf@\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@ldap_conf@\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@ldap_conf@\fR as being
+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.  Multiple \fB\s-1URI\s0\fR
+lines are treated identically to a \fB\s-1URI\s0\fR line containing multiple
+entries.  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-1NETWORK_TIMEOUT\s0\fR seconds" 4
+.IX Item "NETWORK_TIMEOUT seconds"
+An alias for \fB\s-1BIND_TIMELIMIT\s0\fR for OpenLDAP compatibility.
+.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-1TIMEOUT\s0\fR seconds" 4
+.IX Item "TIMEOUT seconds"
+The \fB\s-1TIMEOUT\s0\fR parameter specifies the amount of time, in seconds,
+to wait for a response from the various \s-1LDAP\s0 APIs.
+.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.  Multiple \fB\s-1SUDOERS_BASE\s0\fR lines may be specified,
+in which case they are queried in the order specified.
+.IP "\fB\s-1SUDOERS_SEARCH_FILTER\s0\fR ldap_filter" 4
+.IX Item "SUDOERS_SEARCH_FILTER ldap_filter"
+An \s-1LDAP\s0 filter which is used to restrict the set of records returned
+when performing a \fBsudo\fR \s-1LDAP\s0 query.  Typically, this is of the
+form \f(CW\*(C`attribute=value\*(C'\fR or \f(CW\*(C`(&(attribute=value)(attribute2=value2))\*(C'\fR.
+.IP "\fB\s-1SUDOERS_TIMED\s0\fR on/true/yes/off/false/no" 4
+.IX Item "SUDOERS_TIMED on/true/yes/off/false/no"
+Whether or not to evaluate the \f(CW\*(C`sudoNotBefore\*(C'\fR and \f(CW\*(C`sudoNotAfter\*(C'\fR
+attributes that implement time-dependent sudoers entries.
+.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@ldap_secret@\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.  Note that disabling the check creates
+an opportunity for man-in-the-middle attacks since the server's
+identity will not be authenticated.  If possible, the \s-1CA\s0's certificate
+should be installed locally so it can be verified.
+.IP "\fB\s-1TLS_CACERT\s0\fR file name" 4
+.IX Item "TLS_CACERT file name"
+An alias for \fB\s-1TLS_CACERTFILE\s0\fR for OpenLDAP compatibility.
+.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.
+Netscape-derived \s-1LDAP\s0 libraries use the same certificate
+database for \s-1CA\s0 and client certificates (see \fB\s-1TLS_CERT\s0\fR).
+.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.
+.SS "Configuring nsswitch.conf"
+.IX Subsection "Configuring nsswitch.conf"
+Unless it is disabled at build time, \fBsudo\fR consults the Name
+Service Switch file, \fI@nsswitch_conf@\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@nsswitch_conf@\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@nsswitch_conf@\fR is supported even when the underlying
+operating system does not use an nsswitch.conf file.
+.SS "Configuring netsvc.conf"
+.IX Subsection "Configuring netsvc.conf"
+On \s-1AIX\s0 systems, the \fI@netsvc_conf@\fR file is consulted instead of
+\&\fI@nsswitch_conf@\fR.  \fBsudo\fR simply treats \fInetsvc.conf\fR as a
+variant of \fInsswitch.conf\fR; information in the previous section
+unrelated to the file format itself still applies.
+.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
+To treat \s-1LDAP\s0 as authoratative and only use the local sudoers file
+if the user is not present in \s-1LDAP\s0, use:
+.PP
+.Vb 1
+\&    sudoers = ldap = auth, files
+.Ve
+.PP
+Note that in the above example, the \f(CW\*(C`auth\*(C'\fR qualfier only affects
+user lookups; both \s-1LDAP\s0 and \fIsudoers\fR will be queried for \f(CW\*(C`Defaults\*(C'\fR
+entries.
+.PP
+If the \fI@netsvc_conf@\fR file is not present or there is no
+sudoers line, the following default is assumed:
+.PP
+.Vb 1
+\&    sudoers = files
+.Ve
+.SH "FILES"
+.IX Header "FILES"
+.ie n .IP "\fI@ldap_conf@\fR" 24
+.el .IP "\fI@ldap_conf@\fR" 24
+.IX Item "@ldap_conf@"
+\&\s-1LDAP\s0 configuration file
+.ie n .IP "\fI@nsswitch_conf@\fR" 24
+.el .IP "\fI@nsswitch_conf@\fR" 24
+.IX Item "@nsswitch_conf@"
+determines sudoers source order
+.ie n .IP "\fI@netsvc_conf@\fR" 24
+.el .IP "\fI@netsvc_conf@\fR" 24
+.IX Item "@netsvc_conf@"
+determines sudoers source order on \s-1AIX\s0
+.SH "EXAMPLES"
+.IX Header "EXAMPLES"
+.SS "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; may be specified multiple times.
+\&  sudoers_base   ou=SUDOers,dc=example,dc=com
+\&  #
+\&  # verbose sudoers matching from ldap
+\&  #sudoers_debug 2
+\&  #
+\&  # Enable support for time\-based entries in sudoers.
+\&  #sudoers_timed yes
+\&  #
+\&  # 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, tls_cert and tls_key may specify either
+\&  # a directory, in which case the files in the directory must have the
+\&  # default names (e.g. cert8.db and key4.db), or the path to the cert
+\&  # and key files themselves.  However, a bug in version 5.0 of the LDAP
+\&  # SDK will prevent specific file names from working.  For this reason
+\&  # it is suggested that tls_cert and tls_key be set to a directory,
+\&  # not a file name.
+\&  #
+\&  # The certificate database 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
+\&  #tls_key /var/ldap
+\&  #
+\&  # If using SASL authentication for LDAP (OpenSSL)
+\&  # use_sasl yes
+\&  # sasl_auth_id <SASL user name>
+\&  # rootuse_sasl yes
+\&  # rootsasl_auth_id <SASL user name for root access>
+\&  # sasl_secprops none
+\&  # krb5_ccname /etc/.ldapcache
+.Ve
+.SS "Sudo schema for OpenLDAP"
+.IX Subsection "Sudo schema for OpenLDAP"
+The following schema, in OpenLDAP format, is included with \fBsudo\fR
+source and binary distributions as \fIschema.OpenLDAP\fR.  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 )
+\&
+\& attributetype ( 1.3.6.1.4.1.15953.9.1.8
+\&    NAME \*(AqsudoNotBefore\*(Aq
+\&    DESC \*(AqStart of time interval for which the entry is valid\*(Aq
+\&    EQUALITY generalizedTimeMatch
+\&    ORDERING generalizedTimeOrderingMatch
+\&    SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+\&
+\& attributetype ( 1.3.6.1.4.1.15953.9.1.9
+\&    NAME \*(AqsudoNotAfter\*(Aq
+\&    DESC \*(AqEnd of time interval for which the entry is valid\*(Aq
+\&    EQUALITY generalizedTimeMatch
+\&    ORDERING generalizedTimeOrderingMatch
+\&    SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+\&
+\& attributeTypes ( 1.3.6.1.4.1.15953.9.1.10
+\&     NAME \*(AqsudoOrder\*(Aq
+\&     DESC \*(Aqan integer to order the sudoRole entries\*(Aq
+\&     EQUALITY integerMatch
+\&     ORDERING integerOrderingMatch
+\&     SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+\&
+\& 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 $ sudoNotBefore $ sudoNotAfter $
+\&          sudoOrder $ description )
+\&    )
+.Ve
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fIldap.conf\fR\|(@mansectform@), \fIsudoers\fR\|(@mansectform@)
+.SH "CAVEATS"
+.IX Header "CAVEATS"
+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/doc/sudoers.ldap.pod b/doc/sudoers.ldap.pod
new file mode 100644 (file)
index 0000000..a981654
--- /dev/null
@@ -0,0 +1,841 @@
+Copyright (c) 2003-2011
+       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.
+
+=pod
+
+=head1 NAME
+
+sudoers.ldap - sudo LDAP configuration
+
+=head1 DESCRIPTION
+
+In addition to the standard I<sudoers> file, B<sudo> may be configured
+via LDAP.  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 Runas_Aliases.  Host netgroups can be used in place
+of Host_Aliases.  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 C<sudoRole>.  Instead of defining
+a Cmnd_Alias that is referenced by multiple users, one can create
+a C<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 attributes:
+
+=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.
+
+The C<sudoRunAsUser> attribute is only available in B<sudo> versions
+1.7.0 and higher.  Older versions of B<sudo> use the C<sudoRunAs>
+attribute instead.
+
+=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.
+
+The C<sudoRunAsGroup> attribute is only available in B<sudo> versions
+1.7.0 and higher.
+
+=item B<sudoNotBefore>
+
+A timestamp in the form C<yyyymmddHHMMZ> that can be used to provide
+a start date/time for when the C<sudoRole> will be valid.  If
+multiple C<sudoNotBefore> entries are present, the earliest is used.
+Note that timestamps must be in Coordinated Universal Time (UTC),
+not the local timezone.
+
+The C<sudoNotBefore> attribute is only available in B<sudo> versions
+1.7.5 and higher and must be explicitly enabled via the B<SUDOERS_TIMED>
+option in F<@ldap_conf@>.
+
+=item B<sudoNotAfter>
+
+A timestamp in the form C<yyyymmddHHMMZ> that indicates an expiration
+date/time, after which the C<sudoRole> will no longer be valid.  If
+multiple C<sudoNotBefore> entries are present, the last one is used.
+Note that timestamps must be in Coordinated Universal Time (UTC),
+not the local timezone.
+
+The C<sudoNotAfter> attribute is only available in B<sudo> versions
+1.7.5 and higher and must be explicitly enabled via the B<SUDOERS_TIMED>
+option in F<@ldap_conf@>.
+
+=item B<sudoOrder>
+
+The C<sudoRole> entries retrieved from the LDAP directory have no
+inherent order.  The C<sudoOrder> attribute is an integer (or
+floating point value for LDAP servers that support it) that is used
+to sort the matching entries.  This allows LDAP-based sudoers entries
+to more closely mimic the behaviour of the sudoers file, where the
+of the entries influences the result.  If multiple entries match,
+the entry with the highest C<sudoOrder> attribute is chosen.  This
+corresponds to the "last match" behavior of the sudoers file.  If
+the C<sudoOrder> attribute is not present, a value of 0 is assumed.
+
+The C<sudoOrder> attribute is only available in B<sudo> versions
+1.7.5 and higher.
+
+=back
+
+Each attribute listed above should contain a single value, but there
+may be multiple instances of each attribute type.  A C<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.
+
+If timed entries are enabled with the B<SUDOERS_TIMED> configuration
+directive, the LDAP queries include a subfilter that limits retrieval
+to entries that satisfy the time constraints, if any.
+
+=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.
+
+The order in which different entries are applied can be controlled
+using the C<sudoOrder> attribute, but there is no way to guarantee
+the order of attributes within a specific entry.  If there are
+conflicting command rules in 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 ignored.  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@> as being
+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>.  Multiple B<URI>
+lines are treated identically to a B<URI> line containing multiple
+entries.  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<NETWORK_TIMEOUT> seconds
+
+An alias for B<BIND_TIMELIMIT> for OpenLDAP compatibility.
+
+=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<TIMEOUT> seconds
+
+The B<TIMEOUT> parameter specifies the amount of time, in seconds,
+to wait for a response from the various LDAP APIs.
+
+=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>.  Multiple B<SUDOERS_BASE> lines may be specified,
+in which case they are queried in the order specified.
+
+=item B<SUDOERS_SEARCH_FILTER> ldap_filter
+
+An LDAP filter which is used to restrict the set of records returned
+when performing a B<sudo> LDAP query.  Typically, this is of the
+form C<attribute=value> or C<(&(attribute=value)(attribute2=value2))>.
+
+=item B<SUDOERS_TIMED> on/true/yes/off/false/no
+
+Whether or not to evaluate the C<sudoNotBefore> and C<sudoNotAfter>
+attributes that implement time-dependent sudoers entries.
+
+=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.  Note that disabling the check creates
+an opportunity for man-in-the-middle attacks since the server's
+identity will not be authenticated.  If possible, the CA's certificate
+should be installed locally so it can be verified.
+
+=item B<TLS_CACERT> file name
+
+An alias for B<TLS_CACERTFILE> for OpenLDAP compatibility.
+
+=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.
+Netscape-derived LDAP libraries use the same certificate
+database for CA and client certificates (see B<TLS_CERT>).
+
+=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.
+
+=head2 Configuring netsvc.conf
+
+On AIX systems, the F<@netsvc_conf@> file is consulted instead of
+F<@nsswitch_conf@>.  B<sudo> simply treats I<netsvc.conf> as a
+variant of I<nsswitch.conf>; information in the previous section
+unrelated to the file format itself still applies.
+
+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
+
+To treat LDAP as authoratative and only use the local sudoers file
+if the user is not present in LDAP, use:
+
+    sudoers = ldap = auth, files
+
+Note that in the above example, the C<auth> qualfier only affects
+user lookups; both LDAP and I<sudoers> will be queried for C<Defaults>
+entries.
+
+If the F<@netsvc_conf@> file is not present or there is no
+sudoers line, the following default is assumed:
+
+    sudoers = files
+
+=head1 FILES
+
+=over 24
+
+=item F<@ldap_conf@>
+
+LDAP configuration file
+
+=item F<@nsswitch_conf@>
+
+determines sudoers source order
+
+=item F<@netsvc_conf@>
+
+determines sudoers source order on AIX
+
+=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; may be specified multiple times.
+  sudoers_base   ou=SUDOers,dc=example,dc=com
+  #
+  # verbose sudoers matching from ldap
+  #sudoers_debug 2
+  #
+  # Enable support for time-based entries in sudoers.
+  #sudoers_timed yes
+  #
+  # 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, tls_cert and tls_key may specify either
+  # a directory, in which case the files in the directory must have the
+  # default names (e.g. cert8.db and key4.db), or the path to the cert
+  # and key files themselves.  However, a bug in version 5.0 of the LDAP
+  # SDK will prevent specific file names from working.  For this reason
+  # it is suggested that tls_cert and tls_key be set to a directory,
+  # not a file name.
+  #
+  # The certificate database 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
+  #tls_key /var/ldap
+  #
+  # If using SASL authentication for LDAP (OpenSSL)
+  # use_sasl yes
+  # sasl_auth_id <SASL user name>
+  # rootuse_sasl yes
+  # rootsasl_auth_id <SASL user name for root access>
+  # sasl_secprops none
+  # krb5_ccname /etc/.ldapcache
+
+=head2 Sudo schema for OpenLDAP 
+
+The following schema, in OpenLDAP format, is included with B<sudo>
+source and binary distributions as F<schema.OpenLDAP>.  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 )
+
+ attributetype ( 1.3.6.1.4.1.15953.9.1.8
+    NAME 'sudoNotBefore'
+    DESC 'Start of time interval for which the entry is valid'
+    EQUALITY generalizedTimeMatch
+    ORDERING generalizedTimeOrderingMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+ attributetype ( 1.3.6.1.4.1.15953.9.1.9
+    NAME 'sudoNotAfter'
+    DESC 'End of time interval for which the entry is valid'
+    EQUALITY generalizedTimeMatch
+    ORDERING generalizedTimeOrderingMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+ attributeTypes ( 1.3.6.1.4.1.15953.9.1.10
+     NAME 'sudoOrder'
+     DESC 'an integer to order the sudoRole entries'
+     EQUALITY integerMatch
+     ORDERING integerOrderingMatch
+     SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+ 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 $ sudoNotBefore $ sudoNotAfter $
+         sudoOrder $ description )
+    )
+
+=head1 SEE ALSO
+
+L<ldap.conf(5)>, L<sudoers(5)>
+
+=head1 CAVEATS
+
+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.
diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in
new file mode 100644 (file)
index 0000000..90868c8
--- /dev/null
@@ -0,0 +1,2034 @@
+.\" Copyright (c) 1994-1996, 1998-2005, 2007-2011
+.\"    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.
+.\" 
+.\" 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.
+.\" 
+.nr SL @SEMAN@
+.nr BA @BAMAN@
+.nr LC @LCMAN@
+.\"
+.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.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 (.SS), 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 @mansectform@"
+.TH SUDOERS @mansectform@ "May 16, 2011" "1.8.1p2" "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 \- default sudo security policy module
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+The \fIsudoers\fR policy module determines a user's \fBsudo\fR privileges.
+It is the default \fBsudo\fR policy plugin.  The policy is driven by
+the \fI@sysconfdir@/sudoers\fR file or, optionally in \s-1LDAP\s0.  The policy
+format is described in detail in the \*(L"\s-1SUDOERS\s0 \s-1FILE\s0 \s-1FORMAT\s0\*(R"
+section.  For information on storing \fIsudoers\fR policy information
+in \s-1LDAP\s0, please see \fIsudoers.ldap\fR\|(@mansectform@).
+.SS "Authentication and Logging"
+.IX Subsection "Authentication and Logging"
+The \fIsudoers\fR security policy requires that most users authenticate
+themselves before they can use \fBsudo\fR.  A password is not required
+if the invoking user is root, if the target user is the same as the
+invoking user, or if the policy has disabled authentication for the
+user or command.  Unlike \fIsu\fR\|(1), when \fIsudoers\fR requires
+authentication, it validates the invoking user's credentials, not
+the target user's (or root's) credentials.  This can be changed via
+the \fIrootpw\fR, \fItargetpw\fR and \fIrunaspw\fR flags, described later.
+.PP
+If a user who is not listed in the policy tries to run a command
+via \fBsudo\fR, mail is sent to the proper authorities.  The address
+used for such mail is configurable via the \fImailto\fR Defaults entry
+(described later) and defaults to \f(CW\*(C`@mailto@\*(C'\fR.
+.PP
+Note that mail will not be sent if an unauthorized user tries to
+run \fBsudo\fR 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
+If \fBsudo\fR is run by root and the \f(CW\*(C`SUDO_USER\*(C'\fR environment variable
+is set, the \fIsudoers\fR policy 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 option to remain useful even when invoked via a
+sudo-run script or program.  Note, however, that the \fIsudoers\fR
+lookup is still done for root, not the user specified by \f(CW\*(C`SUDO_USER\*(C'\fR.
+.PP
+\&\fIsudoers\fR uses time stamp files for credential caching.  Once a
+user has been authenticated, a time stamp is updated and the user
+may then use sudo without a password for a short period of time
+(\f(CW\*(C`@timeout@\*(C'\fR minutes unless overridden by the \fItimeout\fR option.
+By default, \fIsudoers\fR uses a tty-based time stamp which means that
+there is a separate time stamp for each of a user's login sessions.
+The \fItty_tickets\fR option can be disabled to force the use of a
+single time stamp for all of a user's sessions.
+.PP
+\&\fIsudoers\fR can log both successful and unsuccessful attempts (as well
+as errors) to \fIsyslog\fR\|(3), a log file, or both.  By default, \fIsudoers\fR
+will log via \fIsyslog\fR\|(3) but this is changeable via the \fIsyslog\fR
+and \fIlogfile\fR Defaults settings.
+.PP
+\&\fIsudoers\fR also supports logging a command's input and output
+streams.  I/O logging is not on by default but can be enabled using
+the \fIlog_input\fR and \fIlog_output\fR Defaults flags as well as the
+\&\f(CW\*(C`LOG_INPUT\*(C'\fR and \f(CW\*(C`LOG_OUTPUT\*(C'\fR command tags.
+.SS "Command Environment"
+.IX Subsection "Command Environment"
+Since environment variables can influence program behavior, \fIsudoers\fR
+provides a means to restrict which variables from the user's
+environment are inherited by the command to be run.  There are two
+distinct ways \fIsudoers\fR can deal with environment variables.
+.PP
+By default, the \fIenv_reset\fR option is enabled.  This causes commands
+to be executed with a minimal environment containing \f(CW\*(C`TERM\*(C'\fR,
+\&\f(CW\*(C`PATH\*(C'\fR, \f(CW\*(C`HOME\*(C'\fR, \f(CW\*(C`MAIL\*(C'\fR, \f(CW\*(C`SHELL\*(C'\fR, \f(CW\*(C`LOGNAME\*(C'\fR, \f(CW\*(C`USER\*(C'\fR and \f(CW\*(C`USERNAME\*(C'\fR in
+addition to variables from the invoking process permitted by the
+\&\fIenv_check\fR and \fIenv_keep\fR options.  This is effectively a whitelist
+for environment variables.
+.PP
+If, however, the \fIenv_reset\fR option is disabled, any variables not
+explicitly denied by the \fIenv_check\fR and \fIenv_delete\fR options are
+inherited from the invoking process.  In this case, \fIenv_check\fR
+and \fIenv_delete\fR behave like a blacklist.  Since it is not possible
+to blacklist all potentially dangerous environment variables, use
+of the default \fIenv_reset\fR behavior is encouraged.
+.PP
+In all cases, environment variables with a value beginning with
+\&\f(CW\*(C`()\*(C'\fR are removed as they could be interpreted as \fBbash\fR functions.
+The list of environment variables that \fBsudo\fR allows or denies is
+contained in the output of \f(CW\*(C`sudo \-V\*(C'\fR when run as root.
+.PP
+Note that the dynamic linker on most operating systems will remove
+variables that can control dynamic linking from the environment of
+setuid executables, including \fBsudo\fR.  Depending on the operating
+system this may include \f(CW\*(C`_RLD*\*(C'\fR, \f(CW\*(C`DYLD_*\*(C'\fR, \f(CW\*(C`LD_*\*(C'\fR, \f(CW\*(C`LDR_*\*(C'\fR,
+\&\f(CW\*(C`LIBPATH\*(C'\fR, \f(CW\*(C`SHLIB_PATH\*(C'\fR, and others.  These type of variables are
+removed from the environment before \fBsudo\fR even begins execution
+and, as such, it is not possible for \fBsudo\fR to preserve them.
+.PP
+As a special case, If \fBsudo\fR's \fB\-i\fR option (initial login) is
+specified, \fIsudoers\fR will initialize the environment regardless
+of the value of \fIenv_reset\fR.  The \fI\s-1DISPLAY\s0\fR, \fI\s-1PATH\s0\fR and \fI\s-1TERM\s0\fR
+variables remain unchanged; \fI\s-1HOME\s0\fR, \fI\s-1MAIL\s0\fR, \fI\s-1SHELL\s0\fR, \fI\s-1USER\s0\fR,
+and \fI\s-1LOGNAME\s0\fR are set based on the target user.  On Linux and \s-1AIX\s0
+systems the contents of \fI/etc/environment\fR are also included.  All
+other environment variables are removed.
+.SH "SUDOERS FILE FORMAT"
+.IX Header "SUDOERS FILE FORMAT"
+The \fIsudoers\fR file is composed of two types of entries: aliases
+(basically variables) and user specifications (which specify who
+may run what).
+.PP
+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).
+.PP
+The \fIsudoers\fR grammar will be described below in Extended Backus-Naur
+Form (\s-1EBNF\s0).  Don't despair if you don't know what \s-1EBNF\s0 is; it is
+fairly simple, and the definitions below are annotated.
+.SS "Quick guide to \s-1EBNF\s0"
+.IX Subsection "Quick guide to EBNF"
+\&\s-1EBNF\s0 is a concise and exact way of describing the grammar of a language.
+Each \s-1EBNF\s0 definition is made up of \fIproduction rules\fR.  E.g.,
+.PP
+.Vb 1
+\& symbol ::= definition | alternate1 | alternate2 ...
+.Ve
+.PP
+Each \fIproduction rule\fR references others and thus makes up a
+grammar for the language.  \s-1EBNF\s0 also contains the following
+operators, which many readers will recognize from regular
+expressions.  Do not, however, confuse them with \*(L"wildcard\*(R"
+characters, which have different meanings.
+.ie n .IP "\*(C`?\*(C'" 4
+.el .IP "\f(CW\*(C`?\*(C'\fR" 4
+.IX Item "?"
+Means that the preceding symbol (or group of symbols) is optional.
+That is, it may appear once or not at all.
+.ie n .IP "\*(C`*\*(C'" 4
+.el .IP "\f(CW\*(C`*\*(C'\fR" 4
+.IX Item "*"
+Means that the preceding symbol (or group of symbols) may appear
+zero or more times.
+.ie n .IP "\*(C`+\*(C'" 4
+.el .IP "\f(CW\*(C`+\*(C'\fR" 4
+.IX Item "+"
+Means that the preceding symbol (or group of symbols) may appear
+one or more times.
+.PP
+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).
+.SS "Aliases"
+.IX Subsection "Aliases"
+There are four kinds of aliases: \f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_Alias\*(C'\fR,
+\&\f(CW\*(C`Host_Alias\*(C'\fR and \f(CW\*(C`Cmnd_Alias\*(C'\fR.
+.PP
+.Vb 4
+\& 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
+.PP
+.Vb 1
+\& Alias_Type NAME = item1, item2, ...
+.Ve
+.PP
+where \fIAlias_Type\fR is one of \f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_Alias\*(C'\fR, \f(CW\*(C`Host_Alias\*(C'\fR,
+or \f(CW\*(C`Cmnd_Alias\*(C'\fR.  A \f(CW\*(C`NAME\*(C'\fR is a string of uppercase letters, numbers,
+and underscore characters ('_').  A \f(CW\*(C`NAME\*(C'\fR \fBmust\fR 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.,
+.PP
+.Vb 1
+\& Alias_Type NAME = item1, item2, item3 : NAME = item4, item5
+.Ve
+.PP
+The definitions of what constitutes a valid \fIalias\fR member follow.
+.PP
+.Vb 2
+\& User_List ::= User |
+\&               User \*(Aq,\*(Aq User_List
+\&
+\& User ::= \*(Aq!\*(Aq* user name |
+\&          \*(Aq!\*(Aq* #uid |
+\&          \*(Aq!\*(Aq* %group |
+\&          \*(Aq!\*(Aq* %#gid |
+\&          \*(Aq!\*(Aq* +netgroup |
+\&          \*(Aq!\*(Aq* %:nonunix_group |
+\&          \*(Aq!\*(Aq* %:#nonunix_gid |
+\&          \*(Aq!\*(Aq* User_Alias
+.Ve
+.PP
+A \f(CW\*(C`User_List\*(C'\fR is made up of one or more user names, user ids
+(prefixed with '#'), system group names and ids (prefixed with '%'
+and '%#' respectively), netgroups (prefixed with '+'), non-Unix
+group names and IDs (prefixed with '%:' and '%:#' respectively) 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
+A \f(CW\*(C`user name\*(C'\fR, \f(CW\*(C`uid\*(C'\fR, \f(CW\*(C`group\*(C'\fR, \f(CW\*(C`gid\*(C'\fR, \f(CW\*(C`netgroup\*(C'\fR, \f(CW\*(C`nonunix_group\*(C'\fR
+or \f(CW\*(C`nonunix_gid\*(C'\fR may be enclosed in double quotes to avoid the
+need for escaping special characters.  Alternately, special characters
+may be specified in escaped hex mode, e.g. \ex20 for space.  When
+using double quotes, any prefix characters must be included inside
+the quotes.
+.PP
+The actual \f(CW\*(C`nonunix_group\*(C'\fR and \f(CW\*(C`nonunix_gid\*(C'\fR syntax depends on
+the underlying group provider plugin (see the \fIgroup_plugin\fR
+description below).  For instance, the \s-1QAS\s0 \s-1AD\s0 plugin supports the
+following formats:
+.IP "\(bu" 4
+Group in the same domain: \*(L"Group Name\*(R"
+.IP "\(bu" 4
+Group in any domain: \*(L"Group Name@FULLY.QUALIFIED.DOMAIN\*(R"
+.IP "\(bu" 4
+Group \s-1SID:\s0 \*(L"S\-1\-2\-34\-5678901234\-5678901234\-5678901234\-567\*(R"
+.PP
+Note that quotes around group names are optional.  Unquoted strings
+must use a backslash (\e) to escape spaces and special characters.
+See \*(L"Other special characters and reserved words\*(R" for a list of
+characters that need to be escaped.
+.PP
+.Vb 2
+\& Runas_List ::= Runas_Member |
+\&                Runas_Member \*(Aq,\*(Aq Runas_List
+\&
+\& Runas_Member ::= \*(Aq!\*(Aq* user name |
+\&                  \*(Aq!\*(Aq* #uid |
+\&                  \*(Aq!\*(Aq* %group |
+\&                  \*(Aq!\*(Aq* %#gid |
+\&                  \*(Aq!\*(Aq* %:nonunix_group |
+\&                  \*(Aq!\*(Aq* %:#nonunix_gid |
+\&                  \*(Aq!\*(Aq* +netgroup |
+\&                  \*(Aq!\*(Aq* 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 instead
+of \f(CW\*(C`User_Alias\*(C'\fRes it can contain \f(CW\*(C`Runas_Alias\*(C'\fRes.  Note that
+user names 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 user names 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 \*(Aq,\*(Aq Host_List
+\&
+\& Host ::= \*(Aq!\*(Aq* host name |
+\&          \*(Aq!\*(Aq* ip_addr |
+\&          \*(Aq!\*(Aq* network(/netmask)? |
+\&          \*(Aq!\*(Aq* +netgroup |
+\&          \*(Aq!\*(Aq* Host_Alias
+.Ve
+.PP
+A \f(CW\*(C`Host_List\*(C'\fR is made up of one or more host names, \s-1IP\s0 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,
+\&\fBsudo\fR 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 \s-1IP\s0 address notation
+(e.g.\ 255.255.255.0 or ffff:ffff:ffff:ffff::),
+or \s-1CIDR\s0 notation (number of bits, e.g.\ 24 or 64).  A host name may
+include shell-style wildcards (see the Wildcards section below),
+but unless the \f(CW\*(C`host name\*(C'\fR command on your machine returns the fully
+qualified host name, you'll need to use the \fIfqdn\fR option for
+wildcards to be useful.  Note \fBsudo\fR only inspects actual network
+interfaces; this means that \s-1IP\s0 address 127.0.0.1 (localhost) will
+never match.  Also, the host name \*(L"localhost\*(R" will only match if
+that is the actual host name, which is usually only the case for
+non-networked systems.
+.PP
+.Vb 2
+\& Cmnd_List ::= Cmnd |
+\&               Cmnd \*(Aq,\*(Aq Cmnd_List
+\&
+\& commandname ::= file name |
+\&                 file name args |
+\&                 file name \*(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
+aliases.  A commandname is a fully qualified file name which may include
+shell-style wildcards (see the Wildcards section below).  A simple
+file name 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 \f(CW""\fR to indicate that the command
+may only be run \fBwithout\fR command line arguments.  A directory is a
+fully qualified path name ending in a '/'.  When you specify a directory
+in a \f(CW\*(C`Cmnd_List\*(C'\fR, the user will be able to run any file within that directory
+(but not in any subdirectories therein).
+.PP
+If a \f(CW\*(C`Cmnd\*(C'\fR has associated command line arguments, then the arguments
+in the \f(CW\*(C`Cmnd\*(C'\fR 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 '\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 option (or
+as \fBsudoedit\fR).  It may take command line arguments just as
+a normal command does.
+.SS "Defaults"
+.IX Subsection "Defaults"
+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, 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 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
+\&
+\& Parameter_List ::= 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.
+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 (\f(CW\*(C`"\*(C'\fR) when they contain multiple words.  Special
+characters may be escaped with a backslash (\f(CW\*(C`\e\*(C'\fR).
+.PP
+Lists have two additional assignment operators, \f(CW\*(C`+=\*(C'\fR and \f(CW\*(C`\-=\*(C'\fR.
+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.
+.SS "User Specification"
+.IX Subsection "User Specification"
+.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 \*(Aq,\*(Aq Cmnd_Spec_List
+\&
+.ie \n(SL \& Cmnd_Spec ::= Runas_Spec? SELinux_Spec? Tag_Spec* Cmnd
+.el \& Cmnd_Spec ::= Runas_Spec? Tag_Spec* Cmnd
+\&
+\& Runas_Spec ::= \*(Aq(\*(Aq Runas_List? (\*(Aq:\*(Aq Runas_List)? \*(Aq)\*(Aq
+\&
+.if \n(SL \{\
+\& SELinux_Spec ::= (\*(AqROLE=role\*(Aq | \*(AqTYPE=type\*(Aq)
+\&
+\}
+\& Tag_Spec ::= (\*(AqNOPASSWD:\*(Aq | \*(AqPASSWD:\*(Aq | \*(AqNOEXEC:\*(Aq | \*(AqEXEC:\*(Aq |
+\&               \*(AqSETENV:\*(Aq | \*(AqNOSETENV:\*(Aq | \*(AqLOG_INPUT:\*(Aq | \*(AqNOLOG_INPUT:\*(Aq |
+\&               \*(AqLOG_OUTPUT:\*(Aq | \*(AqNOLOG_OUTPUT:\*(Aq)
+.Ve
+.PP
+A \fBuser specification\fR determines which commands a user may run
+(and as what user) on specified hosts.  By default, commands are
+run as \fBroot\fR, but this can be changed on a per-command basis.
+.PP
+The basic structure of a user specification is `who where = (as_whom)
+what'.  Let's break that down into its constituent parts:
+.SS "Runas_Spec"
+.IX Subsection "Runas_Spec"
+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
+.Ve
+.PP
+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
+.Ve
+.PP
+It is also possible to override a \f(CW\*(C`Runas_Spec\*(C'\fR later on in an
+entry.  If we modify the entry like so:
+.PP
+.Vb 1
+\& dgb    boulder = (operator) /bin/ls, (root) /bin/kill, /usr/bin/lprm
+.Ve
+.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
+Note that while the group portion of the \f(CW\*(C`Runas_Spec\*(C'\fR permits the
+user to run as command with that group, it does not force the user
+to do so.  If no group is specified on the command line, the command
+will run with the group listed in the target user's password database
+entry.  The following would all be permitted by the sudoers entry above:
+.PP
+.Vb 3
+\& $ sudo \-u operator /bin/ls
+\& $ sudo \-u operator \-g operator /bin/ls
+\& $ sudo \-g operator /bin/ls
+.Ve
+.PP
+In the following example, user \fBtcm\fR may run commands that access
+a modem device file with the dialer group.
+.PP
+.Vb 2
+\& tcm    boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \e
+\&        /usr/local/bin/minicom
+.Ve
+.PP
+Note that in this example only the group will be set, the command
+still runs as user \fBtcm\fR.  E.g.
+.PP
+.Vb 1
+\& $ sudo \-g dialer /usr/bin/cu
+.Ve
+.PP
+Multiple users and groups may be present in a \f(CW\*(C`Runas_Spec\*(C'\fR, in
+which case the user may select any combination of users and groups
+via the \fB\-u\fR and \fB\-g\fR options.  In this example:
+.PP
+.Vb 1
+\& alan   ALL = (root, bin : operator, system) ALL
+.Ve
+.PP
+user \fBalan\fR may run any command as either user root or bin,
+optionally setting the group to operator or system.
+.if \n(SL \{\
+.SS "SELinux_Spec"
+.IX Subsection "SELinux_Spec"
+On systems with SELinux support, \fIsudoers\fR entries may optionally have
+an SELinux role and/or type associated with a command.  If a role or
+type is specified with the command it will override any default values
+specified in \fIsudoers\fR.  A role or type specified on the command line,
+however, will supercede the values in \fIsudoers\fR.
+\}
+.SS "Tag_Spec"
+.IX Subsection "Tag_Spec"
+A command may have zero or more tags associated with it.  There are
+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, \f(CW\*(C`NOSETENV\*(C'\fR, \f(CW\*(C`LOG_INPUT\*(C'\fR, \f(CW\*(C`NOLOG_INPUT\*(C'\fR,
+\&\f(CW\*(C`LOG_OUTPUT\*(C'\fR and \f(CW\*(C`NOLOG_OUTPUT\*(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 opposite tag (i.e.: \f(CW\*(C`PASSWD\*(C'\fR overrides
+\&\f(CW\*(C`NOPASSWD\*(C'\fR and \f(CW\*(C`NOEXEC\*(C'\fR overrides \f(CW\*(C`EXEC\*(C'\fR).
+.PP
+\fI\s-1NOPASSWD\s0 and \s-1PASSWD\s0\fR
+.IX Subsection "NOPASSWD and PASSWD"
+.PP
+By default, \fBsudo\fR requires that a user authenticate him or herself
+before running a command.  This behavior can be modified via the
+\&\f(CW\*(C`NOPASSWD\*(C'\fR tag.  Like a \f(CW\*(C`Runas_Spec\*(C'\fR, the \f(CW\*(C`NOPASSWD\*(C'\fR tag sets
+a default for the commands that follow it in the \f(CW\*(C`Cmnd_Spec_List\*(C'\fR.
+Conversely, the \f(CW\*(C`PASSWD\*(C'\fR tag can be used to reverse things.
+For example:
+.PP
+.Vb 1
+\& ray    rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm
+.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 \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
+.Vb 1
+\& ray    rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm
+.Ve
+.PP
+Note, however, that the \f(CW\*(C`PASSWD\*(C'\fR tag has no effect on users who are
+in the group specified by the \fIexempt_group\fR option.
+.PP
+By default, if the \f(CW\*(C`NOPASSWD\*(C'\fR tag is applied to any of the entries
+for a user on the current host, he or she will be able to run
+\&\f(CW\*(C`sudo \-l\*(C'\fR without a password.  Additionally, a user may only run
+\&\f(CW\*(C`sudo \-v\*(C'\fR without a password if the \f(CW\*(C`NOPASSWD\*(C'\fR 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.
+.PP
+\fI\s-1NOEXEC\s0 and \s-1EXEC\s0\fR
+.IX Subsection "NOEXEC and EXEC"
+.PP
+If \fBsudo\fR has been compiled with \fInoexec\fR support and the underlying
+operating system supports it, the \f(CW\*(C`NOEXEC\*(C'\fR tag can be used to prevent
+a dynamically-linked executable from running further commands itself.
+.PP
+In the following example, user \fBaaron\fR may run \fI/usr/bin/more\fR
+and \fI/usr/bin/vi\fR but shell escapes will be disabled.
+.PP
+.Vb 1
+\& aaron  shanty = NOEXEC: /usr/bin/more, /usr/bin/vi
+.Ve
+.PP
+See the \*(L"\s-1PREVENTING\s0 \s-1SHELL\s0 \s-1ESCAPES\s0\*(R" section below for more details
+on how \f(CW\*(C`NOEXEC\*(C'\fR works and whether or not it will work on your system.
+.PP
+\fI\s-1SETENV\s0 and \s-1NOSETENV\s0\fR
+.IX Subsection "SETENV and NOSETENV"
+.PP
+These tags override the value of the \fIsetenv\fR option on a per-command
+basis.  Note that if \f(CW\*(C`SETENV\*(C'\fR has been set for a command, the user
+may disable the \fIenv_reset\fR option from the command line via the
+\&\fB\-E\fR option.  Additionally, environment variables set on the command
+line are not subject to the restrictions imposed by \fIenv_check\fR,
+\&\fIenv_delete\fR, or \fIenv_keep\fR.  As such, only trusted users should
+be allowed to set variables in this manner.  If the command matched
+is \fB\s-1ALL\s0\fR, the \f(CW\*(C`SETENV\*(C'\fR tag is implied for that command; this
+default may be overridden by use of the \f(CW\*(C`NOSETENV\*(C'\fR tag.
+.PP
+\fI\s-1LOG_INPUT\s0 and \s-1NOLOG_INPUT\s0\fR
+.IX Subsection "LOG_INPUT and NOLOG_INPUT"
+.PP
+These tags override the value of the \fIlog_input\fR option on a
+per-command basis.  For more information, see the description of
+\&\fIlog_input\fR in the \*(L"\s-1SUDOERS\s0 \s-1OPTIONS\s0\*(R" section below.
+.PP
+\fI\s-1LOG_OUTPUT\s0 and \s-1NOLOG_OUTPUT\s0\fR
+.IX Subsection "LOG_OUTPUT and NOLOG_OUTPUT"
+.PP
+These tags override the value of the \fIlog_output\fR option on a
+per-command basis.  For more information, see the description of
+\&\fIlog_output\fR in the \*(L"\s-1SUDOERS\s0 \s-1OPTIONS\s0\*(R" section below.
+.SS "Wildcards"
+.IX Subsection "Wildcards"
+\&\fBsudo\fR allows shell-style \fIwildcards\fR (aka meta or glob characters)
+to be used in host names, path names and command line arguments in
+the \fIsudoers\fR file.  Wildcard matching is done via the \fB\s-1POSIX\s0\fR
+\&\fIglob\fR\|(3) and \fIfnmatch\fR\|(3) routines.  Note that these are \fInot\fR
+regular expressions.
+.ie n .IP "\*(C`*\*(C'" 8
+.el .IP "\f(CW\*(C`*\*(C'\fR" 8
+.IX Item "*"
+Matches any set of zero or more characters.
+.ie n .IP "\*(C`?\*(C'" 8
+.el .IP "\f(CW\*(C`?\*(C'\fR" 8
+.IX Item "?"
+Matches any single character.
+.ie n .IP "\*(C`[...]\*(C'" 8
+.el .IP "\f(CW\*(C`[...]\*(C'\fR" 8
+.IX Item "[...]"
+Matches any character in the specified range.
+.ie n .IP "\*(C`[!...]\*(C'" 8
+.el .IP "\f(CW\*(C`[!...]\*(C'\fR" 8
+.IX Item "[!...]"
+Matches any character \fBnot\fR in the specified range.
+.ie n .IP "\*(C`\ex\*(C'" 8
+.el .IP "\f(CW\*(C`\ex\*(C'\fR" 8
+.IX Item "x"
+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 \fIglob\fR\|(3)
+and \fIfnmatch\fR\|(3) functions support 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 file name beginning with a letter.
+.PP
+Note that a forward slash ('/') will \fBnot\fR be matched by
+wildcards used in the path name.  When matching the command
+line arguments, however, a slash \fBdoes\fR get matched by
+wildcards.  This is to make a path like:
+.PP
+.Vb 1
+\&    /usr/bin/*
+.Ve
+.PP
+match \fI/usr/bin/who\fR but not \fI/usr/bin/X11/xterm\fR.
+.SS "Exceptions to wildcard rules"
+.IX Subsection "Exceptions to wildcard rules"
+The following exceptions apply to the above rules:
+.ie n .IP """""" 8
+.el .IP "\f(CW``''\fR" 8
+.IX Item """"""
+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.
+.SS "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 and
+\&\f(CW\*(C`#includedir\*(C'\fR directives.
+.PP
+This can be used, for example, to keep a site-wide \fIsudoers\fR file
+in addition to a local, per-machine file.  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 within \fI/etc/sudoers\fR we would use the
+following line in \fI/etc/sudoers\fR:
+.Sp
+.RS 4
+\&\f(CW\*(C`#include /etc/sudoers.local\*(C'\fR
+.RE
+.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.
+.PP
+The file name may include the \f(CW%h\fR escape, signifying the short form
+of the host name.  I.e., if the machine's host name is \*(L"xerxes\*(R", then
+.PP
+\&\f(CW\*(C`#include /etc/sudoers.%h\*(C'\fR
+.PP
+will cause \fBsudo\fR to include the file \fI/etc/sudoers.xerxes\fR.
+.PP
+The \f(CW\*(C`#includedir\*(C'\fR directive can be used to create a \fIsudo.d\fR
+directory that the system package manager can drop \fIsudoers\fR rules
+into as part of package installation.  For example, given:
+.PP
+\&\f(CW\*(C`#includedir /etc/sudoers.d\*(C'\fR
+.PP
+\&\fBsudo\fR will read each file in \fI/etc/sudoers.d\fR, skipping file
+names that end in \f(CW\*(C`~\*(C'\fR or contain a \f(CW\*(C`.\*(C'\fR character to avoid causing
+problems with package manager or editor temporary/backup files.
+Files are parsed in sorted lexical order.  That is,
+\&\fI/etc/sudoers.d/01_first\fR will be parsed before
+\&\fI/etc/sudoers.d/10_second\fR.  Be aware that because the sorting is
+lexical, not numeric, \fI/etc/sudoers.d/1_whoops\fR would be loaded
+\&\fBafter\fR \fI/etc/sudoers.d/10_second\fR.  Using a consistent number
+of leading zeroes in the file names can be used to avoid such
+problems.
+.PP
+Note that unlike files included via \f(CW\*(C`#include\*(C'\fR, \fBvisudo\fR will not
+edit the files in a \f(CW\*(C`#includedir\*(C'\fR directory unless one of them
+contains a syntax error.  It is still possible to run \fBvisudo\fR
+with the \f(CW\*(C`\-f\*(C'\fR flag to edit the files directly.
+.SS "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
+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.
+.PP
+The reserved word \fB\s-1ALL\s0\fR is a built-in \fIalias\fR that always causes
+a match to succeed.  It can be used wherever one might otherwise
+use a \f(CW\*(C`Cmnd_Alias\*(C'\fR, \f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_Alias\*(C'\fR, or \f(CW\*(C`Host_Alias\*(C'\fR.
+You should not try to define your own \fIalias\fR called \fB\s-1ALL\s0\fR as the
+built-in alias will be used in preference to your own.  Please note
+that using \fB\s-1ALL\s0\fR can be dangerous since in a command context, it
+allows the user to run \fBany\fR command on the system.
+.PP
+An exclamation point ('!') can be used as a logical \fInot\fR operator
+both in an \fIalias\fR and in front of a \f(CW\*(C`Cmnd\*(C'\fR.  This allows one to
+exclude certain values.  Note, however, that using a \f(CW\*(C`!\*(C'\fR in
+conjunction with the built-in \f(CW\*(C`ALL\*(C'\fR alias to allow a user to
+run \*(L"all but a few\*(R" commands rarely works as intended (see \s-1SECURITY\s0
+\&\s-1NOTES\s0 below).
+.PP
+Long lines can be continued with a backslash ('\e') as the last
+character on the line.
+.PP
+Whitespace between elements in a list as well as special syntactic
+characters in a \fIUser Specification\fR ('=', ':', '(', ')') is optional.
+.PP
+The following characters must be escaped with a backslash ('\e') when
+used as part of a word (e.g.\ a user name or host name):
+\&'!', '=', ':', ',', '(', ')', '\e'.
+.SH "SUDOERS OPTIONS"
+.IX Header "SUDOERS OPTIONS"
+\&\fBsudo\fR's behavior can be modified by \f(CW\*(C`Default_Entry\*(C'\fR lines, as
+explained earlier.  A list of all supported Defaults parameters,
+grouped by type, are listed below.
+.PP
+\&\fBBoolean Flags\fR:
+.IP "always_set_home" 16
+.IX Item "always_set_home"
+If enabled, \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 option is
+always implied.  Note that \f(CW\*(C`HOME\*(C'\fR is already set when the the
+\&\fIenv_reset\fR option is enabled, so \fIalways_set_home\fR is only
+effective for configurations where either \fIenv_reset\fR is disabled
+or \f(CW\*(C`HOME\*(C'\fR is present in the \fIenv_keep\fR list.
+This flag is \fIoff\fR by default.
+.IP "authenticate" 16
+.IX Item "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 \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 "compress_io" 16
+.IX Item "compress_io"
+If set, and \fBsudo\fR is configured to log a command's input or output,
+the I/O logs will be compressed using \fBzlib\fR.  This flag is \fIon\fR
+by default when \fBsudo\fR is compiled with \fBzlib\fR support.
+.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
+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 \f(CW\*(C`editor\*(C'\fR
+variable.  \fBvisudo\fR will then only use the \s-1EDITOR\s0 or \s-1VISUAL\s0 if
+they match a value specified in \f(CW\*(C`editor\*(C'\fR.  This flag is \fI@env_editor@\fR by
+default.
+.IP "env_reset" 16
+.IX Item "env_reset"
+If set, \fBsudo\fR will reset the environment to only contain the
+\&\s-1LOGNAME\s0, \s-1MAIL\s0, \s-1SHELL\s0, \s-1USER\s0, \s-1USERNAME\s0 and the \f(CW\*(C`SUDO_*\*(C'\fR variables.  Any
+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 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 \fI@env_reset@\fR by default.
+.IP "fast_glob" 16
+.IX Item "fast_glob"
+Normally, \fBsudo\fR uses the \fIglob\fR\|(3) function to do shell-style
+globbing when matching path names.  However, since it accesses the
+file system, \fIglob\fR\|(3) can take a long time to complete for some
+patterns, especially when the pattern references a network file
+system that is mounted on demand (automounted).  The \fIfast_glob\fR
+option causes \fBsudo\fR to use the \fIfnmatch\fR\|(3) function, which does
+not access the file system to do its matching.  The disadvantage
+of \fIfast_glob\fR is that it is unable to match relative path names
+such as \fI./ls\fR or \fI../bin/ls\fR.  This has security implications
+when path names that include globbing characters are used with the
+negation operator, \f(CW\*(Aq!\*(Aq\fR, as such rules can be trivially bypassed.
+As such, this option should not be used when \fIsudoers\fR contains rules 
+that contain negated path names which include globbing characters.
+This flag is \fIoff\fR by default.
+.IP "fqdn" 16
+.IX Item "fqdn"
+Set this flag if you want to put fully qualified host names in the
+\&\fIsudoers\fR 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 \fIfqdn\fR requires \fBsudo\fR to make \s-1DNS\s0 lookups
+which may make \fBsudo\fR unusable if \s-1DNS\s0 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 \s-1DNS\s0 knows it.  That is,
+you may not use a host alias (\f(CW\*(C`CNAME\*(C'\fR entry) due to performance
+issues and the fact that there is no way to get all aliases from
+\&\s-1DNS\s0.  If your machine's host name (as returned by the \f(CW\*(C`hostname\*(C'\fR
+command) is already fully qualified you shouldn't need to set
+\&\fIfqdn\fR.  This flag is \fI@fqdn@\fR by default.
+.IP "ignore_dot" 16
+.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.
+.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.
+This is intended for Enterprises that wish to prevent the usage of local
+sudoers files so that only \s-1LDAP\s0 is used.  This thwarts the efforts of
+rogue operators who would attempt to add roles to \fI@sysconfdir@/sudoers\fR.
+When this option is present, \fI@sysconfdir@/sudoers\fR does not even need to
+exist. Since this option tells \fBsudo\fR how to behave when no specific \s-1LDAP\s0
+entries have been matched, this sudoOption is only meaningful for the
+\&\f(CW\*(C`cn=defaults\*(C'\fR section.  This flag is \fIoff\fR by default.
+.IP "insults" 16
+.IX Item "insults"
+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 host name will be logged in the (non-syslog) \fBsudo\fR log file.
+This flag is \fIoff\fR by default.
+.IP "log_input" 16
+.IX Item "log_input"
+If set, \fBsudo\fR will run the command in a \fIpseudo tty\fR and log all
+user input.
+If the standard input is not connected to the user's tty, due to
+I/O redirection or because the command is part of a pipeline, that
+input is also captured and stored in a separate log file.
+.Sp
+Input is logged to the directory specified by the \fIiolog_dir\fR
+option (\fI@iolog_dir@\fR by default) using a unique session \s-1ID\s0 that
+is included in the normal \fBsudo\fR log line, prefixed with \fITSID=\fR.
+The \fIiolog_file\fR option may be used to control the format of the
+session \s-1ID\s0.
+.Sp
+Note that user input may contain sensitive information such as
+passwords (even if they are not echoed to the screen), which will
+be stored in the log file unencrypted.  In most cases, logging the
+command output via \fIlog_output\fR is all that is required.
+.IP "log_output" 16
+.IX Item "log_output"
+If set, \fBsudo\fR will run the command in a \fIpseudo tty\fR and log all
+output that is sent to the screen, similar to the \fIscript\fR\|(1) command.
+If the standard output or standard error is not connected to the
+user's tty, due to I/O redirection or because the command is part
+of a pipeline, that output is also captured and stored in separate
+log files.
+.Sp
+Output is logged to the directory specified by the \fIiolog_dir\fR
+option (\fI@iolog_dir@\fR by default) using a unique session \s-1ID\s0 that
+is included in the normal \fBsudo\fR log line, prefixed with \fITSID=\fR.
+The \fIiolog_file\fR option may be used to control the format of the
+session \s-1ID\s0.
+.Sp
+Output logs may be viewed with the \fIsudoreplay\fR\|(@mansectsu@) utility, which
+can also be used to list or search the available logs.
+.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.
+This flag is \fIoff\fR by default.
+.IP "long_otp_prompt" 16
+.IX Item "long_otp_prompt"
+When validating with a One Time Password (\s-1OPT\s0) scheme such as
+\&\fBS/Key\fR or \fB\s-1OPIE\s0\fR, 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 \fI@long_otp_prompt@\fR by default.
+.IP "mail_always" 16
+.IX Item "mail_always"
+Send mail to the \fImailto\fR user every time a users runs \fBsudo\fR.
+This flag is \fIoff\fR by default.
+.IP "mail_badpass" 16
+.IX Item "mail_badpass"
+Send mail to the \fImailto\fR user if the user running \fBsudo\fR does not
+enter the correct password.  This flag is \fIoff\fR by default.
+.IP "mail_no_host" 16
+.IX Item "mail_no_host"
+If set, mail will be sent to the \fImailto\fR user if the invoking
+user exists in the \fIsudoers\fR file, but is not allowed to run
+commands on the current host.  This flag is \fI@mail_no_host@\fR by default.
+.IP "mail_no_perms" 16
+.IX Item "mail_no_perms"
+If set, mail will be sent to the \fImailto\fR user if the invoking
+user is allowed to use \fBsudo\fR but the command they are trying is not
+listed in their \fIsudoers\fR file entry or is explicitly denied.
+This flag is \fI@mail_no_perms@\fR by default.
+.IP "mail_no_user" 16
+.IX Item "mail_no_user"
+If set, mail will be sent to the \fImailto\fR user if the invoking
+user is not in the \fIsudoers\fR file.  This flag is \fI@mail_no_user@\fR
+by default.
+.IP "noexec" 16
+.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.
+.IP "path_info" 16
+.IX Item "path_info"
+Normally, \fBsudo\fR will tell the user when a command could not be
+found in their \f(CW\*(C`PATH\*(C'\fR 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 \f(CW\*(C`PATH\*(C'\fR, \fBsudo\fR will tell the user that they are not
+allowed to run it, which can be confusing.  This flag is \fI@path_info@\fR
+by default.
+.IP "passprompt_override" 16
+.IX Item "passprompt_override"
+The password prompt specified by \fIpassprompt\fR will normally only
+be used if the password prompt provided by systems such as \s-1PAM\s0 matches
+the string \*(L"Password:\*(R".  If \fIpassprompt_override\fR is set, \fIpassprompt\fR
+will always be used.  This flag is \fIoff\fR by default.
+.IP "preserve_groups" 16
+.IX Item "preserve_groups"
+By default, \fBsudo\fR will initialize the group vector to the list of
+groups the target user is in.  When \fIpreserve_groups\fR 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 \fIoff\fR by default.
+.IP "pwfeedback" 16
+.IX Item "pwfeedback"
+By default, \fBsudo\fR reads the password like most other Unix programs,
+by turning off echo until the user hits the return (or enter) key.
+Some users become confused by this as it appears to them that \fBsudo\fR
+has hung at this point.  When \fIpwfeedback\fR is set, \fBsudo\fR will
+provide visual feedback when the user presses a key.  Note that
+this does have a security impact as an onlooker may be able to
+determine the length of the password being entered.
+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.  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
+from \*(L"chaining\*(R" \fBsudo\fR commands to get a root shell by doing something
+like \f(CW"sudo sudo /bin/sh"\fR.  Note, however, that turning off \fIroot_sudo\fR
+will also prevent root from running \fBsudoedit\fR.
+Disabling \fIroot_sudo\fR provides no real additional security; it
+exists purely for historical reasons.
+This flag is \fI@root_sudo@\fR by default.
+.IP "rootpw" 16
+.IX Item "rootpw"
+If set, \fBsudo\fR will prompt for the root password instead of the password
+of the invoking user.  This flag is \fIoff\fR by default.
+.IP "runaspw" 16
+.IX Item "runaspw"
+If set, \fBsudo\fR will prompt for the password of the user defined by the
+\&\fIrunas_default\fR option (defaults to \f(CW\*(C`@runas_default@\*(C'\fR) instead of the
+password of the invoking user.  This flag is \fIoff\fR by default.
+.IP "set_home" 16
+.IX Item "set_home"
+If enabled 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 option imply \fB\-H\fR.  Note that \f(CW\*(C`HOME\*(C'\fR is already
+set when the the \fIenv_reset\fR option is enabled, so \fIset_home\fR is
+only effective for configurations where either \fIenv_reset\fR is disabled
+or \f(CW\*(C`HOME\*(C'\fR is present in the \fIenv_keep\fR list.
+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 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
+option.  Note that if the \fIenv_reset\fR option has not been disabled,
+entries in the \fIenv_keep\fR list will override the value of
+\&\fIset_logname\fR.  This flag is \fIon\fR by default.
+.IP "set_utmp" 16
+.IX Item "set_utmp"
+When enabled, \fBsudo\fR will create an entry in the utmp (or utmpx)
+file when a pseudo-tty is allocated.  A pseudo-tty is allocated by
+\&\fBsudo\fR when the \fIlog_input\fR, \fIlog_output\fR or \fIuse_pty\fR flags
+are enabled.  By default, the new entry will be a copy of the user's
+existing utmp entry (if any), with the tty, time, type and pid
+fields updated.  This flag is \fIon\fR by default.
+.IP "setenv" 16
+.IX Item "setenv"
+Allow the user to disable the \fIenv_reset\fR option from the command
+line via the \fB\-E\fR option.  Additionally, environment variables set
+via the command line are not subject to the restrictions imposed
+by \fIenv_check\fR, \fIenv_delete\fR, or \fIenv_keep\fR.  As such, only
+trusted users should be allowed to set variables in this manner.
+This flag is \fIoff\fR 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 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.
+.IP "stay_setuid" 16
+.IX Item "stay_setuid"
+Normally, when \fBsudo\fR 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 \s-1UID\s0 is left as the invoking
+user's \s-1UID\s0.  In other words, this makes \fBsudo\fR 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 \fIsetreuid()\fR or \fIsetresuid()\fR
+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 option (defaults to \f(CW\*(C`root\*(C'\fR) instead of the password
+of the invoking user.  In addition, the timestamp file name will
+include the target user's name.  Note that this flag precludes the
+use of a uid not listed 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"
+If set, users must authenticate on a per-tty basis.  With this flag
+enabled, \fBsudo\fR will use a file named for the tty the user is
+logged in on in the user's time stamp directory.  If disabled, the
+time stamp of the directory is used instead.  This flag is
+\&\fI@tty_tickets@\fR by default.
+.IP "umask_override" 16
+.IX Item "umask_override"
+If set, \fBsudo\fR will set the umask as specified by \fIsudoers\fR without
+modification.  This makes it possible to specify a more permissive
+umask in \fIsudoers\fR than the user's own umask and matches historical
+behavior.  If \fIumask_override\fR is not set, \fBsudo\fR will set the
+umask to be the union of the user's umask and what is specified in
+\&\fIsudoers\fR.  This flag is \fI@umask_override@\fR by default.
+.if \n(LC \{\
+.IP "use_loginclass" 16
+.IX Item "use_loginclass"
+If set, \fBsudo\fR will apply the defaults specified for the target user's
+login class if one exists.  Only available if \fBsudo\fR is configured with
+the \-\-with\-logincap option.  This flag is \fIoff\fR by default.
+\}
+.IP "use_pty" 16
+.IX Item "use_pty"
+If set, \fBsudo\fR will run the command in a pseudo-pty even if no I/O
+logging is being gone.  A malicious program run under \fBsudo\fR could
+conceivably fork a background process that retains to the user's
+terminal device after the main program has finished executing.  Use
+of this option will make that impossible.  This flag is \fIoff\fR by default.
+.IP "utmp_runas" 16
+.IX Item "utmp_runas"
+If set, \fBsudo\fR will store the name of the runas user when updating
+the utmp (or utmpx) file.  By default, \fBsudo\fR stores the name of
+the invoking user.  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
+\&\fBsudo\fR logs the failure and exits.  The default is \f(CW\*(C`@passwd_tries@\*(C'\fR.
+.PP
+\&\fBIntegers that can be used in a boolean context\fR:
+.IP "loglinelen" 16
+.IX Item "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
+\&\f(CW\*(C`@loglen@\*(C'\fR (use 0 or negate the option to disable word wrap).
+.IP "passwd_timeout" 16
+.IX Item "passwd_timeout"
+Number of minutes before the \fBsudo\fR password prompt times out, or
+\&\f(CW0\fR for no timeout.  The timeout may include a fractional component
+if minute granularity is insufficient, for example \f(CW2.5\fR.  The
+default is \f(CW\*(C`@password_timeout@\*(C'\fR.
+.IP "timestamp_timeout" 16
+.IX Item "timestamp_timeout"
+Number of minutes that can elapse before \fBsudo\fR will ask for a
+passwd again.  The timeout may include a fractional component if
+minute granularity is insufficient, for example \f(CW2.5\fR.  The default
+is \f(CW\*(C`@timeout@\*(C'\fR.  Set this to \f(CW0\fR to always prompt for a password.
+If set to a value less than \f(CW0\fR the user's timestamp will never
+expire.  This can be used to allow users to create or delete their
+own timestamps via \f(CW\*(C`sudo \-v\*(C'\fR and \f(CW\*(C`sudo \-k\*(C'\fR respectively.
+.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 actual umask that is
+used will be the union of the user's umask and the value of the
+\&\fIumask\fR option, which defaults to \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
+.IX Item "badpass_message"
+Message that is displayed if a user enters an incorrect password.
+The default is \f(CW\*(C`@badpass_message@\*(C'\fR unless insults are enabled.
+.IP "editor" 16
+.IX Item "editor"
+A colon (':') separated list of editors allowed to be used with
+\&\fBvisudo\fR.  \fBvisudo\fR will choose the editor that matches the user's
+\&\s-1EDITOR\s0 environment variable if possible, or the first editor in the
+list that exists and is executable.  The default is \f(CW"@editor@"\fR.
+.IP "iolog_dir" 16
+.IX Item "iolog_dir"
+The top-level directory to use when constructing the path name for
+the input/output log directory.  Only used if the \fIlog_input\fR or
+\&\fIlog_output\fR options are enabled or when the \f(CW\*(C`LOG_INPUT\*(C'\fR or
+\&\f(CW\*(C`LOG_OUTPUT\*(C'\fR tags are present for a command.  The session sequence
+number, if any, is stored in the directory.
+The default is \f(CW"@iolog_dir@"\fR.
+.Sp
+The following percent (`\f(CW\*(C`%\*(C'\fR') escape sequences are supported:
+.RS 16
+.ie n .IP "\*(C`%{seq}\*(C'" 4
+.el .IP "\f(CW\*(C`%{seq}\*(C'\fR" 4
+.IX Item "%{seq}"
+expanded to a monotonically increasing base\-36 sequence number, such as 0100A5,
+where every two digits are used to form a new directory, e.g. \fI01/00/A5\fR
+.ie n .IP "\*(C`%{user}\*(C'" 4
+.el .IP "\f(CW\*(C`%{user}\*(C'\fR" 4
+.IX Item "%{user}"
+expanded to the invoking user's login name
+.ie n .IP "\*(C`%{group}\*(C'" 4
+.el .IP "\f(CW\*(C`%{group}\*(C'\fR" 4
+.IX Item "%{group}"
+expanded to the name of the invoking user's real group \s-1ID\s0
+.ie n .IP "\*(C`%{runas_user}\*(C'" 4
+.el .IP "\f(CW\*(C`%{runas_user}\*(C'\fR" 4
+.IX Item "%{runas_user}"
+expanded to the login name of the user the command will
+be run as (e.g. root)
+.ie n .IP "\*(C`%{runas_group}\*(C'" 4
+.el .IP "\f(CW\*(C`%{runas_group}\*(C'\fR" 4
+.IX Item "%{runas_group}"
+expanded to the group name of the user the command will
+be run as (e.g. wheel)
+.ie n .IP "\*(C`%{hostname}\*(C'" 4
+.el .IP "\f(CW\*(C`%{hostname}\*(C'\fR" 4
+.IX Item "%{hostname}"
+expanded to the local host name without the domain name
+.ie n .IP "\*(C`%{command}\*(C'" 4
+.el .IP "\f(CW\*(C`%{command}\*(C'\fR" 4
+.IX Item "%{command}"
+expanded to the base name of the command being run
+.RE
+.RS 16
+.Sp
+In addition, any escape sequences supported by the system's \fIstrftime()\fR
+function will be expanded.
+.Sp
+To include a literal `\f(CW\*(C`%\*(C'\fR' character, the string `\f(CW\*(C`%%\*(C'\fR' should
+be used.
+.Sp
+Path names that end in six or more \f(CW\*(C`X\*(C'\fRs will have the \f(CW\*(C`X\*(C'\fRs replaced
+with a unique combination of digits and letters, similar to the
+\&\fImktemp()\fR function.
+.RE
+.IP "iolog_file" 16
+.IX Item "iolog_file"
+The path name, relative to \fIiolog_dir\fR, in which to store input/output
+logs when the \fIlog_input\fR or \fIlog_output\fR options are enabled or
+when the \f(CW\*(C`LOG_INPUT\*(C'\fR or \f(CW\*(C`LOG_OUTPUT\*(C'\fR tags are present for a command.
+Note that \fIiolog_file\fR may contain directory components.
+The default is \f(CW"%{seq}"\fR.
+.Sp
+See the \fIiolog_dir\fR option above for a list of supported percent
+(`\f(CW\*(C`%\*(C'\fR') escape sequences.
+.IP "mailsub" 16
+.IX Item "mailsub"
+Subject of the mail sent to the \fImailto\fR user. The escape \f(CW%h\fR
+will expand to the host name of the machine.
+Default is \f(CW\*(C`@mailsub@\*(C'\fR.
+.IP "noexec_file" 16
+.IX Item "noexec_file"
+This option is deprecated and will be removed in a future release
+of \fBsudo\fR.  The path to the noexec file should now be set in the
+\&\fI@sysconfdir@/sudo.conf\fR file.
+.IP "passprompt" 16
+.IX Item "passprompt"
+The default prompt to use when asking for a password; can be overridden
+via the \fB\-p\fR option or the \f(CW\*(C`SUDO_PROMPT\*(C'\fR environment variable.
+The following percent (`\f(CW\*(C`%\*(C'\fR') escape sequences are supported:
+.RS 16
+.ie n .IP "%H" 4
+.el .IP "\f(CW%H\fR" 4
+.IX Item "%H"
+expanded to the local host name including the domain name
+(on if the machine's host name is fully qualified or the \fIfqdn\fR
+option is set)
+.ie n .IP "%h" 4
+.el .IP "\f(CW%h\fR" 4
+.IX Item "%h"
+expanded to the local host name without the domain name
+.ie n .IP "%p" 4
+.el .IP "\f(CW%p\fR" 4
+.IX Item "%p"
+expanded to the user whose password is being asked for (respects the 
+\&\fIrootpw\fR, \fItargetpw\fR and \fIrunaspw\fR flags in \fIsudoers\fR)
+.ie n .IP "%U" 4
+.el .IP "\f(CW%U\fR" 4
+.IX Item "%U"
+expanded to the login name of the user the command will
+be run as (defaults to root)
+.ie n .IP "%u" 4
+.el .IP "\f(CW%u\fR" 4
+.IX Item "%u"
+expanded to the invoking user's login name
+.ie n .IP "\*(C`%%\*(C'" 4
+.el .IP "\f(CW\*(C`%%\*(C'\fR" 4
+.IX Item "%%"
+two consecutive \f(CW\*(C`%\*(C'\fR characters are collapsed into a single \f(CW\*(C`%\*(C'\fR character
+.RE
+.RS 16
+.Sp
+The default value is \f(CW\*(C`@passprompt@\*(C'\fR.
+.RE
+.if \n(SL \{\
+.IP "role" 16
+.IX Item "role"
+The default SELinux role to use when constructing a new security
+context to run the command.  The default role may be overridden on
+a per-command basis in \fIsudoers\fR or via command line options.
+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 option is not specified
+on the command line.  This defaults to \f(CW\*(C`@runas_default@\*(C'\fR.
+.IP "syslog_badpri" 16
+.IX Item "syslog_badpri"
+Syslog priority to use when user authenticates unsuccessfully.
+Defaults to \f(CW\*(C`@badpri@\*(C'\fR.
+.Sp
+The following syslog priorities are supported: \fBalert\fR, \fBcrit\fR,
+\&\fBdebug\fR, \fBemerg\fR, \fBerr\fR, \fBinfo\fR, \fBnotice\fR, and \fBwarning\fR.
+.IP "syslog_goodpri" 16
+.IX Item "syslog_goodpri"
+Syslog priority to use when user authenticates successfully.
+Defaults to \f(CW\*(C`@goodpri@\*(C'\fR.
+.Sp
+See syslog_badpri for the list of supported syslog priorities.
+.IP "sudoers_locale" 16
+.IX Item "sudoers_locale"
+Locale to use when parsing the sudoers file, logging commands, and
+sending email.  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.
+The default is \fI@timedir@\fR.
+.IP "timestampowner" 16
+.IX Item "timestampowner"
+The owner of the timestamp directory and the timestamps stored therein.
+The default is \f(CW\*(C`root\*(C'\fR.
+.if \n(SL \{\
+.IP "type" 16
+.IX Item "type"
+The default SELinux type to use when constructing a new security
+context to run the command.  The default type may be overridden on
+a per-command basis in \fIsudoers\fR or via command line options.
+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 "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 either be of the form
+\&\f(CW\*(C`VARIABLE=value\*(C'\fR or \f(CW\*(C`export VARIABLE=value\*(C'\fR.  The value may
+optionally be surrounded by single or double quotes.  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.
+This is not set by default.
+.IP "group_plugin" 12
+.IX Item "group_plugin"
+A string containing a \fIsudoers\fR group plugin with optional arguments.
+This can be used to implement support for the \f(CW\*(C`nonunix_group\*(C'\fR
+syntax described earlier.  The string should consist of the plugin
+path, either fully-qualified or relative to the \fI@prefix@/libexec\fR
+directory, followed by any configuration arguments the plugin
+requires.  These arguments (if any) will be passed to the plugin's
+initialization function.  If arguments are present, the string must
+be enclosed in double quotes (\f(CW\*(C`"\*(C'\fR).
+.Sp
+For example, given \fI/etc/sudo\-group\fR, a group file in Unix group
+format, the sample group plugin can be used:
+.Sp
+.Vb 1
+\&    Defaults sudo_plugin="sample_group.so /etc/sudo\-group"
+.Ve
+.Sp
+For more information see \fIsudo_plugin\fR\|(@mansectform@).
+.IP "lecture" 12
+.IX Item "lecture"
+This option controls when a short lecture will be printed along with
+the password prompt.  It has the following possible values:
+.RS 12
+.IP "always" 8
+.IX Item "always"
+Always lecture the user.
+.IP "never" 8
+.IX Item "never"
+Never lecture the user.
+.IP "once" 8
+.IX Item "once"
+Only lecture the user the first time they run \fBsudo\fR.
+.RE
+.RS 12
+.Sp
+If no value is specified, a value of \fIonce\fR is implied.
+Negating the option results in a value of \fInever\fR being used.
+The default value is \fI@lecture@\fR.
+.RE
+.IP "lecture_file" 12
+.IX Item "lecture_file"
+Path to a file containing an alternate \fBsudo\fR lecture that will
+be used in place of the standard lecture if the named file exists.
+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 option.  It has the following possible values:
+.RS 12
+.IP "all" 8
+.IX Item "all"
+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 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 option.
+.RE
+.RS 12
+.Sp
+If no value is specified, a value of \fIany\fR is implied.
+Negating the option results in a value of \fInever\fR being used.
+The default value is \fIany\fR.
+.RE
+.IP "logfile" 12
+.IX Item "logfile"
+Path to the \fBsudo\fR log file (not the syslog log file).  Setting a path
+turns on logging to a file; negating this option turns it off.
+By default, \fBsudo\fR logs via syslog.
+.IP "mailerflags" 12
+.IX Item "mailerflags"
+Flags to use when invoking mailer. Defaults to \fB\-t\fR.
+.IP "mailerpath" 12
+.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 option is @secure_path@ by default.
+.IP "syslog" 12
+.IX Item "syslog"
+Syslog facility if syslog is being used for logging (negate to
+disable syslog logging).  Defaults to \f(CW\*(C`@logfac@\*(C'\fR.
+.Sp
+The following syslog facilities are supported: \fBauthpriv\fR (if your
+\&\s-1OS\s0 supports it), \fBauth\fR, \fBdaemon\fR, \fBuser\fR, \fBlocal0\fR, \fBlocal1\fR,
+\&\fBlocal2\fR, \fBlocal3\fR, \fBlocal4\fR, \fBlocal5\fR, \fBlocal6\fR, and \fBlocal7\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 option.  It has the following possible values:
+.RS 12
+.IP "all" 8
+.IX Item "all"
+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 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 option.
+.RE
+.RS 12
+.Sp
+If no value is specified, a value of \fIall\fR is implied.
+Negating the option results in a value of \fInever\fR being used.
+The default value is \fIall\fR.
+.RE
+.PP
+\&\fBLists that can be used in a boolean context\fR:
+.IP "env_check" 16
+.IX Item "env_check"
+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
+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
+specified by \f(CW\*(C`env_check\*(C'\fR will be preserved in the environment if
+they pass the aforementioned check.  The default list of environment
+variables to check is displayed when \fBsudo\fR is run by root with
+the \fI\-V\fR option.
+.IP "env_delete" 16
+.IX Item "env_delete"
+Environment variables to be removed from the user's environment
+when the \fIenv_reset\fR option is not in effect.  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 \fI\-V\fR option.
+Note that many operating systems will remove potentially dangerous
+variables from the environment of any setuid process (such as
+\&\fBsudo\fR).
+.IP "env_keep" 16
+.IX Item "env_keep"
+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
+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.
+.SH "FILES"
+.IX Header "FILES"
+.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
+.IX Item "/etc/group"
+Local groups file
+.IP "\fI/etc/netgroup\fR" 24
+.IX Item "/etc/netgroup"
+List of network groups
+.ie n .IP "\fI@iolog_dir@\fR" 24
+.el .IP "\fI@iolog_dir@\fR" 24
+.IX Item "@iolog_dir@"
+I/O log files
+.ie n .IP "\fI@timedir@\fR" 24
+.el .IP "\fI@timedir@\fR" 24
+.IX Item "@timedir@"
+Directory containing time stamps for the \fIsudoers\fR security policy
+.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"
+Below are example \fIsudoers\fR entries.  Admittedly, some of
+these are a bit contrived.  First, we allow a few environment
+variables to pass and then define our \fIaliases\fR:
+.PP
+.Vb 4
+\& # Run X applications through sudo; HOME is used to find the
+\& # .Xauthority file.  Note that other programs use HOME to find
+\& # configuration files and this may lead to privilege escalation!
+\& Defaults env_keep += "DISPLAY HOME"
+\&
+\& # User alias specification
+\& User_Alias     FULLTIMERS = millert, mikef, dowdy
+\& User_Alias     PARTTIMERS = bostley, jwfox, crawl
+\& User_Alias     WEBMASTERS = will, wendy, wim
+\&
+\& # Runas alias specification
+\& Runas_Alias    OP = root, operator
+\& Runas_Alias    DB = oracle, sybase
+\& Runas_Alias    ADMINGRP = adm, oper
+\&
+\& # Host alias specification
+\& Host_Alias     SPARC = bigtime, eclipse, moet, anchor :\e
+\&                SGI = grolsch, dandelion, black :\e
+\&                ALPHA = widget, thalamus, foobar :\e
+\&                HPPA = boa, nag, python
+\& Host_Alias     CUNETS = 128.138.0.0/255.255.0.0
+\& 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
+\&
+\& # Cmnd alias specification
+\& Cmnd_Alias     DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\e
+\&                        /usr/sbin/restore, /usr/sbin/rrestore
+\& Cmnd_Alias     KILL = /usr/bin/kill
+\& Cmnd_Alias     PRINTING = /usr/sbin/lpc, /usr/bin/lprm
+\& Cmnd_Alias     SHUTDOWN = /usr/sbin/shutdown
+\& Cmnd_Alias     HALT = /usr/sbin/halt
+\& Cmnd_Alias     REBOOT = /usr/sbin/reboot
+\& Cmnd_Alias     SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \e
+\&                         /usr/local/bin/tcsh, /usr/bin/rsh, \e
+\&                         /usr/local/bin/zsh
+\& Cmnd_Alias     SU = /usr/bin/su
+\& Cmnd_Alias     PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less
+.Ve
+.PP
+Here we override some of the compiled in default values.  We want
+\&\fBsudo\fR to log via \fIsyslog\fR\|(3) using the \fIauth\fR facility in all
+cases.  We don't want to subject the full time staff to the \fBsudo\fR
+lecture, user \fBmillert\fR need not give a password, and we don't
+want to reset the \f(CW\*(C`LOGNAME\*(C'\fR, \f(CW\*(C`USER\*(C'\fR or \f(CW\*(C`USERNAME\*(C'\fR environment
+variables when running commands as root.  Additionally, on the
+machines in the \fI\s-1SERVERS\s0\fR \f(CW\*(C`Host_Alias\*(C'\fR, 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 \s-1PAGERS\s0 \f(CW\*(C`Cmnd_Alias\*(C'\fR
+(\fI/usr/bin/more\fR, \fI/usr/bin/pg\fR and \fI/usr/bin/less\fR).
+.PP
+.Vb 7
+\& # 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
+.Ve
+.PP
+The \fIUser specification\fR is the part that actually determines who may
+run what.
+.PP
+.Vb 2
+\& root           ALL = (ALL) ALL
+\& %wheel         ALL = (ALL) ALL
+.Ve
+.PP
+We let \fBroot\fR and any user in group \fBwheel\fR run any command on any
+host as any user.
+.PP
+.Vb 1
+\& FULLTIMERS     ALL = NOPASSWD: ALL
+.Ve
+.PP
+Full time sysadmins (\fBmillert\fR, \fBmikef\fR, and \fBdowdy\fR) may run any
+command on any host without authenticating themselves.
+.PP
+.Vb 1
+\& PARTTIMERS     ALL = ALL
+.Ve
+.PP
+Part time sysadmins (\fBbostley\fR, \fBjwfox\fR, and \fBcrawl\fR) may run any
+command on any host but they must authenticate themselves first
+(since the entry lacks the \f(CW\*(C`NOPASSWD\*(C'\fR tag).
+.PP
+.Vb 1
+\& jack           CSNETS = ALL
+.Ve
+.PP
+The user \fBjack\fR may run any command on the machines in the \fI\s-1CSNETS\s0\fR alias
+(the networks \f(CW128.138.243.0\fR, \f(CW128.138.204.0\fR, and \f(CW128.138.242.0\fR).
+Of those networks, only \f(CW128.138.204.0\fR has an explicit netmask (in
+\&\s-1CIDR\s0 notation) indicating it is a class C network.  For the other
+networks in \fI\s-1CSNETS\s0\fR, the local machine's netmask will be used
+during matching.
+.PP
+.Vb 1
+\& lisa           CUNETS = ALL
+.Ve
+.PP
+The user \fBlisa\fR may run any command on any host in the \fI\s-1CUNETS\s0\fR alias
+(the class B network \f(CW128.138.0.0\fR).
+.PP
+.Vb 2
+\& operator       ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\e
+\&                sudoedit /etc/printcap, /usr/oper/bin/
+.Ve
+.PP
+The \fBoperator\fR 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 \fI/usr/oper/bin/\fR.
+.PP
+.Vb 1
+\& joe            ALL = /usr/bin/su operator
+.Ve
+.PP
+The user \fBjoe\fR may only \fIsu\fR\|(1) to operator.
+.PP
+.Vb 1
+\& pete           HPPA = /usr/bin/passwd [A\-Za\-z]*, !/usr/bin/passwd root
+\&
+\& %opers         ALL = (: ADMINGRP) /usr/sbin/
+.Ve
+.PP
+Users in the \fBopers\fR group may run commands in \fI/usr/sbin/\fR as themselves
+with any group in the \fI\s-1ADMINGRP\s0\fR \f(CW\*(C`Runas_Alias\*(C'\fR (the \fBadm\fR and \fBoper\fR
+groups).
+.PP
+The user \fBpete\fR is allowed to change anyone's password except for
+root on the \fI\s-1HPPA\s0\fR machines.  Note that this assumes \fIpasswd\fR\|(1)
+does not take multiple user names on the command line.
+.PP
+.Vb 1
+\& bob            SPARC = (OP) ALL : SGI = (OP) ALL
+.Ve
+.PP
+The user \fBbob\fR may run anything on the \fI\s-1SPARC\s0\fR and \fI\s-1SGI\s0\fR machines
+as any user listed in the \fI\s-1OP\s0\fR \f(CW\*(C`Runas_Alias\*(C'\fR (\fBroot\fR and \fBoperator\fR).
+.PP
+.Vb 1
+\& jim            +biglab = ALL
+.Ve
+.PP
+The user \fBjim\fR may run any command on machines in the \fIbiglab\fR netgroup.
+\&\fBsudo\fR knows that \*(L"biglab\*(R" is a netgroup due to the '+' prefix.
+.PP
+.Vb 1
+\& +secretaries   ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser
+.Ve
+.PP
+Users in the \fBsecretaries\fR 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.
+.PP
+.Vb 1
+\& fred           ALL = (DB) NOPASSWD: ALL
+.Ve
+.PP
+The user \fBfred\fR can run commands as any user in the \fI\s-1DB\s0\fR \f(CW\*(C`Runas_Alias\*(C'\fR
+(\fBoracle\fR or \fBsybase\fR) without giving a password.
+.PP
+.Vb 1
+\& 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 specify any options to the \fIsu\fR\|(1) command.
+.PP
+.Vb 1
+\& jen            ALL, !SERVERS = ALL
+.Ve
+.PP
+The user \fBjen\fR may run any command on any machine except for those
+in the \fI\s-1SERVERS\s0\fR \f(CW\*(C`Host_Alias\*(C'\fR (master, mail, www and ns).
+.PP
+.Vb 1
+\& jill           SERVERS = /usr/bin/, !SU, !SHELLS
+.Ve
+.PP
+For any machine in the \fI\s-1SERVERS\s0\fR \f(CW\*(C`Host_Alias\*(C'\fR, \fBjill\fR may run
+any commands in the directory \fI/usr/bin/\fR except for those commands
+belonging to the \fI\s-1SU\s0\fR and \fI\s-1SHELLS\s0\fR \f(CW\*(C`Cmnd_Aliases\*(C'\fR.
+.PP
+.Vb 1
+\& steve          CSNETS = (operator) /usr/local/op_commands/
+.Ve
+.PP
+The user \fBsteve\fR may run any command in the directory /usr/local/op_commands/
+but only as user operator.
+.PP
+.Vb 1
+\& matt           valkyrie = KILL
+.Ve
+.PP
+On his personal workstation, valkyrie, \fBmatt\fR needs to be able to
+kill hung processes.
+.PP
+.Vb 1
+\& WEBMASTERS     www = (www) ALL, (root) /usr/bin/su www
+.Ve
+.PP
+On the host www, any user in the \fI\s-1WEBMASTERS\s0\fR \f(CW\*(C`User_Alias\*(C'\fR (will,
+wendy, and wim), may run any command as user www (which owns the
+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
+.Ve
+.PP
+Any user may mount or unmount a CD-ROM on the machines in the \s-1CDROM\s0
+\&\f(CW\*(C`Host_Alias\*(C'\fR (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.
+.SH "SECURITY NOTES"
+.IX Header "SECURITY NOTES"
+It is generally not effective to \*(L"subtract\*(R" commands from \f(CW\*(C`ALL\*(C'\fR
+using the '!' operator.  A user can trivially circumvent this
+by copying the desired command to a different name and then
+executing that.  For example:
+.PP
+.Vb 1
+\&    bill        ALL = ALL, !SU, !SHELLS
+.Ve
+.PP
+Doesn't really prevent \fBbill\fR from running the commands listed in
+\&\fI\s-1SU\s0\fR or \fI\s-1SHELLS\s0\fR 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).
+.PP
+Furthermore, if the \fIfast_glob\fR option is in use, it is not possible
+to reliably negate commands where the path name includes globbing
+(aka wildcard) characters.  This is because the C library's
+\&\fIfnmatch\fR\|(3) function cannot resolve relative paths.  While this
+is typically only an inconvenience for rules that grant privileges,
+it can result in a security issue for rules that subtract or revoke
+privileges.
+.PP
+For example, given the following \fIsudoers\fR entry:
+.PP
+.Vb 2
+\& john   ALL = /usr/bin/passwd [a\-zA\-Z0\-9]*, /usr/bin/chsh [a\-zA\-Z0\-9]*,
+\&      /usr/bin/chfn [a\-zA\-Z0\-9]*, !/usr/bin/* root
+.Ve
+.PP
+User \fBjohn\fR can still run \f(CW\*(C`/usr/bin/passwd root\*(C'\fR if \fIfast_glob\fR is
+enabled by changing to \fI/usr/bin\fR and running \f(CW\*(C`./passwd root\*(C'\fR instead.
+.SH "PREVENTING SHELL ESCAPES"
+.IX Header "PREVENTING SHELL ESCAPES"
+Once \fBsudo\fR 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 \fBsudo\fR's access control and logging.
+Common programs that permit shell escapes include shells (obviously),
+editors, paginators, mail and terminal programs.
+.PP
+There are two basic approaches to this problem:
+.IP "restrict" 10
+.IX Item "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 \fBsudoedit\fR is a better solution to
+running editors via \fBsudo\fR.  Due to the large number of programs that
+offer shell escapes, restricting users to the set of programs that
+do not is often unworkable.
+.IP "noexec" 10
+.IX Item "noexec"
+Many systems that support shared libraries have the ability to
+override default library functions by pointing an environment
+variable (usually \f(CW\*(C`LD_PRELOAD\*(C'\fR) to an alternate shared library.
+On such systems, \fBsudo\fR's \fInoexec\fR functionality can be used to
+prevent a program run by \fBsudo\fR 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.
+.Sp
+The \fInoexec\fR feature is known to work on SunOS, Solaris, *BSD,
+Linux, \s-1IRIX\s0, Tru64 \s-1UNIX\s0, MacOS X, HP-UX 11.x and \s-1AIX\s0 5.3 and above.
+It should be supported on most operating systems that support the
+\&\f(CW\*(C`LD_PRELOAD\*(C'\fR 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 \f(CW\*(C`LD_PRELOAD\*(C'\fR is supported.
+.Sp
+On Solaris 10 and higher, \fInoexec\fR uses Solaris privileges instead
+of the \f(CW\*(C`LD_PRELOAD\*(C'\fR environment variable.
+.Sp
+To enable \fInoexec\fR for a command, use the \f(CW\*(C`NOEXEC\*(C'\fR tag as documented
+in the User Specification section above.  Here is that example again:
+.Sp
+.Vb 1
+\& aaron  shanty = NOEXEC: /usr/bin/more, /usr/bin/vi
+.Ve
+.Sp
+This allows user \fBaaron\fR to run \fI/usr/bin/more\fR and \fI/usr/bin/vi\fR
+with \fInoexec\fR 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 \fInoexec\fR you
+can always just try it out and check whether shell escapes work
+when \fInoexec\fR is enabled.
+.PP
+Note that restricting shell escapes is not a panacea.  Programs
+running as root are still capable of many potentially hazardous
+operations (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
+\&\fBsudoedit\fR.
+.SH "SECURITY NOTES"
+.IX Header "SECURITY NOTES"
+\&\fIsudoers\fR will check the ownership of its time stamp directory
+(\fI@timedir@\fR 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
+\&\fIchown\fR\|(2), if the time stamp directory is located in a world-writable
+directory (e.g., \fI/tmp\fR), it is possible for a user to create the
+time stamp directory before \fBsudo\fR is run.  However, because
+\&\fIsudoers\fR checks the ownership and mode of the directory and its
+contents, the only damage that can be done is to \*(L"hide\*(R" files by
+putting them in the time stamp dir.  This is unlikely to happen
+since once the time stamp dir is owned by root and inaccessible by
+any other user, the user placing files there would be unable to get
+them back out.
+.PP
+\&\fIsudoers\fR will not honor time stamps set far in the future.  Time
+stamps with a date greater than current_time + 2 * \f(CW\*(C`TIMEOUT\*(C'\fR will
+be ignored and sudo will log and complain.  This is done to keep a
+user from creating his/her own time stamp with a bogus date on
+systems that allow users to give away files if the time stamp directory
+is located in a world-writable directory.
+.PP
+On systems where the boot time is available, \fIsudoers\fR will ignore
+time stamps that date from before the machine booted.
+.PP
+Since time stamp files live in the file system, they can outlive a
+user's login session.  As a result, a user may be able to login,
+run a command with \fBsudo\fR after authenticating, logout, login
+again, and run \fBsudo\fR without authenticating so long as the time
+stamp file's modification time is within \f(CW\*(C`@timeout@\*(C'\fR minutes (or
+whatever the timeout is set to in \fIsudoers\fR).  When the \fItty_tickets\fR
+option is enabled, the time stamp has per-tty granularity but still
+may outlive the user's session.  On Linux systems where the devpts
+filesystem is used, Solaris systems with the devices filesystem,
+as well as other systems that utilize a devfs filesystem that
+monotonically increase the inode number of devices as they are
+created (such as Mac \s-1OS\s0 X), \fIsudoers\fR is able to determine when a
+tty-based time stamp file is stale and will ignore it.  Administrators
+should not rely on this feature as it is not universally available.
+.PP
+If users have sudo \f(CW\*(C`ALL\*(C'\fR there is nothing to prevent them from
+creating their own program that gives them a root shell (or making
+their own copy of a shell) regardless of any '!' elements in the
+user specification.
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fIrsh\fR\|(1), \fIsu\fR\|(1), \fIfnmatch\fR\|(3), \fIglob\fR\|(3), \fImktemp\fR\|(3), \fIstrftime\fR\|(3),
+\&\fIsudoers.ldap\fR\|(@mansectform@), \fIsudo_plugin\fR\|(@mansectsu@), \fIsudo\fR\|(@mansectsu@), \fIvisudo\fR\|(@mansectsu@)
+.SH "CAVEATS"
+.IX Header "CAVEATS"
+The \fIsudoers\fR file should \fBalways\fR be edited by the \fBvisudo\fR
+command which locks the file and does grammatical checking. It is
+imperative that \fIsudoers\fR be free of syntax errors since \fBsudo\fR
+will not run with a syntactically incorrect \fIsudoers\fR file.
+.PP
+When using netgroups of machines (as opposed to users), if you
+store fully qualified host name in the netgroup (as is usually the
+case), you either need to have the machine's host name be fully qualified
+as returned by the \f(CW\*(C`hostname\*(C'\fR command or use the \fIfqdn\fR option in
+\&\fIsudoers\fR.
+.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/doc/sudoers.man.pl b/doc/sudoers.man.pl
new file mode 100644 (file)
index 0000000..6e5da2c
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/perl -p
+
+BEGIN {
+    $cond = -1;
+}
+
+# Initialize the numeric register we use for conditionals
+if ($cond == -1) {
+    $_ = ".nr SL \@SEMAN\@\n.nr BA \@BAMAN\@\n.nr LC \@LCMAN\@\n.\\\"\n$_";
+    $cond = 0;
+}
+
+# Make SELinux_Spec conditional
+if (/(.*)SELinux_Spec\? (.*)$/) {
+    $_ = ".ie \\n(SL $_.el $1$2\n";
+} elsif (/^(.*SELinux_Spec ::=)/) {
+    $_ = ".if \\n(SL \\{\\\n$_";
+} elsif (/^(.*Tag_Spec ::=)/) {
+    $_ = "\\}\n$_";
+}
+
+if (/^\.S[Sh] "SELinux_Spec"/) {
+    $_ = ".if \\n(SL \\{\\\n$_";
+    $cond = 1;
+} elsif (/^\.IP "(role|type)"/) {
+    $_ = ".if \\n(SL \\{\\\n$_";
+    $cond = 1;
+} elsif (/^\.IP "use_loginclass"/) {
+    $_ = ".if \\n(LC \\{\\\n$_";
+    $cond = 1;
+} elsif ($cond && /^\.(Sh|SS|IP|PP)/) {
+    $_ = "\\}\n$_";
+    $cond = 0;
+}
+
+# Fix up broken pod2man formatting of F<@foo@/bar>
+s/\\fI\\f(\(C)?I\@([^\@]*)\\fI\@/\\fI\@$2\@/g;
+s/\\f\(\CW\@([^\@]*)\\fR\@/\@$1\@/g;
+#\f(CW@secure_path\fR@
diff --git a/doc/sudoers.pod b/doc/sudoers.pod
new file mode 100644 (file)
index 0000000..12509ca
--- /dev/null
@@ -0,0 +1,1968 @@
+Copyright (c) 1994-1996, 1998-2005, 2007-2011
+       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.
+
+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.
+
+=pod
+
+=head1 NAME
+
+sudoers - default sudo security policy module
+
+=head1 DESCRIPTION
+
+The I<sudoers> policy module determines a user's B<sudo> privileges.
+It is the default B<sudo> policy plugin.  The policy is driven by
+the F<@sysconfdir@/sudoers> file or, optionally in LDAP.  The policy
+format is described in detail in the L<"SUDOERS FILE FORMAT">
+section.  For information on storing I<sudoers> policy information
+in LDAP, please see L<sudoers.ldap(5)>.
+
+=head2 Authentication and Logging
+
+The I<sudoers> security policy requires that most users authenticate
+themselves before they can use B<sudo>.  A password is not required
+if the invoking user is root, if the target user is the same as the
+invoking user, or if the policy has disabled authentication for the
+user or command.  Unlike L<su(1)>, when I<sudoers> requires
+authentication, it validates the invoking user's credentials, not
+the target user's (or root's) credentials.  This can be changed via
+the I<rootpw>, I<targetpw> and I<runaspw> flags, described later.
+
+If a user who is not listed in the policy tries to run a command
+via B<sudo>, mail is sent to the proper authorities.  The address
+used for such mail is configurable via the I<mailto> Defaults entry
+(described later) and defaults to C<@mailto@>.
+
+Note that mail will not be sent if an unauthorized user tries to
+run B<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>.
+
+If B<sudo> is run by root and the C<SUDO_USER> environment variable
+is set, the I<sudoers> policy 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> option to remain useful even when invoked via a
+sudo-run script or program.  Note, however, that the I<sudoers>
+lookup is still done for root, not the user specified by C<SUDO_USER>.
+
+I<sudoers> uses time stamp files for credential caching.  Once a
+user has been authenticated, a time stamp is updated and the user
+may then use sudo without a password for a short period of time
+(C<@timeout@> minutes unless overridden by the I<timeout> option.
+By default, I<sudoers> uses a tty-based time stamp which means that
+there is a separate time stamp for each of a user's login sessions.
+The I<tty_tickets> option can be disabled to force the use of a
+single time stamp for all of a user's sessions.
+
+I<sudoers> can log both successful and unsuccessful attempts (as well
+as errors) to syslog(3), a log file, or both.  By default, I<sudoers>
+will log via syslog(3) but this is changeable via the I<syslog>
+and I<logfile> Defaults settings.
+
+I<sudoers> also supports logging a command's input and output
+streams.  I/O logging is not on by default but can be enabled using
+the I<log_input> and I<log_output> Defaults flags as well as the
+C<LOG_INPUT> and C<LOG_OUTPUT> command tags.
+
+=head2 Command Environment
+
+Since environment variables can influence program behavior, I<sudoers>
+provides a means to restrict which variables from the user's
+environment are inherited by the command to be run.  There are two
+distinct ways I<sudoers> can deal with environment variables.
+
+By default, the I<env_reset> option is enabled.  This causes commands
+to be executed with a minimal environment containing C<TERM>,
+C<PATH>, C<HOME>, C<MAIL>, C<SHELL>, C<LOGNAME>, C<USER> and C<USERNAME> in
+addition to variables from the invoking process permitted by the
+I<env_check> and I<env_keep> options.  This is effectively a whitelist
+for environment variables.
+
+If, however, the I<env_reset> option is disabled, any variables not
+explicitly denied by the I<env_check> and I<env_delete> options are
+inherited from the invoking process.  In this case, I<env_check>
+and I<env_delete> behave like a blacklist.  Since it is not possible
+to blacklist all potentially dangerous environment variables, use
+of the default I<env_reset> behavior is encouraged.
+
+In all cases, environment variables with a value beginning with
+C<()> are removed as they could be interpreted as B<bash> functions.
+The list of environment variables that B<sudo> allows or denies is
+contained in the output of C<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 B<sudo>.  Depending on the operating
+system this may include C<_RLD*>, C<DYLD_*>, C<LD_*>, C<LDR_*>,
+C<LIBPATH>, C<SHLIB_PATH>, and others.  These type of variables are
+removed from the environment before B<sudo> even begins execution
+and, as such, it is not possible for B<sudo> to preserve them.
+
+As a special case, If B<sudo>'s B<-i> option (initial login) is
+specified, I<sudoers> will initialize the environment regardless
+of the value of I<env_reset>.  The I<DISPLAY>, I<PATH> and I<TERM>
+variables remain unchanged; I<HOME>, I<MAIL>, I<SHELL>, I<USER>,
+and I<LOGNAME> are set based on the target user.  On Linux and AIX
+systems the contents of F</etc/environment> are also included.  All
+other environment variables are removed.
+
+=head1 SUDOERS FILE FORMAT
+
+The I<sudoers> 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).
+
+The I<sudoers> 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.
+
+=head2 Quick guide to EBNF
+
+EBNF is a concise and exact way of describing the grammar of a language.
+Each EBNF definition is made up of I<production rules>.  E.g.,
+
+ symbol ::= definition | alternate1 | alternate2 ...
+
+Each I<production rule> 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.
+
+=over 4
+
+=item C<?>
+
+Means that the preceding symbol (or group of symbols) is optional.
+That is, it may appear once or not at all.
+
+=item C<*>
+
+Means that the preceding symbol (or group of symbols) may appear
+zero or more times.
+
+=item C<+>
+
+Means that the preceding symbol (or group of symbols) may appear
+one or more times.
+
+=back
+
+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).
+
+=head2 Aliases
+
+There are four kinds of aliases: C<User_Alias>, C<Runas_Alias>,
+C<Host_Alias> and C<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
+
+ Host_Alias ::= NAME '=' Host_List
+
+ Cmnd_Alias ::= NAME '=' Cmnd_List
+
+ NAME ::= [A-Z]([A-Z][0-9]_)*
+
+Each I<alias> definition is of the form
+
+ Alias_Type NAME = item1, item2, ...
+
+where I<Alias_Type> is one of C<User_Alias>, C<Runas_Alias>, C<Host_Alias>,
+or C<Cmnd_Alias>.  A C<NAME> is a string of uppercase letters, numbers,
+and underscore characters ('_').  A C<NAME> B<must> 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 I<alias> member follow.
+
+ User_List ::= User |
+              User ',' User_List
+
+ User ::= '!'* user name |
+         '!'* #uid |
+         '!'* %group |
+         '!'* %#gid |
+         '!'* +netgroup |
+         '!'* %:nonunix_group |
+         '!'* %:#nonunix_gid |
+         '!'* User_Alias
+
+A C<User_List> is made up of one or more user names, user ids
+(prefixed with '#'), system group names and ids (prefixed with '%'
+and '%#' respectively), netgroups (prefixed with '+'), non-Unix
+group names and IDs (prefixed with '%:' and '%:#' respectively) 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.
+
+A C<user name>, C<uid>, C<group>, C<gid>, C<netgroup>, C<nonunix_group>
+or C<nonunix_gid> may be enclosed in double quotes to avoid the
+need for escaping special characters.  Alternately, special characters
+may be specified in escaped hex mode, e.g. \x20 for space.  When
+using double quotes, any prefix characters must be included inside
+the quotes.
+
+The actual C<nonunix_group> and C<nonunix_gid> syntax depends on
+the underlying group provider plugin (see the I<group_plugin>
+description below).  For instance, the QAS AD plugin supports the
+following formats:
+
+=over 4
+
+=item *
+
+Group in the same domain: "Group Name"
+
+=item *
+
+Group in any domain: "Group Name@FULLY.QUALIFIED.DOMAIN"
+
+=item *
+
+Group SID: "S-1-2-34-5678901234-5678901234-5678901234-567"
+
+=back
+
+Note that quotes around group names are optional.  Unquoted strings
+must use a backslash (\) to escape spaces and special characters.
+See L<"Other special characters and reserved words"> for a list of
+characters that need to be escaped.
+
+ Runas_List ::= Runas_Member |
+               Runas_Member ',' Runas_List
+
+ Runas_Member ::= '!'* user name |
+                 '!'* #uid |
+                 '!'* %group |
+                 '!'* %#gid |
+                 '!'* %:nonunix_group |
+                 '!'* %:#nonunix_gid |
+                 '!'* +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
+user names 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 user names 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
+
+ Host ::= '!'* host name |
+         '!'* ip_addr |
+         '!'* network(/netmask)? |
+         '!'* +netgroup |
+         '!'* Host_Alias
+
+A C<Host_List> is made up of one or more host names, 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,
+B<sudo> 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.E<nbsp>255.255.255.0 or ffff:ffff:ffff:ffff::),
+or CIDR notation (number of bits, e.g.E<nbsp>24 or 64).  A host name may
+include shell-style wildcards (see the L<Wildcards> section below),
+but unless the C<host name> command on your machine returns the fully
+qualified host name, you'll need to use the I<fqdn> option for
+wildcards to be useful.  Note B<sudo> only inspects actual network
+interfaces; this means that IP address 127.0.0.1 (localhost) will
+never match.  Also, the host name "localhost" will only match if
+that is the actual host name, which is usually only the case for
+non-networked systems.
+
+ Cmnd_List ::= Cmnd |
+              Cmnd ',' Cmnd_List
+
+ commandname ::= file name |
+                file name args |
+                file name '""'
+
+ Cmnd ::= '!'* commandname |
+         '!'* directory |
+         '!'* "sudoedit" |
+         '!'* Cmnd_Alias
+
+A C<Cmnd_List> is a list of one or more commandnames, directories, and other
+aliases.  A commandname is a fully qualified file name which may include
+shell-style wildcards (see the L<Wildcards> section below).  A simple
+file name 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 C<""> to indicate that the command
+may only be run B<without> command line arguments.  A directory is a
+fully qualified path name ending in a '/'.  When you specify a directory
+in a C<Cmnd_List>, the user will be able to run any file within that directory
+(but not in any subdirectories therein).
+
+If a C<Cmnd> has associated command line arguments, then the arguments
+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> option (or
+as B<sudoedit>).  It may take command line arguments just as
+a normal command does.
+
+=head2 Defaults
+
+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, 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
+
+ Parameter_List ::= Parameter |
+                   Parameter ',' Parameter_List
+
+ Parameter ::= Parameter '=' Value |
+              Parameter '+=' Value |
+              Parameter '-=' Value |
+              '!'* Parameter
+
+Parameters may be B<flags>, B<integer> values, B<strings>, or B<lists>.
+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 (C<">) when they contain multiple words.  Special
+characters may be escaped with a backslash (C<\>).
+
+Lists have two additional assignment operators, C<+=> and C<-=>.
+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
+
+ 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? SELinux_Spec? Tag_Spec* Cmnd
+
+ Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
+
+ SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
+
+ Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' |
+              'SETENV:' | 'NOSETENV:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' |
+               'LOG_OUTPUT:' | 'NOLOG_OUTPUT:')
+
+A B<user specification> determines which commands a user may run
+(and as what user) on specified hosts.  By default, commands are
+run as B<root>, but this can be changed on a per-command basis.
+
+The basic structure of a user specification is `who where = (as_whom)
+what'.  Let's break that down into its constituent parts:
+
+=head2 Runas_Spec
+
+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
+
+The user B<dgb> may run F</bin/ls>, F</bin/kill>, and
+F</usr/bin/lprm> -- but only as B<operator>.  E.g.,
+
+ $ sudo -u operator /bin/ls
+
+It is also possible to override a C<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 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
+
+Note that while the group portion of the C<Runas_Spec> permits the
+user to run as command with that group, it does not force the user
+to do so.  If no group is specified on the command line, the command
+will run with the group listed in the target user's password database
+entry.  The following would all be permitted by the sudoers entry above:
+
+ $ sudo -u operator /bin/ls
+ $ sudo -u operator -g operator /bin/ls
+ $ sudo -g operator /bin/ls
+
+In the following example, user B<tcm> may run commands that access
+a modem device file with the dialer group.
+
+ tcm   boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \
+       /usr/local/bin/minicom
+
+Note that in this example only the group will be set, the command
+still runs as user B<tcm>.  E.g.
+
+ $ sudo -g dialer /usr/bin/cu
+
+Multiple users and groups may be present in a C<Runas_Spec>, in
+which case the user may select any combination of users and groups
+via the B<-u> and B<-g> options.  In this example:
+
+ alan  ALL = (root, bin : operator, system) ALL
+
+user B<alan> may run any command as either user root or bin,
+optionally setting the group to operator or system.
+
+=head2 SELinux_Spec
+
+On systems with SELinux support, I<sudoers> entries may optionally have
+an SELinux role and/or type associated with a command.  If a role or
+type is specified with the command it will override any default values
+specified in I<sudoers>.  A role or type specified on the command line,
+however, will supercede the values in I<sudoers>.
+
+=head2 Tag_Spec
+
+A command may have zero or more tags associated with it.  There are
+eight possible tag values, C<NOPASSWD>, C<PASSWD>, C<NOEXEC>,
+C<EXEC>, C<SETENV>, C<NOSETENV>, C<LOG_INPUT>, C<NOLOG_INPUT>,
+C<LOG_OUTPUT> and C<NOLOG_OUTPUT>.  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 opposite tag (i.e.: C<PASSWD> overrides
+C<NOPASSWD> and C<NOEXEC> overrides C<EXEC>).
+
+=head3 NOPASSWD and PASSWD
+
+By default, B<sudo> requires that a user authenticate him or herself
+before running a command.  This behavior can be modified via the
+C<NOPASSWD> tag.  Like a C<Runas_Spec>, the C<NOPASSWD> tag sets
+a default for the commands that follow it in the C<Cmnd_Spec_List>.
+Conversely, the C<PASSWD> tag can be used to reverse things.
+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 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:
+
+ ray   rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm
+
+Note, however, that the C<PASSWD> tag has no effect on users who are
+in the group specified by the I<exempt_group> option.
+
+By default, if the C<NOPASSWD> tag is applied to any of the entries
+for a user on the current host, he or she will be able to run
+C<sudo -l> without a password.  Additionally, a user may only run
+C<sudo -v> without a password if the C<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.
+
+=head3 NOEXEC and EXEC
+
+If B<sudo> has been compiled with I<noexec> support and the underlying
+operating system supports it, the C<NOEXEC> tag can be used to prevent
+a dynamically-linked executable from running further commands itself.
+
+In the following example, user B<aaron> may run F</usr/bin/more>
+and F</usr/bin/vi> but shell escapes will be disabled.
+
+ aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi
+
+See the L<PREVENTING SHELL ESCAPES> section below for more details
+on how C<NOEXEC> works and whether or not it will work on your system.
+
+=head3 SETENV and NOSETENV
+
+These tags override the value of the I<setenv> option on a per-command
+basis.  Note that if C<SETENV> has been set for a command, the user
+may disable the I<env_reset> option from the command line via the
+B<-E> option.  Additionally, environment variables set on the command
+line are not subject to the restrictions imposed by I<env_check>,
+I<env_delete>, or I<env_keep>.  As such, only trusted users should
+be allowed to set variables in this manner.  If the command matched
+is B<ALL>, the C<SETENV> tag is implied for that command; this
+default may be overridden by use of the C<NOSETENV> tag.
+
+=head3 LOG_INPUT and NOLOG_INPUT
+
+These tags override the value of the I<log_input> option on a
+per-command basis.  For more information, see the description of
+I<log_input> in the L<"SUDOERS OPTIONS"> section below.
+
+=head3 LOG_OUTPUT and NOLOG_OUTPUT
+
+These tags override the value of the I<log_output> option on a
+per-command basis.  For more information, see the description of
+I<log_output> in the L<"SUDOERS OPTIONS"> section below.
+
+=head2 Wildcards
+
+B<sudo> allows shell-style I<wildcards> (aka meta or glob characters)
+to be used in host names, path names and command line arguments in
+the I<sudoers> file.  Wildcard matching is done via the B<POSIX>
+L<glob(3)> and L<fnmatch(3)> routines.  Note that these are I<not>
+regular expressions.
+
+=over 8
+
+=item C<*>
+
+Matches any set of zero or more characters.
+
+=item C<?>
+
+Matches any single character.
+
+=item C<[...]>
+
+Matches any character in the specified range.
+
+=item C<[!...]>
+
+Matches any character B<not> in the specified range.
+
+=item C<\x>
+
+For any character "x", evaluates to "x".  This is used to
+escape special characters such as: "*", "?", "[", and "}".
+
+=back
+
+POSIX character classes may also be used if your system's L<glob(3)>
+and L<fnmatch(3)> functions support them.  However, because the
+C<':'> character has special meaning in I<sudoers>, it must be
+escaped.  For example:
+
+    /bin/ls [[\:alpha\:]]*
+
+Would match any file name beginning with a letter.
+
+Note that a forward slash ('/') will B<not> be matched by
+wildcards used in the path name.  When matching the command
+line arguments, however, a slash B<does> get matched by
+wildcards.  This is to make a path like:
+
+    /usr/bin/*
+
+match F</usr/bin/who> but not F</usr/bin/X11/xterm>.
+
+=head2 Exceptions to wildcard rules
+
+The following exceptions apply to the above rules:
+
+=over 8
+
+=item C<"">
+
+If the empty string C<""> is the only command line argument in the
+I<sudoers> entry it means that command is not allowed to be run
+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> and
+C<#includedir> directives.
+
+This can be used, for example, to keep a site-wide I<sudoers> file
+in addition to a local, per-machine file.  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 within F</etc/sudoers> we would use the
+following line in F</etc/sudoers>:
+
+=over 4
+
+C<#include /etc/sudoers.local>
+
+=back
+
+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.
+
+The file name may include the C<%h> escape, signifying the short form
+of the host name.  I.e., if the machine's host name is "xerxes", then
+
+C<#include /etc/sudoers.%h>
+
+will cause B<sudo> to include the file F</etc/sudoers.xerxes>.
+
+The C<#includedir> directive can be used to create a F<sudo.d>
+directory that the system package manager can drop I<sudoers> rules
+into as part of package installation.  For example, given:
+
+C<#includedir /etc/sudoers.d>
+
+B<sudo> will read each file in F</etc/sudoers.d>, skipping file
+names that end in C<~> or contain a C<.> character to avoid causing
+problems with package manager or editor temporary/backup files.
+Files are parsed in sorted lexical order.  That is,
+F</etc/sudoers.d/01_first> will be parsed before
+F</etc/sudoers.d/10_second>.  Be aware that because the sorting is
+lexical, not numeric, F</etc/sudoers.d/1_whoops> would be loaded
+B<after> F</etc/sudoers.d/10_second>.  Using a consistent number
+of leading zeroes in the file names can be used to avoid such
+problems.
+
+Note that unlike files included via C<#include>, B<visudo> will not
+edit the files in a C<#includedir> directory unless one of them
+contains a syntax error.  It is still possible to run B<visudo>
+with the C<-f> flag to edit the files directly.
+
+=head2 Other special characters and reserved words
+
+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 B<ALL> is a built-in I<alias> that always causes
+a match to succeed.  It can be used wherever one might otherwise
+use a C<Cmnd_Alias>, C<User_Alias>, C<Runas_Alias>, or C<Host_Alias>.
+You should not try to define your own I<alias> called B<ALL> as the
+built-in alias will be used in preference to your own.  Please note
+that using B<ALL> can be dangerous since in a command context, it
+allows the user to run B<any> command on the system.
+
+An exclamation point ('!') can be used as a logical I<not> operator
+both in an I<alias> and in front of a C<Cmnd>.  This allows one to
+exclude certain values.  Note, however, that using a C<!> in
+conjunction with the built-in C<ALL> alias to allow a user to
+run "all but a few" commands rarely works as intended (see SECURITY
+NOTES below).
+
+Long lines can be continued with a backslash ('\') as the last
+character on the line.
+
+Whitespace between elements in a list as well as special syntactic
+characters in a I<User Specification> ('=', ':', '(', ')') is optional.
+
+The following characters must be escaped with a backslash ('\') when
+used as part of a word (e.g.E<nbsp>a user name or host name):
+'!', '=', ':', ',', '(', ')', '\'.
+
+=head1 SUDOERS OPTIONS
+
+B<sudo>'s behavior can be modified by C<Default_Entry> lines, as
+explained earlier.  A list of all supported Defaults parameters,
+grouped by type, are listed below.
+
+B<Boolean Flags>:
+
+=over 16
+
+=item always_set_home
+
+If enabled, 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> option is
+always implied.  Note that C<HOME> is already set when the the
+I<env_reset> option is enabled, so I<always_set_home> is only
+effective for configurations where either I<env_reset> is disabled
+or C<HOME> is present in the I<env_keep> list.
+This flag is I<off> by default.
+
+=item 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 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 compress_io
+
+If set, and B<sudo> is configured to log a command's input or output,
+the I/O logs will be compressed using B<zlib>.  This flag is I<on>
+by default when B<sudo> is compiled with B<zlib> support.
+
+=item env_editor
+
+If set, B<visudo> 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 C<editor>
+variable.  B<visudo> will then only use the EDITOR or VISUAL if
+they match a value specified in C<editor>.  This flag is I<@env_editor@> by
+default.
+
+=item env_reset
+
+If set, B<sudo> will reset the environment to only contain the
+LOGNAME, MAIL, 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 the I<secure_path> option
+is set, its value will be used for the C<PATH> environment variable.
+This flag is I<@env_reset@> by default.
+
+=item fast_glob
+
+Normally, B<sudo> uses the L<glob(3)> function to do shell-style
+globbing when matching path names.  However, since it accesses the
+file system, L<glob(3)> can take a long time to complete for some
+patterns, especially when the pattern references a network file
+system that is mounted on demand (automounted).  The I<fast_glob>
+option causes B<sudo> to use the L<fnmatch(3)> function, which does
+not access the file system to do its matching.  The disadvantage
+of I<fast_glob> is that it is unable to match relative path names
+such as F<./ls> or F<../bin/ls>.  This has security implications
+when path names that include globbing characters are used with the
+negation operator, C<'!'>, as such rules can be trivially bypassed.
+As such, this option should not be used when I<sudoers> contains rules 
+that contain negated path names which include globbing characters.
+This flag is I<off> by default.
+
+=item fqdn
+
+Set this flag if you want to put fully qualified host names in the
+I<sudoers> 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 I<fqdn> requires B<sudo> to make DNS lookups
+which may make B<sudo> 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 (C<CNAME> entry) due to performance
+issues and the fact that there is no way to get all aliases from
+DNS.  If your machine's host name (as returned by the C<hostname>
+command) is already fully qualified you shouldn't need to set
+I<fqdn>.  This flag is I<@fqdn@> by default.
+
+=item ignore_dot
+
+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.
+
+=item ignore_local_sudoers
+
+If set via LDAP, parsing of F<@sysconfdir@/sudoers> 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 F<@sysconfdir@/sudoers>.
+When this option is present, F<@sysconfdir@/sudoers> does not even need to
+exist. Since this option tells B<sudo> how to behave when no specific LDAP
+entries have been matched, this sudoOption is only meaningful for the
+C<cn=defaults> section.  This flag is I<off> by default.
+
+=item insults
+
+If set, B<sudo> will insult users when they enter an incorrect
+password.  This flag is I<@insults@> by default.
+
+=item log_host
+
+If set, the host name will be logged in the (non-syslog) B<sudo> log file.
+This flag is I<off> by default.
+
+=item log_input
+
+If set, B<sudo> will run the command in a I<pseudo tty> and log all
+user input.
+If the standard input is not connected to the user's tty, due to
+I/O redirection or because the command is part of a pipeline, that
+input is also captured and stored in a separate log file.
+
+Input is logged to the directory specified by the I<iolog_dir>
+option (F<@iolog_dir@> by default) using a unique session ID that
+is included in the normal B<sudo> log line, prefixed with I<TSID=>.
+The I<iolog_file> option may be used to control the format of the
+session ID.
+
+Note that user input may contain sensitive information such as
+passwords (even if they are not echoed to the screen), which will
+be stored in the log file unencrypted.  In most cases, logging the
+command output via I<log_output> is all that is required.
+
+=item log_output
+
+If set, B<sudo> will run the command in a I<pseudo tty> and log all
+output that is sent to the screen, similar to the script(1) command.
+If the standard output or standard error is not connected to the
+user's tty, due to I/O redirection or because the command is part
+of a pipeline, that output is also captured and stored in separate
+log files.
+
+Output is logged to the directory specified by the I<iolog_dir>
+option (F<@iolog_dir@> by default) using a unique session ID that
+is included in the normal B<sudo> log line, prefixed with I<TSID=>.
+The I<iolog_file> option may be used to control the format of the
+session ID.
+
+Output logs may be viewed with the L<sudoreplay(8)> utility, which
+can also be used to list or search the available logs.
+
+=item log_year
+
+If set, the four-digit year will be logged in the (non-syslog) B<sudo> log file.
+This flag is I<off> by default.
+
+=item long_otp_prompt
+
+When validating with a One Time Password (OPT) scheme such as
+B<S/Key> or B<OPIE>, 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 I<@long_otp_prompt@> by default.
+
+=item mail_always
+
+Send mail to the I<mailto> user every time a users runs B<sudo>.
+This flag is I<off> by default.
+
+=item mail_badpass
+
+Send mail to the I<mailto> user if the user running B<sudo> does not
+enter the correct password.  This flag is I<off> by default.
+
+=item mail_no_host
+
+If set, mail will be sent to the I<mailto> user if the invoking
+user exists in the I<sudoers> file, but is not allowed to run
+commands on the current host.  This flag is I<@mail_no_host@> by default.
+
+=item mail_no_perms
+
+If set, mail will be sent to the I<mailto> user if the invoking
+user is allowed to use B<sudo> but the command they are trying is not
+listed in their I<sudoers> file entry or is explicitly denied.
+This flag is I<@mail_no_perms@> by default.
+
+=item mail_no_user
+
+If set, mail will be sent to the I<mailto> user if the invoking
+user is not in the I<sudoers> file.  This flag is I<@mail_no_user@>
+by default.
+
+=item noexec
+
+If set, all commands run via B<sudo> will behave as if the C<NOEXEC>
+tag has been set, unless overridden by a C<EXEC> tag.  See the
+description of I<NOEXEC and EXEC> below as well as the L<PREVENTING SHELL
+ESCAPES> section at the end of this manual.  This flag is I<off> by default.
+
+=item path_info
+
+Normally, B<sudo> will tell the user when a command could not be
+found in their C<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 C<PATH>, B<sudo> will tell the user that they are not
+allowed to run it, which can be confusing.  This flag is I<@path_info@>
+by default.
+
+=item passprompt_override
+
+The password prompt specified by I<passprompt> will normally only
+be used if the password prompt provided by systems such as PAM matches
+the string "Password:".  If I<passprompt_override> is set, I<passprompt>
+will always be used.  This flag is I<off> by default.
+
+=item preserve_groups
+
+By default, B<sudo> will initialize the group vector to the list of
+groups the target user is in.  When I<preserve_groups> 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 I<off> by default.
+
+=item pwfeedback
+
+By default, B<sudo> reads the password like most other Unix programs,
+by turning off echo until the user hits the return (or enter) key.
+Some users become confused by this as it appears to them that B<sudo>
+has hung at this point.  When I<pwfeedback> is set, B<sudo> will
+provide visual feedback when the user presses a key.  Note that
+this does have a security impact as an onlooker may be able to
+determine the length of the password being entered.
+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.  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
+
+If set, root is allowed to run B<sudo> too.  Disabling this prevents users
+from "chaining" B<sudo> commands to get a root shell by doing something
+like C<"sudo sudo /bin/sh">.  Note, however, that turning off I<root_sudo>
+will also prevent root from running B<sudoedit>.
+Disabling I<root_sudo> provides no real additional security; it
+exists purely for historical reasons.
+This flag is I<@root_sudo@> by default.
+
+=item rootpw
+
+If set, B<sudo> will prompt for the root password instead of the password
+of the invoking user.  This flag is I<off> by default.
+
+=item runaspw
+
+If set, B<sudo> will prompt for the password of the user defined by the
+I<runas_default> option (defaults to C<@runas_default@>) instead of the
+password of the invoking user.  This flag is I<off> by default.
+
+=item set_home
+
+If enabled 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> option imply B<-H>.  Note that C<HOME> is already
+set when the the I<env_reset> option is enabled, so I<set_home> is
+only effective for configurations where either I<env_reset> is disabled
+or C<HOME> is present in the I<env_keep> list.
+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> 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
+option.  Note that if the I<env_reset> option has not been disabled,
+entries in the I<env_keep> list will override the value of
+I<set_logname>.  This flag is I<on> by default.
+
+=item set_utmp
+
+When enabled, B<sudo> will create an entry in the utmp (or utmpx)
+file when a pseudo-tty is allocated.  A pseudo-tty is allocated by
+B<sudo> when the I<log_input>, I<log_output> or I<use_pty> flags
+are enabled.  By default, the new entry will be a copy of the user's
+existing utmp entry (if any), with the tty, time, type and pid
+fields updated.  This flag is I<on> by default.
+
+=item setenv
+
+Allow the user to disable the I<env_reset> option from the command
+line via the B<-E> option.  Additionally, environment variables set
+via the command line are not subject to the restrictions imposed
+by I<env_check>, I<env_delete>, or I<env_keep>.  As such, only
+trusted users should be allowed to set variables in this manner.
+This flag is I<off> by default.
+
+=item shell_noargs
+
+If set and B<sudo> is invoked with no arguments it acts as if 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.
+
+=item stay_setuid
+
+Normally, when B<sudo> 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 B<sudo> 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 setreuid() or setresuid()
+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> option (defaults to C<root>) instead of the password
+of the invoking user.  In addition, the timestamp file name will
+include the target user's name.  Note that this flag precludes the
+use of a uid not listed in the passwd database as an argument to
+the B<-u> option.  This flag is I<off> by default.
+
+=item tty_tickets
+
+If set, users must authenticate on a per-tty basis.  With this flag
+enabled, B<sudo> will use a file named for the tty the user is
+logged in on in the user's time stamp directory.  If disabled, the
+time stamp of the directory is used instead.  This flag is
+I<@tty_tickets@> by default.
+
+=item umask_override
+
+If set, B<sudo> will set the umask as specified by I<sudoers> without
+modification.  This makes it possible to specify a more permissive
+umask in I<sudoers> than the user's own umask and matches historical
+behavior.  If I<umask_override> is not set, B<sudo> will set the
+umask to be the union of the user's umask and what is specified in
+I<sudoers>.  This flag is I<@umask_override@> by default.
+
+=item use_loginclass
+
+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 use_pty
+
+If set, B<sudo> will run the command in a pseudo-pty even if no I/O
+logging is being gone.  A malicious program run under B<sudo> could
+conceivably fork a background process that retains to the user's
+terminal device after the main program has finished executing.  Use
+of this option will make that impossible.  This flag is I<off> by default.
+
+=item utmp_runas
+
+If set, B<sudo> will store the name of the runas user when updating
+the utmp (or utmpx) file.  By default, B<sudo> stores the name of
+the invoking user.  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
+B<sudo> logs the failure and exits.  The default is C<@passwd_tries@>.
+
+=back
+
+B<Integers that can be used in a boolean context>:
+
+=over 16
+
+=item 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
+C<@loglen@> (use 0 or negate the option to disable word wrap).
+
+=item passwd_timeout
+
+Number of minutes before the B<sudo> password prompt times out, or
+C<0> for no timeout.  The timeout may include a fractional component
+if minute granularity is insufficient, for example C<2.5>.  The
+default is C<@password_timeout@>.
+
+=item timestamp_timeout
+
+Number of minutes that can elapse before B<sudo> will ask for a
+passwd again.  The timeout may include a fractional component if
+minute granularity is insufficient, for example C<2.5>.  The default
+is C<@timeout@>.  Set this to C<0> to always prompt for a password.
+If set to a value less than C<0> the user's timestamp will never
+expire.  This can be used to allow users to create or delete their
+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 actual umask that is
+used will be the union of the user's umask and the value of the
+I<umask> option, which defaults to 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
+
+B<Strings>:
+
+=over 16
+
+=item badpass_message
+
+Message that is displayed if a user enters an incorrect password.
+The default is C<@badpass_message@> unless insults are enabled.
+
+=item editor
+
+A colon (':') separated list of editors allowed to be used with
+B<visudo>.  B<visudo> 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 C<"@editor@">.
+
+=item iolog_dir
+
+The top-level directory to use when constructing the path name for
+the input/output log directory.  Only used if the I<log_input> or
+I<log_output> options are enabled or when the C<LOG_INPUT> or
+C<LOG_OUTPUT> tags are present for a command.  The session sequence
+number, if any, is stored in the directory.
+The default is C<"@iolog_dir@">.
+
+The following percent (`C<%>') escape sequences are supported:
+
+=over 4
+
+=item C<%{seq}>
+
+expanded to a monotonically increasing base-36 sequence number, such as 0100A5,
+where every two digits are used to form a new directory, e.g. F<01/00/A5>
+
+=item C<%{user}>
+
+expanded to the invoking user's login name
+
+=item C<%{group}>
+
+expanded to the name of the invoking user's real group ID
+
+=item C<%{runas_user}>
+
+expanded to the login name of the user the command will
+be run as (e.g. root)
+
+=item C<%{runas_group}>
+
+expanded to the group name of the user the command will
+be run as (e.g. wheel)
+
+=item C<%{hostname}>
+
+expanded to the local host name without the domain name
+
+=item C<%{command}>
+
+expanded to the base name of the command being run
+
+=back
+
+In addition, any escape sequences supported by the system's strftime()
+function will be expanded.
+
+To include a literal `C<%>' character, the string `C<%%>' should
+be used.
+
+Path names that end in six or more C<X>s will have the C<X>s replaced
+with a unique combination of digits and letters, similar to the
+mktemp() function.
+
+=item iolog_file
+
+The path name, relative to I<iolog_dir>, in which to store input/output
+logs when the I<log_input> or I<log_output> options are enabled or
+when the C<LOG_INPUT> or C<LOG_OUTPUT> tags are present for a command.
+Note that I<iolog_file> may contain directory components.
+The default is C<"%{seq}">.
+
+See the I<iolog_dir> option above for a list of supported percent
+(`C<%>') escape sequences.
+
+=item mailsub
+
+Subject of the mail sent to the I<mailto> user. The escape C<%h>
+will expand to the host name of the machine.
+Default is C<@mailsub@>.
+
+=item noexec_file
+
+This option is deprecated and will be removed in a future release
+of B<sudo>.  The path to the noexec file should now be set in the
+F<@sysconfdir@/sudo.conf> file.
+
+=item passprompt
+
+The default prompt to use when asking for a password; can be overridden
+via the B<-p> option or the C<SUDO_PROMPT> environment variable.
+The following percent (`C<%>') escape sequences are supported:
+
+=over 4
+
+=item C<%H>
+
+expanded to the local host name including the domain name
+(on if the machine's host name is fully qualified or the I<fqdn>
+option is set)
+
+=item C<%h>
+
+expanded to the local host name without the domain name
+
+=item C<%p>
+
+expanded to the user whose password is being asked for (respects the 
+I<rootpw>, I<targetpw> and I<runaspw> flags in I<sudoers>)
+
+=item C<%U>
+
+expanded to the login name of the user the command will
+be run as (defaults to root)
+
+=item C<%u>
+
+expanded to the invoking user's login name
+
+=item C<%%>
+
+two consecutive C<%> characters are collapsed into a single C<%> character
+
+=back
+
+The default value is C<@passprompt@>.
+
+=item role
+
+The default SELinux role to use when constructing a new security
+context to run the command.  The default role may be overridden on
+a per-command basis in I<sudoers> or via command line options.
+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> option is not specified
+on the command line.  This defaults to C<@runas_default@>.
+
+=item syslog_badpri
+
+Syslog priority to use when user authenticates unsuccessfully.
+Defaults to C<@badpri@>.
+
+The following syslog priorities are supported: B<alert>, B<crit>,
+B<debug>, B<emerg>, B<err>, B<info>, B<notice>, and B<warning>.
+
+=item syslog_goodpri
+
+Syslog priority to use when user authenticates successfully.
+Defaults to C<@goodpri@>.
+
+See L<syslog_badpri> for the list of supported syslog priorities.
+
+=item sudoers_locale
+
+Locale to use when parsing the sudoers file, logging commands, and
+sending email.  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.
+The default is F<@timedir@>.
+
+=item timestampowner
+
+The owner of the timestamp directory and the timestamps stored therein.
+The default is C<root>.
+
+=item type
+
+The default SELinux type to use when constructing a new security
+context to run the command.  The default type may be overridden on
+a per-command basis in I<sudoers> or via command line options.
+This option is only available whe B<sudo> is built with SELinux support.
+
+=back
+
+B<Strings that can be used in a boolean context>:
+
+=over 12
+
+=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 either be of the form
+C<VARIABLE=value> or C<export VARIABLE=value>.  The value may
+optionally be surrounded by single or double quotes.  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.
+This is not set by default.
+
+=item group_plugin
+
+A string containing a I<sudoers> group plugin with optional arguments.
+This can be used to implement support for the C<nonunix_group>
+syntax described earlier.  The string should consist of the plugin
+path, either fully-qualified or relative to the F<@prefix@/libexec>
+directory, followed by any configuration arguments the plugin
+requires.  These arguments (if any) will be passed to the plugin's
+initialization function.  If arguments are present, the string must
+be enclosed in double quotes (C<">).
+
+For example, given F</etc/sudo-group>, a group file in Unix group
+format, the sample group plugin can be used:
+
+    Defaults sudo_plugin="sample_group.so /etc/sudo-group"
+
+For more information see L<sudo_plugin(5)>.
+
+=item lecture
+
+This option controls when a short lecture will be printed along with
+the password prompt.  It has the following possible values:
+
+=over 8
+
+=item always
+
+Always lecture the user.
+
+=item never
+
+Never lecture the user.
+
+=item once
+
+Only lecture the user the first time they run B<sudo>.
+
+=back
+
+If no value is specified, a value of I<once> is implied.
+Negating the option results in a value of I<never> being used.
+The default value is I<@lecture@>.
+
+=item lecture_file
+
+Path to a file containing an alternate B<sudo> lecture that will
+be used in place of the standard lecture if the named file exists.
+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> option.  It has the following possible values:
+
+=over 8
+
+=item all
+
+All the user's I<sudoers> entries for the current host must have
+the C<NOPASSWD> flag set to avoid entering a password.
+
+=item always
+
+The user must always enter a password to use the B<-l> option.
+
+=item any
+
+At least one of the user's I<sudoers> entries for the current host
+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> option.
+
+=back
+
+If no value is specified, a value of I<any> is implied.
+Negating the option results in a value of I<never> being used.
+The default value is I<any>.
+
+=item logfile
+
+Path to the B<sudo> log file (not the syslog log file).  Setting a path
+turns on logging to a file; negating this option turns it off.
+By default, B<sudo> logs via syslog.
+
+=item mailerflags
+
+Flags to use when invoking mailer. Defaults to B<-t>.
+
+=item mailerpath
+
+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 option is @secure_path@ by default.
+
+=item syslog
+
+Syslog facility if syslog is being used for logging (negate to
+disable syslog logging).  Defaults to C<@logfac@>.
+
+The following syslog facilities are supported: B<authpriv> (if your
+OS supports it), B<auth>, B<daemon>, B<user>, B<local0>, B<local1>,
+B<local2>, B<local3>, B<local4>, B<local5>, B<local6>, and B<local7>.
+
+=item verifypw
+
+This option controls when a password will be required when a user runs
+B<sudo> with the B<-v> option.  It has the following possible values:
+
+=over 8
+
+=item all
+
+All the user's I<sudoers> entries for the current host must have
+the C<NOPASSWD> flag set to avoid entering a password.
+
+=item always
+
+The user must always enter a password to use the B<-v> option.
+
+=item any
+
+At least one of the user's I<sudoers> entries for the current host
+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> option.
+
+=back
+
+If no value is specified, a value of I<all> is implied.
+Negating the option results in a value of I<never> being used.
+The default value is I<all>.
+
+=back
+
+B<Lists that can be used in a boolean context>:
+
+=over 16
+
+=item env_check
+
+Environment variables to be removed from the user's environment if
+the variable's value contains C<%> or C</> 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 C<=>, C<+=>, C<-=>, and C<!> operators respectively.  Regardless
+of whether the C<env_reset> option is enabled or disabled, variables
+specified by C<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 B<sudo> is run by root with
+the I<-V> option.
+
+=item env_delete
+
+Environment variables to be removed from the user's environment
+when the I<env_reset> option is not in effect.  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 C<=>, C<+=>, C<-=>, and C<!> operators
+respectively.  The default list of environment variables to remove
+is displayed when B<sudo> is run by root with the I<-V> option.
+Note that many operating systems will remove potentially dangerous
+variables from the environment of any setuid process (such as
+B<sudo>).
+
+=item env_keep
+
+Environment variables to be preserved in the user's environment
+when the I<env_reset> option is in effect.  This allows fine-grained
+control over the environment B<sudo>-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 C<=>, C<+=>, C<-=>, and
+C<!> operators respectively.  The default list of variables to keep
+is displayed when B<sudo> is run by root with the I<-V> option.
+
+=back
+
+=head1 FILES
+
+=over 24
+
+=item F<@sysconfdir@/sudoers>
+
+List of who can run what
+
+=item F</etc/group>
+
+Local groups file
+
+=item F</etc/netgroup>
+
+List of network groups
+
+=item F<@iolog_dir@>
+
+I/O log files
+
+=item F<@timedir@>
+
+Directory containing time stamps for the I<sudoers> security policy
+
+=item F</etc/environment>
+
+Initial environment for B<-i> mode on Linux and AIX
+
+=back
+
+=head1 EXAMPLES
+
+Below are example I<sudoers> entries.  Admittedly, some of
+these are a bit contrived.  First, we allow a few environment
+variables to pass and then define our I<aliases>:
+
+ # Run X applications through sudo; HOME is used to find the
+ # .Xauthority file.  Note that other programs use HOME to find
+ # configuration files and this may lead to privilege escalation!
+ Defaults env_keep += "DISPLAY HOME"
+
+ # User alias specification
+ User_Alias    FULLTIMERS = millert, mikef, dowdy
+ User_Alias    PARTTIMERS = bostley, jwfox, crawl
+ User_Alias    WEBMASTERS = will, wendy, wim
+
+ # Runas alias specification
+ Runas_Alias   OP = root, operator
+ Runas_Alias   DB = oracle, sybase
+ Runas_Alias   ADMINGRP = adm, oper
+
+ # Host alias specification
+ Host_Alias    SPARC = bigtime, eclipse, moet, anchor :\
+               SGI = grolsch, dandelion, black :\
+               ALPHA = widget, thalamus, foobar :\
+               HPPA = boa, nag, python
+ Host_Alias    CUNETS = 128.138.0.0/255.255.0.0
+ 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
+
+ # Cmnd alias specification
+ Cmnd_Alias    DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\
+                       /usr/sbin/restore, /usr/sbin/rrestore
+ Cmnd_Alias    KILL = /usr/bin/kill
+ Cmnd_Alias    PRINTING = /usr/sbin/lpc, /usr/bin/lprm
+ Cmnd_Alias    SHUTDOWN = /usr/sbin/shutdown
+ Cmnd_Alias    HALT = /usr/sbin/halt
+ Cmnd_Alias    REBOOT = /usr/sbin/reboot
+ Cmnd_Alias    SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \
+                        /usr/local/bin/tcsh, /usr/bin/rsh, \
+                        /usr/local/bin/zsh
+ 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
+B<sudo> to log via L<syslog(3)> using the I<auth> facility in all
+cases.  We don't want to subject the full time staff to the B<sudo>
+lecture, user B<millert> need not give a password, and we don't
+want to reset the C<LOGNAME>, C<USER> or C<USERNAME> environment
+variables when running commands as root.  Additionally, on the
+machines in the I<SERVERS> C<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 C<Cmnd_Alias>
+(F</usr/bin/more>, F</usr/bin/pg> and F</usr/bin/less>).
+
+ # 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
+
+The I<User specification> is the part that actually determines who may
+run what.
+
+ root          ALL = (ALL) ALL
+ %wheel                ALL = (ALL) ALL
+
+We let B<root> and any user in group B<wheel> run any command on any
+host as any user.
+
+ FULLTIMERS    ALL = NOPASSWD: ALL
+
+Full time sysadmins (B<millert>, B<mikef>, and B<dowdy>) may run any
+command on any host without authenticating themselves.
+
+ PARTTIMERS    ALL = ALL
+
+Part time sysadmins (B<bostley>, B<jwfox>, and B<crawl>) may run any
+command on any host but they must authenticate themselves first
+(since the entry lacks the C<NOPASSWD> tag).
+
+ jack          CSNETS = ALL
+
+The user B<jack> may run any command on the machines in the I<CSNETS> alias
+(the networks C<128.138.243.0>, C<128.138.204.0>, and C<128.138.242.0>).
+Of those networks, only C<128.138.204.0> has an explicit netmask (in
+CIDR notation) indicating it is a class C network.  For the other
+networks in I<CSNETS>, the local machine's netmask will be used
+during matching.
+
+ lisa          CUNETS = ALL
+
+The user B<lisa> may run any command on any host in the I<CUNETS> alias
+(the class B network C<128.138.0.0>).
+
+ operator      ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\
+               sudoedit /etc/printcap, /usr/oper/bin/
+
+The B<operator> 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 F</usr/oper/bin/>.
+
+ joe           ALL = /usr/bin/su operator
+
+The user B<joe> may only L<su(1)> to operator.
+
+ pete          HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root
+
+ %opers                ALL = (: ADMINGRP) /usr/sbin/
+
+Users in the B<opers> group may run commands in F</usr/sbin/> as themselves
+with any group in the I<ADMINGRP> C<Runas_Alias> (the B<adm> and B<oper>
+groups).
+
+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)>
+does not take multiple user names on the command line.
+
+ bob           SPARC = (OP) ALL : SGI = (OP) ALL
+
+The user B<bob> may run anything on the I<SPARC> and I<SGI> machines
+as any user listed in the I<OP> C<Runas_Alias> (B<root> and B<operator>).
+
+ jim           +biglab = ALL
+
+The user B<jim> may run any command on machines in the I<biglab> netgroup.
+B<sudo> knows that "biglab" is a netgroup due to the '+' prefix.
+
+ +secretaries  ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser
+
+Users in the B<secretaries> 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 B<fred> can run commands as any user in the I<DB> C<Runas_Alias>
+(B<oracle> or B<sybase>) without giving a password.
+
+ 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 specify any options to the L<su(1)> command.
+
+ jen           ALL, !SERVERS = ALL
+
+The user B<jen> may run any command on any machine except for those
+in the I<SERVERS> C<Host_Alias> (master, mail, www and ns).
+
+ jill          SERVERS = /usr/bin/, !SU, !SHELLS
+
+For any machine in the I<SERVERS> C<Host_Alias>, B<jill> may run
+any commands in the directory F</usr/bin/> except for those commands
+belonging to the I<SU> and I<SHELLS> C<Cmnd_Aliases>.
+
+ steve         CSNETS = (operator) /usr/local/op_commands/
+
+The user B<steve> may run any command in the directory /usr/local/op_commands/
+but only as user operator.
+
+ matt          valkyrie = KILL
+
+On his personal workstation, valkyrie, B<matt> 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 I<WEBMASTERS> C<User_Alias> (will,
+wendy, and wim), may run any command as user www (which owns the
+web pages) or simply L<su(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
+C<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.
+
+=head1 SECURITY NOTES
+
+It is generally not effective to "subtract" commands from C<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<bill> from running the commands listed in
+I<SU> or I<SHELLS> 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).
+
+Furthermore, if the I<fast_glob> option is in use, it is not possible
+to reliably negate commands where the path name includes globbing
+(aka wildcard) characters.  This is because the C library's
+L<fnmatch(3)> function cannot resolve relative paths.  While this
+is typically only an inconvenience for rules that grant privileges,
+it can result in a security issue for rules that subtract or revoke
+privileges.
+
+For example, given the following I<sudoers> entry:
+
+ john  ALL = /usr/bin/passwd [a-zA-Z0-9]*, /usr/bin/chsh [a-zA-Z0-9]*,
+      /usr/bin/chfn [a-zA-Z0-9]*, !/usr/bin/* root
+
+User B<john> can still run C</usr/bin/passwd root> if I<fast_glob> is
+enabled by changing to F</usr/bin> and running C<./passwd root> instead.
+
+=head1 PREVENTING SHELL ESCAPES
+
+Once B<sudo> 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 B<sudo>'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:
+
+=over 10
+
+=item 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 B<sudoedit> is a better solution to
+running editors via B<sudo>.  Due to the large number of programs that
+offer shell escapes, restricting users to the set of programs that
+do not is often unworkable.
+
+=item noexec
+
+Many systems that support shared libraries have the ability to
+override default library functions by pointing an environment
+variable (usually C<LD_PRELOAD>) to an alternate shared library.
+On such systems, B<sudo>'s I<noexec> functionality can be used to
+prevent a program run by B<sudo> 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.
+
+The I<noexec> feature is known to work on SunOS, Solaris, *BSD,
+Linux, IRIX, Tru64 UNIX, MacOS X, HP-UX 11.x and AIX 5.3 and above.
+It should be supported on most operating systems that support the
+C<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 C<LD_PRELOAD> is supported.
+
+On Solaris 10 and higher, I<noexec> uses Solaris privileges instead
+of the C<LD_PRELOAD> environment variable.
+
+To enable I<noexec> for a command, use the C<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 B<aaron> to run F</usr/bin/more> and F</usr/bin/vi>
+with I<noexec> 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 I<noexec> you
+can always just try it out and check whether shell escapes work
+when I<noexec> is enabled.
+
+=back
+
+Note that restricting shell escapes is not a panacea.  Programs
+running as root are still capable of many potentially hazardous
+operations (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
+B<sudoedit>.
+
+=head1 SECURITY NOTES
+
+I<sudoers> will check the ownership of its time stamp directory
+(F<@timedir@> 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
+L<chown(2)>, if the time stamp directory is located in a world-writable
+directory (e.g., F</tmp>), it is possible for a user to create the
+time stamp directory before B<sudo> is run.  However, because
+I<sudoers> 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 time stamp dir.  This is unlikely to happen
+since once the time stamp dir is owned by root and inaccessible by
+any other user, the user placing files there would be unable to get
+them back out.
+
+I<sudoers> will not honor time stamps set far in the future.  Time
+stamps with a date greater than current_time + 2 * C<TIMEOUT> will
+be ignored and sudo will log and complain.  This is done to keep a
+user from creating his/her own time stamp with a bogus date on
+systems that allow users to give away files if the time stamp directory
+is located in a world-writable directory.
+
+On systems where the boot time is available, I<sudoers> will ignore
+time stamps that date from before the machine booted.
+
+Since time stamp files live in the file system, they can outlive a
+user's login session.  As a result, a user may be able to login,
+run a command with B<sudo> after authenticating, logout, login
+again, and run B<sudo> without authenticating so long as the time
+stamp file's modification time is within C<@timeout@> minutes (or
+whatever the timeout is set to in I<sudoers>).  When the I<tty_tickets>
+option is enabled, the time stamp has per-tty granularity but still
+may outlive the user's session.  On Linux systems where the devpts
+filesystem is used, Solaris systems with the devices filesystem,
+as well as other systems that utilize a devfs filesystem that
+monotonically increase the inode number of devices as they are
+created (such as Mac OS X), I<sudoers> is able to determine when a
+tty-based time stamp file is stale and will ignore it.  Administrators
+should not rely on this feature as it is not universally available.
+
+If users have sudo C<ALL> there is nothing to prevent them from
+creating their own program that gives them a root shell (or making
+their own copy of a shell) regardless of any '!' elements in the
+user specification.
+
+=head1 SEE ALSO
+
+L<rsh(1)>, L<su(1)>, L<fnmatch(3)>, L<glob(3)>, L<mktemp(3)>, L<strftime(3)>,
+L<sudoers.ldap(5)>, L<sudo_plugin(8)>, L<sudo(8)>, L<visudo(8)>
+
+=head1 CAVEATS
+
+The I<sudoers> file should B<always> be edited by the B<visudo>
+command which locks the file and does grammatical checking. It is
+imperative that I<sudoers> be free of syntax errors since B<sudo>
+will not run with a syntactically incorrect I<sudoers> file.
+
+When using netgroups of machines (as opposed to users), if you
+store fully qualified host name in the netgroup (as is usually the
+case), you either need to have the machine's host name be fully qualified
+as returned by the C<hostname> command or use the I<fqdn> option in
+I<sudoers>.
+
+=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.
diff --git a/doc/sudoreplay.cat b/doc/sudoreplay.cat
new file mode 100644 (file)
index 0000000..254544c
--- /dev/null
@@ -0,0 +1,263 @@
+SUDOREPLAY(1m)               MAINTENANCE COMMANDS               SUDOREPLAY(1m)
+
+
+
+N\bNA\bAM\bME\bE
+       sudoreplay - replay sudo session logs
+
+S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS
+       s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by [-\b-h\bh] [-\b-d\bd _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by] [-\b-f\bf _\bf_\bi_\bl_\bt_\be_\br] [-\b-m\bm _\bm_\ba_\bx_\b__\bw_\ba_\bi_\bt] [-\b-s\bs
+       _\bs_\bp_\be_\be_\bd_\b__\bf_\ba_\bc_\bt_\bo_\br] ID
+
+       s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by [-\b-h\bh] [-\b-d\bd _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by] -l [search expression]
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+       s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by plays back or lists the output logs created by s\bsu\bud\bdo\bo.  When
+       replaying, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by can play the session back in real-time, or the
+       playback speed may be adjusted (faster or slower) based on the command
+       line options.
+
+       The _\bI_\bD should either be a six character sequence of digits and upper
+       case letters, e.g. 0100A5, or a pattern matching the _\bi_\bo_\bl_\bo_\bg_\b__\bf_\bi_\bl_\be option
+       in the _\bs_\bu_\bd_\bo_\be_\br_\bs file.  When a command is run via s\bsu\bud\bdo\bo with _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt
+       enabled in the _\bs_\bu_\bd_\bo_\be_\br_\bs file, a TSID=ID string is logged via syslog or
+       to the s\bsu\bud\bdo\bo log file.  The _\bI_\bD may also be determined using s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by's
+       list mode.
+
+       In list mode, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by can be used to find the ID of a session based
+       on a number of criteria such as the user, tty or command run.
+
+       In replay mode, if the standard output has not been redirected,
+       s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by will act on the following keys:
+
+       ' ' (space)
+               Pause output; press any key to resume.
+
+       '<'     Reduce the playback speed by one half.
+
+       '>'     Double the playback speed.
+
+O\bOP\bPT\bTI\bIO\bON\bNS\bS
+       s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by accepts the following command line options:
+
+       -d _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by
+                   Use _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by to for the session logs instead of the
+                   default, _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo.
+
+       -f _\bf_\bi_\bl_\bt_\be_\br   By default, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by will play back the command's
+                   standard output, standard error and tty output.  The _\b-_\bf
+                   option can be used to select which of these to output.  The
+                   _\bf_\bi_\bl_\bt_\be_\br argument is a comma-separated list, consisting of
+                   one or more of following: _\bs_\bt_\bd_\bo_\bu_\bt, _\bs_\bt_\bd_\be_\br_\br, and _\bt_\bt_\by_\bo_\bu_\bt.
+
+       -h          The -\b-h\bh (_\bh_\be_\bl_\bp) option causes s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by to print a short
+                   help message to the standard output and exit.
+
+       -l [_\bs_\be_\ba_\br_\bc_\bh _\be_\bx_\bp_\br_\be_\bs_\bs_\bi_\bo_\bn]
+                   Enable "list mode".  In this mode, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by will list
+                   available session IDs.  If a _\bs_\be_\ba_\br_\bc_\bh _\be_\bx_\bp_\br_\be_\bs_\bs_\bi_\bo_\bn is
+                   specified, it will be used to restrict the IDs that are
+                   displayed.  An expression is composed of the following
+                   predicates:
+
+                   command _\bc_\bo_\bm_\bm_\ba_\bn_\bd _\bp_\ba_\bt_\bt_\be_\br_\bn
+                           Evaluates to true if the command run matches
+                           _\bc_\bo_\bm_\bm_\ba_\bn_\bd _\bp_\ba_\bt_\bt_\be_\br_\bn.  On systems with POSIX regular
+                           expression support, the pattern may be an extended
+                           regular expression.  On systems without POSIX
+                           regular expression support, a simple substring
+                           match is performed instead.
+
+                   cwd _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by
+                           Evaluates to true if the command was run with the
+                           specified current working directory.
+
+                   fromdate _\bd_\ba_\bt_\be
+                           Evaluates to true if the command was run on or
+                           after _\bd_\ba_\bt_\be.  See "Date and time format" for a
+                           description of supported date and time formats.
+
+                   group _\br_\bu_\bn_\ba_\bs_\b__\bg_\br_\bo_\bu_\bp
+                           Evaluates to true if the command was run with the
+                           specified _\br_\bu_\bn_\ba_\bs_\b__\bg_\br_\bo_\bu_\bp.  Note that unless a
+                           _\br_\bu_\bn_\ba_\bs_\b__\bg_\br_\bo_\bu_\bp was explicitly specified when s\bsu\bud\bdo\bo was
+                           run this field will be empty in the log.
+
+                   runas _\br_\bu_\bn_\ba_\bs_\b__\bu_\bs_\be_\br
+                           Evaluates to true if the command was run as the
+                           specified _\br_\bu_\bn_\ba_\bs_\b__\bu_\bs_\be_\br.  Note that s\bsu\bud\bdo\bo runs commands
+                           as user _\br_\bo_\bo_\bt by default.
+
+                   todate _\bd_\ba_\bt_\be
+                           Evaluates to true if the command was run on or
+                           prior to _\bd_\ba_\bt_\be.  See "Date and time format" for a
+                           description of supported date and time formats.
+
+                   tty _\bt_\bt_\by Evaluates to true if the command was run on the
+                           specified terminal device.  The _\bt_\bt_\by should be
+                           specified without the _\b/_\bd_\be_\bv_\b/ prefix, e.g.  _\bt_\bt_\by_\b0_\b1
+                           instead of _\b/_\bd_\be_\bv_\b/_\bt_\bt_\by_\b0_\b1.
+
+                   user _\bu_\bs_\be_\br _\bn_\ba_\bm_\be
+                           Evaluates to true if the ID matches a command run
+                           by _\bu_\bs_\be_\br _\bn_\ba_\bm_\be.
+
+                   Predicates may be abbreviated to the shortest unique string
+                   (currently all predicates may be shortened to a single
+                   character).
+
+                   Predicates may be combined using _\ba_\bn_\bd, _\bo_\br and _\b! operators as
+                   well as '(' and ')' for grouping (note that parentheses
+                   must generally be escaped from the shell).  The _\ba_\bn_\bd
+                   operator is optional, adjacent predicates have an implied
+                   _\ba_\bn_\bd unless separated by an _\bo_\br.
+
+       -m _\bm_\ba_\bx_\b__\bw_\ba_\bi_\bt Specify an upper bound on how long to wait between key
+                   presses or output data.  By default, s\bsu\bud\bdo\bo_\b_r\bre\bep\bpl\bla\bay\by will
+                   accurately reproduce the delays between key presses or
+                   program output.  However, this can be tedious when the
+                   session includes long pauses.  When the _\b-_\bm option is
+                   specified, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by will limit these pauses to at most
+                   _\bm_\ba_\bx_\b__\bw_\ba_\bi_\bt seconds.  The value may be specified as a floating
+                   point number, .e.g. _\b2_\b._\b5.
+
+       -s _\bs_\bp_\be_\be_\bd_\b__\bf_\ba_\bc_\bt_\bo_\br
+                   This option causes s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by to adjust the number of
+                   seconds it will wait between key presses or program output.
+                   This can be used to slow down or speed up the display.  For
+                   example, a _\bs_\bp_\be_\be_\bd_\b__\bf_\ba_\bc_\bt_\bo_\br of _\b2 would make the output twice as
+                   fast whereas a _\bs_\bp_\be_\be_\bd_\b__\bf_\ba_\bc_\bt_\bo_\br of <.5> would make the output
+                   twice as slow.
+
+       -V          The -\b-V\bV (version) option causes s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by to print its
+                   version number and exit.
+
+   D\bDa\bat\bte\be a\ban\bnd\bd t\bti\bim\bme\be f\bfo\bor\brm\bma\bat\bt
+       The time and date may be specified multiple ways, common formats
+       include:
+
+       HH:MM:SS am MM/DD/CCYY timezone
+               24 hour time may be used in place of am/pm.
+
+       HH:MM:SS am Month, Day Year timezone
+               24 hour time may be used in place of am/pm, and month and day
+               names may be abbreviated.  Note that month and day of the week
+               names must be specified in English.
+
+       CCYY-MM-DD HH:MM:SS
+               ISO time format
+
+       DD Month CCYY HH:MM:SS
+               The month name may be abbreviated.
+
+       Either time or date may be omitted, the am/pm and timezone are
+       optional.  If no date is specified, the current day is assumed; if no
+       time is specified, the first second of the specified date is used.  The
+       less significant parts of both time and date may also be omitted, in
+       which case zero is assumed.  For example, the following are all valid:
+
+       The following are all valid time and date specifications:
+
+       now     The current time and date.
+
+       tomorrow
+               Exactly one day from now.
+
+       yesterday
+               24 hours ago.
+
+       2 hours ago
+               2 hours ago.
+
+       next Friday
+               The first second of the next Friday.
+
+       this week
+               The current time but the first day of the coming week.
+
+       a fortnight ago
+               The current time but 14 days ago.
+
+       10:01 am 9/17/2009
+               10:01 am, September 17, 2009.
+
+       10:01 am
+               10:01 am on the current day.
+
+       10      10:00 am on the current day.
+
+       9/17/2009
+               00:00 am, September 17, 2009.
+
+       10:01 am Sep 17, 2009
+               10:01 am, September 17, 2009.
+
+F\bFI\bIL\bLE\bES\bS
+       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo        The default I/O log directory.
+
+       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bl_\bo_\bg
+                               Example session log info.
+
+       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bs_\bt_\bd_\bi_\bn
+                               Example session standard input log.
+
+       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bs_\bt_\bd_\bo_\bu_\bt
+                               Example session standard output log.
+
+       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bs_\bt_\bd_\be_\br_\br
+                               Example session standard error log.
+
+       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bt_\bt_\by_\bi_\bn
+                               Example session tty input file.
+
+       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bt_\bt_\by_\bo_\bu_\bt
+                               Example session tty output file.
+
+       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bt_\bi_\bm_\bi_\bn_\bg
+                               Example session timing file.
+
+       Note that the _\bs_\bt_\bd_\bi_\bn, _\bs_\bt_\bd_\bo_\bu_\bt and _\bs_\bt_\bd_\be_\br_\br files will be empty unless s\bsu\bud\bdo\bo
+       was used as part of a pipeline for a particular command.
+
+E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
+       List sessions run by user _\bm_\bi_\bl_\bl_\be_\br_\bt:
+
+        sudoreplay -l user millert
+
+       List sessions run by user _\bb_\bo_\bb with a command containing the string vi:
+
+        sudoreplay -l user bob command vi
+
+       List sessions run by user _\bj_\be_\bf_\bf that match a regular expression:
+
+        sudoreplay -l user jeff command '/bin/[a-z]*sh'
+
+       List sessions run by jeff or bob on the console:
+
+        sudoreplay -l ( user jeff or user bob ) tty console
+
+S\bSE\bEE\bE A\bAL\bLS\bSO\bO
+       _\bs_\bu_\bd_\bo(1m), _\bs_\bc_\br_\bi_\bp_\bt(1)
+
+A\bAU\bUT\bTH\bHO\bOR\bR
+       Todd C. Miller
+
+B\bBU\bUG\bGS\bS
+       If you feel you have found a bug in s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by, 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.
+
+D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
+       s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by 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.8.1p2                          May 16, 2011                   SUDOREPLAY(1m)
diff --git a/doc/sudoreplay.man.in b/doc/sudoreplay.man.in
new file mode 100644 (file)
index 0000000..1c7557a
--- /dev/null
@@ -0,0 +1,412 @@
+.\" Copyright (c) 2009-2011 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.
+.\" 
+.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.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 (.SS), 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 "SUDOREPLAY @mansectsu@"
+.TH SUDOREPLAY @mansectsu@ "May 16, 2011" "1.8.1p2" "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"
+sudoreplay \- replay sudo session logs
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+\&\fBsudoreplay\fR [\fB\-h\fR] [\fB\-d\fR \fIdirectory\fR] [\fB\-f\fR \fIfilter\fR] [\fB\-m\fR \fImax_wait\fR] [\fB\-s\fR \fIspeed_factor\fR] \s-1ID\s0
+.PP
+\&\fBsudoreplay\fR [\fB\-h\fR] [\fB\-d\fR \fIdirectory\fR] \-l [search expression]
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+\&\fBsudoreplay\fR plays back or lists the output logs created by \fBsudo\fR.
+When replaying, \fBsudoreplay\fR can play the session back in real-time,
+or the playback speed may be adjusted (faster or slower) based on
+the command line options.
+.PP
+The \fI\s-1ID\s0\fR should either be a six character sequence of digits and
+upper case letters, e.g. \f(CW\*(C`0100A5\*(C'\fR, or a pattern matching the
+\&\fIiolog_file\fR option in the \fIsudoers\fR file.  When a command is run
+via \fBsudo\fR with \fIlog_output\fR enabled in the \fIsudoers\fR file, a
+\&\f(CW\*(C`TSID=ID\*(C'\fR string is logged via syslog or to the \fBsudo\fR log file.
+The \fI\s-1ID\s0\fR may also be determined using \fBsudoreplay\fR's list mode.
+.PP
+In list mode, \fBsudoreplay\fR can be used to find the \s-1ID\s0 of a session
+based on a number of criteria such as the user, tty or command run.
+.PP
+In replay mode, if the standard output has not been redirected,
+\&\fBsudoreplay\fR will act on the following keys:
+.IP "' ' (space)" 8
+.IX Item "' ' (space)"
+Pause output; press any key to resume.
+.IP "'<'" 8
+Reduce the playback speed by one half.
+.IP "'>'" 8
+Double the playback speed.
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+\&\fBsudoreplay\fR accepts the following command line options:
+.IP "\-d \fIdirectory\fR" 12
+.IX Item "-d directory"
+Use \fIdirectory\fR to for the session logs instead of the default,
+\&\fI/var/log/sudo\-io\fR.
+.IP "\-f \fIfilter\fR" 12
+.IX Item "-f filter"
+By default, \fBsudoreplay\fR will play back the command's standard
+output, standard error and tty output.  The \fI\-f\fR option can be
+used to select which of these to output.  The \fIfilter\fR argument
+is a comma-separated list, consisting of one or more of following:
+\&\fIstdout\fR, \fIstderr\fR, and \fIttyout\fR.
+.IP "\-h" 12
+.IX Item "-h"
+The \fB\-h\fR (\fIhelp\fR) option causes \fBsudoreplay\fR to print a short
+help message to the standard output and exit.
+.IP "\-l [\fIsearch expression\fR]" 12
+.IX Item "-l [search expression]"
+Enable \*(L"list mode\*(R".  In this mode, \fBsudoreplay\fR will list available
+session IDs.  If a \fIsearch expression\fR is specified, it will be
+used to restrict the IDs that are displayed.  An expression is
+composed of the following predicates:
+.RS 12
+.IP "command \fIcommand pattern\fR" 8
+.IX Item "command command pattern"
+Evaluates to true if the command run matches \fIcommand pattern\fR.
+On systems with \s-1POSIX\s0 regular expression support, the pattern may
+be an extended regular expression.  On systems without \s-1POSIX\s0 regular
+expression support, a simple substring match is performed instead.
+.IP "cwd \fIdirectory\fR" 8
+.IX Item "cwd directory"
+Evaluates to true if the command was run with the specified current
+working directory.
+.IP "fromdate \fIdate\fR" 8
+.IX Item "fromdate date"
+Evaluates to true if the command was run on or after \fIdate\fR.
+See \*(L"Date and time format\*(R" for a description of supported
+date and time formats.
+.IP "group \fIrunas_group\fR" 8
+.IX Item "group runas_group"
+Evaluates to true if the command was run with the specified
+\&\fIrunas_group\fR.  Note that unless a \fIrunas_group\fR was explicitly
+specified when \fBsudo\fR was run this field will be empty in the log.
+.IP "runas \fIrunas_user\fR" 8
+.IX Item "runas runas_user"
+Evaluates to true if the command was run as the specified \fIrunas_user\fR.
+Note that \fBsudo\fR runs commands as user \fIroot\fR by default.
+.IP "todate \fIdate\fR" 8
+.IX Item "todate date"
+Evaluates to true if the command was run on or prior to \fIdate\fR.
+See \*(L"Date and time format\*(R" for a description of supported
+date and time formats.
+.IP "tty \fItty\fR" 8
+.IX Item "tty tty"
+Evaluates to true if the command was run on the specified terminal
+device.  The \fItty\fR should be specified without the \fI/dev/\fR prefix,
+e.g.  \fItty01\fR instead of \fI/dev/tty01\fR.
+.IP "user \fIuser name\fR" 8
+.IX Item "user user name"
+Evaluates to true if the \s-1ID\s0 matches a command run by \fIuser name\fR.
+.RE
+.RS 12
+.Sp
+Predicates may be abbreviated to the shortest unique string (currently
+all predicates may be shortened to a single character).
+.Sp
+Predicates may be combined using \fIand\fR, \fIor\fR and \fI!\fR operators
+as well as \f(CW\*(Aq(\*(Aq\fR and \f(CW\*(Aq)\*(Aq\fR for grouping (note that parentheses
+must generally be escaped from the shell).  The \fIand\fR operator is
+optional, adjacent predicates have an implied \fIand\fR unless separated
+by an \fIor\fR.
+.RE
+.IP "\-m \fImax_wait\fR" 12
+.IX Item "-m max_wait"
+Specify an upper bound on how long to wait between key presses or
+output data.  By default, \fBsudo_replay\fR will accurately reproduce
+the delays between key presses or program output.  However, this
+can be tedious when the session includes long pauses.  When the
+\&\fI\-m\fR option is specified, \fBsudoreplay\fR will limit these pauses
+to at most \fImax_wait\fR seconds.  The value may be specified as a
+floating point number, .e.g. \fI2.5\fR.
+.IP "\-s \fIspeed_factor\fR" 12
+.IX Item "-s speed_factor"
+This option causes \fBsudoreplay\fR to adjust the number of seconds
+it will wait between key presses or program output.  This can be
+used to slow down or speed up the display.  For example, a
+\&\fIspeed_factor\fR of \fI2\fR would make the output twice as fast whereas
+a \fIspeed_factor\fR of <.5> would make the output twice as slow.
+.IP "\-V" 12
+.IX Item "-V"
+The \fB\-V\fR (version) option causes \fBsudoreplay\fR to print its version number
+and exit.
+.SS "Date and time format"
+.IX Subsection "Date and time format"
+The time and date may be specified multiple ways, common formats include:
+.IP "\s-1HH:MM:SS\s0 am \s-1MM/DD/CCYY\s0 timezone" 8
+.IX Item "HH:MM:SS am MM/DD/CCYY timezone"
+24 hour time may be used in place of am/pm.
+.IP "\s-1HH:MM:SS\s0 am Month, Day Year timezone" 8
+.IX Item "HH:MM:SS am Month, Day Year timezone"
+24 hour time may be used in place of am/pm, and month and day names
+may be abbreviated.  Note that month and day of the week names must
+be specified in English.
+.IP "CCYY-MM-DD \s-1HH:MM:SS\s0" 8
+.IX Item "CCYY-MM-DD HH:MM:SS"
+\&\s-1ISO\s0 time format
+.IP "\s-1DD\s0 Month \s-1CCYY\s0 \s-1HH:MM:SS\s0" 8
+.IX Item "DD Month CCYY HH:MM:SS"
+The month name may be abbreviated.
+.PP
+Either time or date may be omitted, the am/pm and timezone are
+optional.  If no date is specified, the current day is assumed; if
+no time is specified, the first second of the specified date is
+used.  The less significant parts of both time and date may also
+be omitted, in which case zero is assumed.  For example, the following
+are all valid:
+.PP
+The following are all valid time and date specifications:
+.IP "now" 8
+.IX Item "now"
+The current time and date.
+.IP "tomorrow" 8
+.IX Item "tomorrow"
+Exactly one day from now.
+.IP "yesterday" 8
+.IX Item "yesterday"
+24 hours ago.
+.IP "2 hours ago" 8
+.IX Item "2 hours ago"
+2 hours ago.
+.IP "next Friday" 8
+.IX Item "next Friday"
+The first second of the next Friday.
+.IP "this week" 8
+.IX Item "this week"
+The current time but the first day of the coming week.
+.IP "a fortnight ago" 8
+.IX Item "a fortnight ago"
+The current time but 14 days ago.
+.IP "10:01 am 9/17/2009" 8
+.IX Item "10:01 am 9/17/2009"
+10:01 am, September 17, 2009.
+.IP "10:01 am" 8
+.IX Item "10:01 am"
+10:01 am on the current day.
+.IP "10" 8
+.IX Item "10"
+10:00 am on the current day.
+.IP "9/17/2009" 8
+.IX Item "9/17/2009"
+00:00 am, September 17, 2009.
+.IP "10:01 am Sep 17, 2009" 8
+.IX Item "10:01 am Sep 17, 2009"
+10:01 am, September 17, 2009.
+.SH "FILES"
+.IX Header "FILES"
+.IP "\fI/var/log/sudo\-io\fR" 24
+.IX Item "/var/log/sudo-io"
+The default I/O log directory.
+.IP "\fI/var/log/sudo\-io/00/00/01/log\fR" 24
+.IX Item "/var/log/sudo-io/00/00/01/log"
+Example session log info.
+.IP "\fI/var/log/sudo\-io/00/00/01/stdin\fR" 24
+.IX Item "/var/log/sudo-io/00/00/01/stdin"
+Example session standard input log.
+.IP "\fI/var/log/sudo\-io/00/00/01/stdout\fR" 24
+.IX Item "/var/log/sudo-io/00/00/01/stdout"
+Example session standard output log.
+.IP "\fI/var/log/sudo\-io/00/00/01/stderr\fR" 24
+.IX Item "/var/log/sudo-io/00/00/01/stderr"
+Example session standard error log.
+.IP "\fI/var/log/sudo\-io/00/00/01/ttyin\fR" 24
+.IX Item "/var/log/sudo-io/00/00/01/ttyin"
+Example session tty input file.
+.IP "\fI/var/log/sudo\-io/00/00/01/ttyout\fR" 24
+.IX Item "/var/log/sudo-io/00/00/01/ttyout"
+Example session tty output file.
+.IP "\fI/var/log/sudo\-io/00/00/01/timing\fR" 24
+.IX Item "/var/log/sudo-io/00/00/01/timing"
+Example session timing file.
+.PP
+Note that the \fIstdin\fR, \fIstdout\fR and \fIstderr\fR files will be empty
+unless \fBsudo\fR was used as part of a pipeline for a particular
+command.
+.SH "EXAMPLES"
+.IX Header "EXAMPLES"
+List sessions run by user \fImillert\fR:
+.PP
+.Vb 1
+\& sudoreplay \-l user millert
+.Ve
+.PP
+List sessions run by user \fIbob\fR with a command containing the string vi:
+.PP
+.Vb 1
+\& sudoreplay \-l user bob command vi
+.Ve
+.PP
+List sessions run by user \fIjeff\fR that match a regular expression:
+.PP
+.Vb 1
+\& sudoreplay \-l user jeff command \*(Aq/bin/[a\-z]*sh\*(Aq
+.Ve
+.PP
+List sessions run by jeff or bob on the console:
+.PP
+.Vb 1
+\& sudoreplay \-l ( user jeff or user bob ) tty console
+.Ve
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fIsudo\fR\|(@mansectsu@), \fIscript\fR\|(1)
+.SH "AUTHOR"
+.IX Header "AUTHOR"
+Todd C. Miller
+.SH "BUGS"
+.IX Header "BUGS"
+If you feel you have found a bug in \fBsudoreplay\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"
+\&\fBsudoreplay\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/doc/sudoreplay.pod b/doc/sudoreplay.pod
new file mode 100644 (file)
index 0000000..d01e498
--- /dev/null
@@ -0,0 +1,350 @@
+Copyright (c) 2009-2011 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.
+
+=pod
+
+=head1 NAME
+
+sudoreplay - replay sudo session logs
+
+=head1 SYNOPSIS
+
+B<sudoreplay> [B<-h>] [B<-d> I<directory>] [B<-f> I<filter>] [B<-m> I<max_wait>] [B<-s> I<speed_factor>] ID
+
+B<sudoreplay> [B<-h>] [B<-d> I<directory>] -l [search expression]
+
+=head1 DESCRIPTION
+
+B<sudoreplay> plays back or lists the output logs created by B<sudo>.
+When replaying, B<sudoreplay> can play the session back in real-time,
+or the playback speed may be adjusted (faster or slower) based on
+the command line options.
+
+The I<ID> should either be a six character sequence of digits and
+upper case letters, e.g. C<0100A5>, or a pattern matching the
+I<iolog_file> option in the I<sudoers> file.  When a command is run
+via B<sudo> with I<log_output> enabled in the I<sudoers> file, a
+C<TSID=ID> string is logged via syslog or to the B<sudo> log file.
+The I<ID> may also be determined using B<sudoreplay>'s list mode.
+
+In list mode, B<sudoreplay> can be used to find the ID of a session
+based on a number of criteria such as the user, tty or command run.
+
+In replay mode, if the standard output has not been redirected,
+B<sudoreplay> will act on the following keys:
+
+=over 8
+
+=item ' ' (space)
+
+Pause output; press any key to resume.
+
+=item '<'
+
+Reduce the playback speed by one half.
+
+=item '>'
+
+Double the playback speed.
+
+=back
+
+=head1 OPTIONS
+
+B<sudoreplay> accepts the following command line options:
+
+=over 12
+
+=item -d I<directory>
+
+Use I<directory> to for the session logs instead of the default,
+F</var/log/sudo-io>.
+
+=item -f I<filter>
+
+By default, B<sudoreplay> will play back the command's standard
+output, standard error and tty output.  The I<-f> option can be
+used to select which of these to output.  The I<filter> argument
+is a comma-separated list, consisting of one or more of following:
+I<stdout>, I<stderr>, and I<ttyout>.
+
+=item -h
+
+The B<-h> (I<help>) option causes B<sudoreplay> to print a short
+help message to the standard output and exit.
+
+=item -l [I<search expression>]
+
+Enable "list mode".  In this mode, B<sudoreplay> will list available
+session IDs.  If a I<search expression> is specified, it will be
+used to restrict the IDs that are displayed.  An expression is
+composed of the following predicates:
+
+=over 8
+
+=item command I<command pattern>
+
+Evaluates to true if the command run matches I<command pattern>.
+On systems with POSIX regular expression support, the pattern may
+be an extended regular expression.  On systems without POSIX regular
+expression support, a simple substring match is performed instead.
+
+=item cwd I<directory>
+
+Evaluates to true if the command was run with the specified current
+working directory.
+
+=item fromdate I<date>
+
+Evaluates to true if the command was run on or after I<date>.
+See L<"Date and time format"> for a description of supported
+date and time formats.
+
+=item group I<runas_group>
+
+Evaluates to true if the command was run with the specified
+I<runas_group>.  Note that unless a I<runas_group> was explicitly
+specified when B<sudo> was run this field will be empty in the log.
+
+=item runas I<runas_user>
+
+Evaluates to true if the command was run as the specified I<runas_user>.
+Note that B<sudo> runs commands as user I<root> by default.
+
+=item todate I<date>
+
+Evaluates to true if the command was run on or prior to I<date>.
+See L<"Date and time format"> for a description of supported
+date and time formats.
+
+=item tty I<tty>
+
+Evaluates to true if the command was run on the specified terminal
+device.  The I<tty> should be specified without the F</dev/> prefix,
+e.g.  F<tty01> instead of F</dev/tty01>.
+
+=item user I<user name>
+
+Evaluates to true if the ID matches a command run by I<user name>.
+
+=back
+
+Predicates may be abbreviated to the shortest unique string (currently
+all predicates may be shortened to a single character).
+
+Predicates may be combined using I<and>, I<or> and I<!> operators
+as well as C<'('> and C<')'> for grouping (note that parentheses
+must generally be escaped from the shell).  The I<and> operator is
+optional, adjacent predicates have an implied I<and> unless separated
+by an I<or>.
+
+=item -m I<max_wait>
+
+Specify an upper bound on how long to wait between key presses or
+output data.  By default, B<sudo_replay> will accurately reproduce
+the delays between key presses or program output.  However, this
+can be tedious when the session includes long pauses.  When the
+I<-m> option is specified, B<sudoreplay> will limit these pauses
+to at most I<max_wait> seconds.  The value may be specified as a
+floating point number, .e.g. I<2.5>.
+
+=item -s I<speed_factor>
+
+This option causes B<sudoreplay> to adjust the number of seconds
+it will wait between key presses or program output.  This can be
+used to slow down or speed up the display.  For example, a
+I<speed_factor> of I<2> would make the output twice as fast whereas
+a I<speed_factor> of <.5> would make the output twice as slow.
+
+=item -V
+
+The B<-V> (version) option causes B<sudoreplay> to print its version number
+and exit.
+
+=back
+
+=head2 Date and time format
+
+The time and date may be specified multiple ways, common formats include:
+
+=over 8
+
+=item HH:MM:SS am MM/DD/CCYY timezone
+
+24 hour time may be used in place of am/pm.
+
+=item HH:MM:SS am Month, Day Year timezone
+
+24 hour time may be used in place of am/pm, and month and day names
+may be abbreviated.  Note that month and day of the week names must
+be specified in English.
+
+=item CCYY-MM-DD HH:MM:SS
+
+ISO time format
+
+=item DD Month CCYY HH:MM:SS
+
+The month name may be abbreviated.
+
+=back
+
+Either time or date may be omitted, the am/pm and timezone are
+optional.  If no date is specified, the current day is assumed; if
+no time is specified, the first second of the specified date is
+used.  The less significant parts of both time and date may also
+be omitted, in which case zero is assumed.  For example, the following
+are all valid:
+
+The following are all valid time and date specifications:
+
+=over 8
+
+=item now
+
+The current time and date.
+
+=item tomorrow
+
+Exactly one day from now.
+
+=item yesterday
+
+24 hours ago.
+
+=item 2 hours ago
+
+2 hours ago.
+
+=item next Friday
+
+The first second of the next Friday.
+
+=item this week
+
+The current time but the first day of the coming week.
+
+=item a fortnight ago
+
+The current time but 14 days ago.
+
+=item 10:01 am 9/17/2009
+
+10:01 am, September 17, 2009.
+
+=item 10:01 am
+
+10:01 am on the current day.
+
+=item 10
+
+10:00 am on the current day.
+
+=item 9/17/2009
+
+00:00 am, September 17, 2009.
+
+=item 10:01 am Sep 17, 2009
+
+10:01 am, September 17, 2009.
+
+=back
+
+=head1 FILES
+
+=over 24
+
+=item F</var/log/sudo-io>
+
+The default I/O log directory.
+
+=item F</var/log/sudo-io/00/00/01/log>
+
+Example session log info.
+
+=item F</var/log/sudo-io/00/00/01/stdin>
+
+Example session standard input log.
+
+=item F</var/log/sudo-io/00/00/01/stdout>
+
+Example session standard output log.
+
+=item F</var/log/sudo-io/00/00/01/stderr>
+
+Example session standard error log.
+
+=item F</var/log/sudo-io/00/00/01/ttyin>
+
+Example session tty input file.
+
+=item F</var/log/sudo-io/00/00/01/ttyout>
+
+Example session tty output file.
+
+=item F</var/log/sudo-io/00/00/01/timing>
+
+Example session timing file.
+
+=back
+
+Note that the I<stdin>, I<stdout> and I<stderr> files will be empty
+unless B<sudo> was used as part of a pipeline for a particular
+command.
+
+=head1 EXAMPLES
+
+List sessions run by user I<millert>:
+
+ sudoreplay -l user millert
+
+List sessions run by user I<bob> with a command containing the string vi:
+
+ sudoreplay -l user bob command vi
+
+List sessions run by user I<jeff> that match a regular expression:
+
+ sudoreplay -l user jeff command '/bin/[a-z]*sh'
+
+List sessions run by jeff or bob on the console:
+
+ sudoreplay -l ( user jeff or user bob ) tty console
+
+=head1 SEE ALSO
+
+L<sudo(8)>, L<script(1)>
+
+=head1 AUTHOR
+
+Todd C. Miller
+
+=head1 BUGS
+
+If you feel you have found a bug in B<sudoreplay>, 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<sudoreplay> 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.
diff --git a/doc/visudo.cat b/doc/visudo.cat
new file mode 100644 (file)
index 0000000..5aa5f0f
--- /dev/null
@@ -0,0 +1,146 @@
+VISUDO(1m)                   MAINTENANCE COMMANDS                   VISUDO(1m)
+
+
+
+N\bNA\bAM\bME\bE
+       visudo - edit the sudoers file
+
+S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS
+       v\bvi\bis\bsu\bud\bdo\bo [-\b-c\bch\bhq\bqs\bsV\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 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 one or more 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 "vi".  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_\b-_\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.
+
+       -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/_\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.  In c\bch\bhe\bec\bck\bk-\b-o\bon\bnl\bly\by mode only, the argument to
+                   -\b-f\bf may be "-", indicating that _\bs_\bu_\bd_\bo_\be_\br_\bs will be read from
+                   the standard input.
+
+       -h          The -\b-h\bh (_\bh_\be_\bl_\bp) option causes v\bvi\bis\bsu\bud\bdo\bo to print a short help
+                   message to the standard output and exit.
+
+       -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 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 consider this a
+                   parse error.  Note that it is not possible to differentiate
+                   between an alias and a host name or user name 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.
+
+E\bEN\bNV\bVI\bIR\bRO\bON\bNM\bME\bEN\bNT\bT
+       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/_\be_\bt_\bc_\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.
+           Someone else is currently editing the _\bs_\bu_\bd_\bo_\be_\br_\bs file.
+
+       /etc/sudoers.tmp: Permission denied
+           You didn't run v\bvi\bis\bsu\bud\bdo\bo as root.
+
+       Can't find you in the passwd database
+           Your userid does not appear in the system passwd file.
+
+       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 host name 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: 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(1m)
+
+A\bAU\bUT\bTH\bHO\bOR\bR
+       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
+
+       See the HISTORY file in the sudo distribution or visit
+       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.
+
+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/
+
+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.
+
+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 complete details.
+
+
+
+1.8.1p2                          May 16, 2011                       VISUDO(1m)
diff --git a/doc/visudo.man.in b/doc/visudo.man.in
new file mode 100644 (file)
index 0000000..9003ea8
--- /dev/null
@@ -0,0 +1,307 @@
+.\" Copyright (c) 1996,1998-2005, 2007-2011
+.\"    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.
+.\" 
+.\" 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.
+.\" 
+.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.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 (.SS), 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 "VISUDO @mansectsu@"
+.TH VISUDO @mansectsu@ "May 16, 2011" "1.8.1p2" "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"
+.IX Header "SYNOPSIS"
+\&\fBvisudo\fR [\fB\-chqsV\fR] [\fB\-f\fR \fIsudoers\fR]
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+\&\fBvisudo\fR edits the \fIsudoers\fR file in a safe fashion, analogous to
+\&\fIvipw\fR\|(@mansectsu@).  \fBvisudo\fR locks the \fIsudoers\fR file against multiple
+simultaneous edits, provides basic sanity checks, and checks
+for parse errors.  If the \fIsudoers\fR file is currently being
+edited you will receive a message to try again later.
+.PP
+There is a hard-coded list of one or more editors that \fBvisudo\fR will
+use set at compile-time that may be overridden via the \fIeditor\fR \fIsudoers\fR
+\&\f(CW\*(C`Default\*(C'\fR variable.  This list defaults to \f(CW"@editor@"\fR.  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\-env\-editor\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.
+.PP
+\&\fBvisudo\fR parses the \fIsudoers\fR file after the edit and will
+not save the changes if there is a syntax error.  Upon finding
+an error, \fBvisudo\fR will print a message stating the line number(s)
+where the error occurred and the user will receive the
+\&\*(L"What now?\*(R" prompt.  At this point the user may enter \*(L"e\*(R"
+to re-edit the \fIsudoers\fR file, \*(L"x\*(R" to exit without
+saving the changes, or \*(L"Q\*(R" to quit and save changes.  The
+\&\*(L"Q\*(R" option should be used with extreme care because if \fBvisudo\fR
+believes there to be a parse error, so will \fBsudo\fR and no one
+will be able to \fBsudo\fR again until the error is fixed.
+If \*(L"e\*(R" is typed to edit the  \fIsudoers\fR 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).
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+\&\fBvisudo\fR accepts the following command line options:
+.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
+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 \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
+is the specified \fIsudoers\fR file with \*(L".tmp\*(R" appended to it.
+In \fBcheck-only\fR mode only, the argument to \fB\-f\fR may be \*(L"\-\*(R",
+indicating that \fIsudoers\fR will be read from the standard input.
+.IP "\-h" 12
+.IX Item "-h"
+The \fB\-h\fR (\fIhelp\fR) option causes \fBvisudo\fR to print a short help message
+to the standard output and exit.
+.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 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 host name or user name that consists solely of uppercase
+letters, digits, and the underscore ('_') character.
+.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 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"
+Invoked by visudo as the editor to use
+.ie n .IP "\*(C`EDITOR\*(C'" 16
+.el .IP "\f(CW\*(C`EDITOR\*(C'\fR" 16
+.IX Item "EDITOR"
+Used by visudo if \s-1VISUAL\s0 is not set
+.SH "FILES"
+.IX Header "FILES"
+.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
+.ie n .IP "\fI@sysconfdir@/sudoers.tmp\fR" 24
+.el .IP "\fI@sysconfdir@/sudoers.tmp\fR" 24
+.IX Item "@sysconfdir@/sudoers.tmp"
+Lock file for visudo
+.SH "DIAGNOSTICS"
+.IX Header "DIAGNOSTICS"
+.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.
+.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: {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 host name 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\|(@mansectsu@)
+.SH "AUTHOR"
+.IX Header "AUTHOR"
+Many people have worked on \fIsudo\fR over the years; this version of
+\&\fBvisudo\fR was written by:
+.PP
+.Vb 1
+\& Todd Miller
+.Ve
+.PP
+See the \s-1HISTORY\s0 file in the sudo distribution or visit
+http://www.sudo.ws/sudo/history.html for more details.
+.SH "CAVEATS"
+.IX Header "CAVEATS"
+There is no easy way to prevent a user from gaining a root shell if 
+the editor used by \fBvisudo\fR allows shell escapes.
+.SH "BUGS"
+.IX Header "BUGS"
+If you feel you have found a bug in \fBvisudo\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"
+\&\fBvisudo\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/doc/visudo.pod b/doc/visudo.pod
new file mode 100644 (file)
index 0000000..cffb321
--- /dev/null
@@ -0,0 +1,213 @@
+Copyright (c) 1996,1998-2005, 2007-2011
+       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.
+
+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.
+
+=pod
+
+=head1 NAME
+
+visudo - edit the sudoers file
+
+=head1 SYNOPSIS
+
+B<visudo> [B<-chqsV>] [B<-f> I<sudoers>]
+
+=head1 DESCRIPTION
+
+B<visudo> edits the I<sudoers> file in a safe fashion, analogous to
+L<vipw(8)>.  B<visudo> locks the I<sudoers> file against multiple
+simultaneous edits, provides basic sanity checks, and checks
+for parse errors.  If the I<sudoers> file is currently being
+edited you will receive a message to try again later.
+
+There is a hard-coded list of one or more editors that B<visudo> will
+use set at compile-time that may be overridden via the I<editor> I<sudoers>
+C<Default> variable.  This list defaults to C<"@editor@">.  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-env-editor>
+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>.
+
+B<visudo> parses the I<sudoers> file after the edit and will
+not save the changes if there is a syntax error.  Upon finding
+an error, B<visudo> 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 I<sudoers> 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 B<visudo>
+believes there to be a parse error, so will B<sudo> and no one
+will be able to B<sudo> again until the error is fixed.
+If "e" is typed to edit the  I<sudoers> 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).
+
+=head1 OPTIONS
+
+B<visudo> accepts the following command line options:
+
+=over 12
+
+=item -c
+
+Enable B<check-only> mode.  The existing I<sudoers> file will be
+checked for syntax and a message will be printed to the
+standard output detailing the status of I<sudoers>.
+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 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,
+instead of the default, F<@sysconfdir@/sudoers>.  The lock file used
+is the specified I<sudoers> file with ".tmp" appended to it.
+In B<check-only> mode only, the argument to B<-f> may be "-",
+indicating that I<sudoers> will be read from the standard input.
+
+=item -h
+
+The B<-h> (I<help>) option causes B<visudo> to print a short help message
+to the standard output and exit.
+
+=item -q
+
+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> option.
+
+=item -s
+
+Enable B<strict> checking of the I<sudoers> file.  If an alias is
+used before it is defined, B<visudo> will consider this a parse
+error.  Note that it is not possible to differentiate between an
+alias and a host name or user name that consists solely of uppercase
+letters, digits, and the underscore ('_') character.
+
+=item -V
+
+The B<-V> (version) option causes B<visudo> to print its version number
+and exit.
+
+=back
+
+=head1 ENVIRONMENT
+
+The following environment variables may be consulted depending on
+the value of the I<editor> and I<env_editor> I<sudoers> variables:
+
+=over 16
+
+=item C<VISUAL>
+
+Invoked by visudo as the editor to use
+
+=item C<EDITOR>
+
+Used by visudo if VISUAL is not set
+
+=back
+
+=head1 FILES
+
+=over 24
+
+=item F<@sysconfdir@/sudoers>
+
+List of who can run what
+
+=item F<@sysconfdir@/sudoers.tmp>
+
+Lock file for visudo
+
+=back
+
+=head1 DIAGNOSTICS
+
+=over 4
+
+=item sudoers file busy, try again later.
+
+Someone else is currently editing the I<sudoers> file.
+
+=item @sysconfdir@/sudoers.tmp: Permission denied
+
+You didn't run B<visudo> as root.
+
+=item Can't find you in the passwd database
+
+Your userid does not appear in the system passwd file.
+
+=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 host name 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
+
+=head1 SEE ALSO
+
+L<vi(1)>, L<sudoers(5)>, L<sudo(8)>, L<vipw(8)>
+
+=head1 AUTHOR
+
+Many people have worked on I<sudo> over the years; this version of
+B<visudo> was written by:
+
+ Todd Miller
+
+See the HISTORY file in the sudo distribution or visit
+http://www.sudo.ws/sudo/history.html for more details.
+
+=head1 CAVEATS
+
+There is no easy way to prevent a user from gaining a root shell if 
+the editor used by B<visudo> allows shell escapes.
+
+=head1 BUGS
+
+If you feel you have found a bug in B<visudo>, 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<visudo> 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.
diff --git a/emul/charclass.h b/emul/charclass.h
deleted file mode 100644 (file)
index 15463ff..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * 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/fnmatch.h b/emul/fnmatch.h
deleted file mode 100644 (file)
index 9f65bc5..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*-
- * Copyright (c) 1992, 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. 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.h   8.1 (Berkeley) 6/2/93
- *     $OpenBSD: fnmatch.h,v 1.4 1997/09/22 05:25:32 millert Exp $
- */
-
-#ifndef        _FNMATCH_H_
-#define        _FNMATCH_H_
-
-#define        FNM_NOMATCH     1       /* Match failed. */
-
-#define        FNM_NOESCAPE    0x01    /* Disable backslash escaping. */
-#define        FNM_PATHNAME    0x02    /* Slash must be matched by slash. */
-#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. */
-
-int     fnmatch __P((const char *, const char *, int));
-
-#endif /* !_FNMATCH_H_ */
diff --git a/emul/glob.h b/emul/glob.h
deleted file mode 100644 (file)
index 36efc00..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*     $OpenBSD: glob.h,v 1.8 2003/06/02 19:34:12 millert Exp $        */
-
-/*
- * Copyright (c) 1989, 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.
- *
- *     @(#)glob.h      8.1 (Berkeley) 6/2/93
- */
-
-#ifndef _GLOB_H_
-#define        _GLOB_H_
-
-struct stat;
-typedef struct {
-       int gl_pathc;           /* Count of total paths so far. */
-       int gl_matchc;          /* Count of paths matching pattern. */
-       int gl_offs;            /* Reserved at beginning of gl_pathv. */
-       int gl_flags;           /* Copy of flags parameter to glob. */
-       char **gl_pathv;        /* List of paths matching pattern. */
-                               /* Copy of errfunc parameter to glob. */
-#ifdef __STDC__
-       int (*gl_errfunc)(const char *, int);
-#else
-       int (*gl_errfunc)();
-#endif
-} glob_t;
-
-/* Flags */
-#define        GLOB_APPEND     0x0001  /* Append to output from previous call. */
-#define        GLOB_DOOFFS     0x0002  /* Use gl_offs. */
-#define        GLOB_ERR        0x0004  /* Return on error. */
-#define        GLOB_MARK       0x0008  /* Append / to matching directories. */
-#define        GLOB_NOCHECK    0x0010  /* Return pattern itself if nothing matches. */
-#define        GLOB_NOSORT     0x0020  /* Don't sort. */
-#define        GLOB_NOESCAPE   0x0040  /* Disable backslash escaping. */
-
-/* Non-POSIX extensions */
-#define        GLOB_MAGCHAR    0x0080  /* Pattern had globbing characters. */
-#define        GLOB_BRACE      0x0100  /* Expand braces ala csh. */
-#define        GLOB_TILDE      0x0200  /* Expand tilde names from the passwd file. */
-
-/* Error values returned by glob(3) */
-#define        GLOB_NOSPACE    (-1)    /* Malloc call failed. */
-#define        GLOB_ABORTED    (-2)    /* Unignored error. */
-#define        GLOB_NOMATCH    (-3)    /* No match and GLOB_NOCHECK not set. */
-#define        GLOB_NOSYS      (-4)    /* Function not supported. */
-#define GLOB_ABEND     GLOB_ABORTED
-
-#ifdef __STDC__
-int    glob(const char *, int, int (*)(const char *, int), glob_t *);
-void   globfree(glob_t *);
-#else
-int    glob();
-void   globfree();
-#endif
-
-#endif /* !_GLOB_H_ */
diff --git a/emul/timespec.h b/emul/timespec.h
deleted file mode 100644 (file)
index 681c523..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 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.
- */
-
-#ifndef _SUDO_TIMESPEC_H
-#define _SUDO_TIMESPEC_H
-
-struct timespec {
-    time_t     tv_sec;
-    long       tv_nsec;
-};
-
-#endif /* _SUDO_TIMESPEC_H */
diff --git a/emul/utime.h b/emul/utime.h
deleted file mode 100644 (file)
index e5c63a5..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-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.
- */
-
-#ifndef        _UTIME_H
-#define        _UTIME_H
-
-struct utimbuf {
-       time_t  actime;         /* access time */
-       time_t  modtime;        /* mod time */
-};
-
-#ifdef __STDC__
-int utime(const char *, const struct utimbuf *);
-#else
-int utime();
-#endif
-
-#endif /* _UTIME_H */
diff --git a/env.c b/env.c
deleted file mode 100644 (file)
index 654565e..0000000
--- a/env.c
+++ /dev/null
@@ -1,987 +0,0 @@
-/*
- * Copyright (c) 2000-2005, 2007-2010
- *     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/param.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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <ctype.h>
-#include <errno.h>
-#include <pwd.h>
-
-#include "sudo.h"
-
-/*
- * Flags used in rebuild_env()
- */
-#undef DID_TERM
-#define DID_TERM       0x0001
-#undef DID_PATH
-#define DID_PATH       0x0002
-#undef DID_HOME
-#define DID_HOME       0x0004
-#undef DID_SHELL
-#define DID_SHELL      0x0008
-#undef DID_LOGNAME
-#define DID_LOGNAME    0x0010
-#undef DID_USER
-#define DID_USER       0x0020
-#undef DID_USERNAME
-#define DID_USERNAME           0x0040
-#undef DID_MAIL
-#define DID_MAIL       0x0080
-#undef DID_MAX
-#define DID_MAX        0x00ff
-
-#undef KEPT_TERM
-#define KEPT_TERM      0x0100
-#undef KEPT_PATH
-#define KEPT_PATH      0x0200
-#undef KEPT_HOME
-#define KEPT_HOME      0x0400
-#undef KEPT_SHELL
-#define KEPT_SHELL     0x0800
-#undef KEPT_LOGNAME
-#define KEPT_LOGNAME   0x1000
-#undef KEPT_USER
-#define KEPT_USER      0x2000
-#undef KEPT_USERNAME
-#define KEPT_USERNAME  0x4000
-#undef KEPT_MAIL
-#define KEPT_MAIL      0x8000
-#undef KEPT_MAX
-#define KEPT_MAX       0xff00
-
-struct environment {
-    char **envp;               /* pointer to the new environment */
-    size_t env_size;           /* size of new_environ in char **'s */
-    size_t env_len;            /* number of slots used, not counting NULL */
-    int owned;                 /* do we own envp or is it the system's? */
-};
-
-/*
- * Prototypes
- */
-static void sudo_setenv                __P((const char *, const char *, int));
-static void sudo_putenv                __P((char *, int, int));
-
-extern char **environ;         /* global environment */
-
-/*
- * Copy of the sudo-managed environment.
- */
-static struct environment env;
-
-/*
- * Default table of "bad" variables to remove from the environment.
- * XXX - how to omit TERMCAP if it starts with '/'?
- */
-static const char *initial_badenv_table[] = {
-    "IFS",
-    "CDPATH",
-    "LOCALDOMAIN",
-    "RES_OPTIONS",
-    "HOSTALIASES",
-    "NLSPATH",
-    "PATH_LOCALE",
-    "LD_*",
-    "_RLD*",
-#ifdef __hpux
-    "SHLIB_PATH",
-#endif /* __hpux */
-#ifdef _AIX
-    "LDR_*",
-    "LIBPATH",
-    "AUTHSTATE",
-#endif
-#ifdef __APPLE__
-    "DYLD_*",
-#endif
-#ifdef HAVE_KERB4
-    "KRB_CONF*",
-    "KRBCONFDIR",
-    "KRBTKFILE",
-#endif /* HAVE_KERB4 */
-#ifdef HAVE_KERB5
-    "KRB5_CONFIG*",
-    "KRB5_KTNAME",
-#endif /* HAVE_KERB5 */
-#ifdef HAVE_SECURID
-    "VAR_ACE",
-    "USR_ACE",
-    "DLC_ACE",
-#endif /* HAVE_SECURID */
-    "TERMINFO",                        /* terminfo, exclusive path to terminfo files */
-    "TERMINFO_DIRS",           /* terminfo, path(s) to terminfo files */
-    "TERMPATH",                        /* termcap, path(s) to termcap files */
-    "TERMCAP",                 /* XXX - only if it starts with '/' */
-    "ENV",                     /* ksh, file to source before script runs */
-    "BASH_ENV",                        /* bash, file to source before script runs */
-    "PS4",                     /* bash, prefix for lines in xtrace mode */
-    "GLOBIGNORE",              /* bash, globbing patterns to ignore */
-    "SHELLOPTS",               /* bash, extra command line options */
-    "JAVA_TOOL_OPTIONS",       /* java, extra command line options */
-    "PERLIO_DEBUG ",           /* perl, debugging output file */
-    "PERLLIB",                 /* perl, search path for modules/includes */
-    "PERL5LIB",                        /* perl 5, search path for modules/includes */
-    "PERL5OPT",                        /* perl 5, extra command line options */
-    "PERL5DB",                 /* perl 5, command used to load debugger */
-    "FPATH",                   /* ksh, search path for functions */
-    "NULLCMD",                 /* zsh, command for null file redirection */
-    "READNULLCMD",             /* zsh, command for null file redirection */
-    "ZDOTDIR",                 /* zsh, search path for dot files */
-    "TMPPREFIX",               /* zsh, prefix for temporary files */
-    "PYTHONHOME",              /* python, module search path */
-    "PYTHONPATH",              /* python, search path */
-    "PYTHONINSPECT",           /* python, allow inspection */
-    "PYTHONUSERBASE",          /* python, per user site-packages directory */
-    "RUBYLIB",                 /* ruby, library load path */
-    "RUBYOPT",                 /* ruby, extra command line options */
-    NULL
-};
-
-/*
- * Default table of variables to check for '%' and '/' characters.
- */
-static const char *initial_checkenv_table[] = {
-    "COLORTERM",
-    "LANG",
-    "LANGUAGE",
-    "LC_*",
-    "LINGUAS",
-    "TERM",
-    NULL
-};
-
-/*
- * Default table of variables to preserve in the environment.
- */
-static const char *initial_keepenv_table[] = {
-    "COLORS",
-    "DISPLAY",
-    "HOSTNAME",
-    "KRB5CCNAME",
-    "LS_COLORS",
-    "PATH",
-    "PS1",
-    "PS2",
-    "TZ",
-    "XAUTHORITY",
-    "XAUTHORIZATION",
-#ifdef _AIX
-    "ODMDIR",
-#endif
-    NULL
-};
-
-/*
- * Initialize env based on envp.
- */
-void
-env_init(lazy)
-    int lazy;
-{
-    char * const *ep;
-    size_t len;
-
-    for (ep = environ; *ep != NULL; ep++)
-       continue;
-    len = (size_t)(ep - environ);
-
-    if (lazy) {
-       /*
-        * If we are already initialized due to lazy init (usualy via getenv())
-        * we need to avoid calling malloc() as it may call getenv() itself.
-        */
-       env.envp = environ;
-       env.env_len = len;
-       env.env_size = len;
-    } else if (!env.owned) {
-       env.env_len = len;
-       env.env_size = len + 1 + 128;
-       env.envp = emalloc2(env.env_size, sizeof(char *));
-#ifdef ENV_DEBUG
-       memset(env.envp, 0, env.env_size * sizeof(char *));
-#endif
-       memcpy(env.envp, environ, len * sizeof(char *));
-       env.envp[len] = '\0';
-       env.owned = TRUE;
-    }
-}
-
-char **
-env_get()
-{
-    return env.envp;
-}
-
-/*
- * Similar to setenv(3) but operates on sudo's private copy of the environment
- * (not environ) 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;
-    size_t esize;
-
-    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");
-    }
-    sudo_putenv(estring, dupcheck, TRUE);
-}
-
-/*
- * Version of getenv(3) that uses our own environ pointer.
- */
-char *
-getenv(var)
-    const char *var;
-{
-    char *cp, **ev;
-    size_t vlen = strlen(var);
-
-    if (env.envp == NULL)
-       env_init(TRUE);
-
-    for (ev = env.envp; (cp = *ev) != NULL; ev++) {
-       if (strncmp(var, cp, vlen) == 0 && cp[vlen] == '=')
-           return cp + vlen + 1;
-    }
-    return NULL;
-}
-
-/*
- * Version of setenv(3) that uses our own environ pointer.
- */
-int
-setenv(var, val, overwrite)
-    const char *var;
-    const char *val;
-    int overwrite;
-{
-    char *estring, *ep;
-    const char *cp;
-    size_t esize;
-
-    if (!var || *var == '\0') {
-       errno = EINVAL;
-       return -1;
-    }
-
-    if (env.envp == NULL)
-       env_init(TRUE);
-
-    /*
-     * POSIX says a var name with '=' is an error but BSD
-     * just ignores the '=' and anything after it.
-     */
-    for (cp = var; *cp && *cp != '='; cp++)
-       ;
-    esize = (size_t)(cp - var) + 2;
-    if (val) {
-       esize += strlen(val);   /* glibc treats a NULL val as "" */
-    }
-
-    /* Allocate and fill in estring. */
-    estring = ep = emalloc(esize);
-    for (cp = var; *cp && *cp != '='; cp++)
-       *ep++ = *cp;
-    *ep++ = '=';
-    if (val) {
-       for (cp = val; *cp; cp++)
-           *ep++ = *cp;
-    }
-    *ep = '\0';
-
-#ifdef ENV_DEBUG
-    if (env.envp[env.env_len] != NULL)
-       errorx(1, "setenv: corrupted envp, len mismatch");
-#endif
-    sudo_putenv(estring, TRUE, overwrite);
-    return 0;
-}
-
-/*
- * Version of unsetenv(3) that uses our own environ pointer.
- */
-#ifdef UNSETENV_VOID
-void
-#else
-int
-#endif
-unsetenv(var)
-    const char *var;
-{
-    char **ep;
-    size_t len;
-
-    if (var == NULL || *var == '\0' || strchr(var, '=') != NULL) {
-       errno = EINVAL;
-#ifdef UNSETENV_VOID
-       return;
-#else
-       return -1;
-#endif
-    }
-
-    if (env.envp == NULL)
-       env_init(TRUE);
-
-#ifdef ENV_DEBUG
-    if (env.envp[env.env_len] != NULL)
-       errorx(1, "unsetenv: corrupted envp, len mismatch");
-#endif
-
-    len = strlen(var);
-    for (ep = env.envp; *ep != NULL;) {
-       if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
-           /* Found it; shift remainder + NULL over by one. */
-           char **cur = ep;
-           while ((*cur = *(cur + 1)) != NULL)
-               cur++;
-           /* Keep going, could be multiple instances of the var. */
-       } else {
-           ep++;
-       }
-    }
-    env.env_len = ep - env.envp;
-#ifndef UNSETENV_VOID
-    return 0;
-#endif
-}
-
-/*
- * Version of putenv(3) that uses our own environ pointer.
- */
-int
-#ifdef PUTENV_CONST
-putenv(const char *string)
-#else
-putenv(string)
-    char *string;
-#endif
-{
-    if (env.envp == NULL)
-       env_init(TRUE);
-
-    if (strchr(string, '=') == NULL) {
-       errno = EINVAL;
-       return -1;
-    }
-#ifdef ENV_DEBUG
-    if (env.envp[env.env_len] != NULL)
-       errorx(1, "putenv: corrupted envp, len mismatch");
-#endif
-    sudo_putenv((char *)string, TRUE, TRUE);
-    return 0;
-}
-
-/*
- * Similar to putenv(3) but operates on sudo's private copy of the
- * environment (not environ) and it always overwrites.  The dupcheck param
- * determines whether we need to verify that the variable is not already set.
- * Will only overwrite an existing variable if overwrite is set.
- */
-static void
-sudo_putenv(str, dupcheck, overwrite)
-    char *str;
-    int dupcheck;
-    int overwrite;
-{
-    char **ep;
-    size_t len;
-    int found = FALSE;
-
-    /* Make sure there is room for the new entry plus a NULL. */
-    if (env.env_len + 2 > env.env_size) {
-       env.env_size += 128;
-       if (env.owned) {
-           env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
-       } else {
-           /* We don't own env.envp, allocate a new one. */
-           ep = emalloc2(env.env_size, sizeof(char *));
-           memcpy(ep, env.envp, env.env_size * sizeof(char *));
-           env.envp = ep;
-           env.owned = TRUE;
-       }
-#ifdef ENV_DEBUG
-       memset(env.envp + env.env_len, 0,
-           (env.env_size - env.env_len) * sizeof(char *));
-#endif
-    }
-
-#ifdef ENV_DEBUG
-    if (env.envp[env.env_len] != NULL)
-       errorx(1, "sudo_putenv: corrupted envp, len mismatch");
-#endif
-
-    if (dupcheck) {
-       len = (strchr(str, '=') - str) + 1;
-       for (ep = env.envp; !found && *ep != NULL; ep++) {
-           if (strncmp(str, *ep, len) == 0) {
-               if (overwrite)
-                   *ep = str;
-               found = TRUE;
-           }
-       }
-       /* Prune out duplicate variables. */
-       if (found && overwrite) {
-           while (*ep != NULL) {
-               if (strncmp(str, *ep, len) == 0) {
-                   char **cur = ep;
-                   while ((*cur = *(cur + 1)) != NULL)
-                       cur++;
-               } else {
-                   ep++;
-               }
-           }
-           env.env_len = ep - env.envp;
-       }
-    }
-
-    if (!found) {
-       ep = env.envp + env.env_len;
-       env.env_len++;
-       *ep++ = str;
-       *ep = NULL;
-    }
-}
-
-/*
- * Check the env_delete blacklist.
- * Returns TRUE if the variable was found, else false.
- */
-static int
-matches_env_delete(var)
-    const char *var;
-{
-    struct list_member *cur;
-    size_t len;
-    int iswild, match = FALSE;
-
-    /* Skip anything listed in env_delete. */
-    for (cur = def_env_delete; cur; cur = cur->next) {
-       len = strlen(cur->value);
-       /* Deal with '*' wildcard */
-       if (cur->value[len - 1] == '*') {
-           len--;
-           iswild = TRUE;
-       } else
-           iswild = FALSE;
-       if (strncmp(cur->value, var, len) == 0 &&
-           (iswild || var[len] == '=')) {
-           match = TRUE;
-           break;
-       }
-    }
-    return match;
-}
-
-/*
- * Apply the env_check list.
- * Returns TRUE if the variable is allowed, FALSE if denied
- * or -1 if no match.
- */
-static int
-matches_env_check(var)
-    const char *var;
-{
-    struct list_member *cur;
-    size_t len;
-    int iswild, keepit = -1;
-
-    for (cur = def_env_check; cur; cur = cur->next) {
-       len = strlen(cur->value);
-       /* Deal with '*' wildcard */
-       if (cur->value[len - 1] == '*') {
-           len--;
-           iswild = TRUE;
-       } else
-           iswild = FALSE;
-       if (strncmp(cur->value, var, len) == 0 &&
-           (iswild || var[len] == '=')) {
-           keepit = !strpbrk(var, "/%");
-           break;
-       }
-    }
-    return keepit;
-}
-
-/*
- * Check the env_keep list.
- * Returns TRUE if the variable is allowed else FALSE.
- */
-static int
-matches_env_keep(var)
-    const char *var;
-{
-    struct list_member *cur;
-    size_t len;
-    int iswild, keepit = FALSE;
-
-    for (cur = def_env_keep; cur; cur = cur->next) {
-       len = strlen(cur->value);
-       /* Deal with '*' wildcard */
-       if (cur->value[len - 1] == '*') {
-           len--;
-           iswild = TRUE;
-       } else
-           iswild = FALSE;
-       if (strncmp(cur->value, var, len) == 0 &&
-           (iswild || var[len] == '=')) {
-           keepit = TRUE;
-           break;
-       }
-    }
-    return keepit;
-}
-
-/*
- * Build a new environment and ether clear potentially dangerous
- * variables from the old one or start with a clean slate.
- * Also adds sudo-specific variables (SUDO_*).
- */
-void
-rebuild_env(noexec)
-    int noexec;
-{
-    char **old_envp, **ep, *cp, *ps1;
-    char idbuf[MAX_UID_T_LEN];
-    unsigned int didvar;
-    int reset_home = FALSE;
-
-    /*
-     * Either clean out the environment or reset to a safe default.
-     */
-    ps1 = NULL;
-    didvar = 0;
-    env.env_len = 0;
-    env.env_size = 128;
-    old_envp = env.envp;
-    env.envp = emalloc2(env.env_size, sizeof(char *));
-#ifdef ENV_DEBUG
-    memset(env.envp, 0, env.env_size * sizeof(char *));
-#endif
-
-    /* Reset HOME based on target user if configured to. */
-    if (ISSET(sudo_mode, MODE_RUN)) {
-       if (def_always_set_home ||
-           ISSET(sudo_mode, MODE_RESET_HOME | MODE_LOGIN_SHELL) || 
-           (ISSET(sudo_mode, MODE_SHELL) && def_set_home))
-           reset_home = TRUE;
-    }
-
-    if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
-       /* Pull in vars we want to keep from the old environment. */
-       for (ep = old_envp; *ep; ep++) {
-           int keepit;
-
-           /* Skip variables with values beginning with () (bash functions) */
-           if ((cp = strchr(*ep, '=')) != NULL) {
-               if (strncmp(cp, "=() ", 3) == 0)
-                   continue;
-           }
-
-           /*
-            * First check certain variables for '%' and '/' characters.
-            * If no match there, check the keep list.
-            * If nothing matched, we remove it from the environment.
-            */
-           keepit = matches_env_check(*ep);
-           if (keepit == -1)
-               keepit = matches_env_keep(*ep);
-
-           /* For SUDO_PS1 -> PS1 conversion. */
-           if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
-               ps1 = *ep + 5;
-
-           if (keepit) {
-               /* Preserve variable. */
-               switch (**ep) {
-                   case 'H':
-                       if (strncmp(*ep, "HOME=", 5) == 0)
-                           SET(didvar, DID_HOME);
-                       break;
-                   case 'L':
-                       if (strncmp(*ep, "LOGNAME=", 8) == 0)
-                           SET(didvar, DID_LOGNAME);
-                       break;
-                   case 'M':
-                       if (strncmp(*ep, "MAIL=", 5) == 0)
-                           SET(didvar, DID_MAIL);
-                       break;
-                   case 'P':
-                       if (strncmp(*ep, "PATH=", 5) == 0)
-                           SET(didvar, DID_PATH);
-                       break;
-                   case 'S':
-                       if (strncmp(*ep, "SHELL=", 6) == 0)
-                           SET(didvar, DID_SHELL);
-                       break;
-                   case 'T':
-                       if (strncmp(*ep, "TERM=", 5) == 0)
-                           SET(didvar, DID_TERM);
-                       break;
-                   case 'U':
-                       if (strncmp(*ep, "USER=", 5) == 0)
-                           SET(didvar, DID_USER);
-                       if (strncmp(*ep, "USERNAME=", 5) == 0)
-                           SET(didvar, DID_USERNAME);
-                       break;
-               }
-               sudo_putenv(*ep, FALSE, FALSE);
-           }
-       }
-       didvar |= didvar << 8;          /* convert DID_* to KEPT_* */
-
-       /*
-        * Add in defaults.  In -i mode these come from the runas user,
-        * otherwise they may be from the user's environment (depends
-        * on sudoers options).
-        */
-       if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
-           sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL));
-           sudo_setenv("LOGNAME", runas_pw->pw_name,
-               ISSET(didvar, DID_LOGNAME));
-           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_SHELL))
-               sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE);
-           if (!ISSET(didvar, DID_LOGNAME))
-               sudo_setenv("LOGNAME", user_name, FALSE);
-           if (!ISSET(didvar, DID_USER))
-               sudo_setenv("USER", user_name, FALSE);
-           if (!ISSET(didvar, DID_USERNAME))
-               sudo_setenv("USERNAME", user_name, FALSE);
-       }
-
-       /* If we didn't keep HOME, reset it based on target user. */
-       if (!ISSET(didvar, KEPT_HOME))
-           reset_home = TRUE;
-
-       /*
-        * Set MAIL to target user in -i mode or if MAIL is not preserved
-        * from user's environment.
-        */
-       if (ISSET(sudo_mode, MODE_LOGIN_SHELL) || !ISSET(didvar, KEPT_MAIL)) {
-           cp = _PATH_MAILDIR;
-           if (cp[sizeof(_PATH_MAILDIR) - 2] == '/')
-               easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name);
-           else
-               easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name);
-           sudo_putenv(cp, ISSET(didvar, DID_MAIL), TRUE);
-       }
-    } else {
-       /*
-        * Copy environ entries as long as they don't match env_delete or
-        * env_check.
-        */
-       for (ep = old_envp; *ep; ep++) {
-           int okvar;
-
-           /* Skip variables with values beginning with () (bash functions) */
-           if ((cp = strchr(*ep, '=')) != NULL) {
-               if (strncmp(cp, "=() ", 3) == 0)
-                   continue;
-           }
-
-           /*
-            * First check variables against the blacklist in env_delete.
-            * If no match there check for '%' and '/' characters.
-            */
-           okvar = matches_env_delete(*ep) != TRUE;
-           if (okvar)
-               okvar = matches_env_check(*ep) != FALSE;
-
-           if (okvar) {
-               if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
-                   ps1 = *ep + 5;
-               else if (strncmp(*ep, "PATH=", 5) == 0)
-                   SET(didvar, DID_PATH);
-               else if (strncmp(*ep, "TERM=", 5) == 0)
-                   SET(didvar, DID_TERM);
-               sudo_putenv(*ep, FALSE, FALSE);
-           }
-       }
-    }
-    /* 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);
-    }
-
-    /* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is true. */
-    if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
-       if (!ISSET(didvar, KEPT_LOGNAME))
-           sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE);
-       if (!ISSET(didvar, KEPT_USER))
-           sudo_setenv("USER", runas_pw->pw_name, TRUE);
-       if (!ISSET(didvar, KEPT_USERNAME))
-           sudo_setenv("USERNAME", runas_pw->pw_name, TRUE);
-    }
-
-    /* Set $HOME to target user if not preserving user's value. */
-    if (reset_home)
-       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))
-       sudo_putenv("TERM=unknown", FALSE, FALSE);
-    if (!ISSET(didvar, DID_PATH))
-       sudo_setenv("PATH", _PATH_STDPATH, FALSE);
-
-    /*
-     * Preload a noexec file?  For a list of LD_PRELOAD-alikes, see
-     * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
-     * XXX - should prepend to original value, if any
-     */
-    if (noexec && def_noexec_file != NULL) {
-#if defined(__darwin__) || defined(__APPLE__)
-       sudo_setenv("DYLD_INSERT_LIBRARIES", def_noexec_file, TRUE);
-       sudo_setenv("DYLD_FORCE_FLAT_NAMESPACE", "", TRUE);
-#else
-# if defined(__osf__) || defined(__sgi)
-       easprintf(&cp, "%s:DEFAULT", def_noexec_file);
-       sudo_setenv("_RLD_LIST", cp, TRUE);
-       efree(cp);
-# else
-#  ifdef _AIX
-       sudo_setenv("LDR_PRELOAD", def_noexec_file, TRUE);
-#  else
-       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 != NULL)
-       sudo_putenv(ps1, TRUE, TRUE);
-
-    /* Add the SUDO_COMMAND envariable (cmnd + args). */
-    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. */
-    sudo_setenv("SUDO_USER", user_name, TRUE);
-    snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_uid);
-    sudo_setenv("SUDO_UID", idbuf, TRUE);
-    snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_gid);
-    sudo_setenv("SUDO_GID", idbuf, TRUE);
-
-    /* Free old environment. */
-    efree(old_envp);
-}
-
-void
-insert_env_vars(env_vars)
-    struct list_member *env_vars;
-{
-    struct list_member *cur;
-
-    /* Add user-specified environment variables. */
-    for (cur = env_vars; cur != NULL; cur = cur->next)
-       putenv(cur->value);
-}
-
-/*
- * Validate the list of environment variables passed in on the command
- * line against env_delete, env_check, and env_keep.
- * Calls log_error() if any specified variables are not allowed.
- */
-void
-validate_env_vars(env_vars)
-    struct list_member *env_vars;
-{
-    struct list_member *var;
-    char *eq, *bad = NULL;
-    size_t len, blen = 0, bsize = 0;
-    int okvar;
-
-    /* Add user-specified environment variables. */
-    for (var = env_vars; var != NULL; var = var->next) {
-       if (def_secure_path && !user_is_exempt() &&
-           strncmp(var->value, "PATH=", 5) == 0) {
-           okvar = FALSE;
-       } else if (def_env_reset) {
-           okvar = matches_env_check(var->value);
-           if (okvar == -1)
-               okvar = matches_env_keep(var->value);
-       } else {
-           okvar = matches_env_delete(var->value) == FALSE;
-           if (okvar == FALSE)
-               okvar = matches_env_check(var->value) != FALSE;
-       }
-       if (okvar == FALSE) {
-           /* Not allowed, add to error string, allocating as needed. */
-           if ((eq = strchr(var->value, '=')) != NULL)
-               *eq = '\0';
-           len = strlen(var->value) + 2;
-           if (blen + len >= bsize) {
-               do {
-                   bsize += 1024;
-               } while (blen + len >= bsize);
-               bad = erealloc(bad, bsize);
-               bad[blen] = '\0';
-           }
-           strlcat(bad, var->value, bsize);
-           strlcat(bad, ", ", bsize);
-           blen += len;
-           if (eq != NULL)
-               *eq = '=';
-       }
-    }
-    if (bad != NULL) {
-       bad[blen - 2] = '\0';           /* remove trailing ", " */
-       log_error(NO_MAIL,
-           "sorry, you are not allowed to set the following environment variables: %s", bad);
-       /* NOTREACHED */
-       efree(bad);
-    }
-}
-
-/*
- * Read in /etc/environment ala AIX and Linux.
- * Lines may be in either of three formats:
- *  NAME=VALUE
- *  NAME="VALUE"
- *  NAME='VALUE'
- * with an optional "export" prefix so the shell can source the file.
- * Invalid lines, blank lines, or lines consisting solely of a comment
- * character are skipped.
- */
-void
-read_env_file(path, overwrite)
-    const char *path;
-    int overwrite;
-{
-    FILE *fp;
-    char *cp, *var, *val;
-    size_t var_len, val_len;
-
-    if ((fp = fopen(path, "r")) == NULL)
-       return;
-
-    while ((var = sudo_parseln(fp)) != NULL) {
-       /* Skip blank or comment lines */
-       if (*var == '\0')
-           continue;
-
-       /* Skip optional "export " */
-       if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) {
-           var += 7;
-           while (isspace((unsigned char) *var)) {
-               var++;
-           }
-       }
-
-       /* Must be of the form name=["']value['"] */
-       for (val = var; *val != '\0' && *val != '='; val++)
-           ;
-       if (var == val || *val != '=')
-           continue;
-       var_len = (size_t)(val - var);
-       val_len = strlen(++val);
-
-       /* Strip leading and trailing single/double quotes */
-       if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
-           val[val_len - 1] = '\0';
-           val++;
-           val_len -= 2;
-       }
-
-       cp = emalloc(var_len + 1 + val_len + 1);
-       memcpy(cp, var, var_len + 1); /* includes '=' */
-       memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */
-
-       sudo_putenv(cp, TRUE, overwrite);
-    }
-    fclose(fp);
-}
-
-void
-init_envtables()
-{
-    struct list_member *cur;
-    const char **p;
-
-    /* Fill in the "env_delete" list. */
-    for (p = initial_badenv_table; *p; p++) {
-       cur = emalloc(sizeof(struct list_member));
-       cur->value = estrdup(*p);
-       cur->next = def_env_delete;
-       def_env_delete = cur;
-    }
-
-    /* Fill in the "env_check" list. */
-    for (p = initial_checkenv_table; *p; p++) {
-       cur = emalloc(sizeof(struct list_member));
-       cur->value = estrdup(*p);
-       cur->next = def_env_check;
-       def_env_check = cur;
-    }
-
-    /* Fill in the "env_keep" list. */
-    for (p = initial_keepenv_table; *p; p++) {
-       cur = emalloc(sizeof(struct list_member));
-       cur->value = estrdup(*p);
-       cur->next = def_env_keep;
-       def_env_keep = cur;
-    }
-}
diff --git a/error.c b/error.c
deleted file mode 100644 (file)
index e5cb959..0000000
--- a/error.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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 <config.h>
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "missing.h"
-#include "error.h"
-
-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
deleted file mode 100644 (file)
index 5ac3076..0000000
--- a/error.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.
- */
-
-#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_ */
diff --git a/exec.c b/exec.c
deleted file mode 100644 (file)
index 19dbad2..0000000
--- a/exec.c
+++ /dev/null
@@ -1,637 +0,0 @@
-/*
- * Copyright (c) 2009-2010 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>
-#ifdef HAVE_SYS_SYSMACROS_H
-# include <sys/sysmacros.h>
-#endif
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#ifdef HAVE_TERMIOS_H
-# include <termios.h>
-#else
-# include <termio.h>
-#endif /* HAVE_TERMIOS_H */
-#include <sys/ioctl.h>
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif /* HAVE_SYS_SELECT_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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-#ifdef HAVE_SETLOCALE
-# include <locale.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#ifdef HAVE_SELINUX
-# include <selinux/selinux.h>
-#endif
-
-#include "sudo.h"
-#include "sudo_exec.h"
-
-/* Shared with exec_pty.c for use with handler(). */
-int signal_pipe[2];
-
-#ifdef _PATH_SUDO_IO_LOGDIR
-/* We keep a tailq of signals to forward to child. */
-struct sigforward {
-    struct sigforward *prev, *next;
-    int signo;
-};
-TQ_DECLARE(sigforward)
-static struct sigforward_list sigfwd_list;
-static void forward_signals __P((int fd));
-static void schedule_signal __P((int signo));
-static int log_io;
-#endif /* _PATH_SUDO_IO_LOGDIR */
-
-static int handle_signals __P((int fd, pid_t child,
-    struct command_status *cstat));
-
-/*
- * Like execve(2) but falls back to running through /bin/sh
- * ala execvp(3) if we get ENOEXEC.
- */
-int
-my_execve(path, argv, envp)
-    const char *path;
-    char *argv[];
-    char *envp[];
-{
-    execve(path, argv, envp);
-    if (errno == ENOEXEC) {
-       argv--;                 /* at least one extra slot... */
-       argv[0] = "sh";
-       argv[1] = (char *)path;
-       execve(_PATH_BSHELL, argv, envp);
-    }
-    return -1;
-}
-
-/*
- * Fork and execute a command, returns the child's pid.
- * Sends errno back on sv[1] if execve() fails.
- */
-static int fork_cmnd(path, argv, envp, sv, rbac_enabled)
-    const char *path;
-    char *argv[];
-    char *envp[];
-    int sv[2];
-    int rbac_enabled;
-{
-    struct command_status cstat;
-    sigaction_t sa;
-    pid_t child;
-
-    zero_bytes(&sa, sizeof(sa));
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
-    sa.sa_handler = handler;
-    sigaction(SIGCONT, &sa, NULL);
-
-    child = fork();
-    switch (child) {
-    case -1:
-       error(1, "fork");
-       break;
-    case 0:
-       /* child */
-       close(sv[0]);
-       close(signal_pipe[0]);
-       close(signal_pipe[1]);
-       fcntl(sv[1], F_SETFD, FD_CLOEXEC);
-       restore_signals();
-       if (exec_setup(rbac_enabled, user_ttypath, -1) == TRUE) {
-           /* headed for execve() */
-           closefrom(def_closefrom);
-#ifdef HAVE_SELINUX
-           if (rbac_enabled)
-               selinux_execve(path, argv, envp);
-           else
-#endif
-               my_execve(path, argv, envp);
-       }
-       cstat.type = CMD_ERRNO;
-       cstat.val = errno;
-       send(sv[1], &cstat, sizeof(cstat), 0);
-       _exit(1);
-    }
-    return child;
-}
-
-static struct signal_state {
-    int signo;
-    sigaction_t sa;
-} saved_signals[] = {
-    { SIGALRM },
-    { SIGCHLD },
-    { SIGCONT },
-    { SIGHUP },
-    { SIGINT },
-    { SIGPIPE },
-    { SIGQUIT },
-    { SIGTERM },
-    { SIGTSTP },
-    { SIGTTIN },
-    { SIGTTOU },
-    { SIGUSR1 },
-    { SIGUSR2 },
-    { -1 }
-};
-
-/*
- * Save signal handler state so it can be restored before exec.
- */
-void
-save_signals()
-{
-    struct signal_state *ss;
-
-    for (ss = saved_signals; ss->signo != -1; ss++)
-       sigaction(ss->signo, NULL, &ss->sa);
-}
-
-/*
- * Restore signal handlers to initial state.
- */
-void
-restore_signals()
-{
-    struct signal_state *ss;
-
-    for (ss = saved_signals; ss->signo != -1; ss++)
-       sigaction(ss->signo, &ss->sa, NULL);
-}
-
-/*
- * Execute a command, potentially in a pty with I/O loggging.
- * This is a little bit tricky due to how POSIX job control works and
- * we fact that we have two different controlling terminals to deal with.
- */
-int
-sudo_execve(path, argv, envp, uid, cstat, dowait, bgmode)
-    const char *path;
-    char *argv[];
-    char *envp[];
-    uid_t uid;
-    struct command_status *cstat;
-    int dowait;
-    int bgmode;
-{
-    int maxfd, n, nready, sv[2];
-    int rbac_enabled = 0;
-    fd_set *fdsr, *fdsw;
-    sigaction_t sa;
-    pid_t child;
-
-    /* If running in background mode, fork and exit. */
-    if (bgmode) {
-       switch (fork()) {
-           case -1:
-               cstat->type = CMD_ERRNO;
-               cstat->val = errno;
-               return -1;
-           case 0:
-               /* child continues */   
-               break;
-           default:
-               /* parent exits */
-               exit(0);
-       }
-    }
-
-#ifdef _PATH_SUDO_IO_LOGDIR
-    log_io = def_log_output || def_log_input || def_use_pty;
-    if (log_io) {
-       if (!bgmode)
-           pty_setup(uid);
-       io_log_open();
-       dowait = TRUE;
-    }
-#endif /* _PATH_SUDO_IO_LOGDIR */
-
-#ifdef HAVE_SELINUX
-    rbac_enabled = is_selinux_enabled() > 0 && user_role != NULL;
-    if (rbac_enabled)
-       dowait = TRUE;
-#endif
-
-    /*
-     * If we don't need to wait for the command to finish, just exec it.
-     */
-    if (!dowait) {
-       exec_setup(FALSE, NULL, -1);
-       closefrom(def_closefrom);
-       my_execve(path, argv, envp);
-       cstat->type = CMD_ERRNO;
-       cstat->val = errno;
-       return 127;
-    }
-
-    /*
-     * We communicate with the child over a bi-directional pair of sockets.
-     * Parent sends signal info to child and child sends back wait status.
-     */
-    if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1)
-       error(1, "cannot create sockets");
-
-    /*
-     * We use a pipe to atomically handle signal notification within
-     * the select() loop.
-     */
-    if (pipe_nonblock(signal_pipe) != 0)
-       error(1, "cannot create pipe");
-
-    zero_bytes(&sa, sizeof(sa));
-    sigemptyset(&sa.sa_mask);
-
-    /*
-     * Signals for forward to the child process (excluding SIGCHLD).
-     * Note: HP-UX select() will not be interrupted if SA_RESTART set.
-     */
-    sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
-    sa.sa_handler = handler;
-    sigaction(SIGALRM, &sa, NULL);
-    sigaction(SIGCHLD, &sa, NULL);
-    sigaction(SIGHUP, &sa, NULL);
-    sigaction(SIGINT, &sa, NULL);
-    sigaction(SIGPIPE, &sa, NULL);
-    sigaction(SIGQUIT, &sa, NULL);
-    sigaction(SIGTERM, &sa, NULL);
-    sigaction(SIGUSR1, &sa, NULL);
-    sigaction(SIGUSR2, &sa, NULL);
-
-    /* Max fd we will be selecting on. */
-    maxfd = MAX(sv[0], signal_pipe[0]);
-
-    /*
-     * Child will run the command in the pty, parent will pass data
-     * to and from pty.  Adjusts maxfd as needed.
-     */
-#ifdef _PATH_SUDO_IO_LOGDIR
-    if (log_io)
-       child = fork_pty(path, argv, envp, sv, rbac_enabled, &maxfd);
-    else
-#endif
-       child = fork_cmnd(path, argv, envp, sv, rbac_enabled);
-    close(sv[1]);
-
-#ifdef HAVE_SETLOCALE
-    /*
-     * I/O logging must be in the C locale for floating point numbers
-     * to be logged consistently.
-     */
-    setlocale(LC_ALL, "C");
-#endif
-
-    /*
-     * In the event loop we pass input from user tty to master
-     * and pass output from master to stdout and IO plugin.
-     */
-    fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
-    fdsw = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
-    for (;;) {
-       zero_bytes(fdsw, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
-       zero_bytes(fdsr, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
-
-       FD_SET(signal_pipe[0], fdsr);
-       FD_SET(sv[0], fdsr);
-#ifdef _PATH_SUDO_IO_LOGDIR
-       if (!tq_empty(&sigfwd_list))
-           FD_SET(sv[0], fdsw);
-       if (log_io)
-           fd_set_iobs(fdsr, fdsw); /* XXX - better name */
-#endif
-       nready = select(maxfd + 1, fdsr, fdsw, NULL, NULL);
-       if (nready == -1) {
-           if (errno == EINTR)
-               continue;
-           error(1, "select failed");
-       }
-#ifdef _PATH_SUDO_IO_LOGDIR
-       if (FD_ISSET(sv[0], fdsw)) {
-           forward_signals(sv[0]);
-       }
-#endif /* _PATH_SUDO_IO_LOGDIR */
-       if (FD_ISSET(signal_pipe[0], fdsr)) {
-           n = handle_signals(signal_pipe[0], child, cstat);
-           if (n == 0) {
-               /* Child has exited, cstat is set, we are done. */
-               goto done;
-           }
-           if (n == -1) {
-               /* Error reading signal_pipe[0], should not happen. */
-               break;
-           }
-           /* Restart event loop so signals get sent to child immediately. */
-           continue;
-       }
-       if (FD_ISSET(sv[0], fdsr)) {
-           /* read child status */
-           n = recv(sv[0], cstat, sizeof(*cstat), 0);
-           if (n == -1) {
-               if (errno == EINTR)
-                   continue;
-#ifdef _PATH_SUDO_IO_LOGDIR
-               /*
-                * If not logging I/O we will receive ECONNRESET when
-                * the command is executed.  It is safe to ignore this.
-                */
-               if (log_io && errno != EAGAIN) {
-                   cstat->type = CMD_ERRNO;
-                   cstat->val = errno;
-                   break;
-               }
-#endif
-           }
-#ifdef _PATH_SUDO_IO_LOGDIR /* XXX */
-           if (cstat->type == CMD_WSTATUS) {
-               if (WIFSTOPPED(cstat->val)) {
-                   /* Suspend parent and tell child how to resume on return. */
-                   n = suspend_parent(WSTOPSIG(cstat->val));
-                   schedule_signal(n);
-                   continue;
-               } else {
-                   /* Child exited or was killed, either way we are done. */
-                   break;
-               }
-           } else
-#endif /* _PATH_SUDO_IO_LOGDIR */
-           if (cstat->type == CMD_ERRNO) {
-               /* Child was unable to execute command or broken pipe. */
-               break;
-           }
-       }
-
-#ifdef _PATH_SUDO_IO_LOGDIR
-       if (perform_io(fdsr, fdsw, cstat) != 0) {
-           /* I/O error, kill child if still alive and finish. */
-           schedule_signal(SIGKILL);
-           forward_signals(sv[0]);
-           break;
-       }
-#endif /* _PATH_SUDO_IO_LOGDIR */
-    }
-
-#ifdef _PATH_SUDO_IO_LOGDIR
-    if (log_io) {
-       /* Flush any remaining output and free pty-related memory. */
-       pty_close(cstat);
-    }
-#endif /* _PATH_SUDO_IO_LOGDIR */
-
-#ifdef HAVE_SELINUX
-    if (rbac_enabled) {
-       /* This is probably not needed in log_io mode. */
-       if (selinux_restore_tty() != 0)
-           warningx("unable to restore tty label");
-    }
-#endif
-
-done:
-    efree(fdsr);
-    efree(fdsw);
-#ifdef _PATH_SUDO_IO_LOGDIR
-    while (!tq_empty(&sigfwd_list)) {
-       struct sigforward *sigfwd = tq_first(&sigfwd_list);
-       tq_remove(&sigfwd_list, sigfwd);
-       efree(sigfwd);
-    }
-#endif /* _PATH_SUDO_IO_LOGDIR */
-
-    return cstat->type == CMD_ERRNO ? -1 : 0;
-}
-
-/*
- * Read signals on fd written to by handler().
- * Returns -1 on error, 0 on child exit, else 1.
- */
-static int
-handle_signals(fd, child, cstat)
-    int fd;
-    pid_t child;
-    struct command_status *cstat;
-{
-    unsigned char signo;
-    ssize_t nread;
-    int status;
-    pid_t pid;
-
-    for (;;) {
-       /* read signal pipe */
-       nread = read(signal_pipe[0], &signo, sizeof(signo));
-       if (nread <= 0) {
-           /* It should not be possible to get EOF but just in case. */
-           if (nread == 0)
-               errno = ECONNRESET;
-           /* Restart if interrupted by signal so the pipe doesn't fill. */
-           if (errno == EINTR)
-               continue;
-           /* If pipe is empty, we are done. */
-           if (errno == EAGAIN)
-               break;
-           cstat->type = CMD_ERRNO;
-           cstat->val = errno;
-           return -1;
-       }
-       if (signo == SIGCHLD) {
-           /*
-            * If logging I/O, child is the intermediate process,
-            * otherwise it is the command itself.
-            */
-           do {
-#ifdef sudo_waitpid
-               pid = sudo_waitpid(child, &status, WUNTRACED|WNOHANG);
-#else
-               pid = wait(&status);
-#endif
-           } while (pid == -1 && errno == EINTR);
-           if (pid == child) {
-               /* If not logging I/O and child has exited we are done. */
-#ifdef _PATH_SUDO_IO_LOGDIR
-               if (!log_io)
-#endif
-               {
-                   if (WIFSTOPPED(status)) {
-                       /*
-                        * Save the controlling terminal's process group
-                        * so we can restore it after we resume.
-                        */
-#ifdef HAVE_TCSETPGRP
-                       pid_t saved_pgrp = (pid_t)-1;
-                       int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
-                       if (fd != -1)
-                           saved_pgrp = tcgetpgrp(fd);
-#endif /* HAVE_TCSETPGRP */
-                       if (kill(getpid(), WSTOPSIG(status)) != 0)
-                           warning("kill(%d, %d)", getpid(), WSTOPSIG(status));
-#ifdef HAVE_TCSETPGRP
-                       if (fd != -1) {
-                           if (saved_pgrp != (pid_t)-1)
-                               (void)tcsetpgrp(fd, saved_pgrp);
-                           close(fd);
-                       }
-#endif /* HAVE_TCSETPGRP */
-                   } else {
-                       /* Child has exited, we are done. */
-                       cstat->type = CMD_WSTATUS;
-                       cstat->val = status;
-                       return 0;
-                   }
-               }
-               /* Else we get ECONNRESET on sv[0] if child dies. */
-           }
-       } else {
-#ifdef _PATH_SUDO_IO_LOGDIR
-           if (log_io) {
-               /* Schedule signo to be forwared to the child. */
-               schedule_signal(signo);
-           } else
-#endif
-           {
-               /* Nothing listening on sv[0], send directly. */
-               if (kill(child, signo) != 0)
-                   warning("kill(%d, %d)", child, signo);
-           }
-       }
-    }
-    return 1;
-}
-
-#ifdef _PATH_SUDO_IO_LOGDIR
-/*
- * Forward signals in sigfwd_list to child listening on fd.
- */
-static void
-forward_signals(sock)
-    int sock;
-{
-    struct sigforward *sigfwd;
-    struct command_status cstat;
-    ssize_t nsent;
-
-    while (!tq_empty(&sigfwd_list)) {
-       sigfwd = tq_first(&sigfwd_list);
-       cstat.type = CMD_SIGNO;
-       cstat.val = sigfwd->signo;
-       do {
-           nsent = send(sock, &cstat, sizeof(cstat), 0);
-       } while (nsent == -1 && errno == EINTR);
-       tq_remove(&sigfwd_list, sigfwd);
-       efree(sigfwd);
-       if (nsent != sizeof(cstat)) {
-           if (errno == EPIPE) {
-               /* Other end of socket gone, empty out sigfwd_list. */
-               while (!tq_empty(&sigfwd_list)) {
-                   sigfwd = tq_first(&sigfwd_list);
-                   tq_remove(&sigfwd_list, sigfwd);
-                   efree(sigfwd);
-               }
-           }
-           break;
-       }
-    }
-}
-
-/*
- * Schedule a signal to be forwared.
- */
-static void
-schedule_signal(signo)
-    int signo;
-{
-    struct sigforward *sigfwd;
-
-    sigfwd = emalloc(sizeof(*sigfwd));
-    sigfwd->prev = sigfwd;
-    sigfwd->next = NULL;
-    sigfwd->signo = signo;
-    tq_append(&sigfwd_list, sigfwd);
-}
-#endif /* _PATH_SUDO_IO_LOGDIR */
-
-/*
- * Generic handler for signals passed from parent -> child.
- * The other end of signal_pipe is checked in the main event loop.
- */
-RETSIGTYPE
-handler(s)
-    int s;
-{
-    unsigned char signo = (unsigned char)s;
-
-    /*
-     * The pipe is non-blocking, if we overflow the kernel's pipe
-     * buffer we drop the signal.  This is not a problem in practice.
-     */
-    if (write(signal_pipe[1], &signo, sizeof(signo)) == -1)
-       /* shut up glibc */;
-}
-
-/*
- * Open a pipe and make both ends non-blocking.
- * Returns 0 on success and -1 on error.
- */
-int
-pipe_nonblock(fds)
-    int fds[2];
-{
-    int flags, rval;
-
-    rval = pipe(fds);
-    if (rval != -1) {
-       flags = fcntl(fds[0], F_GETFL, 0);
-       if (flags != -1 && !ISSET(flags, O_NONBLOCK))
-           rval = fcntl(fds[0], F_SETFL, flags | O_NONBLOCK);
-       if (rval != -1) {
-           flags = fcntl(fds[1], F_GETFL, 0);
-           if (flags != -1 && !ISSET(flags, O_NONBLOCK))
-               rval = fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
-       }
-       if (rval == -1) {
-           close(fds[0]);
-           close(fds[1]);
-       }
-    }
-
-    return rval;
-}
diff --git a/exec_pty.c b/exec_pty.c
deleted file mode 100644 (file)
index ec54a1f..0000000
+++ /dev/null
@@ -1,1064 +0,0 @@
-/*
- * Copyright (c) 2009-2010 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>
-#ifdef HAVE_SYS_SYSMACROS_H
-# include <sys/sysmacros.h>
-#endif
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#ifdef HAVE_TERMIOS_H
-# include <termios.h>
-#else
-# include <termio.h>
-#endif /* HAVE_TERMIOS_H */
-#include <sys/ioctl.h>
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif /* HAVE_SYS_SELECT_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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-
-#include "sudo.h"
-#include "sudo_exec.h"
-
-#define SFD_STDIN      0
-#define SFD_STDOUT     1
-#define SFD_STDERR     2
-#define SFD_MASTER     3
-#define SFD_SLAVE      4
-#define SFD_USERTTY    5
-
-#define TERM_COOKED    0
-#define TERM_RAW       1
-
-/* Compatibility with older tty systems. */
-#if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
-# define TIOCGWINSZ    TIOCGSIZE
-# define TIOCSWINSZ    TIOCSSIZE
-# define winsize       ttysize
-#endif
-
-struct io_buffer {
-    struct io_buffer *next;
-    int len; /* buffer length (how much produced) */
-    int off; /* write position (how much already consumed) */
-    int rfd;  /* reader (producer) */
-    int wfd; /* writer (consumer) */
-    int (*action) __P((const char *buf, unsigned int len));
-    char buf[16 * 1024];
-};
-
-static char slavename[PATH_MAX];
-static int foreground;
-static int io_fds[6] = { -1, -1, -1, -1, -1, -1};
-static int pipeline = FALSE;
-static int tty_initialized;
-static int ttymode = TERM_COOKED;
-static pid_t ppgrp, child, child_pgrp;
-static struct io_buffer *iobufs;
-
-static void flush_output __P((void));
-static int exec_monitor __P((const char *path, char *argv[],
-    char *envp[], int, int));
-static void exec_pty __P((const char *path, char *argv[],
-    char *envp[], int));
-static RETSIGTYPE sigwinch __P((int s));
-static void sync_ttysize __P((int src, int dst));
-static void deliver_signal __P((pid_t pid, int signo));
-static int safe_close __P((int fd));
-
-/*
- * Allocate a pty if /dev/tty is a tty.
- * Fills in io_fds[SFD_USERTTY], io_fds[SFD_MASTER], io_fds[SFD_SLAVE]
- * and slavename globals.
- */
-void
-pty_setup(uid)
-    uid_t uid;
-{
-    io_fds[SFD_USERTTY] = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
-    if (io_fds[SFD_USERTTY] != -1) {
-       if (!get_pty(&io_fds[SFD_MASTER], &io_fds[SFD_SLAVE],
-           slavename, sizeof(slavename), uid))
-           error(1, "Can't get pty");
-    }
-}
-
-/*
- * Check whether we are running in the foregroup.
- * Updates the foreground global and does lazy init of the
- * the pty slave as needed.
- */
-static void
-check_foreground()
-{
-    if (io_fds[SFD_USERTTY] != -1) {
-       foreground = tcgetpgrp(io_fds[SFD_USERTTY]) == ppgrp;
-       if (foreground && !tty_initialized) {
-           if (term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE])) {
-               tty_initialized = 1;
-               sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]);
-           }
-       }
-    }
-}
-
-/*
- * Suspend sudo if the underlying command is suspended.
- * Returns SIGCONT_FG if the child should be resume in the
- * foreground or SIGCONT_BG if it is a background process.
- */
-int
-suspend_parent(signo)
-    int signo;
-{
-    sigaction_t sa, osa;
-    int n, oldmode = ttymode, rval = 0;
-
-    switch (signo) {
-    case SIGTTOU:
-    case SIGTTIN:
-       /*
-        * If we are the foreground process, just resume the child.
-        * Otherwise, re-send the signal with the handler disabled.
-        */
-       if (!foreground)
-           check_foreground();
-       if (foreground) {
-           if (ttymode != TERM_RAW) {
-               do {
-                   n = term_raw(io_fds[SFD_USERTTY], 0);
-               } while (!n && errno == EINTR);
-               ttymode = TERM_RAW;
-           }
-           rval = SIGCONT_FG; /* resume child in foreground */
-           break;
-       }
-       ttymode = TERM_RAW;
-       /* FALLTHROUGH */
-    case SIGSTOP:
-    case SIGTSTP:
-       /* Flush any remaining output before suspending. */
-       flush_output();
-
-       /* Restore original tty mode before suspending. */
-       if (oldmode != TERM_COOKED) {
-           do {
-               n = term_restore(io_fds[SFD_USERTTY], 0);
-           } while (!n && errno == EINTR);
-       }
-
-       /* Suspend self and continue child when we resume. */
-       sa.sa_handler = SIG_DFL;
-       sigaction(signo, &sa, &osa);
-       if (killpg(ppgrp, signo) != 0)
-           warning("killpg(%d, %d)", ppgrp, signo);
-
-       /* Check foreground/background status on resume. */
-       check_foreground();
-
-       /*
-        * Only modify term if we are foreground process and either
-        * the old tty mode was not cooked or child got SIGTT{IN,OU}
-        */
-       if (ttymode != TERM_COOKED) {
-           if (foreground) {
-               /* Set raw mode. */
-               do {
-                   n = term_raw(io_fds[SFD_USERTTY], 0);
-               } while (!n && errno == EINTR);
-           } else {
-               /* Background process, no access to tty. */
-               ttymode = TERM_COOKED;
-           }
-       }
-
-       sigaction(signo, &osa, NULL);
-       rval = ttymode == TERM_RAW ? SIGCONT_FG : SIGCONT_BG;
-       break;
-    }
-
-    return rval;
-}
-
-/*
- * Kill child with increasing urgency.
- */
-static void
-terminate_child(pid, use_pgrp)
-    pid_t pid;
-    int use_pgrp;
-{
-    /*
-     * Note that SIGCHLD will interrupt the sleep()
-     */
-    if (use_pgrp) {
-       killpg(pid, SIGHUP);
-       killpg(pid, SIGTERM);
-       sleep(2);
-       killpg(pid, SIGKILL);
-    } else {
-       kill(pid, SIGHUP);
-       kill(pid, SIGTERM);
-       sleep(2);
-       kill(pid, SIGKILL);
-    }
-}
-
-/*
- * Allocate a new io_buffer struct and insert it at the head of the list.
- * Returns the new head element.
- */
-static struct io_buffer *
-io_buf_new(rfd, wfd, action, head)
-    int rfd;
-    int wfd;
-    int (*action) __P((const char *, unsigned int));
-    struct io_buffer *head;
-{
-    struct io_buffer *iob;
-
-    iob = emalloc(sizeof(*iob));
-    zero_bytes(iob, sizeof(*iob));
-    iob->rfd = rfd;
-    iob->wfd = wfd;
-    iob->action = action;
-    iob->next = head;
-    return iob;
-}
-
-/*
- * Read/write iobufs depending on fdsr and fdsw.
- * Fills in cstat on error.
- * Returns the number of errors.
- */
-int
-perform_io(fdsr, fdsw, cstat)
-    fd_set *fdsr;
-    fd_set *fdsw;
-    struct command_status *cstat;
-{
-    struct io_buffer *iob;
-    int n, errors = 0;
-
-    for (iob = iobufs; iob; iob = iob->next) {
-       if (iob->rfd != -1 && FD_ISSET(iob->rfd, fdsr)) {
-           do {
-               n = read(iob->rfd, iob->buf + iob->len,
-                   sizeof(iob->buf) - iob->len);
-           } while (n == -1 && errno == EINTR);
-           switch (n) {
-               case -1:
-                   if (errno == EAGAIN)
-                       break;
-                   if (errno != ENXIO && errno != EBADF) {
-                       errors++;
-                       break;
-                   }
-                   /* FALLTHROUGH */
-               case 0:
-                   /* got EOF or pty has gone away */
-                   safe_close(iob->rfd);
-                   iob->rfd = -1;
-                   break;
-               default:
-                   if (!iob->action(iob->buf + iob->len, n))
-                       terminate_child(child, TRUE);
-                   iob->len += n;
-                   break;
-           }
-       }
-       if (iob->wfd != -1 && FD_ISSET(iob->wfd, fdsw)) {
-           do {
-               n = write(iob->wfd, iob->buf + iob->off,
-                   iob->len - iob->off);
-           } while (n == -1 && errno == EINTR);
-           if (n == -1) {
-               if (errno == EPIPE || errno == ENXIO || errno == EBADF) {
-                   /* other end of pipe closed or pty revoked */
-                   if (iob->rfd != -1) {
-                       safe_close(iob->rfd);
-                       iob->rfd = -1;
-                   }
-                   safe_close(iob->wfd);
-                   iob->wfd = -1;
-                   continue;
-               }
-               if (errno != EAGAIN)
-                   errors++;
-           } else {
-               iob->off += n;
-           }
-       }
-    }
-    if (errors && cstat != NULL) {
-       cstat->type = CMD_ERRNO;
-       cstat->val = errno;
-    }
-    return errors;
-}
-
-/*
- * Fork a monitor process which runs the actual command as its own child
- * process with std{in,out,err} hooked up to the pty or pipes as appropriate.
- * Returns the child pid.
- */
-int
-fork_pty(path, argv, envp, sv, rbac_enabled, maxfd)
-    const char *path;
-    char *argv[];
-    char *envp[];
-    int sv[2];
-    int rbac_enabled;
-    int *maxfd;
-{
-    struct command_status cstat;
-    struct io_buffer *iob;
-    int io_pipe[3][2], n;
-    sigaction_t sa;
-
-    ppgrp = getpgrp(); /* parent's pgrp, so child can signal us */
-
-    zero_bytes(&sa, sizeof(sa));
-    sigemptyset(&sa.sa_mask);
-
-    if (io_fds[SFD_USERTTY] != -1) {
-       sa.sa_flags = SA_RESTART;
-       sa.sa_handler = sigwinch;
-       sigaction(SIGWINCH, &sa, NULL);
-    }
-
-    /*
-     * Setup stdin/stdout/stderr for child, to be duped after forking.
-     */
-    io_fds[SFD_STDIN] = io_fds[SFD_SLAVE];
-    io_fds[SFD_STDOUT] = io_fds[SFD_SLAVE];
-    io_fds[SFD_STDERR] = io_fds[SFD_SLAVE];
-
-    /* Copy /dev/tty -> pty master */
-    if (io_fds[SFD_USERTTY] != -1) {
-       iobufs = io_buf_new(io_fds[SFD_USERTTY], io_fds[SFD_MASTER],
-           log_ttyin, iobufs);
-
-       /* Copy pty master -> /dev/tty */
-       iobufs = io_buf_new(io_fds[SFD_MASTER], io_fds[SFD_USERTTY],
-           log_ttyout, iobufs);
-
-       /* Are we the foreground process? */
-       foreground = tcgetpgrp(io_fds[SFD_USERTTY]) == ppgrp;
-    }
-
-    /*
-     * If either stdin, stdout or stderr is not a tty we use a pipe
-     * to interpose ourselves instead of duping the pty fd.
-     */
-    memset(io_pipe, 0, sizeof(io_pipe));
-    if (io_fds[SFD_STDIN] == -1 || !isatty(STDIN_FILENO)) {
-       pipeline = TRUE;
-       if (pipe(io_pipe[STDIN_FILENO]) != 0)
-           error(1, "unable to create pipe");
-       iobufs = io_buf_new(STDIN_FILENO, io_pipe[STDIN_FILENO][1],
-           log_stdin, iobufs);
-       io_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0];
-    }
-    if (io_fds[SFD_STDOUT] == -1 || !isatty(STDOUT_FILENO)) {
-       pipeline = TRUE;
-       if (pipe(io_pipe[STDOUT_FILENO]) != 0)
-           error(1, "unable to create pipe");
-       iobufs = io_buf_new(io_pipe[STDOUT_FILENO][0], STDOUT_FILENO,
-           log_stdout, iobufs);
-       io_fds[SFD_STDOUT] = io_pipe[STDOUT_FILENO][1];
-    }
-    if (io_fds[SFD_STDERR] == -1 || !isatty(STDERR_FILENO)) {
-       if (pipe(io_pipe[STDERR_FILENO]) != 0)
-           error(1, "unable to create pipe");
-       iobufs = io_buf_new(io_pipe[STDERR_FILENO][0], STDERR_FILENO,
-           log_stderr, iobufs);
-       io_fds[SFD_STDERR] = io_pipe[STDERR_FILENO][1];
-    }
-
-    /* Job control signals to relay from parent to child. */
-    sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
-    sa.sa_handler = handler;
-    sigaction(SIGTSTP, &sa, NULL);
-
-    if (foreground) {
-       /* Copy terminal attrs from user tty -> pty slave. */
-       if (term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE])) {
-           tty_initialized = 1;
-           sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]);
-       }
-
-       /* Start out in raw mode if we are not part of a pipeline. */
-       if (!pipeline) {
-           ttymode = TERM_RAW;
-           do {
-               n = term_raw(io_fds[SFD_USERTTY], 0);
-           } while (!n && errno == EINTR);
-           if (!n)
-               error(1, "Can't set terminal to raw mode");
-       }
-    }
-
-    child = fork();
-    switch (child) {
-    case -1:
-       error(1, "fork");
-       break;
-    case 0:
-       /* child */
-       close(sv[0]);
-       close(signal_pipe[0]);
-       close(signal_pipe[1]);
-       fcntl(sv[1], F_SETFD, FD_CLOEXEC);
-       if (exec_setup(rbac_enabled, slavename, io_fds[SFD_SLAVE]) == TRUE) {
-           /* Close the other end of the stdin/stdout/stderr pipes and exec. */
-           if (io_pipe[STDIN_FILENO][1])
-               close(io_pipe[STDIN_FILENO][1]);
-           if (io_pipe[STDOUT_FILENO][0])
-               close(io_pipe[STDOUT_FILENO][0]);
-           if (io_pipe[STDERR_FILENO][0])
-               close(io_pipe[STDERR_FILENO][0]);
-           exec_monitor(path, argv, envp, sv[1], rbac_enabled);
-       }
-       cstat.type = CMD_ERRNO;
-       cstat.val = errno;
-       send(sv[1], &cstat, sizeof(cstat), 0);
-       _exit(1);
-    }
-
-    /* Close the other end of the stdin/stdout/stderr pipes. */
-    if (io_pipe[STDIN_FILENO][0])
-       close(io_pipe[STDIN_FILENO][0]);
-    if (io_pipe[STDOUT_FILENO][1])
-       close(io_pipe[STDOUT_FILENO][1]);
-    if (io_pipe[STDERR_FILENO][1])
-       close(io_pipe[STDERR_FILENO][1]);
-
-    for (iob = iobufs; iob; iob = iob->next) {
-       /* Adjust maxfd. */
-       if (iob->rfd > *maxfd)
-           *maxfd = iob->rfd;
-       if (iob->wfd > *maxfd)
-           *maxfd = iob->wfd;
-
-       /* Set non-blocking mode. */
-       n = fcntl(iob->rfd, F_GETFL, 0);
-       if (n != -1 && !ISSET(n, O_NONBLOCK))
-           (void) fcntl(iob->rfd, F_SETFL, n | O_NONBLOCK);
-       n = fcntl(iob->wfd, F_GETFL, 0);
-       if (n != -1 && !ISSET(n, O_NONBLOCK))
-           (void) fcntl(iob->wfd, F_SETFL, n | O_NONBLOCK);
-    }
-
-    return child;
-}
-
-/*
- * Flush any remaining output and restore /dev/tty to the way we found it.
- * If the command died due to a signal, writes the reason to stdout.
- */
-void
-pty_close(cstat)
-    struct command_status *cstat;
-{
-    int n;
-
-    /* Flush any remaining output (the plugin already got it) */
-    if (io_fds[SFD_USERTTY] != -1) {
-       n = fcntl(io_fds[SFD_USERTTY], F_GETFL, 0);
-       if (n != -1 && ISSET(n, O_NONBLOCK)) {
-           CLR(n, O_NONBLOCK);
-           (void) fcntl(io_fds[SFD_USERTTY], F_SETFL, n);
-       }
-    }
-    flush_output();
-
-    if (io_fds[SFD_USERTTY] != -1) {
-       do {
-           n = term_restore(io_fds[SFD_USERTTY], 0);
-       } while (!n && errno == EINTR);
-    }
-
-    /* If child was signalled, write the reason to stdout like the shell. */
-    if (cstat->type == CMD_WSTATUS && WIFSIGNALED(cstat->val)) {
-       int signo = WTERMSIG(cstat->val);
-       if (signo && signo != SIGINT && signo != SIGPIPE) {
-           const char *reason = strsignal(signo);
-           n = io_fds[SFD_USERTTY] != -1 ?
-               io_fds[SFD_USERTTY] : STDOUT_FILENO;
-           if (write(n, reason, strlen(reason)) != -1) {
-               if (WCOREDUMP(cstat->val)) {
-                   if (write(n, " (core dumped)", 14) == -1)
-                       /* shut up glibc */;
-               }
-               if (write(n, "\n", 1) == -1)
-                   /* shut up glibc */;
-           }
-       }
-    }
-}
-
-
-/*
- * Fill in fdsr and fdsw based on the io buffers list.
- * Called prior to select().
- */
-void
-fd_set_iobs(fdsr, fdsw)
-    fd_set *fdsr;
-    fd_set *fdsw;
-{
-    struct io_buffer *iob;
-
-    for (iob = iobufs; iob; iob = iob->next) {
-       if (iob->rfd == -1 && iob->wfd == -1)
-           continue;
-       if (iob->off == iob->len) {
-           iob->off = iob->len = 0;
-           /* Forward the EOF from reader to writer. */
-           if (iob->rfd == -1) {
-               safe_close(iob->wfd);
-               iob->wfd = -1;
-           }
-       }
-       /* Don't read/write /dev/tty if we are not in the foreground. */
-       if (iob->rfd != -1 &&
-           (ttymode == TERM_RAW || iob->rfd != io_fds[SFD_USERTTY])) {
-           if (iob->len != sizeof(iob->buf))
-               FD_SET(iob->rfd, fdsr);
-       }
-       if (iob->wfd != -1 &&
-           (foreground || iob->wfd != io_fds[SFD_USERTTY])) {
-           if (iob->len > iob->off)
-               FD_SET(iob->wfd, fdsw);
-       }
-    }
-}
-
-/*
- * Deliver a relayed signal to the command.
- */
-static void
-deliver_signal(pid, signo)
-    pid_t pid;
-    int signo;
-{
-    int status;
-
-    /* Handle signal from parent. */
-    switch (signo) {
-    case SIGCONT_FG:
-       /* Continue in foreground, grant it controlling tty. */
-       do {
-           status = tcsetpgrp(io_fds[SFD_SLAVE], child_pgrp);
-       } while (status == -1 && errno == EINTR);
-       killpg(pid, SIGCONT);
-       break;
-    case SIGCONT_BG:
-       /* Continue in background, I take controlling tty. */
-       do {
-           status = tcsetpgrp(io_fds[SFD_SLAVE], getpid());
-       } while (status == -1 && errno == EINTR);
-       killpg(pid, SIGCONT);
-       break;
-    case SIGKILL:
-       _exit(1); /* XXX */
-       /* NOTREACHED */
-    default:
-       /* Relay signal to child. */
-       killpg(pid, signo);
-       break;
-    }
-}
-
-/*
- * Send status to parent over socketpair.
- * Return value is the same as send(2).
- */
-static int
-send_status(fd, cstat)
-    int fd;
-    struct command_status *cstat;
-{
-    int n = -1;
-
-    if (cstat->type != CMD_INVALID) {
-       do {
-           n = send(fd, cstat, sizeof(*cstat), 0);
-       } while (n == -1 && errno == EINTR);
-       cstat->type = CMD_INVALID; /* prevent re-sending */
-    }
-    return n;
-}
-
-/*
- * Wait for child status after receiving SIGCHLD.
- * If the child was stopped, the status is send back to the parent.
- * Otherwise, cstat is filled in but not sent.
- * Returns TRUE if child is still alive, else FALSE.
- */
-static int
-handle_sigchld(backchannel, cstat)
-    int backchannel;
-    struct command_status *cstat;
-{
-    int status, alive = TRUE;
-    pid_t pid;
-
-    /* read child status */
-    do {
-#ifdef sudo_waitpid
-       pid = sudo_waitpid(child, &status, WUNTRACED|WNOHANG);
-#else
-       pid = wait(&status);
-#endif
-    } while (pid == -1 && errno == EINTR);
-    if (pid == child) {
-       if (cstat->type != CMD_ERRNO) {
-           cstat->type = CMD_WSTATUS;
-           cstat->val = status;
-           if (WIFSTOPPED(status)) {
-               do {
-                   child_pgrp = tcgetpgrp(io_fds[SFD_SLAVE]);
-               } while (child_pgrp == -1 && errno == EINTR);
-               if (send_status(backchannel, cstat) == -1)
-                   return alive; /* XXX */
-           }
-       }
-       if (!WIFSTOPPED(status))
-           alive = FALSE;
-    }
-    return alive;
-}
-
-/*
- * Monitor process that creates a new session with the controlling tty,
- * resets signal handlers and forks a child to call exec_pty().
- * Waits for status changes from the command and relays them to the
- * parent and relays signals from the parent to the command.
- * Returns an error if fork(2) fails, else calls _exit(2).
- */
-static int
-exec_monitor(path, argv, envp, backchannel, rbac)
-    const char *path;
-    char *argv[];
-    char *envp[];
-    int backchannel;
-    int rbac;
-{
-    struct command_status cstat;
-    struct timeval tv;
-    fd_set *fdsr;
-    sigaction_t sa;
-    int errpipe[2], maxfd, n, status;
-    int alive = TRUE;
-    unsigned char signo;
-
-    /* Close unused fds. */
-    if (io_fds[SFD_MASTER] != -1)
-       close(io_fds[SFD_MASTER]);
-    if (io_fds[SFD_USERTTY] != -1)
-       close(io_fds[SFD_USERTTY]);
-
-    /*
-     * We use a pipe to atomically handle signal notification within
-     * the select() loop.
-     */
-    if (pipe_nonblock(signal_pipe) != 0)
-       error(1, "cannot create pipe");
-
-    /* Reset SIGWINCH. */
-    zero_bytes(&sa, sizeof(sa));
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = SA_RESTART;
-    sa.sa_handler = SIG_DFL;
-    sigaction(SIGWINCH, &sa, NULL);
-
-    /* Ignore any SIGTTIN or SIGTTOU we get. */
-    sa.sa_handler = SIG_IGN;
-    sigaction(SIGTTIN, &sa, NULL);
-    sigaction(SIGTTOU, &sa, NULL);
-
-    /* Note: HP-UX select() will not be interrupted if SA_RESTART set */
-    sa.sa_flags = SA_INTERRUPT;
-    sa.sa_handler = handler;
-    sigaction(SIGCHLD, &sa, NULL);
-
-    /*
-     * Start a new session with the parent as the session leader
-     * and the slave pty as the controlling terminal.
-     * This allows us to be notified when the child has been suspended.
-     */
-    if (setsid() == -1) {
-       warning("setsid");
-       goto bad;
-    }
-    if (io_fds[SFD_SLAVE] != -1) {
-#ifdef TIOCSCTTY
-       if (ioctl(io_fds[SFD_SLAVE], TIOCSCTTY, NULL) != 0)
-           error(1, "unable to set controlling tty");
-#else
-       /* Set controlling tty by reopening slave. */
-       if ((n = open(slavename, O_RDWR)) >= 0)
-           close(n);
-#endif
-    }
-
-    /*
-     * If stdin/stdout is not a tty, start command in the background
-     * since it might be part of a pipeline that reads from /dev/tty.
-     * In this case, we rely on the command receiving SIGTTOU or SIGTTIN
-     * when it needs access to the controlling tty.
-     */
-    if (pipeline)
-       foreground = 0;
-
-    /* Start command and wait for it to stop or exit */
-    if (pipe(errpipe) == -1)
-       error(1, "unable to create pipe");
-    child = fork();
-    if (child == -1) {
-       warning("Can't fork");
-       goto bad;
-    }
-    if (child == 0) {
-       /* We pass errno back to our parent via pipe on exec failure. */
-       close(backchannel);
-       close(signal_pipe[0]);
-       close(signal_pipe[1]);
-       close(errpipe[0]);
-       fcntl(errpipe[1], F_SETFD, FD_CLOEXEC);
-       restore_signals();
-
-       /* setup tty and exec command */
-       exec_pty(path, argv, envp, rbac);
-       cstat.type = CMD_ERRNO;
-       cstat.val = errno;
-       if (write(errpipe[1], &cstat, sizeof(cstat)) == -1)
-           /* shut up glibc */;
-       _exit(1);
-    }
-    close(errpipe[1]);
-
-    /* If any of stdin/stdout/stderr are pipes, close them in parent. */
-    if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE])
-       close(io_fds[SFD_STDIN]);
-    if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE])
-       close(io_fds[SFD_STDOUT]);
-    if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE])
-       close(io_fds[SFD_STDERR]);
-
-    /*
-     * Put child in its own process group.  If we are starting the command
-     * in the foreground, assign its pgrp to the tty.
-     */
-    child_pgrp = child;
-    setpgid(child, child_pgrp);
-    if (foreground) {
-       do {
-           status = tcsetpgrp(io_fds[SFD_SLAVE], child_pgrp);
-       } while (status == -1 && errno == EINTR);
-    }
-
-    /* Wait for errno on pipe, signal on backchannel or for SIGCHLD */
-    maxfd = MAX(MAX(errpipe[0], signal_pipe[0]), backchannel);
-    fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
-    zero_bytes(fdsr, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
-    zero_bytes(&cstat, sizeof(cstat));
-    tv.tv_sec = 0;
-    tv.tv_usec = 0;
-    for (;;) {
-       /* Check for signal on backchannel or errno on errpipe. */
-       FD_SET(backchannel, fdsr);
-       FD_SET(signal_pipe[0], fdsr);
-       if (errpipe[0] != -1)
-           FD_SET(errpipe[0], fdsr);
-       maxfd = MAX(MAX(errpipe[0], signal_pipe[0]), backchannel);
-
-       /* If command exited we just poll, there may be data on errpipe. */
-       n = select(maxfd + 1, fdsr, NULL, NULL, alive ? NULL : &tv);
-       if (n <= 0) {
-           if (n == 0)
-               goto done;
-           if (errno == EINTR)
-               continue;
-           error(1, "select failed");
-       }
-
-       if (FD_ISSET(signal_pipe[0], fdsr)) {
-           n = read(signal_pipe[0], &signo, sizeof(signo));
-           if (n == -1) {
-               if (errno == EINTR || errno == EAGAIN)
-                   continue;
-               warning("error reading from signal pipe");
-               goto done;
-           }
-           /*
-            * Handle SIGCHLD specially and deliver other signals
-            * directly to the child.
-            */
-           if (signo == SIGCHLD)
-               alive = handle_sigchld(backchannel, &cstat);
-           else
-               deliver_signal(child, signo);
-           continue;
-       }
-       if (errpipe[0] != -1 && FD_ISSET(errpipe[0], fdsr)) {
-           /* read errno or EOF from command pipe */
-           n = read(errpipe[0], &cstat, sizeof(cstat));
-           if (n == -1) {
-               if (errno == EINTR)
-                   continue;
-               warning("error reading from pipe");
-               goto done;
-           }
-           /* Got errno or EOF, either way we are done with errpipe. */
-           FD_CLR(errpipe[0], fdsr);
-           close(errpipe[0]);
-           errpipe[0] = -1;
-       }
-       if (FD_ISSET(backchannel, fdsr)) {
-           struct command_status cstmp;
-
-           /* read command from backchannel, should be a signal */
-           n = recv(backchannel, &cstmp, sizeof(cstmp), 0);
-           if (n == -1) {
-               if (errno == EINTR)
-                   continue;
-               warning("error reading from socketpair");
-               goto done;
-           }
-           if (cstmp.type != CMD_SIGNO) {
-               warningx("unexpected reply type on backchannel: %d", cstmp.type);
-               continue;
-           }
-           deliver_signal(child, cstmp.val);
-       }
-    }
-
-done:
-    if (alive) {
-       /* XXX An error occurred, should send an error back. */
-       kill(child, SIGKILL);
-    } else {
-       /* Send parent status. */
-       send_status(backchannel, &cstat);
-    }
-    _exit(1);
-
-bad:
-    return errno;
-}
-
-/*
- * Flush any output buffered in iobufs or readable from the fds.
- * Does not read from /dev/tty.
- */
-static void
-flush_output()
-{
-    struct io_buffer *iob;
-    struct timeval tv;
-    fd_set *fdsr, *fdsw;
-    int nready, nwriters, maxfd = -1;
-
-    /* Determine maxfd */
-    for (iob = iobufs; iob; iob = iob->next) {
-       if (iob->rfd > maxfd)
-           maxfd = iob->rfd;
-       if (iob->wfd > maxfd)
-           maxfd = iob->wfd;
-    }
-    if (maxfd == -1)
-       return;
-
-    fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
-    fdsw = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
-    for (;;) {
-       zero_bytes(fdsw, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
-       zero_bytes(fdsr, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
-
-       nwriters = 0;
-       for (iob = iobufs; iob; iob = iob->next) {
-           /* Don't read from /dev/tty while flushing. */
-           if (io_fds[SFD_USERTTY] != -1 && iob->rfd == io_fds[SFD_USERTTY])
-               continue;
-           if (iob->rfd == -1 && iob->wfd == -1)
-               continue;
-           if (iob->off == iob->len) {
-               iob->off = iob->len = 0;
-               /* Forward the EOF from reader to writer. */
-               if (iob->rfd == -1) {
-                   safe_close(iob->wfd);
-                   iob->wfd = -1;
-               }
-           }
-           if (iob->rfd != -1) {
-               if (iob->len != sizeof(iob->buf))
-                   FD_SET(iob->rfd, fdsr);
-           }
-           if (iob->wfd != -1) {
-               if (iob->len > iob->off) {
-                   nwriters++;
-                   FD_SET(iob->wfd, fdsw);
-               }
-           }
-       }
-
-       /* Don't sleep in select if there are no buffers that need writing. */
-       tv.tv_sec = 0;
-       tv.tv_usec = 0;
-       nready = select(maxfd + 1, fdsr, fdsw, NULL, nwriters ? NULL : &tv);
-       if (nready <= 0) {
-           if (nready == 0)
-               break; /* all I/O flushed */
-           if (errno == EINTR)
-               continue;
-           error(1, "select failed");
-       }
-       if (perform_io(fdsr, fdsw, NULL) != 0)
-           break;
-    }
-    efree(fdsr);
-    efree(fdsw);
-}
-
-/*
- * Sets up std{in,out,err} and executes the actual command.
- * Returns only if execve() fails.
- */
-static void
-exec_pty(path, argv, envp, rbac_enabled)
-    const char *path;
-    char *argv[];
-    char *envp[];
-    int rbac_enabled;
-{
-    pid_t self = getpid();
-
-    /* Set child process group here too to avoid a race. */
-    setpgid(0, self);
-
-    /* Wire up standard fds, note that stdout/stderr may be pipes. */
-    if (dup2(io_fds[SFD_STDIN], STDIN_FILENO) == -1 ||
-       dup2(io_fds[SFD_STDOUT], STDOUT_FILENO) == -1 ||
-       dup2(io_fds[SFD_STDERR], STDERR_FILENO) == -1)
-       error(1, "dup2");
-
-    /* Wait for parent to grant us the tty if we are foreground. */
-    if (foreground) {
-       while (tcgetpgrp(io_fds[SFD_SLAVE]) != self)
-           ; /* spin */
-    }
-
-    /* We have guaranteed that the slave fd is > 2 */
-    if (io_fds[SFD_SLAVE] != -1)
-       close(io_fds[SFD_SLAVE]);
-    if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE])
-       close(io_fds[SFD_STDIN]);
-    if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE])
-       close(io_fds[SFD_STDOUT]);
-    if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE])
-       close(io_fds[SFD_STDERR]);
-
-    closefrom(def_closefrom);
-#ifdef HAVE_SELINUX
-    if (rbac_enabled)
-       selinux_execve(path, argv, envp);
-    else
-#endif
-       my_execve(path, argv, envp);
-}
-
-/*
- * Propagates tty size change signals to pty being used by the command.
- */
-static void
-sync_ttysize(src, dst)
-    int src;
-    int dst;
-{
-#ifdef TIOCGWINSZ
-    struct winsize wsize;
-    pid_t pgrp;
-
-    if (ioctl(src, TIOCGWINSZ, &wsize) == 0) {
-           ioctl(dst, TIOCSWINSZ, &wsize);
-           if ((pgrp = tcgetpgrp(dst)) != -1)
-               killpg(pgrp, SIGWINCH);
-    }
-#endif
-}
-
-/*
- * Handler for SIGWINCH in parent.
- */
-static void
-sigwinch(s)
-    int s;
-{
-    int serrno = errno;
-
-    sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]);
-    errno = serrno;
-}
-
-/*
- * Only close the fd if it is not /dev/tty or std{in,out,err}.
- * Return value is the same as send(2).
- */
-static int
-safe_close(fd)
-    int fd;
-{
-    /* Avoid closing /dev/tty or std{in,out,err}. */
-    if (fd < 3 || fd == io_fds[SFD_USERTTY]) {
-       errno = EINVAL;
-       return -1;
-    }
-    return close(fd);
-}
diff --git a/fileops.c b/fileops.c
deleted file mode 100644 (file)
index ae9a7df..0000000
--- a/fileops.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2007, 2009, 2010
- *     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/param.h>
-#include <sys/time.h>
-#ifdef HAVE_FLOCK
-# include <sys/file.h>
-#endif /* HAVE_FLOCK */
-#include <stdio.h>
-#ifdef HAVE_STRING_H
-# include <string.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#include <ctype.h>
-#include <limits.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <fcntl.h>
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-#ifndef HAVE_TIMESPEC
-# include "emul/timespec.h"
-#endif
-
-#include "sudo.h"
-
-#ifndef LINE_MAX
-# define LINE_MAX 2048
-#endif
-
-/*
- * Update the access and modify times on an fd or file.
- */
-int
-touch(fd, path, tvp)
-    int fd;
-    char *path;
-    struct timeval *tvp;
-{
-    struct timeval times[2];
-
-    if (tvp != NULL) {
-       times[0].tv_sec = times[1].tv_sec = tvp->tv_sec;
-       times[0].tv_usec = times[1].tv_usec = tvp->tv_usec;
-    }
-
-#if defined(HAVE_FUTIME) || defined(HAVE_FUTIMES)
-    if (fd != -1)
-       return futimes(fd, tvp ? times : NULL);
-    else
-#endif
-    if (path != NULL)
-       return utimes(path, tvp ? times : NULL);
-    else
-       return -1;
-}
-
-/*
- * Lock/unlock a file.
- */
-#ifdef HAVE_LOCKF
-int
-lock_file(fd, lockit)
-    int fd;
-    int lockit;
-{
-    int op = 0;
-
-    switch (lockit) {
-       case SUDO_LOCK:
-           op = F_LOCK;
-           break;
-       case SUDO_TLOCK:
-           op = F_TLOCK;
-           break;
-       case SUDO_UNLOCK:
-           op = F_ULOCK;
-           break;
-    }
-    return lockf(fd, op, 0) == 0;
-}
-#elif HAVE_FLOCK
-int
-lock_file(fd, lockit)
-    int fd;
-    int lockit;
-{
-    int op = 0;
-
-    switch (lockit) {
-       case SUDO_LOCK:
-           op = LOCK_EX;
-           break;
-       case SUDO_TLOCK:
-           op = LOCK_EX | LOCK_NB;
-           break;
-       case SUDO_UNLOCK:
-           op = LOCK_UN;
-           break;
-    }
-    return flock(fd, op) == 0;
-}
-#else
-int
-lock_file(fd, lockit)
-    int fd;
-    int lockit;
-{
-#ifdef F_SETLK
-    int func;
-    struct flock lock;
-
-    lock.l_start = 0;
-    lock.l_len = 0;
-    lock.l_pid = getpid();
-    lock.l_type = (lockit == SUDO_UNLOCK) ? F_UNLCK : F_WRLCK;
-    lock.l_whence = SEEK_SET;
-    func = (lockit == SUDO_LOCK) ? F_SETLKW : F_SETLK;
-
-    return fcntl(fd, func, &lock) == 0;
-#else
-    return TRUE;
-#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((unsigned char)buf[len - 1]))
-           buf[--len] = '\0';
-       for (cp = buf; isblank((unsigned char)*cp); cp++)
-           continue;
-    }
-    return cp;
-}
diff --git a/find_path.c b/find_path.c
deleted file mode 100644 (file)
index fb7fb5f..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-2005, 2010
- *     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/param.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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-
-#include "sudo.h"
-
-/*
- * This function finds the full pathname for a command and
- * stores it in a statically allocated array, filling in a pointer
- * to the array.  Returns FOUND if the command was found, NOT_FOUND
- * if it was not found, or NOT_FOUND_DOT if it would have been found
- * but it is in '.' and IGNORE_DOT is set.
- */
-int
-find_path(infile, outfile, sbp, path, ignore_dot)
-    char *infile;              /* file to find */
-    char **outfile;            /* result parameter */
-    struct stat *sbp;          /* stat result parameter */
-    char *path;                        /* path to search */
-    int ignore_dot;            /* don't check cwd */
-{
-    static char command[PATH_MAX]; /* qualified filename */
-    char *n;                   /* for traversing path */
-    char *origpath;            /* so we can free path later */
-    char *result = NULL;       /* result of path/file lookup */
-    int checkdot = 0;          /* check current dir? */
-    int len;                   /* length parameter */
-
-    if (strlen(infile) >= PATH_MAX)
-       errorx(1, "%s: File name too long", infile);
-
-    /*
-     * If we were given a fully qualified or relative path
-     * there is no need to look at $PATH.
-     */
-    if (strchr(infile, '/')) {
-       strlcpy(command, infile, sizeof(command));      /* paranoia */
-       if (sudo_goodpath(command, sbp)) {
-           *outfile = command;
-           return FOUND;
-       } else
-           return NOT_FOUND;
-    }
-
-    if (path == NULL)
-       return NOT_FOUND;
-    path = estrdup(path);
-    origpath = path;
-
-    do {
-       if ((n = strchr(path, ':')))
-           *n = '\0';
-
-       /*
-        * Search current dir last if it is in PATH This will miss sneaky
-        * things like using './' or './/'
-        */
-       if (*path == '\0' || (*path == '.' && *(path + 1) == '\0')) {
-           checkdot = 1;
-           path = n + 1;
-           continue;
-       }
-
-       /*
-        * Resolve the path and exit the loop if found.
-        */
-       len = snprintf(command, sizeof(command), "%s/%s", path, infile);
-       if (len <= 0 || len >= sizeof(command))
-           errorx(1, "%s: File name too long", infile);
-       if ((result = sudo_goodpath(command, sbp)))
-           break;
-
-       path = n + 1;
-
-    } while (n);
-    efree(origpath);
-
-    /*
-     * Check current dir if dot was in the PATH
-     */
-    if (!result && checkdot) {
-       len = snprintf(command, sizeof(command), "./%s", infile);
-       if (len <= 0 || len >= sizeof(command))
-           errorx(1, "%s: File name too long", infile);
-       result = sudo_goodpath(command, sbp);
-       if (result && ignore_dot)
-           return NOT_FOUND_DOT;
-    }
-
-    if (result) {
-       *outfile = result;
-       return FOUND;
-    } else
-       return NOT_FOUND;
-}
diff --git a/fnmatch.c b/fnmatch.c
deleted file mode 100644 (file)
index 723e53d..0000000
--- a/fnmatch.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (c) 2008, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
- * Copyright (c) 1989, 1993, 1994
- *     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.
- */
-
-/*
- * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
- * Compares a filename or pathname to a pattern.
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-
-#include <stdio.h>
-#include <ctype.h>
-#ifdef HAVE_STRING_H
-# include <string.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-
-#include "missing.h"
-#include "emul/fnmatch.h"
-#include "emul/charclass.h"
-
-#undef EOS
-#define        EOS     '\0'
-
-#define        RANGE_MATCH     1
-#define        RANGE_NOMATCH   0
-#define        RANGE_ERROR     (-1)
-
-#if defined(LIBC_SCCS) && !defined(lint)
-__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 *, int, int, char **));
-static int classmatch __P((const char *, int, int, const char **));
-
-int
-fnmatch(pattern, string, flags)
-       const char *pattern, *string;
-       int flags;
-{
-       const char *stringstart;
-       char *newp;
-       char c, test;
-
-       for (stringstart = string;;)
-               switch (c = *pattern++) {
-               case EOS:
-                       if (ISSET(flags, FNM_LEADING_DIR) && *string == '/')
-                               return 0;
-                       return *string == EOS ? 0 : FNM_NOMATCH;
-               case '?':
-                       if (*string == EOS)
-                               return FNM_NOMATCH;
-                       if (*string == '/' && ISSET(flags, FNM_PATHNAME))
-                               return FNM_NOMATCH;
-                       if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
-                           (string == stringstart ||
-                           (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
-                               return FNM_NOMATCH;
-                       ++string;
-                       break;
-               case '*':
-                       c = *pattern;
-                       /* Collapse multiple stars. */
-                       while (c == '*')
-                               c = *++pattern;
-
-                       if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
-                           (string == stringstart ||
-                           (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
-                               return FNM_NOMATCH;
-
-                       /* Optimize for pattern with * at end or before /. */
-                       if (c == EOS) {
-                               if (ISSET(flags, FNM_PATHNAME))
-                                       return ISSET(flags, FNM_LEADING_DIR) ||
-                                           strchr(string, '/') == NULL ?
-                                           0 : FNM_NOMATCH;
-                               else
-                                       return 0;
-                       } else if (c == '/' && ISSET(flags, FNM_PATHNAME)) {
-                               if ((string = strchr(string, '/')) == NULL)
-                                       return FNM_NOMATCH;
-                               break;
-                       }
-
-                       /* General case, use recursion. */
-                       while ((test = *string) != EOS) {
-                               if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
-                                       return 0;
-                               if (test == '/' && ISSET(flags, FNM_PATHNAME))
-                                       break;
-                               ++string;
-                       }
-                       return FNM_NOMATCH;
-               case '[':
-                       if (*string == EOS)
-                               return FNM_NOMATCH;
-                       if (*string == '/' && ISSET(flags, FNM_PATHNAME))
-                               return FNM_NOMATCH;
-                       if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
-                           (string == stringstart ||
-                           (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
-                               return FNM_NOMATCH;
-
-                       switch (rangematch(pattern, *string, flags, &newp)) {
-                       case RANGE_ERROR:
-                               /* not a good range, treat as normal text */
-                               goto normal;
-                       case RANGE_MATCH:
-                               pattern = newp;
-                               break;
-                       case RANGE_NOMATCH:
-                               return FNM_NOMATCH;
-                       }
-                       ++string;
-                       break;
-               case '\\':
-                       if (!ISSET(flags, FNM_NOESCAPE)) {
-                               if ((c = *pattern++) == EOS) {
-                                       c = '\\';
-                                       --pattern;
-                               }
-                       }
-                       /* FALLTHROUGH */
-               default:
-               normal:
-                       if (c != *string && !(ISSET(flags, FNM_CASEFOLD) &&
-                                (tolower((unsigned char)c) ==
-                                tolower((unsigned char)*string))))
-                               return FNM_NOMATCH;
-                       ++string;
-                       break;
-               }
-       /* NOTREACHED */
-}
-
-static int
-#ifdef __STDC__
-rangematch(const char *pattern, int test, int flags, char **newp)
-#else
-rangematch(pattern, test, flags, newp)
-       const char *pattern;
-       int test;
-       int flags;
-       char **newp;
-#endif
-{
-       int negate, ok, rv;
-       char c, c2;
-
-       /*
-        * A bracket expression starting with an unquoted circumflex
-        * character produces unspecified results (IEEE 1003.2-1992,
-        * 3.13.2).  This implementation treats it like '!', for
-        * consistency with the regular expression syntax.
-        * J.T. Conklin (conklin@ngai.kaleida.com)
-        */
-       if ((negate = (*pattern == '!' || *pattern == '^')))
-               ++pattern;
-
-       if (ISSET(flags, FNM_CASEFOLD))
-               test = tolower(test);
-
-       /*
-        * A right bracket shall lose its special meaning and represent
-        * itself in a bracket expression if it occurs first in the list.
-        * -- POSIX.2 2.8.3.2
-        */
-       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)
-                       return RANGE_ERROR;
-               if (c == '/' && ISSET(flags, FNM_PATHNAME))
-                       return RANGE_NOMATCH;
-               if (ISSET(flags, FNM_CASEFOLD))
-                       c = tolower((unsigned char)c);
-               if (*pattern == '-'
-                   && (c2 = *(pattern+1)) != EOS && c2 != ']') {
-                       pattern += 2;
-                       if (c2 == '\\' && !ISSET(flags, FNM_NOESCAPE))
-                               c2 = *pattern++;
-                       if (c2 == EOS)
-                               return RANGE_ERROR;
-                       if (ISSET(flags, FNM_CASEFOLD))
-                               c2 = tolower((unsigned char)c2);
-                       if (c <= test && test <= c2)
-                               ok = 1;
-               } else if (c == test)
-                       ok = 1;
-       } while ((c = *pattern++) != ']');
-
-       *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;
-}
diff --git a/get_pty.c b/get_pty.c
deleted file mode 100644 (file)
index 8549794..0000000
--- a/get_pty.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2009-2010 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 <sys/stat.h>
-#include <sys/ioctl.h>
-#ifdef HAVE_SYS_STROPTS_H
-#include <sys/stropts.h>
-#endif /* HAVE_SYS_STROPTS_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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <errno.h>
-#include <fcntl.h>
-#include <grp.h>
-#include <pwd.h>
-
-#ifdef HAVE_UTIL_H
-# include <util.h>
-#endif
-#ifdef HAVE_PTY_H
-# include <pty.h>
-#endif
-
-#include "sudo.h"
-
-#if defined(HAVE_OPENPTY)
-int
-get_pty(master, slave, name, namesz, ttyuid)
-    int *master;
-    int *slave;
-    char *name;
-    size_t namesz;
-    uid_t ttyuid;
-{
-    struct group *gr;
-    gid_t ttygid = -1;
-
-    if ((gr = sudo_getgrnam("tty")) != NULL) {
-       ttygid = gr->gr_gid;
-       gr_delref(gr);
-    }
-
-    if (openpty(master, slave, name, NULL, NULL) != 0)
-       return 0;
-    if (chown(name, ttyuid, ttygid) != 0)
-       return 0;
-    return 1;
-}
-
-#elif defined(HAVE__GETPTY)
-int
-get_pty(master, slave, name, namesz, ttyuid)
-    int *master;
-    int *slave;
-    char *name;
-    size_t namesz;
-    uid_t ttyuid;
-{
-    char *line;
-
-    /* IRIX-style dynamic ptys (may fork) */
-    line = _getpty(master, O_RDWR, S_IRUSR|S_IWUSR|S_IWGRP, 0);
-    if (line == NULL)
-       return 0;
-    *slave = open(line, O_RDWR|O_NOCTTY, 0);
-    if (*slave == -1) {
-       close(*master);
-       return 0;
-    }
-    (void) chown(line, ttyuid, -1);
-    strlcpy(name, line, namesz);
-    return 1;
-}
-#elif defined(HAVE_GRANTPT)
-# ifndef HAVE_POSIX_OPENPT
-static int
-posix_openpt(oflag)
-    int oflag;
-{
-    int fd;
-
-#  ifdef _AIX
-    fd = open("/dev/ptc", oflag);
-#  else
-    fd = open("/dev/ptmx", oflag);
-#  endif
-    return fd;
-}
-# endif /* HAVE_POSIX_OPENPT */
-
-int
-get_pty(master, slave, name, namesz, ttyuid)
-    int *master;
-    int *slave;
-    char *name;
-    size_t namesz;
-    uid_t ttyuid;
-{
-    char *line;
-
-    *master = posix_openpt(O_RDWR|O_NOCTTY);
-    if (*master == -1)
-       return 0;
-
-    (void) grantpt(*master); /* may fork */
-    if (unlockpt(*master) != 0) {
-       close(*master);
-       return 0;
-    }
-    line = ptsname(*master);
-    if (line == NULL) {
-       close(*master);
-       return 0;
-    }
-    *slave = open(line, O_RDWR|O_NOCTTY, 0);
-    if (*slave == -1) {
-       close(*master);
-       return 0;
-    }
-# if defined(I_PUSH) && !defined(_AIX)
-    ioctl(*slave, I_PUSH, "ptem");     /* pseudo tty emulation module */
-    ioctl(*slave, I_PUSH, "ldterm");   /* line discipline module */
-# endif
-    (void) chown(line, ttyuid, -1);
-    strlcpy(name, line, namesz);
-    return 1;
-}
-
-#else /* Old-style BSD ptys */
-
-static char line[] = "/dev/ptyXX";
-
-int
-get_pty(master, slave, name, namesz, ttyuid)
-    int *master;
-    int *slave;
-    char *name;
-    size_t namesz;
-    uid_t ttyuid;
-{
-    char *bank, *cp;
-    struct group *gr;
-    gid_t ttygid = -1;
-
-    if ((gr = sudo_getgrnam("tty")) != NULL)
-       ttygid = gr->gr_gid;
-
-    for (bank = "pqrs"; *bank != '\0'; bank++) {
-       line[sizeof("/dev/ptyX") - 2] = *bank;
-       for (cp = "0123456789abcdef"; *cp != '\0'; cp++) {
-           line[sizeof("/dev/ptyXX") - 2] = *cp;
-           *master = open(line, O_RDWR|O_NOCTTY, 0);
-           if (*master == -1) {
-               if (errno == ENOENT)
-                   return 0; /* out of ptys */
-               continue; /* already in use */
-           }
-           line[sizeof("/dev/p") - 2] = 't';
-           (void) chown(line, ttyuid, ttygid);
-           (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
-# ifdef HAVE_REVOKE
-           (void) revoke(line);
-# endif
-           *slave = open(line, O_RDWR|O_NOCTTY, 0);
-           if (*slave != -1) {
-                   strlcpy(name, line, namesz);
-                   return 1; /* success */
-           }
-           (void) close(*master);
-       }
-    }
-    return 0;
-}
-#endif /* HAVE_OPENPTY */
diff --git a/getcwd.c b/getcwd.c
deleted file mode 100644 (file)
index 1260ad4..0000000
--- a/getcwd.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (c) 1989, 1991, 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. 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/param.h>
-#include <sys/stat.h>
-
-#include <errno.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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
-# include <malloc.h>
-#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_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 "missing.h"
-
-#define        ISDOT(dp) \
-       (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
-           (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
-
-char *
-getcwd(pt, size)
-       char *pt;
-       size_t size;
-{
-       struct dirent *dp;
-       DIR *dir = NULL;
-       dev_t dev;
-       ino_t ino;
-       int first;
-       char *bpt, *bup;
-       struct stat s;
-       dev_t root_dev;
-       ino_t root_ino;
-       size_t ptsize, upsize;
-       int save_errno;
-       char *ept, *eup, *up;
-
-       /*
-        * If no buffer specified by the user, allocate one as necessary.
-        * If a buffer is specified, the size has to be non-zero.  The path
-        * is built from the end of the buffer backwards.
-        */
-       if (pt) {
-               ptsize = 0;
-               if (!size) {
-                       errno = EINVAL;
-                       return NULL;
-               }
-               ept = pt + size;
-       } else {
-               if ((pt = malloc(ptsize = 1024 - 4)) == NULL)
-                       return NULL;
-               ept = pt + ptsize;
-       }
-       bpt = ept - 1;
-       *bpt = '\0';
-
-       /*
-        * Allocate bytes (1024 - malloc space) for the string of "../"'s.
-        * Should always be enough (it's 340 levels).  If it's not, allocate
-        * as necessary.  Special * case the first stat, it's ".", not "..".
-        */
-       if ((up = malloc(upsize = 1024 - 4)) == NULL)
-               goto err;
-       eup = up + PATH_MAX;
-       bup = up;
-       up[0] = '.';
-       up[1] = '\0';
-
-       /* Save root values, so know when to stop. */
-       if (stat("/", &s))
-               goto err;
-       root_dev = s.st_dev;
-       root_ino = s.st_ino;
-
-       errno = 0;                      /* XXX readdir has no error return. */
-
-       for (first = 1;; first = 0) {
-               /* Stat the current level. */
-               if (lstat(up, &s))
-                       goto err;
-
-               /* Save current node values. */
-               ino = s.st_ino;
-               dev = s.st_dev;
-
-               /* Check for reaching root. */
-               if (root_dev == dev && root_ino == ino) {
-                       *--bpt = '/';
-                       /*
-                        * It's unclear that it's a requirement to copy the
-                        * path to the beginning of the buffer, but it's always
-                        * been that way and stuff would probably break.
-                        */
-                       bcopy(bpt, pt, ept - bpt);
-                       free(up);
-                       return pt;
-               }
-
-               /*
-                * Build pointer to the parent directory, allocating memory
-                * as necessary.  Max length is 3 for "../", the largest
-                * possible component name, plus a trailing NULL.
-                */
-               if (bup + 3  + MAXNAMLEN + 1 >= eup) {
-                       char *nup;
-
-                       if ((nup = realloc(up, upsize *= 2)) == NULL)
-                               goto err;
-                       up = nup;
-                       bup = up;
-                       eup = up + upsize;
-               }
-               *bup++ = '.';
-               *bup++ = '.';
-               *bup = '\0';
-
-               /* Open and stat parent directory. */
-               if (!(dir = opendir(up)) || fstat(dirfd(dir), &s))
-                       goto err;
-
-               /* Add trailing slash for next directory. */
-               *bup++ = '/';
-
-               /*
-                * If it's a mount point, have to stat each element because
-                * the inode number in the directory is for the entry in the
-                * parent directory, not the inode number of the mounted file.
-                */
-               save_errno = 0;
-               if (s.st_dev == dev) {
-                       for (;;) {
-                               if (!(dp = readdir(dir)))
-                                       goto notfound;
-                               if (dp->d_fileno == ino)
-                                       break;
-                       }
-               } else
-                       for (;;) {
-                               if (!(dp = readdir(dir)))
-                                       goto notfound;
-                               if (ISDOT(dp))
-                                       continue;
-                               bcopy(dp->d_name, bup, NAMLEN(dp) + 1);
-
-                               /* Save the first error for later. */
-                               if (lstat(up, &s)) {
-                                       if (!save_errno)
-                                               save_errno = errno;
-                                       errno = 0;
-                                       continue;
-                               }
-                               if (s.st_dev == dev && s.st_ino == ino)
-                                       break;
-                       }
-
-               /*
-                * Check for length of the current name, preceding slash,
-                * leading slash.
-                */
-               if (bpt - pt <= NAMLEN(dp) + (first ? 1 : 2)) {
-                       size_t len, off;
-                       char *npt;
-
-                       if (!ptsize) {
-                               errno = ERANGE;
-                               goto err;
-                       }
-                       off = bpt - pt;
-                       len = ept - bpt;
-                       if ((npt = realloc(pt, ptsize *= 2)) == NULL)
-                               goto err;
-                       pt = npt;
-                       bpt = pt + off;
-                       ept = pt + ptsize;
-                       bcopy(bpt, ept - len, len);
-                       bpt = ept - len;
-               }
-               if (!first)
-                       *--bpt = '/';
-               bpt -= NAMLEN(dp);
-               bcopy(dp->d_name, bpt, NAMLEN(dp));
-               (void)closedir(dir);
-
-               /* Truncate any file name. */
-               *bup = '\0';
-       }
-
-notfound:
-       /*
-        * If readdir set errno, use it, not any saved error; otherwise,
-        * didn't find the current directory in its parent directory, set
-        * errno to ENOENT.
-        */
-       if (!errno)
-               errno = save_errno ? save_errno : ENOENT;
-       /* FALLTHROUGH */
-err:
-       if (ptsize)
-               free(pt);
-       if (up)
-               free(up);
-       if (dir)
-               (void)closedir(dir);
-       return NULL;
-}
diff --git a/getdate.c b/getdate.c
deleted file mode 100644 (file)
index 7544c3f..0000000
--- a/getdate.c
+++ /dev/null
@@ -1,1596 +0,0 @@
-#include <config.h>
-#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 "getdate.y"
-/*
-**  Originally written by Steven M. Bellovin <smb@research.att.com> while
-**  at the University of North Carolina at Chapel Hill.  Later tweaked by
-**  a couple of people on Usenet.  Completely overhauled by Rich $alz
-**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
-**
-**  This grammar has 10 shift/reduce conflicts.
-**
-**  This code is in the public domain and has no copyright.
-*/
-/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
-/* SUPPRESS 288 on yyerrlab *//* Label unused */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/time.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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-#include <ctype.h>
-
-#include "missing.h"
-
-
-#define EPOCH          1970
-#define HOUR(x)                ((time_t)(x) * 60)
-#define SECSPERDAY     (24L * 60L * 60L)
-
-
-/*
-**  An entry in the lexical lookup table.
-*/
-typedef struct _TABLE {
-    char       *name;
-    int                type;
-    time_t     value;
-} TABLE;
-
-
-/*
-**  Daylight-savings mode:  on, off, or not yet known.
-*/
-typedef enum _DSTMODE {
-    DSTon, DSToff, DSTmaybe
-} DSTMODE;
-
-/*
-**  Meridian:  am, pm, or 24-hour style.
-*/
-typedef enum _MERIDIAN {
-    MERam, MERpm, MER24
-} MERIDIAN;
-
-
-/*
-**  Global variables.  We could get rid of most of these by using a good
-**  union as the yacc stack.  (This routine was originally written before
-**  yacc had the %union construct.)  Maybe someday; right now we only use
-**  the %union very rarely.
-*/
-static char    *yyInput;
-static DSTMODE yyDSTmode;
-static time_t  yyDayOrdinal;
-static time_t  yyDayNumber;
-static int     yyHaveDate;
-static int     yyHaveDay;
-static int     yyHaveRel;
-static int     yyHaveTime;
-static int     yyHaveZone;
-static time_t  yyTimezone;
-static time_t  yyDay;
-static time_t  yyHour;
-static time_t  yyMinutes;
-static time_t  yyMonth;
-static time_t  yySeconds;
-static time_t  yyYear;
-static MERIDIAN        yyMeridian;
-static time_t  yyRelMonth;
-static time_t  yyRelSeconds;
-
-static int     yyerror __P((char *s));
-static int     yylex __P((void));
-static int     yyparse __P((void));
-
-#line 107 "getdate.y"
-#ifndef YYSTYPE_DEFINED
-#define YYSTYPE_DEFINED
-typedef union {
-    time_t             Number;
-    enum _MERIDIAN     Meridian;
-} YYSTYPE;
-#endif /* YYSTYPE_DEFINED */
-#line 125 "y.tab.c"
-#define tAGO 257
-#define tDAY 258
-#define tDAYZONE 259
-#define tID 260
-#define tMERIDIAN 261
-#define tMINUTE_UNIT 262
-#define tMONTH 263
-#define tMONTH_UNIT 264
-#define tSEC_UNIT 265
-#define tSNUMBER 266
-#define tUNUMBER 267
-#define tZONE 268
-#define tDST 269
-#define YYERRCODE 256
-#if defined(__cplusplus) || defined(__STDC__)
-const short yylhs[] =
-#else
-short yylhs[] =
-#endif
-       {                                        -1,
-    0,    0,    2,    2,    2,    2,    2,    2,    3,    3,
-    3,    3,    3,    4,    4,    4,    6,    6,    6,    5,
-    5,    5,    5,    5,    5,    5,    5,    7,    7,    9,
-    9,    9,    9,    9,    9,    9,    9,    9,    8,    1,
-    1,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yylen[] =
-#else
-short yylen[] =
-#endif
-       {                                         2,
-    0,    2,    1,    1,    1,    1,    1,    1,    2,    4,
-    4,    6,    6,    1,    1,    2,    1,    2,    2,    3,
-    5,    3,    3,    2,    4,    2,    3,    2,    1,    2,
-    2,    1,    2,    2,    1,    2,    2,    1,    1,    0,
-    1,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yydefred[] =
-#else
-short yydefred[] =
-#endif
-       {                                      1,
-    0,    0,   15,   32,    0,   38,   35,    0,    0,    0,
-    2,    3,    4,    5,    6,    7,    8,    0,   18,    0,
-   31,   36,   33,   19,    9,   30,    0,   37,   34,    0,
-    0,    0,   16,   28,    0,   23,   27,   22,    0,    0,
-   25,   41,   11,    0,   10,    0,    0,   21,   13,   12,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yydgoto[] =
-#else
-short yydgoto[] =
-#endif
-       {                                       1,
-   45,   11,   12,   13,   14,   15,   16,   17,   18,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yysindex[] =
-#else
-short yysindex[] =
-#endif
-       {                                      0,
- -249,  -38,    0,    0, -260,    0,    0, -240,  -47, -248,
-    0,    0,    0,    0,    0,    0,    0, -237,    0,  -18,
-    0,    0,    0,    0,    0,    0, -262,    0,    0, -239,
- -238, -236,    0,    0, -235,    0,    0,    0,  -56,  -19,
-    0,    0,    0, -234,    0, -232, -258,    0,    0,    0,};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yyrindex[] =
-#else
-short yyrindex[] =
-#endif
-       {                                      0,
-    0,    1,    0,    0,    0,    0,    0,    0,   69,   12,
-    0,    0,    0,    0,    0,    0,    0,   23,    0,   34,
-    0,    0,    0,    0,    0,    0,   67,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,   56,   45,
-    0,    0,    0,    0,    0,    0,   56,    0,    0,    0,};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yygindex[] =
-#else
-short yygindex[] =
-#endif
-       {                                      0,
-  -17,    0,    0,    0,    0,    0,    0,    0,    0,
-};
-#define YYTABLESIZE 337
-#if defined(__cplusplus) || defined(__STDC__)
-const short yytable[] =
-#else
-short yytable[] =
-#endif
-       {                                      32,
-   17,   44,   42,   36,   37,   19,   20,   49,    2,    3,
-   31,   14,    4,    5,    6,    7,    8,    9,   10,   34,
-   33,   21,   29,   22,   23,   35,   38,   46,   39,   50,
-   40,   41,   47,   24,   48,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,   20,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,   40,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,   26,    0,   39,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,   42,    0,    0,    0,    0,   43,
-   24,    0,    0,   25,   26,   27,   28,   29,   30,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,   17,   17,
-    0,    0,   17,   17,   17,   17,   17,   17,   17,   14,
-   14,    0,    0,   14,   14,   14,   14,   14,   14,   14,
-   29,   29,    0,    0,   29,   29,   29,   29,   29,   29,
-   29,   24,   24,    0,    0,   24,   24,   24,   24,   24,
-   24,   24,   20,   20,    0,    0,   20,   20,   20,   20,
-   20,   20,   20,   40,   40,    0,    0,   40,   40,   40,
-   40,    0,   40,   40,   26,   26,    0,   39,   26,   26,
-   26,   26,    0,    0,   26,   39,   39,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yycheck[] =
-#else
-short yycheck[] =
-#endif
-       {                                      47,
-    0,   58,  261,  266,  267,   44,  267,  266,  258,  259,
-   58,    0,  262,  263,  264,  265,  266,  267,  268,  257,
-  269,  262,    0,  264,  265,   44,  266,   47,  267,   47,
-  267,  267,  267,    0,  267,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,    0,   -1,    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,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,  261,   -1,   -1,   -1,   -1,  266,
-  258,   -1,   -1,  261,  262,  263,  264,  265,  266,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  258,  259,
-   -1,   -1,  262,  263,  264,  265,  266,  267,  268,  258,
-  259,   -1,   -1,  262,  263,  264,  265,  266,  267,  268,
-  258,  259,   -1,   -1,  262,  263,  264,  265,  266,  267,
-  268,  258,  259,   -1,   -1,  262,  263,  264,  265,  266,
-  267,  268,  258,  259,   -1,   -1,  262,  263,  264,  265,
-  266,  267,  268,  258,  259,   -1,   -1,  262,  263,  264,
-  265,   -1,  267,  268,  258,  259,   -1,  259,  262,  263,
-  264,  265,   -1,   -1,  268,  267,  268,
-};
-#define YYFINAL 1
-#ifndef YYDEBUG
-#define YYDEBUG 0
-#endif
-#define YYMAXTOKEN 269
-#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,0,0,0,"tAGO","tDAY",
-"tDAYZONE","tID","tMERIDIAN","tMINUTE_UNIT","tMONTH","tMONTH_UNIT","tSEC_UNIT",
-"tSNUMBER","tUNUMBER","tZONE","tDST",
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const char * const yyrule[] =
-#else
-char *yyrule[] =
-#endif
-       {"$accept : spec",
-"spec :",
-"spec : spec item",
-"item : time",
-"item : zone",
-"item : date",
-"item : day",
-"item : rel",
-"item : number",
-"time : tUNUMBER tMERIDIAN",
-"time : tUNUMBER ':' tUNUMBER o_merid",
-"time : tUNUMBER ':' tUNUMBER tSNUMBER",
-"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid",
-"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER",
-"zone : tZONE",
-"zone : tDAYZONE",
-"zone : tZONE tDST",
-"day : tDAY",
-"day : tDAY ','",
-"day : tUNUMBER tDAY",
-"date : tUNUMBER '/' tUNUMBER",
-"date : tUNUMBER '/' tUNUMBER '/' tUNUMBER",
-"date : tUNUMBER tSNUMBER tSNUMBER",
-"date : tUNUMBER tMONTH tSNUMBER",
-"date : tMONTH tUNUMBER",
-"date : tMONTH tUNUMBER ',' tUNUMBER",
-"date : tUNUMBER tMONTH",
-"date : tUNUMBER tMONTH tUNUMBER",
-"rel : relunit tAGO",
-"rel : relunit",
-"relunit : tUNUMBER tMINUTE_UNIT",
-"relunit : tSNUMBER tMINUTE_UNIT",
-"relunit : tMINUTE_UNIT",
-"relunit : tSNUMBER tSEC_UNIT",
-"relunit : tUNUMBER tSEC_UNIT",
-"relunit : tSEC_UNIT",
-"relunit : tSNUMBER tMONTH_UNIT",
-"relunit : tUNUMBER tMONTH_UNIT",
-"relunit : tMONTH_UNIT",
-"number : tUNUMBER",
-"o_merid :",
-"o_merid : tMERIDIAN",
-};
-#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 326 "getdate.y"
-
-/* Month and day table. */
-static TABLE const MonthDayTable[] = {
-    { "january",       tMONTH,  1 },
-    { "february",      tMONTH,  2 },
-    { "march",         tMONTH,  3 },
-    { "april",         tMONTH,  4 },
-    { "may",           tMONTH,  5 },
-    { "june",          tMONTH,  6 },
-    { "july",          tMONTH,  7 },
-    { "august",                tMONTH,  8 },
-    { "september",     tMONTH,  9 },
-    { "sept",          tMONTH,  9 },
-    { "october",       tMONTH, 10 },
-    { "november",      tMONTH, 11 },
-    { "december",      tMONTH, 12 },
-    { "sunday",                tDAY, 0 },
-    { "monday",                tDAY, 1 },
-    { "tuesday",       tDAY, 2 },
-    { "tues",          tDAY, 2 },
-    { "wednesday",     tDAY, 3 },
-    { "wednes",                tDAY, 3 },
-    { "thursday",      tDAY, 4 },
-    { "thur",          tDAY, 4 },
-    { "thurs",         tDAY, 4 },
-    { "friday",                tDAY, 5 },
-    { "saturday",      tDAY, 6 },
-    { NULL }
-};
-
-/* Time units table. */
-static TABLE const UnitsTable[] = {
-    { "year",          tMONTH_UNIT,    12 },
-    { "month",         tMONTH_UNIT,    1 },
-    { "fortnight",     tMINUTE_UNIT,   14 * 24 * 60 },
-    { "week",          tMINUTE_UNIT,   7 * 24 * 60 },
-    { "day",           tMINUTE_UNIT,   1 * 24 * 60 },
-    { "hour",          tMINUTE_UNIT,   60 },
-    { "minute",                tMINUTE_UNIT,   1 },
-    { "min",           tMINUTE_UNIT,   1 },
-    { "second",                tSEC_UNIT,      1 },
-    { "sec",           tSEC_UNIT,      1 },
-    { NULL }
-};
-
-/* Assorted relative-time words. */
-static TABLE const OtherTable[] = {
-    { "tomorrow",      tMINUTE_UNIT,   1 * 24 * 60 },
-    { "yesterday",     tMINUTE_UNIT,   -1 * 24 * 60 },
-    { "today",         tMINUTE_UNIT,   0 },
-    { "now",           tMINUTE_UNIT,   0 },
-    { "last",          tUNUMBER,       -1 },
-    { "this",          tMINUTE_UNIT,   0 },
-    { "next",          tUNUMBER,       2 },
-    { "first",         tUNUMBER,       1 },
-/*  { "second",                tUNUMBER,       2 }, */
-    { "third",         tUNUMBER,       3 },
-    { "fourth",                tUNUMBER,       4 },
-    { "fifth",         tUNUMBER,       5 },
-    { "sixth",         tUNUMBER,       6 },
-    { "seventh",       tUNUMBER,       7 },
-    { "eighth",                tUNUMBER,       8 },
-    { "ninth",         tUNUMBER,       9 },
-    { "tenth",         tUNUMBER,       10 },
-    { "eleventh",      tUNUMBER,       11 },
-    { "twelfth",       tUNUMBER,       12 },
-    { "ago",           tAGO,   1 },
-    { NULL }
-};
-
-/* The timezone table. */
-/* Some of these are commented out because a time_t can't store a float. */
-static TABLE const TimezoneTable[] = {
-    { "gmt",   tZONE,     HOUR( 0) },  /* Greenwich Mean */
-    { "ut",    tZONE,     HOUR( 0) },  /* Universal (Coordinated) */
-    { "utc",   tZONE,     HOUR( 0) },
-    { "wet",   tZONE,     HOUR( 0) },  /* Western European */
-    { "bst",   tDAYZONE,  HOUR( 0) },  /* British Summer */
-    { "wat",   tZONE,     HOUR( 1) },  /* West Africa */
-    { "at",    tZONE,     HOUR( 2) },  /* Azores */
-#if    0
-    /* For completeness.  BST is also British Summer, and GST is
-     * also Guam Standard. */
-    { "bst",   tZONE,     HOUR( 3) },  /* Brazil Standard */
-    { "gst",   tZONE,     HOUR( 3) },  /* Greenland Standard */
-#endif
-#if 0
-    { "nft",   tZONE,     HOUR(3.5) }, /* Newfoundland */
-    { "nst",   tZONE,     HOUR(3.5) }, /* Newfoundland Standard */
-    { "ndt",   tDAYZONE,  HOUR(3.5) }, /* Newfoundland Daylight */
-#endif
-    { "ast",   tZONE,     HOUR( 4) },  /* Atlantic Standard */
-    { "adt",   tDAYZONE,  HOUR( 4) },  /* Atlantic Daylight */
-    { "est",   tZONE,     HOUR( 5) },  /* Eastern Standard */
-    { "edt",   tDAYZONE,  HOUR( 5) },  /* Eastern Daylight */
-    { "cst",   tZONE,     HOUR( 6) },  /* Central Standard */
-    { "cdt",   tDAYZONE,  HOUR( 6) },  /* Central Daylight */
-    { "mst",   tZONE,     HOUR( 7) },  /* Mountain Standard */
-    { "mdt",   tDAYZONE,  HOUR( 7) },  /* Mountain Daylight */
-    { "pst",   tZONE,     HOUR( 8) },  /* Pacific Standard */
-    { "pdt",   tDAYZONE,  HOUR( 8) },  /* Pacific Daylight */
-    { "yst",   tZONE,     HOUR( 9) },  /* Yukon Standard */
-    { "ydt",   tDAYZONE,  HOUR( 9) },  /* Yukon Daylight */
-    { "hst",   tZONE,     HOUR(10) },  /* Hawaii Standard */
-    { "hdt",   tDAYZONE,  HOUR(10) },  /* Hawaii Daylight */
-    { "cat",   tZONE,     HOUR(10) },  /* Central Alaska */
-    { "ahst",  tZONE,     HOUR(10) },  /* Alaska-Hawaii Standard */
-    { "nt",    tZONE,     HOUR(11) },  /* Nome */
-    { "idlw",  tZONE,     HOUR(12) },  /* International Date Line West */
-    { "cet",   tZONE,     -HOUR(1) },  /* Central European */
-    { "met",   tZONE,     -HOUR(1) },  /* Middle European */
-    { "mewt",  tZONE,     -HOUR(1) },  /* Middle European Winter */
-    { "mest",  tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
-    { "swt",   tZONE,     -HOUR(1) },  /* Swedish Winter */
-    { "sst",   tDAYZONE,  -HOUR(1) },  /* Swedish Summer */
-    { "fwt",   tZONE,     -HOUR(1) },  /* French Winter */
-    { "fst",   tDAYZONE,  -HOUR(1) },  /* French Summer */
-    { "eet",   tZONE,     -HOUR(2) },  /* Eastern Europe, USSR Zone 1 */
-    { "bt",    tZONE,     -HOUR(3) },  /* Baghdad, USSR Zone 2 */
-#if 0
-    { "it",    tZONE,     -HOUR(3.5) },/* Iran */
-#endif
-    { "zp4",   tZONE,     -HOUR(4) },  /* USSR Zone 3 */
-    { "zp5",   tZONE,     -HOUR(5) },  /* USSR Zone 4 */
-#if 0
-    { "ist",   tZONE,     -HOUR(5.5) },/* Indian Standard */
-#endif
-    { "zp6",   tZONE,     -HOUR(6) },  /* USSR Zone 5 */
-#if    0
-    /* For completeness.  NST is also Newfoundland Stanard, and SST is
-     * also Swedish Summer. */
-    { "nst",   tZONE,     -HOUR(6.5) },/* North Sumatra */
-    { "sst",   tZONE,     -HOUR(7) },  /* South Sumatra, USSR Zone 6 */
-#endif /* 0 */
-    { "wast",  tZONE,     -HOUR(7) },  /* West Australian Standard */
-    { "wadt",  tDAYZONE,  -HOUR(7) },  /* West Australian Daylight */
-#if 0
-    { "jt",    tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
-#endif
-    { "cct",   tZONE,     -HOUR(8) },  /* China Coast, USSR Zone 7 */
-    { "jst",   tZONE,     -HOUR(9) },  /* Japan Standard, USSR Zone 8 */
-#if 0
-    { "cast",  tZONE,     -HOUR(9.5) },/* Central Australian Standard */
-    { "cadt",  tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
-#endif
-    { "east",  tZONE,     -HOUR(10) }, /* Eastern Australian Standard */
-    { "eadt",  tDAYZONE,  -HOUR(10) }, /* Eastern Australian Daylight */
-    { "gst",   tZONE,     -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
-    { "nzt",   tZONE,     -HOUR(12) }, /* New Zealand */
-    { "nzst",  tZONE,     -HOUR(12) }, /* New Zealand Standard */
-    { "nzdt",  tDAYZONE,  -HOUR(12) }, /* New Zealand Daylight */
-    { "idle",  tZONE,     -HOUR(12) }, /* International Date Line East */
-    {  NULL  }
-};
-
-/* Military timezone table. */
-static TABLE const MilitaryTable[] = {
-    { "a",     tZONE,  HOUR(  1) },
-    { "b",     tZONE,  HOUR(  2) },
-    { "c",     tZONE,  HOUR(  3) },
-    { "d",     tZONE,  HOUR(  4) },
-    { "e",     tZONE,  HOUR(  5) },
-    { "f",     tZONE,  HOUR(  6) },
-    { "g",     tZONE,  HOUR(  7) },
-    { "h",     tZONE,  HOUR(  8) },
-    { "i",     tZONE,  HOUR(  9) },
-    { "k",     tZONE,  HOUR( 10) },
-    { "l",     tZONE,  HOUR( 11) },
-    { "m",     tZONE,  HOUR( 12) },
-    { "n",     tZONE,  HOUR(- 1) },
-    { "o",     tZONE,  HOUR(- 2) },
-    { "p",     tZONE,  HOUR(- 3) },
-    { "q",     tZONE,  HOUR(- 4) },
-    { "r",     tZONE,  HOUR(- 5) },
-    { "s",     tZONE,  HOUR(- 6) },
-    { "t",     tZONE,  HOUR(- 7) },
-    { "u",     tZONE,  HOUR(- 8) },
-    { "v",     tZONE,  HOUR(- 9) },
-    { "w",     tZONE,  HOUR(-10) },
-    { "x",     tZONE,  HOUR(-11) },
-    { "y",     tZONE,  HOUR(-12) },
-    { "z",     tZONE,  HOUR(  0) },
-    { NULL }
-};
-
-\f
-
-
-/* ARGSUSED */
-static int
-yyerror(s)
-    char       *s;
-{
-  return 0;
-}
-
-
-static time_t
-ToSeconds(Hours, Minutes, Seconds, Meridian)
-    time_t     Hours;
-    time_t     Minutes;
-    time_t     Seconds;
-    MERIDIAN   Meridian;
-{
-    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
-       return -1;
-    switch (Meridian) {
-    case MER24:
-       if (Hours < 0 || Hours > 23)
-           return -1;
-       return (Hours * 60L + Minutes) * 60L + Seconds;
-    case MERam:
-       if (Hours < 1 || Hours > 12)
-           return -1;
-       if (Hours == 12)
-           Hours = 0;
-       return (Hours * 60L + Minutes) * 60L + Seconds;
-    case MERpm:
-       if (Hours < 1 || Hours > 12)
-           return -1;
-       if (Hours == 12)
-           Hours = 0;
-       return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
-    default:
-       abort ();
-    }
-    /* NOTREACHED */
-}
-
-
-/* Year is either
-   * A negative number, which means to use its absolute value (why?)
-   * A number from 0 to 99, which means a year from 1900 to 1999, or
-   * The actual year (>=100).  */
-static time_t
-Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
-    time_t     Month;
-    time_t     Day;
-    time_t     Year;
-    time_t     Hours;
-    time_t     Minutes;
-    time_t     Seconds;
-    MERIDIAN   Meridian;
-    DSTMODE    DSTmode;
-{
-    static int DaysInMonth[12] = {
-       31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-    };
-    time_t     tod;
-    time_t     Julian;
-    int                i;
-
-    if (Year < 0)
-       Year = -Year;
-    if (Year < 69)
-       Year += 2000;
-    else if (Year < 100) {
-       Year += 1900;
-       if (Year < EPOCH)
-               Year += 100;
-    }
-    DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
-                   ? 29 : 28;
-    /* Checking for 2038 bogusly assumes that time_t is 32 bits.  But
-       I'm too lazy to try to check for time_t overflow in another way.  */
-    if (Year < EPOCH || Year > 2038
-     || Month < 1 || Month > 12
-     /* Lint fluff:  "conversion from long may lose accuracy" */
-     || Day < 1 || Day > DaysInMonth[(int)--Month])
-       return -1;
-
-    for (Julian = Day - 1, i = 0; i < Month; i++)
-       Julian += DaysInMonth[i];
-    for (i = EPOCH; i < Year; i++)
-       Julian += 365 + (i % 4 == 0);
-    Julian *= SECSPERDAY;
-    Julian += yyTimezone * 60L;
-    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
-       return -1;
-    Julian += tod;
-    if (DSTmode == DSTon
-     || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
-       Julian -= 60 * 60;
-    return Julian;
-}
-
-
-static time_t
-DSTcorrect(Start, Future)
-    time_t     Start;
-    time_t     Future;
-{
-    time_t     StartDay;
-    time_t     FutureDay;
-
-    StartDay = (localtime(&Start)->tm_hour + 1) % 24;
-    FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
-    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
-}
-
-
-static time_t
-RelativeDate(Start, DayOrdinal, DayNumber)
-    time_t     Start;
-    time_t     DayOrdinal;
-    time_t     DayNumber;
-{
-    struct tm  *tm;
-    time_t     now;
-
-    now = Start;
-    tm = localtime(&now);
-    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
-    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
-    return DSTcorrect(Start, now);
-}
-
-
-static time_t
-RelativeMonth(Start, RelMonth)
-    time_t     Start;
-    time_t     RelMonth;
-{
-    struct tm  *tm;
-    time_t     Month;
-    time_t     Year;
-
-    if (RelMonth == 0)
-       return 0;
-    tm = localtime(&Start);
-    Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
-    Year = Month / 12;
-    Month = Month % 12 + 1;
-    return DSTcorrect(Start,
-           Convert(Month, (time_t)tm->tm_mday, Year,
-               (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
-               MER24, DSTmaybe));
-}
-
-
-static int
-LookupWord(buff)
-    char               *buff;
-{
-    char               *p;
-    char               *q;
-    const TABLE                *tp;
-    int                        i;
-    int                        abbrev;
-
-    /* Make it lowercase. */
-    for (p = buff; *p; p++)
-       if (isupper((unsigned char)*p))
-           *p = tolower((unsigned char)*p);
-
-    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
-       yylval.Meridian = MERam;
-       return tMERIDIAN;
-    }
-    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
-       yylval.Meridian = MERpm;
-       return tMERIDIAN;
-    }
-
-    /* See if we have an abbreviation for a month. */
-    if (strlen(buff) == 3)
-       abbrev = 1;
-    else if (strlen(buff) == 4 && buff[3] == '.') {
-       abbrev = 1;
-       buff[3] = '\0';
-    }
-    else
-       abbrev = 0;
-
-    for (tp = MonthDayTable; tp->name; tp++) {
-       if (abbrev) {
-           if (strncmp(buff, tp->name, 3) == 0) {
-               yylval.Number = tp->value;
-               return tp->type;
-           }
-       }
-       else if (strcmp(buff, tp->name) == 0) {
-           yylval.Number = tp->value;
-           return tp->type;
-       }
-    }
-
-    for (tp = TimezoneTable; tp->name; tp++)
-       if (strcmp(buff, tp->name) == 0) {
-           yylval.Number = tp->value;
-           return tp->type;
-       }
-
-    if (strcmp(buff, "dst") == 0) 
-       return tDST;
-
-    for (tp = UnitsTable; tp->name; tp++)
-       if (strcmp(buff, tp->name) == 0) {
-           yylval.Number = tp->value;
-           return tp->type;
-       }
-
-    /* Strip off any plural and try the units table again. */
-    i = strlen(buff) - 1;
-    if (buff[i] == 's') {
-       buff[i] = '\0';
-       for (tp = UnitsTable; tp->name; tp++)
-           if (strcmp(buff, tp->name) == 0) {
-               yylval.Number = tp->value;
-               return tp->type;
-           }
-       buff[i] = 's';          /* Put back for "this" in OtherTable. */
-    }
-
-    for (tp = OtherTable; tp->name; tp++)
-       if (strcmp(buff, tp->name) == 0) {
-           yylval.Number = tp->value;
-           return tp->type;
-       }
-
-    /* Military timezones. */
-    if (buff[1] == '\0' && isalpha((unsigned char)*buff)) {
-       for (tp = MilitaryTable; tp->name; tp++)
-           if (strcmp(buff, tp->name) == 0) {
-               yylval.Number = tp->value;
-               return tp->type;
-           }
-    }
-
-    /* Drop out any periods and try the timezone table again. */
-    for (i = 0, p = q = buff; *q; q++)
-       if (*q != '.')
-           *p++ = *q;
-       else
-           i++;
-    *p = '\0';
-    if (i)
-       for (tp = TimezoneTable; tp->name; tp++)
-           if (strcmp(buff, tp->name) == 0) {
-               yylval.Number = tp->value;
-               return tp->type;
-           }
-
-    return tID;
-}
-
-
-static int
-yylex()
-{
-    char               c;
-    char               *p;
-    char               buff[20];
-    int                        Count;
-    int                        sign;
-
-    for ( ; ; ) {
-       while (isspace((unsigned char)*yyInput))
-           yyInput++;
-
-       if (isdigit((unsigned char)(c = *yyInput)) || c == '-' || c == '+') {
-           if (c == '-' || c == '+') {
-               sign = c == '-' ? -1 : 1;
-               if (!isdigit((unsigned char)*++yyInput))
-                   /* skip the '-' sign */
-                   continue;
-           }
-           else
-               sign = 0;
-           for (yylval.Number = 0; isdigit((unsigned char)(c = *yyInput++)); )
-               yylval.Number = 10 * yylval.Number + c - '0';
-           yyInput--;
-           if (sign < 0)
-               yylval.Number = -yylval.Number;
-           return sign ? tSNUMBER : tUNUMBER;
-       }
-       if (isalpha((unsigned char)c)) {
-           for (p = buff; isalpha((unsigned char)(c = *yyInput++)) || c == '.'; )
-               if (p < &buff[sizeof buff - 1])
-                   *p++ = c;
-           *p = '\0';
-           yyInput--;
-           return LookupWord(buff);
-       }
-       if (c != '(')
-           return *yyInput++;
-       Count = 0;
-       do {
-           c = *yyInput++;
-           if (c == '\0')
-               return c;
-           if (c == '(')
-               Count++;
-           else if (c == ')')
-               Count--;
-       } while (Count > 0);
-    }
-}
-
-#define TM_YEAR_ORIGIN 1900
-
-/* Yield A - B, measured in seconds.  */
-static long
-difftm (a, b)
-     struct tm *a, *b;
-{
-  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
-  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
-  int days = (
-             /* difference in day of year */
-             a->tm_yday - b->tm_yday
-             /* + intervening leap days */
-             +  ((ay >> 2) - (by >> 2))
-             -  (ay/100 - by/100)
-             +  ((ay/100 >> 2) - (by/100 >> 2))
-             /* + difference in years * 365 */
-             +  (long)(ay-by) * 365
-             );
-  return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
-             + (a->tm_min - b->tm_min))
-         + (a->tm_sec - b->tm_sec));
-}
-
-time_t
-get_date(p)
-    char               *p;
-{
-    struct tm          *tm, *gmt, gmtbuf;
-    time_t             Start;
-    time_t             tod;
-    time_t             now;
-    time_t             timezone;
-
-    yyInput = p;
-    (void)time (&now);
-
-    gmt = gmtime (&now);
-    if (gmt != NULL)
-    {
-       /* Make a copy, in case localtime modifies *tm (I think
-          that comment now applies to *gmt, but I am too
-          lazy to dig into how gmtime and locatime allocate the
-          structures they return pointers to).  */
-       gmtbuf = *gmt;
-       gmt = &gmtbuf;
-    }
-
-    if (! (tm = localtime (&now)))
-       return -1;
-
-    if (gmt != NULL)
-       timezone = difftm (gmt, tm) / 60;
-    else
-       /* We are on a system like VMS, where the system clock is
-          in local time and the system has no concept of timezones.
-          Hopefully we can fake this out (for the case in which the
-          user specifies no timezone) by just saying the timezone
-          is zero.  */
-       timezone = 0;
-
-    if(tm->tm_isdst)
-       timezone += 60;
-
-    tm = localtime(&now);
-    yyYear = tm->tm_year + 1900;
-    yyMonth = tm->tm_mon + 1;
-    yyDay = tm->tm_mday;
-    yyTimezone = timezone;
-    yyDSTmode = DSTmaybe;
-    yyHour = 0;
-    yyMinutes = 0;
-    yySeconds = 0;
-    yyMeridian = MER24;
-    yyRelSeconds = 0;
-    yyRelMonth = 0;
-    yyHaveDate = 0;
-    yyHaveDay = 0;
-    yyHaveRel = 0;
-    yyHaveTime = 0;
-    yyHaveZone = 0;
-
-    if (yyparse()
-     || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
-       return -1;
-
-    if (yyHaveDate || yyHaveTime || yyHaveDay) {
-       Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
-                   yyMeridian, yyDSTmode);
-       if (Start < 0)
-           return -1;
-    }
-    else {
-       Start = now;
-       if (!yyHaveRel)
-           Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
-    }
-
-    Start += yyRelSeconds;
-    Start += RelativeMonth(Start, yyRelMonth);
-
-    if (yyHaveDay && !yyHaveDate) {
-       tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
-       Start += tod;
-    }
-
-    /* Have to do *something* with a legitimate -1 so it's distinguishable
-     * from the error return value.  (Alternately could set errno on error.) */
-    return Start == -1 ? 0 : Start;
-}
-
-
-#if    defined(TEST)
-
-/* ARGSUSED */
-int
-main(ac, av)
-    int                ac;
-    char       *av[];
-{
-    char       buff[128];
-    time_t     d;
-
-    (void)printf("Enter date, or blank line to exit.\n\t> ");
-    (void)fflush(stdout);
-    while (gets(buff) && buff[0]) {
-       d = get_date(buff);
-       if (d == -1)
-           (void)printf("Bad format - couldn't convert.\n");
-       else
-           (void)printf("%s", ctime(&d));
-       (void)printf("\t> ");
-       (void)fflush(stdout);
-    }
-    exit(0);
-    /* NOTREACHED */
-}
-#endif /* defined(TEST) */
-#line 979 "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 3:
-#line 125 "getdate.y"
-{
-           yyHaveTime++;
-       }
-break;
-case 4:
-#line 128 "getdate.y"
-{
-           yyHaveZone++;
-       }
-break;
-case 5:
-#line 131 "getdate.y"
-{
-           yyHaveDate++;
-       }
-break;
-case 6:
-#line 134 "getdate.y"
-{
-           yyHaveDay++;
-       }
-break;
-case 7:
-#line 137 "getdate.y"
-{
-           yyHaveRel++;
-       }
-break;
-case 9:
-#line 143 "getdate.y"
-{
-           yyHour = yyvsp[-1].Number;
-           yyMinutes = 0;
-           yySeconds = 0;
-           yyMeridian = yyvsp[0].Meridian;
-       }
-break;
-case 10:
-#line 149 "getdate.y"
-{
-           yyHour = yyvsp[-3].Number;
-           yyMinutes = yyvsp[-1].Number;
-           yySeconds = 0;
-           yyMeridian = yyvsp[0].Meridian;
-       }
-break;
-case 11:
-#line 155 "getdate.y"
-{
-           yyHour = yyvsp[-3].Number;
-           yyMinutes = yyvsp[-1].Number;
-           yyMeridian = MER24;
-           yyDSTmode = DSToff;
-           yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60);
-       }
-break;
-case 12:
-#line 162 "getdate.y"
-{
-           yyHour = yyvsp[-5].Number;
-           yyMinutes = yyvsp[-3].Number;
-           yySeconds = yyvsp[-1].Number;
-           yyMeridian = yyvsp[0].Meridian;
-       }
-break;
-case 13:
-#line 168 "getdate.y"
-{
-           yyHour = yyvsp[-5].Number;
-           yyMinutes = yyvsp[-3].Number;
-           yySeconds = yyvsp[-1].Number;
-           yyMeridian = MER24;
-           yyDSTmode = DSToff;
-           yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60);
-       }
-break;
-case 14:
-#line 178 "getdate.y"
-{
-           yyTimezone = yyvsp[0].Number;
-           yyDSTmode = DSToff;
-       }
-break;
-case 15:
-#line 182 "getdate.y"
-{
-           yyTimezone = yyvsp[0].Number;
-           yyDSTmode = DSTon;
-       }
-break;
-case 16:
-#line 187 "getdate.y"
-{
-           yyTimezone = yyvsp[-1].Number;
-           yyDSTmode = DSTon;
-       }
-break;
-case 17:
-#line 193 "getdate.y"
-{
-           yyDayOrdinal = 1;
-           yyDayNumber = yyvsp[0].Number;
-       }
-break;
-case 18:
-#line 197 "getdate.y"
-{
-           yyDayOrdinal = 1;
-           yyDayNumber = yyvsp[-1].Number;
-       }
-break;
-case 19:
-#line 201 "getdate.y"
-{
-           yyDayOrdinal = yyvsp[-1].Number;
-           yyDayNumber = yyvsp[0].Number;
-       }
-break;
-case 20:
-#line 207 "getdate.y"
-{
-           yyMonth = yyvsp[-2].Number;
-           yyDay = yyvsp[0].Number;
-       }
-break;
-case 21:
-#line 211 "getdate.y"
-{
-           if (yyvsp[-4].Number >= 100) {
-               yyYear = yyvsp[-4].Number;
-               yyMonth = yyvsp[-2].Number;
-               yyDay = yyvsp[0].Number;
-           } else {
-               yyMonth = yyvsp[-4].Number;
-               yyDay = yyvsp[-2].Number;
-               yyYear = yyvsp[0].Number;
-           }
-       }
-break;
-case 22:
-#line 222 "getdate.y"
-{
-           /* ISO 8601 format.  yyyy-mm-dd.  */
-           yyYear = yyvsp[-2].Number;
-           yyMonth = -yyvsp[-1].Number;
-           yyDay = -yyvsp[0].Number;
-       }
-break;
-case 23:
-#line 228 "getdate.y"
-{
-           /* e.g. 17-JUN-1992.  */
-           yyDay = yyvsp[-2].Number;
-           yyMonth = yyvsp[-1].Number;
-           yyYear = -yyvsp[0].Number;
-       }
-break;
-case 24:
-#line 234 "getdate.y"
-{
-           yyMonth = yyvsp[-1].Number;
-           yyDay = yyvsp[0].Number;
-       }
-break;
-case 25:
-#line 238 "getdate.y"
-{
-           yyMonth = yyvsp[-3].Number;
-           yyDay = yyvsp[-2].Number;
-           yyYear = yyvsp[0].Number;
-       }
-break;
-case 26:
-#line 243 "getdate.y"
-{
-           yyMonth = yyvsp[0].Number;
-           yyDay = yyvsp[-1].Number;
-       }
-break;
-case 27:
-#line 247 "getdate.y"
-{
-           yyMonth = yyvsp[-1].Number;
-           yyDay = yyvsp[-2].Number;
-           yyYear = yyvsp[0].Number;
-       }
-break;
-case 28:
-#line 254 "getdate.y"
-{
-           yyRelSeconds = -yyRelSeconds;
-           yyRelMonth = -yyRelMonth;
-       }
-break;
-case 30:
-#line 261 "getdate.y"
-{
-           yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L;
-       }
-break;
-case 31:
-#line 264 "getdate.y"
-{
-           yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L;
-       }
-break;
-case 32:
-#line 267 "getdate.y"
-{
-           yyRelSeconds += yyvsp[0].Number * 60L;
-       }
-break;
-case 33:
-#line 270 "getdate.y"
-{
-           yyRelSeconds += yyvsp[-1].Number;
-       }
-break;
-case 34:
-#line 273 "getdate.y"
-{
-           yyRelSeconds += yyvsp[-1].Number;
-       }
-break;
-case 35:
-#line 276 "getdate.y"
-{
-           yyRelSeconds++;
-       }
-break;
-case 36:
-#line 279 "getdate.y"
-{
-           yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
-       }
-break;
-case 37:
-#line 282 "getdate.y"
-{
-           yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
-       }
-break;
-case 38:
-#line 285 "getdate.y"
-{
-           yyRelMonth += yyvsp[0].Number;
-       }
-break;
-case 39:
-#line 290 "getdate.y"
-{
-           if (yyHaveTime && yyHaveDate && !yyHaveRel)
-               yyYear = yyvsp[0].Number;
-           else {
-               if(yyvsp[0].Number>10000) {
-                   yyHaveDate++;
-                   yyDay= (yyvsp[0].Number)%100;
-                   yyMonth= (yyvsp[0].Number/100)%100;
-                   yyYear = yyvsp[0].Number/10000;
-               }
-               else {
-                   yyHaveTime++;
-                   if (yyvsp[0].Number < 100) {
-                       yyHour = yyvsp[0].Number;
-                       yyMinutes = 0;
-                   }
-                   else {
-                       yyHour = yyvsp[0].Number / 100;
-                       yyMinutes = yyvsp[0].Number % 100;
-                   }
-                   yySeconds = 0;
-                   yyMeridian = MER24;
-               }
-           }
-       }
-break;
-case 40:
-#line 317 "getdate.y"
-{
-           yyval.Meridian = MER24;
-       }
-break;
-case 41:
-#line 320 "getdate.y"
-{
-           yyval.Meridian = yyvsp[0].Meridian;
-       }
-break;
-#line 1474 "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/getdate.y b/getdate.y
deleted file mode 100644 (file)
index 7094083..0000000
--- a/getdate.y
+++ /dev/null
@@ -1,962 +0,0 @@
-%{
-/*
-**  Originally written by Steven M. Bellovin <smb@research.att.com> while
-**  at the University of North Carolina at Chapel Hill.  Later tweaked by
-**  a couple of people on Usenet.  Completely overhauled by Rich $alz
-**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
-**
-**  This grammar has 10 shift/reduce conflicts.
-**
-**  This code is in the public domain and has no copyright.
-*/
-/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
-/* SUPPRESS 288 on yyerrlab *//* Label unused */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/time.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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-#include <ctype.h>
-
-#include "missing.h"
-
-
-#define EPOCH          1970
-#define HOUR(x)                ((time_t)(x) * 60)
-#define SECSPERDAY     (24L * 60L * 60L)
-
-
-/*
-**  An entry in the lexical lookup table.
-*/
-typedef struct _TABLE {
-    char       *name;
-    int                type;
-    time_t     value;
-} TABLE;
-
-
-/*
-**  Daylight-savings mode:  on, off, or not yet known.
-*/
-typedef enum _DSTMODE {
-    DSTon, DSToff, DSTmaybe
-} DSTMODE;
-
-/*
-**  Meridian:  am, pm, or 24-hour style.
-*/
-typedef enum _MERIDIAN {
-    MERam, MERpm, MER24
-} MERIDIAN;
-
-
-/*
-**  Global variables.  We could get rid of most of these by using a good
-**  union as the yacc stack.  (This routine was originally written before
-**  yacc had the %union construct.)  Maybe someday; right now we only use
-**  the %union very rarely.
-*/
-static char    *yyInput;
-static DSTMODE yyDSTmode;
-static time_t  yyDayOrdinal;
-static time_t  yyDayNumber;
-static int     yyHaveDate;
-static int     yyHaveDay;
-static int     yyHaveRel;
-static int     yyHaveTime;
-static int     yyHaveZone;
-static time_t  yyTimezone;
-static time_t  yyDay;
-static time_t  yyHour;
-static time_t  yyMinutes;
-static time_t  yyMonth;
-static time_t  yySeconds;
-static time_t  yyYear;
-static MERIDIAN        yyMeridian;
-static time_t  yyRelMonth;
-static time_t  yyRelSeconds;
-
-static int     yyerror __P((char *s));
-static int     yylex __P((void));
-static int     yyparse __P((void));
-
-%}
-
-%union {
-    time_t             Number;
-    enum _MERIDIAN     Meridian;
-}
-
-%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
-%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
-
-%type  <Number>        tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
-%type  <Number>        tSEC_UNIT tSNUMBER tUNUMBER tZONE
-%type  <Meridian>      tMERIDIAN o_merid
-
-%%
-
-spec   : /* NULL */
-       | spec item
-       ;
-
-item   : time {
-           yyHaveTime++;
-       }
-       | zone {
-           yyHaveZone++;
-       }
-       | date {
-           yyHaveDate++;
-       }
-       | day {
-           yyHaveDay++;
-       }
-       | rel {
-           yyHaveRel++;
-       }
-       | number
-       ;
-
-time   : tUNUMBER tMERIDIAN {
-           yyHour = $1;
-           yyMinutes = 0;
-           yySeconds = 0;
-           yyMeridian = $2;
-       }
-       | tUNUMBER ':' tUNUMBER o_merid {
-           yyHour = $1;
-           yyMinutes = $3;
-           yySeconds = 0;
-           yyMeridian = $4;
-       }
-       | tUNUMBER ':' tUNUMBER tSNUMBER {
-           yyHour = $1;
-           yyMinutes = $3;
-           yyMeridian = MER24;
-           yyDSTmode = DSToff;
-           yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
-       }
-       | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
-           yyHour = $1;
-           yyMinutes = $3;
-           yySeconds = $5;
-           yyMeridian = $6;
-       }
-       | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
-           yyHour = $1;
-           yyMinutes = $3;
-           yySeconds = $5;
-           yyMeridian = MER24;
-           yyDSTmode = DSToff;
-           yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
-       }
-       ;
-
-zone   : tZONE {
-           yyTimezone = $1;
-           yyDSTmode = DSToff;
-       }
-       | tDAYZONE {
-           yyTimezone = $1;
-           yyDSTmode = DSTon;
-       }
-       |
-         tZONE tDST {
-           yyTimezone = $1;
-           yyDSTmode = DSTon;
-       }
-       ;
-
-day    : tDAY {
-           yyDayOrdinal = 1;
-           yyDayNumber = $1;
-       }
-       | tDAY ',' {
-           yyDayOrdinal = 1;
-           yyDayNumber = $1;
-       }
-       | tUNUMBER tDAY {
-           yyDayOrdinal = $1;
-           yyDayNumber = $2;
-       }
-       ;
-
-date   : tUNUMBER '/' tUNUMBER {
-           yyMonth = $1;
-           yyDay = $3;
-       }
-       | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
-           if ($1 >= 100) {
-               yyYear = $1;
-               yyMonth = $3;
-               yyDay = $5;
-           } else {
-               yyMonth = $1;
-               yyDay = $3;
-               yyYear = $5;
-           }
-       }
-       | tUNUMBER tSNUMBER tSNUMBER {
-           /* ISO 8601 format.  yyyy-mm-dd.  */
-           yyYear = $1;
-           yyMonth = -$2;
-           yyDay = -$3;
-       }
-       | tUNUMBER tMONTH tSNUMBER {
-           /* e.g. 17-JUN-1992.  */
-           yyDay = $1;
-           yyMonth = $2;
-           yyYear = -$3;
-       }
-       | tMONTH tUNUMBER {
-           yyMonth = $1;
-           yyDay = $2;
-       }
-       | tMONTH tUNUMBER ',' tUNUMBER {
-           yyMonth = $1;
-           yyDay = $2;
-           yyYear = $4;
-       }
-       | tUNUMBER tMONTH {
-           yyMonth = $2;
-           yyDay = $1;
-       }
-       | tUNUMBER tMONTH tUNUMBER {
-           yyMonth = $2;
-           yyDay = $1;
-           yyYear = $3;
-       }
-       ;
-
-rel    : relunit tAGO {
-           yyRelSeconds = -yyRelSeconds;
-           yyRelMonth = -yyRelMonth;
-       }
-       | relunit
-       ;
-
-relunit        : tUNUMBER tMINUTE_UNIT {
-           yyRelSeconds += $1 * $2 * 60L;
-       }
-       | tSNUMBER tMINUTE_UNIT {
-           yyRelSeconds += $1 * $2 * 60L;
-       }
-       | tMINUTE_UNIT {
-           yyRelSeconds += $1 * 60L;
-       }
-       | tSNUMBER tSEC_UNIT {
-           yyRelSeconds += $1;
-       }
-       | tUNUMBER tSEC_UNIT {
-           yyRelSeconds += $1;
-       }
-       | tSEC_UNIT {
-           yyRelSeconds++;
-       }
-       | tSNUMBER tMONTH_UNIT {
-           yyRelMonth += $1 * $2;
-       }
-       | tUNUMBER tMONTH_UNIT {
-           yyRelMonth += $1 * $2;
-       }
-       | tMONTH_UNIT {
-           yyRelMonth += $1;
-       }
-       ;
-
-number : tUNUMBER {
-           if (yyHaveTime && yyHaveDate && !yyHaveRel)
-               yyYear = $1;
-           else {
-               if($1>10000) {
-                   yyHaveDate++;
-                   yyDay= ($1)%100;
-                   yyMonth= ($1/100)%100;
-                   yyYear = $1/10000;
-               }
-               else {
-                   yyHaveTime++;
-                   if ($1 < 100) {
-                       yyHour = $1;
-                       yyMinutes = 0;
-                   }
-                   else {
-                       yyHour = $1 / 100;
-                       yyMinutes = $1 % 100;
-                   }
-                   yySeconds = 0;
-                   yyMeridian = MER24;
-               }
-           }
-       }
-       ;
-
-o_merid        : /* NULL */ {
-           $$ = MER24;
-       }
-       | tMERIDIAN {
-           $$ = $1;
-       }
-       ;
-
-%%
-
-/* Month and day table. */
-static TABLE const MonthDayTable[] = {
-    { "january",       tMONTH,  1 },
-    { "february",      tMONTH,  2 },
-    { "march",         tMONTH,  3 },
-    { "april",         tMONTH,  4 },
-    { "may",           tMONTH,  5 },
-    { "june",          tMONTH,  6 },
-    { "july",          tMONTH,  7 },
-    { "august",                tMONTH,  8 },
-    { "september",     tMONTH,  9 },
-    { "sept",          tMONTH,  9 },
-    { "october",       tMONTH, 10 },
-    { "november",      tMONTH, 11 },
-    { "december",      tMONTH, 12 },
-    { "sunday",                tDAY, 0 },
-    { "monday",                tDAY, 1 },
-    { "tuesday",       tDAY, 2 },
-    { "tues",          tDAY, 2 },
-    { "wednesday",     tDAY, 3 },
-    { "wednes",                tDAY, 3 },
-    { "thursday",      tDAY, 4 },
-    { "thur",          tDAY, 4 },
-    { "thurs",         tDAY, 4 },
-    { "friday",                tDAY, 5 },
-    { "saturday",      tDAY, 6 },
-    { NULL }
-};
-
-/* Time units table. */
-static TABLE const UnitsTable[] = {
-    { "year",          tMONTH_UNIT,    12 },
-    { "month",         tMONTH_UNIT,    1 },
-    { "fortnight",     tMINUTE_UNIT,   14 * 24 * 60 },
-    { "week",          tMINUTE_UNIT,   7 * 24 * 60 },
-    { "day",           tMINUTE_UNIT,   1 * 24 * 60 },
-    { "hour",          tMINUTE_UNIT,   60 },
-    { "minute",                tMINUTE_UNIT,   1 },
-    { "min",           tMINUTE_UNIT,   1 },
-    { "second",                tSEC_UNIT,      1 },
-    { "sec",           tSEC_UNIT,      1 },
-    { NULL }
-};
-
-/* Assorted relative-time words. */
-static TABLE const OtherTable[] = {
-    { "tomorrow",      tMINUTE_UNIT,   1 * 24 * 60 },
-    { "yesterday",     tMINUTE_UNIT,   -1 * 24 * 60 },
-    { "today",         tMINUTE_UNIT,   0 },
-    { "now",           tMINUTE_UNIT,   0 },
-    { "last",          tUNUMBER,       -1 },
-    { "this",          tMINUTE_UNIT,   0 },
-    { "next",          tUNUMBER,       2 },
-    { "first",         tUNUMBER,       1 },
-/*  { "second",                tUNUMBER,       2 }, */
-    { "third",         tUNUMBER,       3 },
-    { "fourth",                tUNUMBER,       4 },
-    { "fifth",         tUNUMBER,       5 },
-    { "sixth",         tUNUMBER,       6 },
-    { "seventh",       tUNUMBER,       7 },
-    { "eighth",                tUNUMBER,       8 },
-    { "ninth",         tUNUMBER,       9 },
-    { "tenth",         tUNUMBER,       10 },
-    { "eleventh",      tUNUMBER,       11 },
-    { "twelfth",       tUNUMBER,       12 },
-    { "ago",           tAGO,   1 },
-    { NULL }
-};
-
-/* The timezone table. */
-/* Some of these are commented out because a time_t can't store a float. */
-static TABLE const TimezoneTable[] = {
-    { "gmt",   tZONE,     HOUR( 0) },  /* Greenwich Mean */
-    { "ut",    tZONE,     HOUR( 0) },  /* Universal (Coordinated) */
-    { "utc",   tZONE,     HOUR( 0) },
-    { "wet",   tZONE,     HOUR( 0) },  /* Western European */
-    { "bst",   tDAYZONE,  HOUR( 0) },  /* British Summer */
-    { "wat",   tZONE,     HOUR( 1) },  /* West Africa */
-    { "at",    tZONE,     HOUR( 2) },  /* Azores */
-#if    0
-    /* For completeness.  BST is also British Summer, and GST is
-     * also Guam Standard. */
-    { "bst",   tZONE,     HOUR( 3) },  /* Brazil Standard */
-    { "gst",   tZONE,     HOUR( 3) },  /* Greenland Standard */
-#endif
-#if 0
-    { "nft",   tZONE,     HOUR(3.5) }, /* Newfoundland */
-    { "nst",   tZONE,     HOUR(3.5) }, /* Newfoundland Standard */
-    { "ndt",   tDAYZONE,  HOUR(3.5) }, /* Newfoundland Daylight */
-#endif
-    { "ast",   tZONE,     HOUR( 4) },  /* Atlantic Standard */
-    { "adt",   tDAYZONE,  HOUR( 4) },  /* Atlantic Daylight */
-    { "est",   tZONE,     HOUR( 5) },  /* Eastern Standard */
-    { "edt",   tDAYZONE,  HOUR( 5) },  /* Eastern Daylight */
-    { "cst",   tZONE,     HOUR( 6) },  /* Central Standard */
-    { "cdt",   tDAYZONE,  HOUR( 6) },  /* Central Daylight */
-    { "mst",   tZONE,     HOUR( 7) },  /* Mountain Standard */
-    { "mdt",   tDAYZONE,  HOUR( 7) },  /* Mountain Daylight */
-    { "pst",   tZONE,     HOUR( 8) },  /* Pacific Standard */
-    { "pdt",   tDAYZONE,  HOUR( 8) },  /* Pacific Daylight */
-    { "yst",   tZONE,     HOUR( 9) },  /* Yukon Standard */
-    { "ydt",   tDAYZONE,  HOUR( 9) },  /* Yukon Daylight */
-    { "hst",   tZONE,     HOUR(10) },  /* Hawaii Standard */
-    { "hdt",   tDAYZONE,  HOUR(10) },  /* Hawaii Daylight */
-    { "cat",   tZONE,     HOUR(10) },  /* Central Alaska */
-    { "ahst",  tZONE,     HOUR(10) },  /* Alaska-Hawaii Standard */
-    { "nt",    tZONE,     HOUR(11) },  /* Nome */
-    { "idlw",  tZONE,     HOUR(12) },  /* International Date Line West */
-    { "cet",   tZONE,     -HOUR(1) },  /* Central European */
-    { "met",   tZONE,     -HOUR(1) },  /* Middle European */
-    { "mewt",  tZONE,     -HOUR(1) },  /* Middle European Winter */
-    { "mest",  tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
-    { "swt",   tZONE,     -HOUR(1) },  /* Swedish Winter */
-    { "sst",   tDAYZONE,  -HOUR(1) },  /* Swedish Summer */
-    { "fwt",   tZONE,     -HOUR(1) },  /* French Winter */
-    { "fst",   tDAYZONE,  -HOUR(1) },  /* French Summer */
-    { "eet",   tZONE,     -HOUR(2) },  /* Eastern Europe, USSR Zone 1 */
-    { "bt",    tZONE,     -HOUR(3) },  /* Baghdad, USSR Zone 2 */
-#if 0
-    { "it",    tZONE,     -HOUR(3.5) },/* Iran */
-#endif
-    { "zp4",   tZONE,     -HOUR(4) },  /* USSR Zone 3 */
-    { "zp5",   tZONE,     -HOUR(5) },  /* USSR Zone 4 */
-#if 0
-    { "ist",   tZONE,     -HOUR(5.5) },/* Indian Standard */
-#endif
-    { "zp6",   tZONE,     -HOUR(6) },  /* USSR Zone 5 */
-#if    0
-    /* For completeness.  NST is also Newfoundland Stanard, and SST is
-     * also Swedish Summer. */
-    { "nst",   tZONE,     -HOUR(6.5) },/* North Sumatra */
-    { "sst",   tZONE,     -HOUR(7) },  /* South Sumatra, USSR Zone 6 */
-#endif /* 0 */
-    { "wast",  tZONE,     -HOUR(7) },  /* West Australian Standard */
-    { "wadt",  tDAYZONE,  -HOUR(7) },  /* West Australian Daylight */
-#if 0
-    { "jt",    tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
-#endif
-    { "cct",   tZONE,     -HOUR(8) },  /* China Coast, USSR Zone 7 */
-    { "jst",   tZONE,     -HOUR(9) },  /* Japan Standard, USSR Zone 8 */
-#if 0
-    { "cast",  tZONE,     -HOUR(9.5) },/* Central Australian Standard */
-    { "cadt",  tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
-#endif
-    { "east",  tZONE,     -HOUR(10) }, /* Eastern Australian Standard */
-    { "eadt",  tDAYZONE,  -HOUR(10) }, /* Eastern Australian Daylight */
-    { "gst",   tZONE,     -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
-    { "nzt",   tZONE,     -HOUR(12) }, /* New Zealand */
-    { "nzst",  tZONE,     -HOUR(12) }, /* New Zealand Standard */
-    { "nzdt",  tDAYZONE,  -HOUR(12) }, /* New Zealand Daylight */
-    { "idle",  tZONE,     -HOUR(12) }, /* International Date Line East */
-    {  NULL  }
-};
-
-/* Military timezone table. */
-static TABLE const MilitaryTable[] = {
-    { "a",     tZONE,  HOUR(  1) },
-    { "b",     tZONE,  HOUR(  2) },
-    { "c",     tZONE,  HOUR(  3) },
-    { "d",     tZONE,  HOUR(  4) },
-    { "e",     tZONE,  HOUR(  5) },
-    { "f",     tZONE,  HOUR(  6) },
-    { "g",     tZONE,  HOUR(  7) },
-    { "h",     tZONE,  HOUR(  8) },
-    { "i",     tZONE,  HOUR(  9) },
-    { "k",     tZONE,  HOUR( 10) },
-    { "l",     tZONE,  HOUR( 11) },
-    { "m",     tZONE,  HOUR( 12) },
-    { "n",     tZONE,  HOUR(- 1) },
-    { "o",     tZONE,  HOUR(- 2) },
-    { "p",     tZONE,  HOUR(- 3) },
-    { "q",     tZONE,  HOUR(- 4) },
-    { "r",     tZONE,  HOUR(- 5) },
-    { "s",     tZONE,  HOUR(- 6) },
-    { "t",     tZONE,  HOUR(- 7) },
-    { "u",     tZONE,  HOUR(- 8) },
-    { "v",     tZONE,  HOUR(- 9) },
-    { "w",     tZONE,  HOUR(-10) },
-    { "x",     tZONE,  HOUR(-11) },
-    { "y",     tZONE,  HOUR(-12) },
-    { "z",     tZONE,  HOUR(  0) },
-    { NULL }
-};
-
-\f
-
-
-/* ARGSUSED */
-static int
-yyerror(s)
-    char       *s;
-{
-  return 0;
-}
-
-
-static time_t
-ToSeconds(Hours, Minutes, Seconds, Meridian)
-    time_t     Hours;
-    time_t     Minutes;
-    time_t     Seconds;
-    MERIDIAN   Meridian;
-{
-    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
-       return -1;
-    switch (Meridian) {
-    case MER24:
-       if (Hours < 0 || Hours > 23)
-           return -1;
-       return (Hours * 60L + Minutes) * 60L + Seconds;
-    case MERam:
-       if (Hours < 1 || Hours > 12)
-           return -1;
-       if (Hours == 12)
-           Hours = 0;
-       return (Hours * 60L + Minutes) * 60L + Seconds;
-    case MERpm:
-       if (Hours < 1 || Hours > 12)
-           return -1;
-       if (Hours == 12)
-           Hours = 0;
-       return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
-    default:
-       abort ();
-    }
-    /* NOTREACHED */
-}
-
-
-/* Year is either
-   * A negative number, which means to use its absolute value (why?)
-   * A number from 0 to 99, which means a year from 1900 to 1999, or
-   * The actual year (>=100).  */
-static time_t
-Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
-    time_t     Month;
-    time_t     Day;
-    time_t     Year;
-    time_t     Hours;
-    time_t     Minutes;
-    time_t     Seconds;
-    MERIDIAN   Meridian;
-    DSTMODE    DSTmode;
-{
-    static int DaysInMonth[12] = {
-       31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-    };
-    time_t     tod;
-    time_t     Julian;
-    int                i;
-
-    if (Year < 0)
-       Year = -Year;
-    if (Year < 69)
-       Year += 2000;
-    else if (Year < 100) {
-       Year += 1900;
-       if (Year < EPOCH)
-               Year += 100;
-    }
-    DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
-                   ? 29 : 28;
-    /* Checking for 2038 bogusly assumes that time_t is 32 bits.  But
-       I'm too lazy to try to check for time_t overflow in another way.  */
-    if (Year < EPOCH || Year > 2038
-     || Month < 1 || Month > 12
-     /* Lint fluff:  "conversion from long may lose accuracy" */
-     || Day < 1 || Day > DaysInMonth[(int)--Month])
-       return -1;
-
-    for (Julian = Day - 1, i = 0; i < Month; i++)
-       Julian += DaysInMonth[i];
-    for (i = EPOCH; i < Year; i++)
-       Julian += 365 + (i % 4 == 0);
-    Julian *= SECSPERDAY;
-    Julian += yyTimezone * 60L;
-    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
-       return -1;
-    Julian += tod;
-    if (DSTmode == DSTon
-     || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
-       Julian -= 60 * 60;
-    return Julian;
-}
-
-
-static time_t
-DSTcorrect(Start, Future)
-    time_t     Start;
-    time_t     Future;
-{
-    time_t     StartDay;
-    time_t     FutureDay;
-
-    StartDay = (localtime(&Start)->tm_hour + 1) % 24;
-    FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
-    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
-}
-
-
-static time_t
-RelativeDate(Start, DayOrdinal, DayNumber)
-    time_t     Start;
-    time_t     DayOrdinal;
-    time_t     DayNumber;
-{
-    struct tm  *tm;
-    time_t     now;
-
-    now = Start;
-    tm = localtime(&now);
-    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
-    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
-    return DSTcorrect(Start, now);
-}
-
-
-static time_t
-RelativeMonth(Start, RelMonth)
-    time_t     Start;
-    time_t     RelMonth;
-{
-    struct tm  *tm;
-    time_t     Month;
-    time_t     Year;
-
-    if (RelMonth == 0)
-       return 0;
-    tm = localtime(&Start);
-    Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
-    Year = Month / 12;
-    Month = Month % 12 + 1;
-    return DSTcorrect(Start,
-           Convert(Month, (time_t)tm->tm_mday, Year,
-               (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
-               MER24, DSTmaybe));
-}
-
-
-static int
-LookupWord(buff)
-    char               *buff;
-{
-    char               *p;
-    char               *q;
-    const TABLE                *tp;
-    int                        i;
-    int                        abbrev;
-
-    /* Make it lowercase. */
-    for (p = buff; *p; p++)
-       if (isupper((unsigned char)*p))
-           *p = tolower((unsigned char)*p);
-
-    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
-       yylval.Meridian = MERam;
-       return tMERIDIAN;
-    }
-    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
-       yylval.Meridian = MERpm;
-       return tMERIDIAN;
-    }
-
-    /* See if we have an abbreviation for a month. */
-    if (strlen(buff) == 3)
-       abbrev = 1;
-    else if (strlen(buff) == 4 && buff[3] == '.') {
-       abbrev = 1;
-       buff[3] = '\0';
-    }
-    else
-       abbrev = 0;
-
-    for (tp = MonthDayTable; tp->name; tp++) {
-       if (abbrev) {
-           if (strncmp(buff, tp->name, 3) == 0) {
-               yylval.Number = tp->value;
-               return tp->type;
-           }
-       }
-       else if (strcmp(buff, tp->name) == 0) {
-           yylval.Number = tp->value;
-           return tp->type;
-       }
-    }
-
-    for (tp = TimezoneTable; tp->name; tp++)
-       if (strcmp(buff, tp->name) == 0) {
-           yylval.Number = tp->value;
-           return tp->type;
-       }
-
-    if (strcmp(buff, "dst") == 0) 
-       return tDST;
-
-    for (tp = UnitsTable; tp->name; tp++)
-       if (strcmp(buff, tp->name) == 0) {
-           yylval.Number = tp->value;
-           return tp->type;
-       }
-
-    /* Strip off any plural and try the units table again. */
-    i = strlen(buff) - 1;
-    if (buff[i] == 's') {
-       buff[i] = '\0';
-       for (tp = UnitsTable; tp->name; tp++)
-           if (strcmp(buff, tp->name) == 0) {
-               yylval.Number = tp->value;
-               return tp->type;
-           }
-       buff[i] = 's';          /* Put back for "this" in OtherTable. */
-    }
-
-    for (tp = OtherTable; tp->name; tp++)
-       if (strcmp(buff, tp->name) == 0) {
-           yylval.Number = tp->value;
-           return tp->type;
-       }
-
-    /* Military timezones. */
-    if (buff[1] == '\0' && isalpha((unsigned char)*buff)) {
-       for (tp = MilitaryTable; tp->name; tp++)
-           if (strcmp(buff, tp->name) == 0) {
-               yylval.Number = tp->value;
-               return tp->type;
-           }
-    }
-
-    /* Drop out any periods and try the timezone table again. */
-    for (i = 0, p = q = buff; *q; q++)
-       if (*q != '.')
-           *p++ = *q;
-       else
-           i++;
-    *p = '\0';
-    if (i)
-       for (tp = TimezoneTable; tp->name; tp++)
-           if (strcmp(buff, tp->name) == 0) {
-               yylval.Number = tp->value;
-               return tp->type;
-           }
-
-    return tID;
-}
-
-
-static int
-yylex()
-{
-    char               c;
-    char               *p;
-    char               buff[20];
-    int                        Count;
-    int                        sign;
-
-    for ( ; ; ) {
-       while (isspace((unsigned char)*yyInput))
-           yyInput++;
-
-       if (isdigit((unsigned char)(c = *yyInput)) || c == '-' || c == '+') {
-           if (c == '-' || c == '+') {
-               sign = c == '-' ? -1 : 1;
-               if (!isdigit((unsigned char)*++yyInput))
-                   /* skip the '-' sign */
-                   continue;
-           }
-           else
-               sign = 0;
-           for (yylval.Number = 0; isdigit((unsigned char)(c = *yyInput++)); )
-               yylval.Number = 10 * yylval.Number + c - '0';
-           yyInput--;
-           if (sign < 0)
-               yylval.Number = -yylval.Number;
-           return sign ? tSNUMBER : tUNUMBER;
-       }
-       if (isalpha((unsigned char)c)) {
-           for (p = buff; isalpha((unsigned char)(c = *yyInput++)) || c == '.'; )
-               if (p < &buff[sizeof buff - 1])
-                   *p++ = c;
-           *p = '\0';
-           yyInput--;
-           return LookupWord(buff);
-       }
-       if (c != '(')
-           return *yyInput++;
-       Count = 0;
-       do {
-           c = *yyInput++;
-           if (c == '\0')
-               return c;
-           if (c == '(')
-               Count++;
-           else if (c == ')')
-               Count--;
-       } while (Count > 0);
-    }
-}
-
-#define TM_YEAR_ORIGIN 1900
-
-/* Yield A - B, measured in seconds.  */
-static long
-difftm (a, b)
-     struct tm *a, *b;
-{
-  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
-  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
-  int days = (
-             /* difference in day of year */
-             a->tm_yday - b->tm_yday
-             /* + intervening leap days */
-             +  ((ay >> 2) - (by >> 2))
-             -  (ay/100 - by/100)
-             +  ((ay/100 >> 2) - (by/100 >> 2))
-             /* + difference in years * 365 */
-             +  (long)(ay-by) * 365
-             );
-  return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
-             + (a->tm_min - b->tm_min))
-         + (a->tm_sec - b->tm_sec));
-}
-
-time_t
-get_date(p)
-    char               *p;
-{
-    struct tm          *tm, *gmt, gmtbuf;
-    time_t             Start;
-    time_t             tod;
-    time_t             now;
-    time_t             timezone;
-
-    yyInput = p;
-    (void)time (&now);
-
-    gmt = gmtime (&now);
-    if (gmt != NULL)
-    {
-       /* Make a copy, in case localtime modifies *tm (I think
-          that comment now applies to *gmt, but I am too
-          lazy to dig into how gmtime and locatime allocate the
-          structures they return pointers to).  */
-       gmtbuf = *gmt;
-       gmt = &gmtbuf;
-    }
-
-    if (! (tm = localtime (&now)))
-       return -1;
-
-    if (gmt != NULL)
-       timezone = difftm (gmt, tm) / 60;
-    else
-       /* We are on a system like VMS, where the system clock is
-          in local time and the system has no concept of timezones.
-          Hopefully we can fake this out (for the case in which the
-          user specifies no timezone) by just saying the timezone
-          is zero.  */
-       timezone = 0;
-
-    if(tm->tm_isdst)
-       timezone += 60;
-
-    tm = localtime(&now);
-    yyYear = tm->tm_year + 1900;
-    yyMonth = tm->tm_mon + 1;
-    yyDay = tm->tm_mday;
-    yyTimezone = timezone;
-    yyDSTmode = DSTmaybe;
-    yyHour = 0;
-    yyMinutes = 0;
-    yySeconds = 0;
-    yyMeridian = MER24;
-    yyRelSeconds = 0;
-    yyRelMonth = 0;
-    yyHaveDate = 0;
-    yyHaveDay = 0;
-    yyHaveRel = 0;
-    yyHaveTime = 0;
-    yyHaveZone = 0;
-
-    if (yyparse()
-     || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
-       return -1;
-
-    if (yyHaveDate || yyHaveTime || yyHaveDay) {
-       Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
-                   yyMeridian, yyDSTmode);
-       if (Start < 0)
-           return -1;
-    }
-    else {
-       Start = now;
-       if (!yyHaveRel)
-           Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
-    }
-
-    Start += yyRelSeconds;
-    Start += RelativeMonth(Start, yyRelMonth);
-
-    if (yyHaveDay && !yyHaveDate) {
-       tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
-       Start += tod;
-    }
-
-    /* Have to do *something* with a legitimate -1 so it's distinguishable
-     * from the error return value.  (Alternately could set errno on error.) */
-    return Start == -1 ? 0 : Start;
-}
-
-
-#if    defined(TEST)
-
-/* ARGSUSED */
-int
-main(ac, av)
-    int                ac;
-    char       *av[];
-{
-    char       buff[128];
-    time_t     d;
-
-    (void)printf("Enter date, or blank line to exit.\n\t> ");
-    (void)fflush(stdout);
-    while (gets(buff) && buff[0]) {
-       d = get_date(buff);
-       if (d == -1)
-           (void)printf("Bad format - couldn't convert.\n");
-       else
-           (void)printf("%s", ctime(&d));
-       (void)printf("\t> ");
-       (void)fflush(stdout);
-    }
-    exit(0);
-    /* NOTREACHED */
-}
-#endif /* defined(TEST) */
diff --git a/getline.c b/getline.c
deleted file mode 100644 (file)
index 2b3d324..0000000
--- a/getline.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2009-2010 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 <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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#include <limits.h>
-
-#include "missing.h"
-#include "alloc.h"
-
-#ifndef LINE_MAX
-# define LINE_MAX 2048
-#endif
-
-#ifdef HAVE_FGETLN
-ssize_t
-getline(bufp, bufsizep, fp)
-    char **bufp;
-    size_t *bufsizep;
-    FILE *fp;
-{
-    char *buf;
-    size_t bufsize;
-    size_t len;
-
-    buf = fgetln(fp, &len);
-    if (buf) {
-       bufsize = *bufp ? *bufsizep : 0;
-       if (bufsize < len + 1) {
-           bufsize = len + 1;
-           *bufp = erealloc(*bufp, bufsize);
-           *bufsizep = bufsize;
-       }
-       memcpy(*bufp, buf, len);
-       (*bufp)[len] = '\0';
-    }
-    return buf ? len : -1;
-}
-#else
-ssize_t
-getline(bufp, bufsizep, fp)
-    char **bufp;
-    size_t *bufsizep;
-    FILE *fp;
-{
-    char *buf;
-    size_t bufsize;
-    ssize_t len = 0;
-
-    buf = *bufp;
-    bufsize = *bufsizep;
-    if (buf == NULL || bufsize == 0) {
-       bufsize = LINE_MAX;
-       buf = erealloc(buf, LINE_MAX);
-    }
-
-    for (;;) {
-       if (fgets(buf + len, bufsize - len, fp) == NULL) {
-           len = -1;
-           break;
-       }
-       len = strlen(buf);
-       if (!len || buf[len - 1] == '\n' || feof(fp))
-           break;
-       bufsize *= 2;
-       buf = erealloc(buf, bufsize);
-    }
-    *bufp = buf;
-    *bufsizep = bufsize;
-    return len;
-}
-#endif
diff --git a/getprogname.c b/getprogname.c
deleted file mode 100644 (file)
index 0790222..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2003-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.
- *
- * 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 <stdio.h>
-#include <string.h>
-
-#include "missing.h"
-
-const char *
-getprogname()
-{
-    static const char *progname;
-    extern int Argc;
-    extern char **Argv;
-
-    if (progname == NULL) {
-       if (Argc < 0)
-           progname = "sudo";
-       else if ((progname = strrchr(Argv[0], '/')) != NULL)
-           progname++;
-       else
-           progname = Argv[0];
-    }
-    return progname;
-}
diff --git a/getspwuid.c b/getspwuid.c
deleted file mode 100644 (file)
index 7a7ffb8..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-2005, 2010
- *     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
-# include <string.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <grp.h>
-#ifdef HAVE_GETSPNAM
-# include <shadow.h>
-#endif /* HAVE_GETSPNAM */
-#ifdef HAVE_GETPRPWNAM
-# ifdef __hpux
-#  undef MAXINT
-#  include <hpsecurity.h>
-# else
-#  include <sys/security.h>
-# endif /* __hpux */
-# include <prot.h>
-#endif /* HAVE_GETPRPWNAM */
-#ifdef HAVE_GETPWANAM
-# include <sys/label.h>
-# include <sys/audit.h>
-# include <pwdadj.h>
-#endif /* HAVE_GETPWANAM */
-#ifdef HAVE_GETAUTHUID
-# include <auth.h>
-#endif /* HAVE_GETAUTHUID */
-
-#include "sudo.h"
-
-/*
- * 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.
- */
-char *
-sudo_getepw(pw)
-    const struct passwd *pw;
-{
-    char *epw = NULL;
-
-    /* If there is a function to check for shadow enabled, use it... */
-#ifdef HAVE_ISCOMSEC
-    if (!iscomsec())
-       goto done;
-#endif /* HAVE_ISCOMSEC */
-#ifdef HAVE_ISSECURE
-    if (!issecure())
-       goto done;
-#endif /* HAVE_ISSECURE */
-
-#ifdef HAVE_GETPRPWNAM
-    {
-       struct pr_passwd *spw;
-
-       if ((spw = getprpwnam(pw->pw_name)) && spw->ufld.fd_encrypt) {
-# ifdef __alpha
-           crypt_type = spw->ufld.fd_oldcrypt;
-# endif /* __alpha */
-           epw = spw->ufld.fd_encrypt;
-       }
-    }
-#endif /* HAVE_GETPRPWNAM */
-#ifdef HAVE_GETSPNAM
-    {
-       struct spwd *spw;
-
-       if ((spw = getspnam(pw->pw_name)) && spw->sp_pwdp)
-           epw = spw->sp_pwdp;
-    }
-#endif /* HAVE_GETSPNAM */
-#ifdef HAVE_GETSPWUID
-    {
-       struct s_passwd *spw;
-
-       if ((spw = getspwuid(pw->pw_uid)) && spw->pw_passwd)
-           epw = spw->pw_passwd;
-    }
-#endif /* HAVE_GETSPWUID */
-#ifdef HAVE_GETPWANAM
-    {
-       struct passwd_adjunct *spw;
-
-       if ((spw = getpwanam(pw->pw_name)) && spw->pwa_passwd)
-           epw = spw->pwa_passwd;
-    }
-#endif /* HAVE_GETPWANAM */
-#ifdef HAVE_GETAUTHUID
-    {
-       AUTHORIZATION *spw;
-
-       if ((spw = getauthuid(pw->pw_uid)) && spw->a_password)
-           epw = spw->a_password;
-    }
-#endif /* HAVE_GETAUTHUID */
-
-#if defined(HAVE_ISCOMSEC) || defined(HAVE_ISSECURE)
-done:
-#endif
-    /* If no shadow password, fall back on regular password. */
-    return estrdup(epw ? epw : pw->pw_passwd);
-}
-
-void
-sudo_setspent()
-{
-#ifdef HAVE_GETPRPWNAM
-    setprpwent();
-#endif
-#ifdef HAVE_GETSPNAM
-    setspent();
-#endif
-#ifdef HAVE_GETSPWUID
-    setspwent();
-#endif
-#ifdef HAVE_GETPWANAM
-    setpwaent();
-#endif
-#ifdef HAVE_GETAUTHUID
-    setauthent();
-#endif
-}
-
-void
-sudo_endspent()
-{
-#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
-}
diff --git a/gettime.c b/gettime.c
deleted file mode 100644 (file)
index 6cb15d7..0000000
--- a/gettime.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2004-2005, 2008, 2010
- *     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/time.h>
-#include <stdio.h>
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-
-#include "missing.h"
-
-/*
- * Get the current time via gettimeofday() for systems with
- * timespecs in struct stat or, otherwise, using time().
- */
-int
-gettime(tv)
-    struct timeval *tv;
-{
-    int rval;
-#if defined(HAVE_GETTIMEOFDAY) && (defined(HAVE_ST_MTIM) || defined(HAVE_ST_MTIMESPEC))
-    rval = gettimeofday(tv, NULL);
-#else
-    rval = (int)time(&tv->tv_sec);
-    tv->tv_usec = 0;
-#endif
-    return rval;
-}
diff --git a/glob.c b/glob.c
deleted file mode 100644 (file)
index 66dcadc..0000000
--- a/glob.c
+++ /dev/null
@@ -1,953 +0,0 @@
-/*
- * Copyright (c) 2008-2010 Todd C. Miller <Todd.Miller@courtesan.com>
- * Copyright (c) 1989, 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.
- *
- *     @(#)glob.c      8.3 (Berkeley) 10/13/93
- */
-
-/*
- * glob(3) -- a superset of the one defined in POSIX 1003.2.
- *
- * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
- *
- * Optional extra services, controlled by flags not defined by POSIX:
- *
- * GLOB_MAGCHAR:
- *     Set in gl_flags if pattern contained a globbing character.
- * GLOB_TILDE:
- *     expand ~user/foo to the /home/dir/of/user/foo
- * GLOB_BRACE:
- *     expand {1,2}{a,b} to 1a 1b 2a 2b
- * gl_matchc:
- *     Number of matches in the current invocation of glob.
- */
-
-#include <config.h>
-
-#include <sys/param.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 */
-#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
-# include <malloc.h>
-#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
-#ifdef HAVE_STRING_H
-# include <string.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <ctype.h>
-#ifdef HAVE_DIRENT_H
-# include <dirent.h>
-#else
-# define dirent direct
-# 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 <errno.h>
-#include <limits.h>
-#include <pwd.h>
-
-#include "missing.h"
-#include "emul/glob.h"
-#include "emul/charclass.h"
-
-#define        DOLLAR          '$'
-#define        DOT             '.'
-#define        EOS             '\0'
-#define        LBRACKET        '['
-#define        NOT             '!'
-#define        QUESTION        '?'
-#define        QUOTE           '\\'
-#define        RANGE           '-'
-#define        RBRACKET        ']'
-#define        SEP             '/'
-#define        STAR            '*'
-#define        TILDE           '~'
-#define        UNDERSCORE      '_'
-#define        LBRACE          '{'
-#define        RBRACE          '}'
-#define        SLASH           '/'
-#define        COMMA           ','
-
-#ifndef DEBUG
-
-#define        M_QUOTE         0x8000
-#define        M_PROTECT       0x4000
-#define        M_MASK          0xffff
-#define        M_ASCII         0x00ff
-
-typedef unsigned short Char;
-
-#else
-
-#define        M_QUOTE         0x80
-#define        M_PROTECT       0x40
-#define        M_MASK          0xff
-#define        M_ASCII         0x7f
-
-typedef char Char;
-
-#endif
-
-
-#define        CHAR(c)         ((Char)((c)&M_ASCII))
-#define        META(c)         ((Char)((c)|M_QUOTE))
-#define        M_ALL           META('*')
-#define        M_END           META(']')
-#define        M_NOT           META('!')
-#define        M_ONE           META('?')
-#define        M_RNG           META('-')
-#define        M_SET           META('[')
-#define        M_CLASS         META(':')
-#define        ismeta(c)       (((c)&M_QUOTE) != 0)
-
-
-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((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 *));
-static int      glob2 __P((Char *, Char *, Char *, Char *, Char *, Char *,
-                   glob_t *));
-static int      glob3 __P((Char *, Char *, Char *, Char *, Char *, Char *,
-                   Char *, Char *, glob_t *));
-static int      globextend __P((const Char *, glob_t *));
-static const Char *
-                globtilde __P((const Char *, Char *, size_t, glob_t *));
-static int      globexp1 __P((const Char *, glob_t *));
-static int      globexp2 __P((const Char *, const Char *, glob_t *, int *));
-static int      match __P((Char *, Char *, Char *));
-#ifdef DEBUG
-static void     qprintf __P((const char *, Char *));
-#endif
-
-extern struct passwd *sudo_getpwnam __P((const char *));
-extern struct passwd *sudo_getpwuid __P((uid_t));
-extern void pw_delref __P((struct passwd *));
-
-int
-glob(pattern, flags, errfunc, pglob)
-       const char *pattern;
-       int flags, (*errfunc) __P((const char *, int));
-       glob_t *pglob;
-{
-       const unsigned char *patnext;
-       int c;
-       Char *bufnext, *bufend, patbuf[PATH_MAX];
-
-       patnext = (unsigned char *) pattern;
-       if (!(flags & GLOB_APPEND)) {
-               pglob->gl_pathc = 0;
-               pglob->gl_pathv = NULL;
-               if (!(flags & GLOB_DOOFFS))
-                       pglob->gl_offs = 0;
-       }
-       pglob->gl_flags = flags & ~GLOB_MAGCHAR;
-       pglob->gl_errfunc = errfunc;
-       pglob->gl_matchc = 0;
-
-       bufnext = patbuf;
-       bufend = bufnext + PATH_MAX - 1;
-       if (flags & GLOB_NOESCAPE)
-               while (bufnext < bufend && (c = *patnext++) != EOS)
-                       *bufnext++ = c;
-       else {
-               /* Protect the quoted characters. */
-               while (bufnext < bufend && (c = *patnext++) != EOS)
-                       if (c == QUOTE) {
-                               if ((c = *patnext++) == EOS) {
-                                       c = QUOTE;
-                                       --patnext;
-                               }
-                               *bufnext++ = c | M_PROTECT;
-                       } else
-                               *bufnext++ = c;
-       }
-       *bufnext = EOS;
-
-       if (flags & GLOB_BRACE)
-               return globexp1(patbuf, pglob);
-       else
-               return glob0(patbuf, pglob);
-}
-
-/*
- * Expand recursively a glob {} pattern. When there is no more expansion
- * invoke the standard globbing routine to glob the rest of the magic
- * characters
- */
-static int
-globexp1(pattern, pglob)
-       const Char *pattern;
-       glob_t *pglob;
-{
-       const Char* ptr = pattern;
-       int rv;
-
-       /* Protect a single {}, for find(1), like csh */
-       if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
-               return glob0(pattern, pglob);
-
-       while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
-               if (!globexp2(ptr, pattern, pglob, &rv))
-                       return rv;
-
-       return glob0(pattern, pglob);
-}
-
-
-/*
- * Recursive brace globbing helper. Tries to expand a single brace.
- * If it succeeds then it invokes globexp1 with the new pattern.
- * If it fails then it tries to glob the rest of the pattern and returns.
- */
-static int
-globexp2(ptr, pattern, pglob, rv)
-       const Char *ptr, *pattern;
-       glob_t *pglob;
-       int *rv;
-{
-       int     i;
-       Char   *lm, *ls;
-       const Char *pe, *pm, *pl;
-       Char    patbuf[PATH_MAX];
-
-       /* copy part up to the brace */
-       for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
-               continue;
-       *lm = EOS;
-       ls = lm;
-
-       /* Find the balanced brace */
-       for (i = 0, pe = ++ptr; *pe; pe++)
-               if (*pe == LBRACKET) {
-                       /* Ignore everything between [] */
-                       for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
-                               continue;
-                       if (*pe == EOS) {
-                               /*
-                                * We could not find a matching RBRACKET.
-                                * Ignore and just look for RBRACE
-                                */
-                               pe = pm;
-                       }
-               } else if (*pe == LBRACE)
-                       i++;
-               else if (*pe == RBRACE) {
-                       if (i == 0)
-                               break;
-                       i--;
-               }
-
-       /* Non matching braces; just glob the pattern */
-       if (i != 0 || *pe == EOS) {
-               *rv = glob0(patbuf, pglob);
-               return 0;
-       }
-
-       for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
-               switch (*pm) {
-               case LBRACKET:
-                       /* Ignore everything between [] */
-                       for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
-                               continue;
-                       if (*pm == EOS) {
-                               /*
-                                * We could not find a matching RBRACKET.
-                                * Ignore and just look for RBRACE
-                                */
-                               pm = pl;
-                       }
-                       break;
-
-               case LBRACE:
-                       i++;
-                       break;
-
-               case RBRACE:
-                       if (i) {
-                               i--;
-                               break;
-                       }
-                       /* FALLTHROUGH */
-               case COMMA:
-                       if (i && *pm == COMMA)
-                               break;
-                       else {
-                               /* Append the current string */
-                               for (lm = ls; (pl < pm); *lm++ = *pl++)
-                                       continue;
-
-                               /*
-                                * Append the rest of the pattern after the
-                                * closing brace
-                                */
-                               for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
-                                       continue;
-
-                               /* Expand the current pattern */
-#ifdef DEBUG
-                               qprintf("globexp2:", patbuf);
-#endif
-                               *rv = globexp1(patbuf, pglob);
-
-                               /* move after the comma, to the next string */
-                               pl = pm + 1;
-                       }
-                       break;
-
-               default:
-                       break;
-               }
-       }
-       *rv = 0;
-       return 0;
-}
-
-
-
-/*
- * expand tilde from the passwd file.
- */
-static const Char *
-globtilde(pattern, patbuf, patbuf_len, pglob)
-       const Char *pattern;
-       Char *patbuf;
-       size_t patbuf_len;
-       glob_t *pglob;
-{
-       struct passwd *pwd = NULL;
-       char *h;
-       const Char *p;
-       Char *b, *eb;
-
-       if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
-               return pattern;
-
-       /* Copy up to the end of the string or / */
-       eb = &patbuf[patbuf_len - 1];
-       for (p = pattern + 1, h = (char *) patbuf;
-           h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
-               continue;
-
-       *h = EOS;
-
-       if (((char *) patbuf)[0] == EOS) {
-               /*
-                * handle a plain ~ or ~/ by expanding $HOME
-                * first and then trying the password file
-                */
-               if ((h = getenv("HOME")) == NULL) {
-                       if ((pwd = sudo_getpwuid(getuid())) == NULL)
-                               return pattern;
-                       else
-                               h = pwd->pw_dir;
-               }
-       } else {
-               /*
-                * Expand a ~user
-                */
-               if ((pwd = sudo_getpwnam((char*) patbuf)) == NULL)
-                       return pattern;
-               else
-                       h = pwd->pw_dir;
-       }
-
-       /* Copy the home directory */
-       for (b = patbuf; b < eb && *h; *b++ = *h++)
-               continue;
-
-       /* Append the rest of the pattern */
-       while (b < eb && (*b++ = *p++) != EOS)
-               continue;
-       *b = EOS;
-
-       if (pwd)
-           pw_delref(pwd);
-
-       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
- * quotes), calls glob1() to do the real pattern matching, and finally
- * sorts the list (unless unsorted operation is requested).  Returns 0
- * if things went well, nonzero if errors occurred.  It is not an error
- * to find no matches.
- */
-static int
-glob0(pattern, pglob)
-       const Char *pattern;
-       glob_t *pglob;
-{
-       const Char *qpatnext;
-       int c, err, oldpathc;
-       Char *bufnext, patbuf[PATH_MAX];
-
-       qpatnext = globtilde(pattern, patbuf, PATH_MAX, pglob);
-       oldpathc = pglob->gl_pathc;
-       bufnext = patbuf;
-
-       /* We don't need to check for buffer overflow any more. */
-       while ((c = *qpatnext++) != EOS) {
-               switch (c) {
-               case LBRACKET:
-                       c = *qpatnext;
-                       if (c == NOT)
-                               ++qpatnext;
-                       if (*qpatnext == EOS ||
-                           g_strchr(qpatnext+1, RBRACKET) == NULL) {
-                               *bufnext++ = LBRACKET;
-                               if (c == NOT)
-                                       --qpatnext;
-                               break;
-                       }
-                       *bufnext++ = M_SET;
-                       if (c == NOT)
-                               *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) {
-                                       *bufnext++ = M_RNG;
-                                       *bufnext++ = CHAR(c);
-                                       qpatnext += 2;
-                               }
-                       } while ((c = *qpatnext++) != RBRACKET);
-                       pglob->gl_flags |= GLOB_MAGCHAR;
-                       *bufnext++ = M_END;
-                       break;
-               case QUESTION:
-                       pglob->gl_flags |= GLOB_MAGCHAR;
-                       *bufnext++ = M_ONE;
-                       break;
-               case STAR:
-                       pglob->gl_flags |= GLOB_MAGCHAR;
-                       /* collapse adjacent stars to one,
-                        * to avoid exponential behavior
-                        */
-                       if (bufnext == patbuf || bufnext[-1] != M_ALL)
-                               *bufnext++ = M_ALL;
-                       break;
-               default:
-                       *bufnext++ = CHAR(c);
-                       break;
-               }
-       }
-       *bufnext = EOS;
-#ifdef DEBUG
-       qprintf("glob0:", patbuf);
-#endif
-
-       if ((err = glob1(patbuf, patbuf + PATH_MAX - 1, pglob)) != 0)
-               return err;
-
-       /*
-        * If there was no match we are going to append the pattern
-        * if GLOB_NOCHECK was specified.
-        */
-       if (pglob->gl_pathc == oldpathc) {
-               if (pglob->gl_flags & GLOB_NOCHECK)
-                       return globextend(pattern, pglob);
-               else
-                       return GLOB_NOMATCH;
-       }
-       if (!(pglob->gl_flags & GLOB_NOSORT))
-               qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
-                   pglob->gl_pathc - oldpathc, sizeof(char *), compare);
-       return 0;
-}
-
-static int
-compare(p, q)
-       const void *p, *q;
-{
-       return strcmp(*(char **)p, *(char **)q);
-}
-
-static int
-glob1(pattern, pattern_last,  pglob)
-       Char *pattern, *pattern_last;
-       glob_t *pglob;
-{
-       Char pathbuf[PATH_MAX];
-
-       /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
-       if (*pattern == EOS)
-               return 0;
-       return glob2(pathbuf, pathbuf + PATH_MAX - 1,
-           pathbuf, pathbuf + PATH_MAX - 1,
-           pattern, pattern_last, pglob);
-}
-
-/*
- * The functions glob2 and glob3 are mutually recursive; there is one level
- * of recursion for each segment in the pattern that contains one or more
- * meta characters.
- */
-static int
-glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last, pglob)
-       Char *pathbuf, *pathbuf_last;
-       Char *pathend, *pathend_last;
-       Char *pattern, *pattern_last;
-       glob_t *pglob;
-{
-       struct stat sb;
-       Char *p, *q;
-       int anymeta;
-
-       /*
-        * Loop over pattern segments until end of pattern or until
-        * segment with meta character found.
-        */
-       for (anymeta = 0;;) {
-               if (*pattern == EOS) {          /* End of pattern? */
-                       *pathend = EOS;
-                       if (g_lstat(pathbuf, &sb, pglob))
-                               return 0;
-
-                       if (((pglob->gl_flags & GLOB_MARK) &&
-                           pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
-                           (S_ISLNK(sb.st_mode) &&
-                           (g_stat(pathbuf, &sb, pglob) == 0) &&
-                           S_ISDIR(sb.st_mode)))) {
-                               if (pathend+1 > pathend_last)
-                                       return 1;
-                               *pathend++ = SEP;
-                               *pathend = EOS;
-                       }
-                       ++pglob->gl_matchc;
-                       return globextend(pathbuf, pglob);
-               }
-
-               /* Find end of next segment, copy tentatively to pathend. */
-               q = pathend;
-               p = pattern;
-               while (*p != EOS && *p != SEP) {
-                       if (ismeta(*p))
-                               anymeta = 1;
-                       if (q+1 > pathend_last)
-                               return 1;
-                       *q++ = *p++;
-               }
-
-               if (!anymeta) {         /* No expansion, do next segment. */
-                       pathend = q;
-                       pattern = p;
-                       while (*pattern == SEP) {
-                               if (pathend+1 > pathend_last)
-                                       return 1;
-                               *pathend++ = *pattern++;
-                       }
-               } else
-                       /* Need expansion, recurse. */
-                       return glob3(pathbuf, pathbuf_last, pathend,
-                           pathend_last, pattern, pattern_last,
-                           p, pattern_last, pglob);
-       }
-       /* NOTREACHED */
-}
-
-static int
-glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last,
-    restpattern, restpattern_last, pglob)
-       Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
-       Char *pattern, *pattern_last, *restpattern, *restpattern_last;
-       glob_t *pglob;
-{
-       struct dirent *dp;
-       DIR *dirp;
-       int err;
-       char buf[PATH_MAX];
-
-       if (pathend > pathend_last)
-               return 1;
-       *pathend = EOS;
-       errno = 0;
-
-       if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
-               /* TODO: don't call for ENOENT or ENOTDIR? */
-               if (pglob->gl_errfunc) {
-                       if (g_Ctoc(pathbuf, buf, sizeof(buf)))
-                               return GLOB_ABORTED;
-                       if (pglob->gl_errfunc(buf, errno) ||
-                           pglob->gl_flags & GLOB_ERR)
-                               return GLOB_ABORTED;
-               }
-               return 0;
-       }
-
-       err = 0;
-
-       /* Search directory for matching names. */
-       while ((dp = readdir(dirp))) {
-               unsigned char *sc;
-               Char *dc;
-
-               /* Initial DOT must be matched literally. */
-               if (dp->d_name[0] == DOT && *pattern != DOT)
-                       continue;
-               dc = pathend;
-               sc = (unsigned char *) dp->d_name;
-               while (dc < pathend_last && (*dc++ = *sc++) != EOS)
-                       continue;
-               if (dc >= pathend_last) {
-                       *dc = EOS;
-                       err = 1;
-                       break;
-               }
-
-               if (!match(pathend, pattern, restpattern)) {
-                       *pathend = EOS;
-                       continue;
-               }
-               err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
-                   restpattern, restpattern_last, pglob);
-               if (err)
-                       break;
-       }
-
-       closedir(dirp);
-       return err;
-}
-
-/*
- * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
- * add the new item, and update gl_pathc.
- *
- * This assumes the BSD realloc, which only copies the block when its size
- * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
- * behavior.
- *
- * Return 0 if new item added, error code if memory couldn't be allocated.
- *
- * Invariant of the glob_t structure:
- *     Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
- *     gl_pathv points to (gl_offs + gl_pathc + 1) items.
- */
-static int
-globextend(path, pglob)
-       const Char *path;
-       glob_t *pglob;
-{
-       char **pathv;
-       int i;
-       unsigned int newsize, len;
-       char *copy;
-       const Char *p;
-
-       newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
-       pathv = pglob->gl_pathv ?
-           (char **)realloc((char *)pglob->gl_pathv, newsize) :
-           (char **)malloc(newsize);
-       if (pathv == NULL) {
-               if (pglob->gl_pathv) {
-                       free(pglob->gl_pathv);
-                       pglob->gl_pathv = NULL;
-               }
-               return GLOB_NOSPACE;
-       }
-
-       if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
-               /* first time around -- clear initial gl_offs items */
-               pathv += pglob->gl_offs;
-               for (i = pglob->gl_offs; --i >= 0; )
-                       *--pathv = NULL;
-       }
-       pglob->gl_pathv = pathv;
-
-       for (p = path; *p++;)
-               continue;
-       len = (size_t)(p - path);
-       if ((copy = malloc(len)) != NULL) {
-               if (g_Ctoc(path, copy, len)) {
-                       free(copy);
-                       return GLOB_NOSPACE;
-               }
-               pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
-       }
-       pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
-
-       return copy == NULL ? GLOB_NOSPACE : 0;
-}
-
-/*
- * pattern matching function for filenames.  Each occurrence of the *
- * pattern causes a recursion level.
- */
-static int
-match(name, pat, patend)
-       Char *name, *pat, *patend;
-{
-       int ok, negate_range;
-       Char c, k;
-
-       while (pat < patend) {
-               c = *pat++;
-               switch (c & M_MASK) {
-               case M_ALL:
-                       if (pat == patend)
-                               return 1;
-                       do {
-                           if (match(name, pat, patend))
-                                   return 1;
-                       } while (*name++ != EOS);
-                       return 0;
-               case M_ONE:
-                       if (*name++ == EOS)
-                               return 0;
-                       break;
-               case M_SET:
-                       ok = 0;
-                       if ((k = *name++) == EOS)
-                               return 0;
-                       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;
-                                       pat += 2;
-                               } else if (c == k)
-                                       ok = 1;
-                       }
-                       if (ok == negate_range)
-                               return 0;
-                       break;
-               default:
-                       if (*name++ != c)
-                               return 0;
-                       break;
-               }
-       }
-       return *name == EOS;
-}
-
-/* Free allocated data belonging to a glob_t structure. */
-void
-globfree(pglob)
-       glob_t *pglob;
-{
-       int i;
-       char **pp;
-
-       if (pglob->gl_pathv != NULL) {
-               pp = pglob->gl_pathv + pglob->gl_offs;
-               for (i = pglob->gl_pathc; i--; ++pp)
-                       if (*pp)
-                               free(*pp);
-               free(pglob->gl_pathv);
-               pglob->gl_pathv = NULL;
-       }
-}
-
-static DIR *
-g_opendir(str, pglob)
-       Char *str;
-       glob_t *pglob;
-{
-       char buf[PATH_MAX];
-
-       if (!*str) {
-               buf[0] = '.';
-               buf[1] = '\0';
-       } else {
-               if (g_Ctoc(str, buf, sizeof(buf)))
-                       return NULL;
-       }
-       return opendir(buf);
-}
-
-static int
-g_lstat(fn, sb, pglob)
-       Char *fn;
-       struct stat *sb;
-       glob_t *pglob;
-{
-       char buf[PATH_MAX];
-
-       if (g_Ctoc(fn, buf, sizeof(buf)))
-               return -1;
-       return lstat(buf, sb);
-}
-
-static int
-g_stat(fn, sb, pglob)
-       Char *fn;
-       struct stat *sb;
-       glob_t *pglob;
-{
-       char buf[PATH_MAX];
-
-       if (g_Ctoc(fn, buf, sizeof(buf)))
-               return -1;
-       return stat(buf, sb);
-}
-
-static Char *
-g_strchr(str, ch)
-       const Char *str;
-       int ch;
-{
-       do {
-               if (*str == ch)
-                       return (Char *)str;
-       } while (*str++);
-       return NULL;
-}
-
-static int
-g_Ctoc(str, buf, len)
-       const Char *str;
-       char *buf;
-       unsigned int len;
-{
-
-       while (len--) {
-               if ((*buf++ = *str++) == EOS)
-                       return 0;
-       }
-       return 1;
-}
-
-#ifdef DEBUG
-static void
-qprintf(str, s)
-       const char *str;
-       Char *s;
-{
-       Char *p;
-
-       (void)printf("%s:\n", str);
-       for (p = s; *p; p++)
-               (void)printf("%c", CHAR(*p));
-       (void)printf("\n");
-       for (p = s; *p; p++)
-               (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
-       (void)printf("\n");
-       for (p = s; *p; p++)
-               (void)printf("%c", ismeta(*p) ? '_' : ' ');
-       (void)printf("\n");
-}
-#endif
diff --git a/goodpath.c b/goodpath.c
deleted file mode 100644 (file)
index 45066d3..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-2005, 2010
- *     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 HAVE_STRING_H
-# include <string.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <errno.h>
-
-#include "sudo.h"
-
-/*
- * Verify that path is a normal file and executable by root.
- */
-char *
-sudo_goodpath(path, sbp)
-    const char *path;
-    struct stat *sbp;
-{
-    struct stat sb;
-
-    /* Check for brain damage */
-    if (path == NULL || path[0] == '\0')
-       return NULL;
-
-    if (stat(path, &sb))
-       return NULL;
-
-    /* Make sure path describes an executable regular file. */
-    if (!S_ISREG(sb.st_mode) || !(sb.st_mode & 0000111)) {
-       errno = EACCES;
-       return NULL;
-    }
-
-    if (sbp != NULL)
-       (void) memcpy(sbp, &sb, sizeof(struct stat));
-    return (char *)path;
-}
diff --git a/gram.c b/gram.c
deleted file mode 100644 (file)
index ed7e21b..0000000
--- a/gram.c
+++ /dev/null
@@ -1,1665 +0,0 @@
-#include <config.h>
-#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-2010
- *     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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_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"
-
-/*
- * 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 112 "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 138 "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 LOG_INPUT 275
-#define NOLOG_INPUT 276
-#define LOG_OUTPUT 277
-#define NOLOG_OUTPUT 278
-#define ALL 279
-#define COMMENT 280
-#define HOSTALIAS 281
-#define CMNDALIAS 282
-#define USERALIAS 283
-#define RUNASALIAS 284
-#define ERROR 285
-#define TYPE 286
-#define ROLE 287
-#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,   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,    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,   85,   87,   88,   89,    0,    0,    0,    0,    0,
-   86,    5,    0,    0,    0,    0,    0,    0,   81,   83,
-    0,    0,    3,    6,    0,    0,   17,    0,   29,   32,
-   31,   33,   30,    0,   27,    0,   68,    0,    0,   64,
-   63,   62,    0,   37,   73,    0,    0,    0,   65,    0,
-    0,   70,    0,    0,   78,    0,    0,   75,   84,    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,   82,    0,    0,   21,   22,
-   23,   18,   69,   74,    0,   66,    0,   71,    0,   79,
-    0,   76,    0,   34,    0,    0,   25,    0,    0,    0,
-    0,    0,    0,   51,    0,    0,   94,   96,   95,    0,
-   90,   92,    0,    0,   47,   35,    0,    0,    0,   44,
-   45,   93,    0,    0,   40,   39,   52,   53,   54,   55,
-   56,   57,   58,   59,   60,   61,   36,   91,
-};
-#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
-       {                                    475,
- -270,    0,    0,    0,    0,  -29,  567,  594,  594,   -2,
-    0,    0, -240, -222, -216, -212, -241,    0,    0,    0,
-  -25,  475,    0,    0,  -10, -207,    0,    9,    0,    0,
-    0,    0,    0, -235,    0,  -33,    0,  -31,  -31,    0,
-    0,    0, -242,    0,    0,  -30,   -7,    3,    0,   -6,
-    4,    0,   -5,    6,    0,   -1,    8,    0,    0,  594,
-  -20,    0,   10,    0, -205, -196, -194,    0,  -29,    0,
-  567,    9,    9,    9,    0,   -2,    9,  567, -240,   -2,
- -222,  594, -216,  594, -212,    0,   31,  567,    0,    0,
-    0,    0,    0,    0,   26,    0,   28,    0,   29,    0,
-   29,    0,  541,    0,   32, -247,    0,   86,  -15,   33,
-   31,   14,   16,    0, -208, -204,    0,    0,    0, -231,
-    0,    0,   38,   86,    0,    0, -179, -178,  491,    0,
-    0,    0,   86,   38,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yyrindex[] =
-#else
-short yyrindex[] =
-#endif
-       {                                     87,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,   90,    0,    0,    1,    0,    0,  177,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,  207,    0,    0,
-  237,    0,    0,  271,    0,    0,  300,    0,    0,    0,
-    0,    0,  329,    0,    0,    0,    0,    0,    0,    0,
-    0,  358,  387,  417,    0,    0,  446,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,  -26,    0,    0,    0,
-    0,    0,    0,    0,   30,    0,   59,    0,   89,    0,
-  118,    0,    0,    0,  148,  514,    0,    0,   45,    0,
-  -26,    0,    0,    0,  537,  565,    0,    0,    0,    0,
-    0,    0,   50,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,   52,    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,
-  -17,    0,   27,   11,   54,  -64,   15,   64,    2,   34,
-   39,   84,   -3,  -27,  -18,  -21,    0,    0,   19,    0,
-    0,    0,  -12,   -4,    0,   88,    0,    0,    0,    0,
-   35,   40,   23,   37,
-};
-#define YYTABLESIZE 873
-#if defined(__cplusplus) || defined(__STDC__)
-const short yytable[] =
-#else
-short yytable[] =
-#endif
-       {                                      26,
-   19,   26,   26,   26,   38,   39,   46,   34,   36,   24,
-   71,   94,   60,   76,   40,   41,    2,   47,   60,    3,
-    4,    5,   29,   71,   30,   31,  117,   32,   60,   67,
-   43,  118,   66,   19,   67,   50,   42,   11,  112,  113,
-   87,   53,  124,   33,   19,   56,   72,  119,   73,   74,
-   65,   68,   69,   78,   80,   82,   77,   89,   72,   84,
-   79,   81,   67,   83,  147,   85,   90,   88,   91,   71,
-  103,   76,   60,  125,  127,  111,  128,  112,   99,   95,
-  101,  133,  113,  135,  136,   48,    1,   67,   80,    2,
-   50,   72,   49,  126,   97,   92,   75,   70,   86,  109,
-   59,  132,  134,  131,   93,  148,  107,  102,    0,   64,
-  130,    0,    0,   96,    0,    0,   72,   77,  120,  100,
-   98,   80,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,   80,   26,    0,    0,
-   77,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,   77,   12,    0,    0,    0,
-   26,    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,    9,    0,    0,   12,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,   25,    0,   25,   25,   25,
-   46,   46,   29,    0,   30,   31,   10,   32,    0,    9,
-    0,    0,   46,   46,   46,   46,   46,   46,   46,   46,
-   46,   46,   46,   33,   40,   41,   19,    0,   19,   46,
-   46,   19,   19,   19,   19,   19,   19,   19,   19,   10,
-    8,    0,    0,    0,    0,    0,   42,    0,    0,   19,
-   19,   19,   19,   19,   19,   67,    0,   67,    0,    0,
-   67,   67,   67,   67,   67,   67,   67,   67,    0,   11,
-    0,    0,    0,    8,    0,    0,    0,    0,   67,   67,
-   67,   67,   67,   67,   72,    0,   72,    0,    0,   72,
-   72,   72,   72,   72,   72,   72,   72,    0,    7,    0,
-    0,    0,   11,    0,    0,    0,    0,   72,   72,   72,
-   72,   72,   72,  117,   80,    0,   80,    0,  118,   80,
-   80,   80,   80,   80,   80,   80,   80,   15,    0,    0,
-    0,    7,    0,    0,  119,    0,    0,   80,   80,   80,
-   80,   80,   80,   77,    0,   77,    0,    0,   77,   77,
-   77,   77,   77,   77,   77,   77,   13,    0,    0,    0,
-   15,    0,    0,    0,    0,    0,   77,   77,   77,   77,
-   77,   77,    0,   26,    0,   26,    0,    0,   26,   26,
-   26,   26,   26,   26,   26,   26,   14,    0,    0,   13,
-    0,    0,    0,    0,    0,    0,   26,   26,   26,   26,
-   26,   26,   12,    0,   12,    0,    0,   12,   12,   12,
-   12,   12,   12,   12,   12,   16,    0,    0,    0,   14,
-    0,    0,    0,    0,    0,   12,   12,   12,   12,   12,
-   12,    0,    9,    0,    9,    0,    0,    9,    9,    9,
-    9,    9,    9,    9,    9,    0,    0,    0,   16,    0,
-    0,    0,    0,    0,    0,    9,    9,    9,    9,    9,
-    9,    0,   10,    0,   10,    0,    0,   10,   10,   10,
-   10,   10,   10,   10,   10,    0,    0,   17,    0,    0,
-    0,    0,    0,    0,    0,   10,   10,   10,   10,   10,
-   10,    0,    0,   43,    0,    0,    8,    0,    8,    0,
-    0,    8,    8,    8,    8,    8,    8,    8,    8,    0,
-    0,    0,    0,    0,    0,    0,   41,    0,    0,    8,
-    8,    8,    8,    8,    8,   11,    0,   11,    0,    0,
-   11,   11,   11,   11,   11,   11,   11,   11,    0,   42,
-    0,    0,    0,   17,    0,    0,    0,    0,   11,   11,
-   11,   11,   11,   11,    7,    0,    7,    0,    0,    7,
-    7,    7,    7,    7,    7,    7,    7,   43,  108,   34,
-    0,    0,    0,    0,    0,    0,    0,    7,    7,    7,
-    7,    7,    7,   15,    0,   15,    0,    0,   15,   15,
-   15,   15,   15,   15,   15,   15,   17,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,   15,   15,   15,   15,
-   15,   15,   13,    0,   13,    0,    0,   13,   13,   13,
-   13,   13,   13,   13,   13,    0,    0,    0,    0,    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,    0,    0,    0,    0,   14,   14,   14,   14,   14,
-   14,   16,    0,   16,    0,    0,   16,   16,   16,   16,
-   16,   16,   16,   16,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,   16,   16,   16,   16,   16,   16,
-    1,    0,    2,    0,    0,    3,    4,    5,    6,    7,
-    8,    9,   10,    0,    0,    0,    0,   40,   41,    0,
-    0,    0,    0,   11,   12,   13,   14,   15,   16,  137,
-  138,  139,  140,  141,  142,  143,  144,  145,  146,   42,
-   41,   41,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,   41,   41,   41,   41,   41,   41,   41,   41,
-   41,   41,   41,   42,   42,    0,    0,    0,    2,    0,
-    0,    3,    4,    5,    0,   42,   42,   42,   42,   42,
-   42,   42,   42,   42,   42,   42,    0,    0,    0,   11,
-    0,   43,   43,    0,   29,    0,   30,   31,    0,   32,
-    0,    0,    0,   43,   43,   43,   43,   43,   43,   43,
-   43,   43,   43,   43,    0,   33,    0,    0,    0,    0,
-    0,    2,    0,    0,    3,    4,    5,    0,    0,    0,
-    0,    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,   33,   33,   33,    8,    9,   33,   33,    7,  280,
-   44,   76,   44,   44,  257,  258,  258,  258,   44,  261,
-  262,  263,  258,   44,  260,  261,  258,  263,   44,    0,
-   33,  263,   43,   33,   45,  258,  279,  279,  286,  287,
-   61,  258,   58,  279,   44,  258,   36,  279,   38,   39,
-   61,  259,   44,   61,   61,   61,   46,  263,    0,   61,
-   58,   58,   33,   58,  129,   58,  263,   58,  263,   44,
-   40,   44,   44,   41,   61,   44,   61,  286,   82,   78,
-   84,   44,  287,  263,  263,   41,    0,   58,    0,    0,
-   41,   33,   41,  111,   80,   69,   43,   34,   60,  103,
-   17,  120,  124,  116,   71,  133,   88,   85,   -1,   22,
-  115,   -1,   -1,   79,   -1,   -1,   58,    0,   33,   83,
-   81,   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   58,    0,   -1,   -1,
-   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   58,    0,   -1,   -1,   -1,
-   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   58,    0,   -1,   -1,   33,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,  259,   -1,  259,  259,  259,
-  257,  258,  258,   -1,  260,  261,    0,  263,   -1,   33,
-   -1,   -1,  269,  270,  271,  272,  273,  274,  275,  276,
-  277,  278,  279,  279,  257,  258,  256,   -1,  258,  286,
-  287,  261,  262,  263,  264,  265,  266,  267,  268,   33,
-    0,   -1,   -1,   -1,   -1,   -1,  279,   -1,   -1,  279,
-  280,  281,  282,  283,  284,  256,   -1,  258,   -1,   -1,
-  261,  262,  263,  264,  265,  266,  267,  268,   -1,    0,
-   -1,   -1,   -1,   33,   -1,   -1,   -1,   -1,  279,  280,
-  281,  282,  283,  284,  256,   -1,  258,   -1,   -1,  261,
-  262,  263,  264,  265,  266,  267,  268,   -1,    0,   -1,
-   -1,   -1,   33,   -1,   -1,   -1,   -1,  279,  280,  281,
-  282,  283,  284,  258,  256,   -1,  258,   -1,  263,  261,
-  262,  263,  264,  265,  266,  267,  268,    0,   -1,   -1,
-   -1,   33,   -1,   -1,  279,   -1,   -1,  279,  280,  281,
-  282,  283,  284,  256,   -1,  258,   -1,   -1,  261,  262,
-  263,  264,  265,  266,  267,  268,    0,   -1,   -1,   -1,
-   33,   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,
-  283,  284,   -1,  256,   -1,  258,   -1,   -1,  261,  262,
-  263,  264,  265,  266,  267,  268,    0,   -1,   -1,   33,
-   -1,   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,
-  283,  284,  256,   -1,  258,   -1,   -1,  261,  262,  263,
-  264,  265,  266,  267,  268,    0,   -1,   -1,   -1,   33,
-   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,  283,
-  284,   -1,  256,   -1,  258,   -1,   -1,  261,  262,  263,
-  264,  265,  266,  267,  268,   -1,   -1,   -1,   33,   -1,
-   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,  283,
-  284,   -1,  256,   -1,  258,   -1,   -1,  261,  262,  263,
-  264,  265,  266,  267,  268,   -1,   -1,   33,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,  283,
-  284,   -1,   -1,   33,   -1,   -1,  256,   -1,  258,   -1,
-   -1,  261,  262,  263,  264,  265,  266,  267,  268,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   33,   -1,   -1,  279,
-  280,  281,  282,  283,  284,  256,   -1,  258,   -1,   -1,
-  261,  262,  263,  264,  265,  266,  267,  268,   -1,   33,
-   -1,   -1,   -1,   33,   -1,   -1,   -1,   -1,  279,  280,
-  281,  282,  283,  284,  256,   -1,  258,   -1,   -1,  261,
-  262,  263,  264,  265,  266,  267,  268,   33,   58,   33,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,  279,  280,  281,
-  282,  283,  284,  256,   -1,  258,   -1,   -1,  261,  262,
-  263,  264,  265,  266,  267,  268,   33,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,
-  283,  284,  256,   -1,  258,   -1,   -1,  261,  262,  263,
-  264,  265,  266,  267,  268,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,  283,
-  284,   -1,  256,   -1,  258,   -1,   -1,  261,  262,  263,
-  264,  265,  266,  267,  268,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,  283,
-  284,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
-  265,  266,  267,  268,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,  279,  280,  281,  282,  283,  284,
-  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,  265,
-  266,  267,  268,   -1,   -1,   -1,   -1,  257,  258,   -1,
-   -1,   -1,   -1,  279,  280,  281,  282,  283,  284,  269,
-  270,  271,  272,  273,  274,  275,  276,  277,  278,  279,
-  257,  258,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,  269,  270,  271,  272,  273,  274,  275,  276,
-  277,  278,  279,  257,  258,   -1,   -1,   -1,  258,   -1,
-   -1,  261,  262,  263,   -1,  269,  270,  271,  272,  273,
-  274,  275,  276,  277,  278,  279,   -1,   -1,   -1,  279,
-   -1,  257,  258,   -1,  258,   -1,  260,  261,   -1,  263,
-   -1,   -1,   -1,  269,  270,  271,  272,  273,  274,  275,
-  276,  277,  278,  279,   -1,  279,   -1,   -1,   -1,   -1,
-   -1,  258,   -1,   -1,  261,  262,  263,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,  279,
-};
-#define YYFINAL 18
-#ifndef YYDEBUG
-#define YYDEBUG 0
-#endif
-#define YYMAXTOKEN 287
-#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","LOG_INPUT","NOLOG_INPUT",
-"LOG_OUTPUT","NOLOG_OUTPUT","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",
-"cmndtag : cmndtag LOG_INPUT",
-"cmndtag : cmndtag NOLOG_INPUT",
-"cmndtag : cmndtag LOG_OUTPUT",
-"cmndtag : cmndtag NOLOG_OUTPUT",
-"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 606 "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();
-
-    init_lexer();
-
-    efree(sudoers);
-    sudoers = path ? estrdup(path) : NULL;
-
-    parse_error = FALSE;
-    errorlineno = -1;
-    errorfile = NULL;
-    verbose = !quiet;
-}
-#line 774 "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 187 "gram.y"
-{ ; }
-break;
-case 5:
-#line 195 "gram.y"
-{
-                           ;
-                       }
-break;
-case 6:
-#line 198 "gram.y"
-{
-                           yyerrok;
-                       }
-break;
-case 7:
-#line 201 "gram.y"
-{
-                           add_userspec(yyvsp[-1].member, yyvsp[0].privilege);
-                       }
-break;
-case 8:
-#line 204 "gram.y"
-{
-                           ;
-                       }
-break;
-case 9:
-#line 207 "gram.y"
-{
-                           ;
-                       }
-break;
-case 10:
-#line 210 "gram.y"
-{
-                           ;
-                       }
-break;
-case 11:
-#line 213 "gram.y"
-{
-                           ;
-                       }
-break;
-case 12:
-#line 216 "gram.y"
-{
-                           add_defaults(DEFAULTS, NULL, yyvsp[0].defaults);
-                       }
-break;
-case 13:
-#line 219 "gram.y"
-{
-                           add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults);
-                       }
-break;
-case 14:
-#line 222 "gram.y"
-{
-                           add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults);
-                       }
-break;
-case 15:
-#line 225 "gram.y"
-{
-                           add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults);
-                       }
-break;
-case 16:
-#line 228 "gram.y"
-{
-                           add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults);
-                       }
-break;
-case 18:
-#line 234 "gram.y"
-{
-                           list_append(yyvsp[-2].defaults, yyvsp[0].defaults);
-                           yyval.defaults = yyvsp[-2].defaults;
-                       }
-break;
-case 19:
-#line 240 "gram.y"
-{
-                           yyval.defaults = new_default(yyvsp[0].string, NULL, TRUE);
-                       }
-break;
-case 20:
-#line 243 "gram.y"
-{
-                           yyval.defaults = new_default(yyvsp[0].string, NULL, FALSE);
-                       }
-break;
-case 21:
-#line 246 "gram.y"
-{
-                           yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, TRUE);
-                       }
-break;
-case 22:
-#line 249 "gram.y"
-{
-                           yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+');
-                       }
-break;
-case 23:
-#line 252 "gram.y"
-{
-                           yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-');
-                       }
-break;
-case 25:
-#line 258 "gram.y"
-{
-                           list_append(yyvsp[-2].privilege, yyvsp[0].privilege);
-                           yyval.privilege = yyvsp[-2].privilege;
-                       }
-break;
-case 26:
-#line 264 "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 274 "gram.y"
-{
-                           yyval.member = yyvsp[0].member;
-                           yyval.member->negated = FALSE;
-                       }
-break;
-case 28:
-#line 278 "gram.y"
-{
-                           yyval.member = yyvsp[0].member;
-                           yyval.member->negated = TRUE;
-                       }
-break;
-case 29:
-#line 284 "gram.y"
-{
-                           yyval.member = new_member(yyvsp[0].string, ALIAS);
-                       }
-break;
-case 30:
-#line 287 "gram.y"
-{
-                           yyval.member = new_member(NULL, ALL);
-                       }
-break;
-case 31:
-#line 290 "gram.y"
-{
-                           yyval.member = new_member(yyvsp[0].string, NETGROUP);
-                       }
-break;
-case 32:
-#line 293 "gram.y"
-{
-                           yyval.member = new_member(yyvsp[0].string, NTWKADDR);
-                       }
-break;
-case 33:
-#line 296 "gram.y"
-{
-                           yyval.member = new_member(yyvsp[0].string, WORD);
-                       }
-break;
-case 35:
-#line 302 "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 (yyvsp[0].cmndspec->tags.log_input == UNSPEC)
-                               yyvsp[0].cmndspec->tags.log_input = yyvsp[0].cmndspec->prev->tags.log_input;
-                           if (yyvsp[0].cmndspec->tags.log_output == UNSPEC)
-                               yyvsp[0].cmndspec->tags.log_output = yyvsp[0].cmndspec->prev->tags.log_output;
-                           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 334 "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 360 "gram.y"
-{
-                           yyval.member = yyvsp[0].member;
-                           yyval.member->negated = FALSE;
-                       }
-break;
-case 38:
-#line 364 "gram.y"
-{
-                           yyval.member = yyvsp[0].member;
-                           yyval.member->negated = TRUE;
-                       }
-break;
-case 39:
-#line 370 "gram.y"
-{
-                           yyval.string = yyvsp[0].string;
-                       }
-break;
-case 40:
-#line 375 "gram.y"
-{
-                           yyval.string = yyvsp[0].string;
-                       }
-break;
-case 41:
-#line 380 "gram.y"
-{
-                           yyval.seinfo.role = NULL;
-                           yyval.seinfo.type = NULL;
-                       }
-break;
-case 42:
-#line 384 "gram.y"
-{
-                           yyval.seinfo.role = yyvsp[0].string;
-                           yyval.seinfo.type = NULL;
-                       }
-break;
-case 43:
-#line 388 "gram.y"
-{
-                           yyval.seinfo.type = yyvsp[0].string;
-                           yyval.seinfo.role = NULL;
-                       }
-break;
-case 44:
-#line 392 "gram.y"
-{
-                           yyval.seinfo.role = yyvsp[-1].string;
-                           yyval.seinfo.type = yyvsp[0].string;
-                       }
-break;
-case 45:
-#line 396 "gram.y"
-{
-                           yyval.seinfo.type = yyvsp[-1].string;
-                           yyval.seinfo.role = yyvsp[0].string;
-                       }
-break;
-case 46:
-#line 402 "gram.y"
-{
-                           yyval.runas = NULL;
-                       }
-break;
-case 47:
-#line 405 "gram.y"
-{
-                           yyval.runas = yyvsp[-1].runas;
-                       }
-break;
-case 48:
-#line 410 "gram.y"
-{
-                           yyval.runas = emalloc(sizeof(struct runascontainer));
-                           yyval.runas->runasusers = yyvsp[0].member;
-                           yyval.runas->runasgroups = NULL;
-                       }
-break;
-case 49:
-#line 415 "gram.y"
-{
-                           yyval.runas = emalloc(sizeof(struct runascontainer));
-                           yyval.runas->runasusers = yyvsp[-2].member;
-                           yyval.runas->runasgroups = yyvsp[0].member;
-                       }
-break;
-case 50:
-#line 420 "gram.y"
-{
-                           yyval.runas = emalloc(sizeof(struct runascontainer));
-                           yyval.runas->runasusers = NULL;
-                           yyval.runas->runasgroups = yyvsp[0].member;
-                       }
-break;
-case 51:
-#line 427 "gram.y"
-{
-                           yyval.tag.nopasswd = yyval.tag.noexec = yyval.tag.setenv =
-                               yyval.tag.log_input = yyval.tag.log_output = UNSPEC;
-                       }
-break;
-case 52:
-#line 431 "gram.y"
-{
-                           yyval.tag.nopasswd = TRUE;
-                       }
-break;
-case 53:
-#line 434 "gram.y"
-{
-                           yyval.tag.nopasswd = FALSE;
-                       }
-break;
-case 54:
-#line 437 "gram.y"
-{
-                           yyval.tag.noexec = TRUE;
-                       }
-break;
-case 55:
-#line 440 "gram.y"
-{
-                           yyval.tag.noexec = FALSE;
-                       }
-break;
-case 56:
-#line 443 "gram.y"
-{
-                           yyval.tag.setenv = TRUE;
-                       }
-break;
-case 57:
-#line 446 "gram.y"
-{
-                           yyval.tag.setenv = FALSE;
-                       }
-break;
-case 58:
-#line 449 "gram.y"
-{
-                           yyval.tag.log_input = TRUE;
-                       }
-break;
-case 59:
-#line 452 "gram.y"
-{
-                           yyval.tag.log_input = FALSE;
-                       }
-break;
-case 60:
-#line 455 "gram.y"
-{
-                           yyval.tag.log_output = TRUE;
-                       }
-break;
-case 61:
-#line 458 "gram.y"
-{
-                           yyval.tag.log_output = FALSE;
-                       }
-break;
-case 62:
-#line 463 "gram.y"
-{
-                           yyval.member = new_member(NULL, ALL);
-                       }
-break;
-case 63:
-#line 466 "gram.y"
-{
-                           yyval.member = new_member(yyvsp[0].string, ALIAS);
-                       }
-break;
-case 64:
-#line 469 "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 67:
-#line 481 "gram.y"
-{
-                           char *s;
-                           if ((s = alias_add(yyvsp[-2].string, HOSTALIAS, yyvsp[0].member)) != NULL) {
-                               yyerror(s);
-                               YYERROR;
-                           }
-                       }
-break;
-case 69:
-#line 491 "gram.y"
-{
-                           list_append(yyvsp[-2].member, yyvsp[0].member);
-                           yyval.member = yyvsp[-2].member;
-                       }
-break;
-case 72:
-#line 501 "gram.y"
-{
-                           char *s;
-                           if ((s = alias_add(yyvsp[-2].string, CMNDALIAS, yyvsp[0].member)) != NULL) {
-                               yyerror(s);
-                               YYERROR;
-                           }
-                       }
-break;
-case 74:
-#line 511 "gram.y"
-{
-                           list_append(yyvsp[-2].member, yyvsp[0].member);
-                           yyval.member = yyvsp[-2].member;
-                       }
-break;
-case 77:
-#line 521 "gram.y"
-{
-                           char *s;
-                           if ((s = alias_add(yyvsp[-2].string, RUNASALIAS, yyvsp[0].member)) != NULL) {
-                               yyerror(s);
-                               YYERROR;
-                           }
-                       }
-break;
-case 80:
-#line 534 "gram.y"
-{
-                           char *s;
-                           if ((s = alias_add(yyvsp[-2].string, USERALIAS, yyvsp[0].member)) != NULL) {
-                               yyerror(s);
-                               YYERROR;
-                           }
-                       }
-break;
-case 82:
-#line 544 "gram.y"
-{
-                           list_append(yyvsp[-2].member, yyvsp[0].member);
-                           yyval.member = yyvsp[-2].member;
-                       }
-break;
-case 83:
-#line 550 "gram.y"
-{
-                           yyval.member = yyvsp[0].member;
-                           yyval.member->negated = FALSE;
-                       }
-break;
-case 84:
-#line 554 "gram.y"
-{
-                           yyval.member = yyvsp[0].member;
-                           yyval.member->negated = TRUE;
-                       }
-break;
-case 85:
-#line 560 "gram.y"
-{
-                           yyval.member = new_member(yyvsp[0].string, ALIAS);
-                       }
-break;
-case 86:
-#line 563 "gram.y"
-{
-                           yyval.member = new_member(NULL, ALL);
-                       }
-break;
-case 87:
-#line 566 "gram.y"
-{
-                           yyval.member = new_member(yyvsp[0].string, NETGROUP);
-                       }
-break;
-case 88:
-#line 569 "gram.y"
-{
-                           yyval.member = new_member(yyvsp[0].string, USERGROUP);
-                       }
-break;
-case 89:
-#line 572 "gram.y"
-{
-                           yyval.member = new_member(yyvsp[0].string, WORD);
-                       }
-break;
-case 91:
-#line 578 "gram.y"
-{
-                           list_append(yyvsp[-2].member, yyvsp[0].member);
-                           yyval.member = yyvsp[-2].member;
-                       }
-break;
-case 92:
-#line 584 "gram.y"
-{
-                           yyval.member = yyvsp[0].member;
-                           yyval.member->negated = FALSE;
-                       }
-break;
-case 93:
-#line 588 "gram.y"
-{
-                           yyval.member = yyvsp[0].member;
-                           yyval.member->negated = TRUE;
-                       }
-break;
-case 94:
-#line 594 "gram.y"
-{
-                           yyval.member = new_member(yyvsp[0].string, ALIAS);
-                       }
-break;
-case 95:
-#line 597 "gram.y"
-{
-                           yyval.member = new_member(NULL, ALL);
-                       }
-break;
-case 96:
-#line 600 "gram.y"
-{
-                           yyval.member = new_member(yyvsp[0].string, WORD);
-                       }
-break;
-#line 1543 "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
deleted file mode 100644 (file)
index 2bec420..0000000
--- a/gram.h
+++ /dev/null
@@ -1,47 +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 DEFAULTS_CMND 268
-#define NOPASSWD 269
-#define PASSWD 270
-#define NOEXEC 271
-#define EXEC 272
-#define SETENV 273
-#define NOSETENV 274
-#define LOG_INPUT 275
-#define NOLOG_INPUT 276
-#define LOG_OUTPUT 277
-#define NOLOG_OUTPUT 278
-#define ALL 279
-#define COMMENT 280
-#define HOSTALIAS 281
-#define CMNDALIAS 282
-#define USERALIAS 283
-#define RUNASALIAS 284
-#define ERROR 285
-#define TYPE 286
-#define ROLE 287
-#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
deleted file mode 100644 (file)
index 9a07ee7..0000000
--- a/gram.y
+++ /dev/null
@@ -1,794 +0,0 @@
-%{
-/*
- * Copyright (c) 1996, 1998-2005, 2007-2010
- *     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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_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"
-
-/*
- * 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>    LOG_INPUT              /* log user's cmnd input */
-%token <tok>    NOLOG_INPUT            /* don't log user's cmnd input */
-%token <tok>    LOG_OUTPUT             /* log cmnd output */
-%token <tok>    NOLOG_OUTPUT           /* don't log cmnd output */
-%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 ($3->tags.log_input == UNSPEC)
-                               $3->tags.log_input = $3->prev->tags.log_input;
-                           if ($3->tags.log_output == UNSPEC)
-                               $3->tags.log_output = $3->prev->tags.log_output;
-                           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 =
-                               $$.log_input = $$.log_output = 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;
-                       }
-               |       cmndtag LOG_INPUT {
-                           $$.log_input = TRUE;
-                       }
-               |       cmndtag NOLOG_INPUT {
-                           $$.log_input = FALSE;
-                       }
-               |       cmndtag LOG_OUTPUT {
-                           $$.log_output = TRUE;
-                       }
-               |       cmndtag NOLOG_OUTPUT {
-                           $$.log_output = 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();
-
-    init_lexer();
-
-    efree(sudoers);
-    sudoers = path ? estrdup(path) : NULL;
-
-    parse_error = FALSE;
-    errorlineno = -1;
-    errorfile = NULL;
-    verbose = !quiet;
-}
diff --git a/include/Makefile.in b/include/Makefile.in
new file mode 100644 (file)
index 0000000..150ca62
--- /dev/null
@@ -0,0 +1,82 @@
+#
+# Copyright (c) 2011 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.
+#
+# @configure_input@
+#
+
+#### Start of system configuration section. ####
+
+srcdir = @srcdir@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+includedir = @includedir@
+
+# Our install program supports extra flags...
+INSTALL = $(SHELL) $(top_srcdir)/install-sh -c
+
+# Where to install things...
+prefix = @prefix@
+datarootdir = @datarootdir@
+localstatedir = @localstatedir@
+
+# User and group ids the installed files should be "owned" by
+install_uid = 0
+install_gid = 0
+
+#### End of system configuration section. ####
+
+SHELL = @SHELL@
+
+all:
+
+Makefile: $(srcdir)/Makefile.in
+       (cd $(top_builddir) && ./config.status --file include/Makefile)
+
+.SUFFIXES: .h
+
+pre-install:
+
+install: install-dirs install-includes
+
+install-dirs:
+       $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(includedir)
+
+install-binaries:
+
+install-doc:
+
+install-includes: install-dirs
+       $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 $(srcdir)/sudo_plugin.h $(DESTDIR)$(includedir)
+
+install-plugin:
+
+uninstall:
+       -rm -f $(DESTDIR)$(includedir)/sudo_plugin.h
+
+check:
+
+clean:
+
+mostlyclean: clean
+
+distclean: clean
+       -rm -rf Makefile
+
+clobber: distclean
+
+realclean: distclean
+
+cleandir: distclean
diff --git a/include/alloc.h b/include/alloc.h
new file mode 100644 (file)
index 0000000..912654e
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2009-2010 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.
+ */
+
+#ifndef _SUDO_ALLOC_H
+#define _SUDO_ALLOC_H
+
+#include <stdarg.h>
+
+int     easprintf(char **, const char *, ...) __printflike(2, 3);
+int     evasprintf(char **, const char *, va_list) __printflike(2, 0);
+void    efree(void *);
+void   *emalloc(size_t);
+void   *emalloc2(size_t, size_t);
+void   *erealloc(void *, size_t);
+void   *erealloc3(void *, size_t, size_t);
+char   *estrdup(const char *);
+char   *estrndup(const char *, size_t);
+
+#endif /* _SUDO_ALLOC_H */
diff --git a/include/error.h b/include/error.h
new file mode 100644 (file)
index 0000000..190bd26
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2004, 2010 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.
+ */
+
+#ifndef _SUDO_ERROR_H_
+#define        _SUDO_ERROR_H_
+
+#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 *, ...);
+
+#endif /* _SUDO_ERROR_H_ */
diff --git a/include/fileops.h b/include/fileops.h
new file mode 100644 (file)
index 0000000..e1c93a6
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef _SUDO_FILEOPS_H
+#define _SUDO_FILEOPS_H
+
+/*
+ * Flags for lock_file()
+ */
+#define SUDO_LOCK      1               /* lock a file */
+#define SUDO_TLOCK     2               /* test & lock a file (non-blocking) */
+#define SUDO_UNLOCK    4               /* unlock a file */
+
+struct timeval;
+
+int lock_file(int, int);
+int touch(int, char *, struct timeval *);
+char *sudo_parseln(FILE *);
+
+#endif /* _SUDO_FILEOPS_H */
diff --git a/include/lbuf.h b/include/lbuf.h
new file mode 100644 (file)
index 0000000..501eeaf
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2007, 2010 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.
+ */
+
+#ifndef _SUDO_LBUF_H
+#define _SUDO_LBUF_H
+
+/*
+ * Line buffer struct.
+ */
+struct lbuf {
+    int (*output)(const char *);
+    char *buf;
+    const char *continuation;
+    int indent;
+    int len;
+    int size;
+    int cols;
+};
+
+void lbuf_init(struct lbuf *, int (*)(const char *), int, const char *, int);
+void lbuf_destroy(struct lbuf *);
+void lbuf_append(struct lbuf *, ...);
+void lbuf_append_quoted(struct lbuf *, const char *, ...);
+void lbuf_print(struct lbuf *);
+
+#endif /* _SUDO_LBUF_H */
diff --git a/include/list.h b/include/list.h
new file mode 100644 (file)
index 0000000..1055e22
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2007, 2010 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.
+ */
+
+#ifndef _SUDO_LIST_H
+#define _SUDO_LIST_H
+
+/*
+ * Convenience macro for declaring a list head.
+ */
+#define TQ_DECLARE(n)                                  \
+struct n##_list {                                      \
+    struct n *first;                                   \
+    struct n *last;                                    \
+};
+
+/*
+ * 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(void *);
+void tq_append(void *, void *);
+void tq_remove(void *, void *);
+void list_append(void *, void *);
+void list2tq(void *, void *);
+
+#endif /* _SUDO_LIST_H */
diff --git a/include/missing.h b/include/missing.h
new file mode 100644 (file)
index 0000000..68d5879
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2008, 2009-2010
+ *     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.
+ */
+
+#ifndef _SUDO_MISSING_H
+#define _SUDO_MISSING_H
+
+#include <stdio.h>
+#include <stdarg.h>
+
+/*
+ * Macros and functions that may be missing on some operating systems.
+ */
+
+/* Define away __attribute__ for non-gcc or old gcc */
+#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__))
+# else
+#  define __unused
+# endif
+#endif
+
+/* 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)))
+# else
+#  define __printflike(f, v)
+# endif
+#endif
+
+/*
+ * Some systems lack full limit definitions.
+ */
+#ifndef OPEN_MAX
+# define OPEN_MAX      256
+#endif
+
+#ifndef INT_MAX
+# define INT_MAX       0x7fffffff
+#endif
+
+#ifndef PATH_MAX
+# ifdef MAXPATHLEN
+#  define PATH_MAX             MAXPATHLEN
+# else
+#  ifdef _POSIX_PATH_MAX
+#   define PATH_MAX            _POSIX_PATH_MAX
+#  else
+#   define PATH_MAX            1024
+#  endif
+# endif
+#endif
+
+#ifndef MAXHOSTNAMELEN
+# define MAXHOSTNAMELEN                64
+#endif
+
+/*
+ * Posix versions for those without...
+ */
+#ifndef _S_IFMT
+# define _S_IFMT               S_IFMT
+#endif /* _S_IFMT */
+#ifndef _S_IFREG
+# define _S_IFREG              S_IFREG
+#endif /* _S_IFREG */
+#ifndef _S_IFDIR
+# define _S_IFDIR              S_IFDIR
+#endif /* _S_IFDIR */
+#ifndef _S_IFLNK
+# define _S_IFLNK              S_IFLNK
+#endif /* _S_IFLNK */
+#ifndef S_ISREG
+# define S_ISREG(m)            (((m) & _S_IFMT) == _S_IFREG)
+#endif /* S_ISREG */
+#ifndef S_ISDIR
+# define S_ISDIR(m)            (((m) & _S_IFMT) == _S_IFDIR)
+#endif /* S_ISDIR */
+
+/*
+ * Some OS's may not have this.
+ */
+#ifndef S_IRWXU
+# define S_IRWXU               0000700         /* rwx for owner */
+#endif /* S_IRWXU */
+
+/*
+ * These should be defined in <unistd.h> but not everyone has them.
+ */
+#ifndef STDIN_FILENO
+# define       STDIN_FILENO    0
+#endif
+#ifndef STDOUT_FILENO
+# define       STDOUT_FILENO   1
+#endif
+#ifndef STDERR_FILENO
+# define       STDERR_FILENO   2
+#endif
+
+/*
+ * BSD defines these in <sys/param.h> but others may not.
+ */
+#ifndef MIN
+# define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef MAX
+# define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+/*
+ * Simple isblank() macro and function for systems without it.
+ */
+#ifndef HAVE_ISBLANK
+int isblank(int);
+# define isblank(_x)   ((_x) == ' ' || (_x) == '\t')
+#endif
+
+/*
+ * NCR's SVr4 has _innetgr(3) instead of innetgr(3) for some reason.
+ */
+#ifdef HAVE__INNETGR
+# define innetgr(n, h, u, d)   (_innetgr(n, h, u, d))
+# define HAVE_INNETGR 1
+#endif /* HAVE__INNETGR */
+
+/*
+ * On POSIX systems, O_NOCTTY is the default so some OS's may lack this define.
+ */
+#ifndef O_NOCTTY
+# define O_NOCTTY      0
+#endif /* O_NOCTTY */
+
+/*
+ * Add IRIX-like sigaction_t for those without it.
+ * SA_RESTART is not required by POSIX; SunOS has SA_INTERRUPT instead.
+ */
+#ifndef HAVE_SIGACTION_T
+typedef struct sigaction sigaction_t;
+#endif
+#ifndef SA_INTERRUPT
+# define SA_INTERRUPT  0
+#endif
+#ifndef SA_RESTART
+# define SA_RESTART    0
+#endif
+
+/*
+ * If dirfd() does not exists, hopefully dd_fd does.
+ */
+#if !defined(HAVE_DIRFD) && defined(HAVE_DD_FD)
+# define dirfd(_d)     ((_d)->dd_fd)
+# define HAVE_DIRFD
+#endif
+
+/*
+ * Define futimes() in terms of futimesat() if needed.
+ */
+#if !defined(HAVE_FUTIMES) && defined(HAVE_FUTIMESAT)
+# define futimes(_f, _tv)      futimesat(_f, NULL, _tv)
+# define HAVE_FUTIMES
+#endif
+
+#if !defined(HAVE_KILLPG) && !defined(killpg)
+# define killpg(s)     kill(-(s))
+#endif
+
+/*
+ * If we lack getprogname(), emulate with __progname if possible.
+ * Otherwise, add a prototype for use with our own getprogname.c.
+ */
+#ifndef HAVE_GETPROGNAME
+# ifdef HAVE___PROGNAME
+extern const char *__progname;
+#  define getprogname()          (__progname)
+# else
+const char *getprogname(void);
+void setprogname(const char *);
+#endif /* HAVE___PROGNAME */
+#endif /* !HAVE_GETPROGNAME */
+
+#ifndef timevalclear
+# define timevalclear(tv)      ((tv)->tv_sec = (tv)->tv_usec = 0)
+#endif
+#ifndef timevalisset
+# define timevalisset(tv)      ((tv)->tv_sec || (tv)->tv_usec)
+#endif
+#ifndef timevalcmp
+# define timevalcmp(tv1, tv2, op)                                             \
+    (((tv1)->tv_sec == (tv2)->tv_sec) ?                                               \
+       ((tv1)->tv_usec op (tv2)->tv_usec) :                                   \
+       ((tv1)->tv_sec op (tv2)->tv_sec))
+#endif
+#ifndef timevaladd
+# define timevaladd(tv1, tv2)                                                 \
+    do {                                                                      \
+       (tv1)->tv_sec += (tv2)->tv_sec;                                        \
+       (tv1)->tv_usec += (tv2)->tv_usec;                                      \
+       if ((tv1)->tv_usec >= 1000000) {                                       \
+           (tv1)->tv_sec++;                                                   \
+           (tv1)->tv_usec -= 1000000;                                         \
+       }                                                                      \
+    } while (0)
+#endif
+#ifndef timevalsub
+# define timevalsub(tv1, tv2)                                                 \
+    do {                                                                      \
+       (tv1)->tv_sec -= (tv2)->tv_sec;                                        \
+       (tv1)->tv_usec -= (tv2)->tv_usec;                                      \
+       if ((tv1)->tv_usec < 0) {                                              \
+           (tv1)->tv_sec--;                                                   \
+           (tv1)->tv_usec += 1000000;                                         \
+       }                                                                      \
+    } while (0)
+#endif
+
+/* Not all systems define NSIG in signal.h */
+#if !defined(NSIG)
+# if defined(_NSIG)
+#  define NSIG _NSIG
+# elif defined(__NSIG)
+#  define NSIG __NSIG
+# else
+#  define NSIG 64
+# endif
+#endif
+
+#ifndef WCOREDUMP
+# define WCOREDUMP(x)  ((x) & 0x80)
+#endif
+
+#ifndef HAVE_SETEUID
+#  if defined(HAVE_SETRESUID)
+#    define seteuid(u) setresuid(-1, (u), -1)
+#    define setegid(g) setresgid(-1, (g), -1)
+#    define HAVE_SETEUID 1
+#  elif defined(HAVE_SETREUID)
+#    define seteuid(u) setreuid(-1, (u))
+#    define setegid(g) setregid(-1, (g))
+#    define HAVE_SETEUID 1
+#  endif
+#endif /* HAVE_SETEUID */
+
+/*
+ * HP-UX does not declare innetgr() or getdomainname().
+ * Solaris does not declare getdomainname().
+ */
+#if defined(__hpux)
+int innetgr(const char *, const char *, const char *, const char *);
+#endif
+#if defined(__hpux) || defined(__sun)
+int getdomainname(char *, size_t);
+#endif
+
+/* Functions "missing" from libc. */
+
+struct timeval;
+struct timespec;
+
+#ifndef HAVE_CLOSEFROM
+void closefrom(int);
+#endif
+#ifndef HAVE_GETCWD
+char *getcwd(char *, size_t size);
+#endif
+#ifndef HAVE_GETLINE
+ssize_t getline(char **, size_t *, FILE *);
+#endif
+#ifndef HAVE_UTIMES
+int utimes(const char *, const struct timeval *);
+#endif
+#ifdef HAVE_FUTIME
+int futimes(int, const struct timeval *);
+#endif
+#ifndef HAVE_SNPRINTF
+int snprintf(char *, size_t, const char *, ...) __printflike(3, 4);
+#endif
+#ifndef HAVE_VSNPRINTF
+int vsnprintf(char *, size_t, const char *, va_list) __printflike(3, 0);
+#endif
+#ifndef HAVE_ASPRINTF
+int asprintf(char **, const char *, ...) __printflike(2, 3);
+#endif
+#ifndef HAVE_VASPRINTF
+int vasprintf(char **, const char *, va_list) __printflike(2, 0);
+#endif
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *, const char *, size_t);
+#endif
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *, const char *, size_t);
+#endif
+#ifndef HAVE_MEMRCHR
+void *memrchr(const void *, int, size_t);
+#endif
+#ifndef HAVE_MKDTEMP
+char *mkdtemp(char *);
+#endif
+#ifndef HAVE_MKSTEMPS
+int mkstemps(char *, int);
+#endif
+#ifndef HAVE_NANOSLEEP
+int nanosleep(const struct timespec *, struct timespec *);
+#endif
+#ifndef HAVE_SETENV
+int setenv(const char *, const char *, int);
+#endif
+#ifndef HAVE_UNSETENV
+int unsetenv(const char *);
+#endif
+#ifndef HAVE_STRSIGNAL
+char *strsignal(int);
+#endif
+
+#endif /* _SUDO_MISSING_H */
diff --git a/include/sudo_plugin.h b/include/sudo_plugin.h
new file mode 100644 (file)
index 0000000..2306503
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2009-2011 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.
+ */
+
+#ifndef _SUDO_PLUGIN_H
+#define _SUDO_PLUGIN_H
+
+/* API version major/minor */
+#define SUDO_API_VERSION_MAJOR 1
+#define SUDO_API_VERSION_MINOR 1
+#define SUDO_API_MKVERSION(x, y) ((x << 16) | y)
+#define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR)
+
+/* Getters and setters for API version */
+#define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16)
+#define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
+#define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \
+    *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \
+} while(0)
+#define SUDO_VERSION_SET_MINOR(vp, n) do { \
+    *(vp) = (*(vp) & 0xffff0000) | (n); \
+} while(0)
+
+/* Conversation function types and defines */
+struct sudo_conv_message {
+#define SUDO_CONV_PROMPT_ECHO_OFF   0x0001  /* do not echo user input */
+#define SUDO_CONV_PROMPT_ECHO_ON    0x0002  /* echo user input */
+#define SUDO_CONV_ERROR_MSG        0x0003  /* error message */
+#define SUDO_CONV_INFO_MSG         0x0004  /* informational message */
+#define SUDO_CONV_PROMPT_MASK      0x0005  /* mask user input */
+#define SUDO_CONV_PROMPT_ECHO_OK    0x1000  /* flag: allow echo if no tty */
+    int msg_type;
+    int timeout;
+    const char *msg;
+};
+
+struct sudo_conv_reply {
+    char *reply;
+};
+
+typedef int (*sudo_conv_t)(int num_msgs, const struct sudo_conv_message msgs[],
+       struct sudo_conv_reply replies[]);
+typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...);
+
+/* Policy plugin type and defines */
+struct passwd;
+struct policy_plugin {
+#define SUDO_POLICY_PLUGIN     1
+    unsigned int type; /* always SUDO_POLICY_PLUGIN */
+    unsigned int version; /* always SUDO_API_VERSION */
+    int (*open)(unsigned int version, sudo_conv_t conversation,
+       sudo_printf_t sudo_printf, char * const settings[],
+       char * const user_info[], char * const user_env[]);
+    void (*close)(int exit_status, int error); /* wait status or error */
+    int (*show_version)(int verbose);
+    int (*check_policy)(int argc, char * const argv[],
+       char *env_add[], char **command_info[],
+       char **argv_out[], char **user_env_out[]);
+    int (*list)(int argc, char * const argv[], int verbose,
+       const char *list_user);
+    int (*validate)(void);
+    void (*invalidate)(int remove);
+    int (*init_session)(struct passwd *pwd);
+};
+
+/* I/O plugin type and defines */
+struct io_plugin {
+#define SUDO_IO_PLUGIN     2
+    unsigned int type; /* always SUDO_IO_PLUGIN */
+    unsigned int version; /* always SUDO_API_VERSION */
+    int (*open)(unsigned int version, sudo_conv_t conversation,
+       sudo_printf_t sudo_printf, char * const settings[],
+       char * const user_info[], char * const command_info[],
+       int argc, char * const argv[], char * const user_env[]);
+    void (*close)(int exit_status, int error); /* wait status or error */
+    int (*show_version)(int verbose);
+    int (*log_ttyin)(const char *buf, unsigned int len);
+    int (*log_ttyout)(const char *buf, unsigned int len);
+    int (*log_stdin)(const char *buf, unsigned int len);
+    int (*log_stdout)(const char *buf, unsigned int len);
+    int (*log_stderr)(const char *buf, unsigned int len);
+};
+
+/* Sudoers group plugin version major/minor */
+#define GROUP_API_VERSION_MAJOR 1
+#define GROUP_API_VERSION_MINOR 0
+#define GROUP_API_VERSION ((GROUP_API_VERSION_MAJOR << 16) | GROUP_API_VERSION_MINOR)
+
+/* Getters and setters for group version */
+#define GROUP_API_VERSION_GET_MAJOR(v) ((v) >> 16)
+#define GROUP_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
+#define GROUP_API_VERSION_SET_MAJOR(vp, n) do { \
+    *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \
+} while(0)
+#define GROUP_API_VERSION_SET_MINOR(vp, n) do { \
+    *(vp) = (*(vp) & 0xffff0000) | (n); \
+} while(0)
+
+/*
+ * version: for compatibility checking
+ * group_init: return 1 on success, 0 if unconfigured, -1 on error.
+ * group_cleanup: called to clean up resources used by provider
+ * user_in_group: returns 1 if user is in group, 0 if not.
+ *                note that pwd may be NULL if the user is not in passwd.
+ */
+struct sudoers_group_plugin {
+    unsigned int version;
+    int (*init)(int version, sudo_printf_t sudo_printf, char *const argv[]);
+    void (*cleanup)(void);
+    int (*query)(const char *user, const char *group, const struct passwd *pwd);
+};
+
+#endif /* _SUDO_PLUGIN_H */
diff --git a/ins_2001.h b/ins_2001.h
deleted file mode 100644 (file)
index 63a5d64..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 1996, 1998, 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.
- */
-
-#ifndef _SUDO_INS_2001_H
-#define _SUDO_INS_2001_H
-
-    /*
-     * HAL insults (paraphrased) from 2001.
-     */
-
-    "Just what do you think you're doing Dave?",
-    "It can only be attributed to human error.",
-    "That's something I cannot allow to happen.",
-    "My mind is going. I can feel it.",
-    "Sorry about this, I know it's a bit silly.",
-    "Take a stress pill and think things over.",
-    "This mission is too important for me to allow you to jeopardize it.",
-    "I feel much better now.",
-
-#endif /* _SUDO_INS_2001_H */
diff --git a/ins_classic.h b/ins_classic.h
deleted file mode 100644 (file)
index b1942bd..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 1996, 1998, 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.
- */
-
-#ifndef _SUDO_INS_CLASSIC_H
-#define _SUDO_INS_CLASSIC_H
-
-    /*
-     * Insults from the original sudo(8).
-     */
-
-    "Wrong!  You cheating scum!",
-#ifdef PC_INSULTS
-    "And you call yourself a Rocket Scientist!",
-#else
-    "No soap, honkie-lips.",
-#endif
-    "Where did you learn to type?",
-    "Are you on drugs?",
-    "My pet ferret can type better than you!",
-    "You type like i drive.",
-    "Do you think like you type?",
-    "Your mind just hasn't been the same since the electro-shock, has it?",
-
-#endif /* _SUDO_INS_CLASSIC_H */
diff --git a/ins_csops.h b/ins_csops.h
deleted file mode 100644 (file)
index 20e9b02..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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
- * 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.
- */
-
-#ifndef _SUDO_INS_CSOPS_H
-#define _SUDO_INS_CSOPS_H
-
-    /*
-     * CSOps insults (may be site dependent).
-     */
-
-    "Maybe if you used more than just two fingers...",
-    "BOB says:  You seem to have forgotten your passwd, enter another!",
-    "stty: unknown mode: doofus",
-    "I can't hear you -- I'm using the scrambler.",
-    "The more you drive -- the dumber you get.",
-#ifdef PC_INSULTS
-    "Listen, broccoli brains, I don't have time to listen to this trash.",
-#else
-    "Listen, burrito brains, I don't have time to listen to this trash.",
-#endif
-    "I've seen penguins that can type better than that.",
-    "Have you considered trying to match wits with a rutabaga?",
-    "You speak an infinite deal of nothing",
-
-#endif /* _SUDO_INS_CSOPS_H */
diff --git a/ins_goons.h b/ins_goons.h
deleted file mode 100644 (file)
index 16a262a..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 1996, 1998, 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.
- */
-
-#ifndef _SUDO_INS_GOONS_H
-#define _SUDO_INS_GOONS_H
-
-    /*
-     * Insults from the "Goon Show."
-     */
-
-    "You silly, twisted boy you.",
-    "He has fallen in the water!",
-    "We'll all be murdered in our beds!",
-    "You can't come in. Our tiger has got flu",
-    "I don't wish to know that.",
-    "What, what, what, what, what, what, what, what, what, what?",
-    "You can't get the wood, you know.",
-    "You'll starve!",
-    "... and it used to be so popular...",
-    "Pauses for audience applause, not a sausage",
-    "Hold it up to the light --- not a brain in sight!",
-    "Have a gorilla...",
-    "There must be cure for it!",
-    "There's a lot of it about, you know.",
-    "You do that again and see what happens...",
-    "Ying Tong Iddle I Po",
-    "Harm can come to a young lad like that!",
-    "And with that remarks folks, the case of the Crown vs yourself was proven.",
-    "Speak English you fool --- there are no subtitles in this scene.",
-    "You gotta go owwwww!",
-    "I have been called worse.",
-    "It's only your word against mine.",
-    "I think ... err ... I think ... I think I'll go home",
-
-#endif /* _SUDO_INS_GOONS_H */
diff --git a/insults.h b/insults.h
deleted file mode 100644 (file)
index bdb3fc6..0000000
--- a/insults.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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
- * 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.
- */
-
-#ifndef _SUDO_INSULTS_H
-#define _SUDO_INSULTS_H
-
-#if defined(HAL_INSULTS) || defined(GOONS_INSULTS) || defined(CLASSIC_INSULTS) || defined(CSOPS_INSULTS)
-
-/*
- * Use one or more set of insults as determined by configure
- */
-
-char *insults[] = {
-
-# ifdef HAL_INSULTS
-#  include "ins_2001.h"
-# endif
-
-# ifdef GOONS_INSULTS
-#  include "ins_goons.h"
-# endif
-
-# ifdef CLASSIC_INSULTS
-#  include "ins_classic.h"
-# endif
-
-# ifdef CSOPS_INSULTS
-#  include "ins_csops.h"
-# endif
-
-    (char *) 0
-
-};
-
-/*
- * How may I insult you?  Let me count the ways...
- */
-#define NOFINSULTS (sizeof(insults) / sizeof(insults[0]) - 1)
-
-/*
- * return a pseudo-random insult.
- */
-#define INSULT         (insults[time(NULL) % NOFINSULTS])
-
-#endif /* HAL_INSULTS || GOONS_INSULTS || CLASSIC_INSULTS || CSOPS_INSULTS */
-
-#endif /* _SUDO_INSULTS_H */
diff --git a/interfaces.c b/interfaces.c
deleted file mode 100644 (file)
index 502cb94..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-2005, 2007-2010
- *     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.
- */
-
-/*
- * Suppress a warning w/ gcc on Digital UN*X.
- * The system headers should really do this....
- */
-#if defined(__osf__) && !defined(__cplusplus)
-struct mbuf;
-struct rtentry;
-#endif
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-#if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFCONF)
-# include <sys/sockio.h>
-#endif
-#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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <netdb.h>
-#include <errno.h>
-#ifdef _ISC
-# include <sys/stream.h>
-# include <sys/sioctl.h>
-# include <sys/stropts.h>
-# define STRSET(cmd, param, len) {strioctl.ic_cmd=(cmd);\
-                                strioctl.ic_dp=(param);\
-                                strioctl.ic_timout=0;\
-                                strioctl.ic_len=(len);}
-#endif /* _ISC */
-#ifdef _MIPS
-# include <net/soioctl.h>
-#endif /* _MIPS */
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#ifdef HAVE_GETIFADDRS
-# include <ifaddrs.h>
-#endif
-
-#include "sudo.h"
-#include "interfaces.h"
-
-/* Minix apparently lacks IFF_LOOPBACK */
-#ifndef IFF_LOOPBACK
-# define IFF_LOOPBACK  0
-#endif
-
-#ifdef HAVE_GETIFADDRS
-
-/*
- * Allocate and fill in the interfaces global variable with the
- * machine's ip addresses and netmasks.
- */
-void
-load_interfaces()
-{
-    struct ifaddrs *ifa, *ifaddrs;
-    struct sockaddr_in *sin;
-#ifdef HAVE_IN6_ADDR
-    struct sockaddr_in6 *sin6;
-#endif
-    int i;
-
-    if (getifaddrs(&ifaddrs))
-       return;
-
-    /* Allocate space for the interfaces list. */
-    for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) {
-       /* Skip interfaces marked "down" and "loopback". */
-       if (ifa->ifa_addr == NULL || !ISSET(ifa->ifa_flags, IFF_UP) ||
-           ISSET(ifa->ifa_flags, IFF_LOOPBACK))
-           continue;
-
-       switch(ifa->ifa_addr->sa_family) {
-           case AF_INET:
-#ifdef HAVE_IN6_ADDR
-           case AF_INET6:
-#endif
-               num_interfaces++;
-               break;
-       }
-    }
-    if (num_interfaces == 0)
-       return;
-    interfaces =
-       (struct interface *) emalloc2(num_interfaces, sizeof(struct interface));
-
-    /* Store the ip addr / netmask pairs. */
-    for (ifa = ifaddrs, i = 0; ifa != NULL; ifa = ifa -> ifa_next) {
-       /* Skip interfaces marked "down" and "loopback". */
-       if (ifa->ifa_addr == NULL || !ISSET(ifa->ifa_flags, IFF_UP) ||
-           ISSET(ifa->ifa_flags, IFF_LOOPBACK))
-               continue;
-
-       switch(ifa->ifa_addr->sa_family) {
-           case AF_INET:
-               sin = (struct sockaddr_in *)ifa->ifa_addr;
-               if (sin == NULL)
-                   continue;
-               memcpy(&interfaces[i].addr, &sin->sin_addr,
-                   sizeof(struct in_addr));
-               sin = (struct sockaddr_in *)ifa->ifa_netmask;
-               if (sin == NULL)
-                   continue;
-               memcpy(&interfaces[i].netmask, &sin->sin_addr,
-                   sizeof(struct in_addr));
-               interfaces[i].family = AF_INET;
-               i++;
-               break;
-#ifdef HAVE_IN6_ADDR
-           case AF_INET6:
-               sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
-               if (sin6 == NULL)
-                   continue;
-               memcpy(&interfaces[i].addr, &sin6->sin6_addr,
-                   sizeof(struct in6_addr));
-               sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask;
-               if (sin6 == NULL)
-                   continue;
-               memcpy(&interfaces[i].netmask, &sin6->sin6_addr,
-                   sizeof(struct in6_addr));
-               interfaces[i].family = AF_INET6;
-               i++;
-               break;
-#endif /* HAVE_IN6_ADDR */
-       }
-    }
-#ifdef HAVE_FREEIFADDRS
-    freeifaddrs(ifaddrs);
-#else
-    efree(ifaddrs);
-#endif
-}
-
-#elif defined(SIOCGIFCONF) && !defined(STUB_LOAD_INTERFACES)
-
-/*
- * Allocate and fill in the interfaces global variable with the
- * machine's ip addresses and netmasks.
- */
-void
-load_interfaces()
-{
-    struct ifconf *ifconf;
-    struct ifreq *ifr, ifr_tmp;
-    struct sockaddr_in *sin;
-    int sock, n, i;
-    size_t len = sizeof(struct ifconf) + BUFSIZ;
-    char *previfname = "", *ifconf_buf = NULL;
-#ifdef _ISC
-    struct strioctl strioctl;
-#endif /* _ISC */
-
-    sock = socket(AF_INET, SOCK_DGRAM, 0);
-    if (sock < 0)
-       error(1, "cannot open socket");
-
-    /*
-     * Get interface configuration or return (leaving num_interfaces == 0)
-     */
-    for (;;) {
-       ifconf_buf = erealloc(ifconf_buf, len);
-       ifconf = (struct ifconf *) ifconf_buf;
-       ifconf->ifc_len = len - sizeof(struct ifconf);
-       ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf));
-
-#ifdef _ISC
-       STRSET(SIOCGIFCONF, (caddr_t) ifconf, len);
-       if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) {
-#else
-       /* Note that some kernels return EINVAL if the buffer is too small */
-       if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL) {
-#endif /* _ISC */
-           efree(ifconf_buf);
-           (void) close(sock);
-           return;
-       }
-
-       /* Break out of loop if we have a big enough buffer. */
-       if (ifconf->ifc_len + sizeof(struct ifreq) < len)
-           break;
-       len += BUFSIZ;
-    }
-
-    /* Allocate space for the maximum number of interfaces that could exist. */
-    if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0)
-       return;
-    interfaces = (struct interface *) emalloc2(n, sizeof(struct interface));
-
-    /* For each interface, store the ip address and netmask. */
-    for (i = 0; i < ifconf->ifc_len; ) {
-       /* Get a pointer to the current interface. */
-       ifr = (struct ifreq *) &ifconf->ifc_buf[i];
-
-       /* Set i to the subscript of the next interface. */
-       i += sizeof(struct ifreq);
-#ifdef HAVE_SA_LEN
-       if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
-           i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
-#endif /* HAVE_SA_LEN */
-
-       /* Skip duplicates and interfaces with NULL addresses. */
-       sin = (struct sockaddr_in *) &ifr->ifr_addr;
-       if (sin->sin_addr.s_addr == 0 ||
-           strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0)
-           continue;
-
-       if (ifr->ifr_addr.sa_family != AF_INET)
-               continue;
-
-#ifdef SIOCGIFFLAGS
-       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
-           ifr_tmp = *ifr;
-       
-       /* Skip interfaces marked "down" and "loopback". */
-       if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) ||
-           ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK))
-               continue;
-
-       sin = (struct sockaddr_in *) &ifr->ifr_addr;
-       interfaces[num_interfaces].addr.ip4.s_addr = sin->sin_addr.s_addr;
-
-       /* Stash the name of the interface we saved. */
-       previfname = ifr->ifr_name;
-
-       /* Get the netmask. */
-       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
-       STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp));
-       if (ioctl(sock, I_STR, (caddr_t) &strioctl) == 0) {
-#else
-       if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) == 0) {
-#endif /* _ISC */
-           sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
-
-           interfaces[num_interfaces].netmask.ip4.s_addr = sin->sin_addr.s_addr;
-       } else {
-#else
-       {
-#endif /* SIOCGIFNETMASK */
-           if (IN_CLASSC(interfaces[num_interfaces].addr.ip4.s_addr))
-               interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSC_NET);
-           else if (IN_CLASSB(interfaces[num_interfaces].addr.ip4.s_addr))
-               interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSB_NET);
-           else
-               interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSA_NET);
-       }
-
-       /* Only now can we be sure it was a good/interesting interface. */
-       interfaces[num_interfaces].family = AF_INET;
-       num_interfaces++;
-    }
-
-    /* If the expected size < real size, realloc the array. */
-    if (n != num_interfaces) {
-       if (num_interfaces != 0)
-           interfaces = (struct interface *) erealloc3(interfaces,
-               num_interfaces, sizeof(struct interface));
-       else
-           efree(interfaces);
-    }
-    efree(ifconf_buf);
-    (void) close(sock);
-}
-
-#else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */
-
-/*
- * Stub function for those without SIOCGIFCONF
- */
-void
-load_interfaces()
-{
-    return;
-}
-
-#endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */
-
-void
-dump_interfaces()
-{
-    int i;
-#ifdef HAVE_IN6_ADDR
-    char addrbuf[INET6_ADDRSTRLEN], maskbuf[INET6_ADDRSTRLEN];
-#endif
-
-    puts("Local IP address and netmask pairs:");
-    for (i = 0; i < num_interfaces; i++) {
-       switch(interfaces[i].family) {
-           case AF_INET:
-               printf("\t%s / ", inet_ntoa(interfaces[i].addr.ip4));
-               puts(inet_ntoa(interfaces[i].netmask.ip4));
-               break;
-#ifdef HAVE_IN6_ADDR
-           case AF_INET6:
-               inet_ntop(AF_INET6, &interfaces[i].addr.ip6,
-                   addrbuf, sizeof(addrbuf));
-               inet_ntop(AF_INET6, &interfaces[i].netmask.ip6,
-                   maskbuf, sizeof(maskbuf));
-               printf("\t%s / %s\n", addrbuf, maskbuf);
-               break;
-#endif /* HAVE_IN6_ADDR */
-       }
-    }
-}
diff --git a/interfaces.h b/interfaces.h
deleted file mode 100644 (file)
index 06b0b85..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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
- * 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.
- */
-
-#ifndef _SUDO_INTERFACES_H
-#define _SUDO_INTERFACES_H
-
-/*
- * Union to hold either strucr in_addr or in6_add
- */
-union sudo_in_addr_un {
-    struct in_addr ip4;
-#ifdef HAVE_IN6_ADDR
-    struct in6_addr ip6;
-#endif
-};
-
-/*
- * IP address and netmask pairs for checking against local interfaces.
- */
-struct interface {
-    int family;        /* AF_INET or AF_INET6 */
-    union sudo_in_addr_un addr;
-    union sudo_in_addr_un netmask;
-};
-
-/*
- * Prototypes for external functions.
- */
-void load_interfaces   __P((void));
-void dump_interfaces   __P((void));
-
-/*
- * Definitions for external variables.
- */
-#ifndef _SUDO_MAIN
-extern struct interface *interfaces;
-extern int num_interfaces;
-#endif
-
-#endif /* _SUDO_INTERFACES_H */
diff --git a/iolog.c b/iolog.c
deleted file mode 100644 (file)
index 131770e..0000000
--- a/iolog.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (c) 2009-2010 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 <sys/stat.h>
-#include <sys/time.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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <pwd.h>
-#include <grp.h>
-#ifdef HAVE_ZLIB_H
-# include <zlib.h>
-#endif
-
-#include "sudo.h"
-
-union io_fd {
-    FILE *f;
-#ifdef HAVE_ZLIB_H
-    gzFile g;
-#endif
-    void *v;
-};
-
-struct script_buf {
-    int len; /* buffer length (how much read in) */
-    int off; /* write position (how much already consumed) */
-    char buf[16 * 1024];
-};
-
-#define IOFD_STDIN     0
-#define IOFD_STDOUT    1
-#define IOFD_STDERR    2
-#define IOFD_TTYIN     3
-#define IOFD_TTYOUT    4
-#define IOFD_TIMING    5
-#define IOFD_MAX       6
-
-#ifdef __STDC__
-# define SESSID_MAX    2176782336U
-#else
-# define SESSID_MAX    (unsigned long)2176782336
-#endif
-
-static sigset_t ttyblock;
-static struct timeval last_time;
-static union io_fd io_fds[IOFD_MAX];
-
-void
-io_nextid()
-{
-    struct stat sb;
-    char buf[32], *ep;
-    int fd, i;
-    unsigned long id = 0;
-    int len;
-    ssize_t nread;
-    char pathbuf[PATH_MAX];
-    static const char b36char[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-    /*
-     * Create I/O log directory if it doesn't already exist.
-     */
-    if (stat(def_iolog_dir, &sb) != 0) {
-       if (mkdir(def_iolog_dir, S_IRWXU) != 0)
-           log_error(USE_ERRNO, "Can't mkdir %s", def_iolog_dir);
-    } else if (!S_ISDIR(sb.st_mode)) {
-       log_error(0, "%s exists but is not a directory (0%o)",
-           def_iolog_dir, (unsigned int) sb.st_mode);
-    }
-
-    /*
-     * Open sequence file
-     */
-    len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", def_iolog_dir);
-    if (len <= 0 || len >= sizeof(pathbuf)) {
-       errno = ENAMETOOLONG;
-       log_error(USE_ERRNO, "%s/seq", pathbuf);
-    }
-    fd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
-    if (fd == -1)
-       log_error(USE_ERRNO, "cannot open %s", pathbuf);
-    lock_file(fd, SUDO_LOCK);
-
-    /* Read seq number (base 36). */
-    nread = read(fd, buf, sizeof(buf));
-    if (nread != 0) {
-       if (nread == -1)
-           log_error(USE_ERRNO, "cannot read %s", pathbuf);
-       id = strtoul(buf, &ep, 36);
-       if (buf == ep || id >= SESSID_MAX)
-           log_error(0, "invalid sequence number %s", pathbuf);
-    }
-    id++;
-
-    /*
-     * Convert id to a string and stash in sudo_user.sessid.
-     * Note that that least significant digits go at the end of the string.
-     */
-    for (i = 5; i >= 0; i--) {
-       buf[i] = b36char[id % 36];
-       id /= 36;
-    }
-    buf[6] = '\n';
-
-    /* Stash id logging purposes */
-    memcpy(sudo_user.sessid, buf, 6);
-    sudo_user.sessid[6] = '\0';
-
-    /* Rewind and overwrite old seq file. */
-    if (lseek(fd, 0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7)
-       log_error(USE_ERRNO, "Can't write to %s", pathbuf);
-    close(fd);
-}
-
-static int
-build_idpath(pathbuf, pathsize)
-    char *pathbuf;
-    size_t pathsize;
-{
-    struct stat sb;
-    int i, len;
-
-    if (sudo_user.sessid[0] == '\0')
-       log_error(0, "tried to build a session id path without a session id");
-
-    /*
-     * Path is of the form /var/log/sudo-io/00/00/01.
-     */
-    len = snprintf(pathbuf, pathsize, "%s/%c%c/%c%c/%c%c", def_iolog_dir,
-       sudo_user.sessid[0], sudo_user.sessid[1], sudo_user.sessid[2],
-       sudo_user.sessid[3], sudo_user.sessid[4], sudo_user.sessid[5]);
-    if (len <= 0 && len >= pathsize) {
-       errno = ENAMETOOLONG;
-       log_error(USE_ERRNO, "%s/%s", def_iolog_dir, sudo_user.sessid);
-    }
-
-    /*
-     * Create the intermediate subdirs as needed.
-     */
-    for (i = 6; i > 0; i -= 3) {
-       pathbuf[len - i] = '\0';
-       if (stat(pathbuf, &sb) != 0) {
-           if (mkdir(pathbuf, S_IRWXU) != 0)
-               log_error(USE_ERRNO, "Can't mkdir %s", pathbuf);
-       } else if (!S_ISDIR(sb.st_mode)) {
-           log_error(0, "%s: %s", pathbuf, strerror(ENOTDIR));
-       }
-       pathbuf[len - i] = '/';
-    }
-
-    return len;
-}
-
-static void *
-open_io_fd(pathbuf, len, suffix, docompress)
-    char *pathbuf;
-    int len;
-    const char *suffix;
-    int docompress;
-{
-    void *vfd = NULL;
-    int fd;
-
-    pathbuf[len] = '\0';
-    strlcat(pathbuf, suffix, PATH_MAX);
-    fd = open(pathbuf, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
-    if (fd != -1) {
-       fcntl(fd, F_SETFD, FD_CLOEXEC);
-#ifdef HAVE_ZLIB_H
-       if (docompress)
-           vfd = gzdopen(fd, "w");
-       else
-#endif
-           vfd = fdopen(fd, "w");
-    }
-    return vfd;
-}
-
-int
-io_log_open()
-{
-    char pathbuf[PATH_MAX];
-    FILE *io_logfile;
-    int len;
-
-    if (!def_log_input && !def_log_output)
-       return FALSE;
-
-    /*
-     * Build a path containing the session id split into two-digit subdirs,
-     * so ID 000001 becomes /var/log/sudo-io/00/00/01.
-     */
-    len = build_idpath(pathbuf, sizeof(pathbuf));
-    if (len == -1)
-       return -1;
-
-    if (mkdir(pathbuf, S_IRUSR|S_IWUSR|S_IXUSR) != 0)
-       log_error(USE_ERRNO, "Can't mkdir %s", pathbuf);
-
-    /*
-     * We create 7 files: a log file, a timing file and 5 for input/output.
-     */
-    io_logfile = open_io_fd(pathbuf, len, "/log", FALSE);
-    if (io_logfile == NULL)
-       log_error(USE_ERRNO, "Can't create %s", pathbuf);
-
-    io_fds[IOFD_TIMING].v = open_io_fd(pathbuf, len, "/timing", def_compress_io);
-    if (io_fds[IOFD_TIMING].v == NULL)
-       log_error(USE_ERRNO, "Can't create %s", pathbuf);
-
-    if (def_log_input) {
-       io_fds[IOFD_TTYIN].v = open_io_fd(pathbuf, len, "/ttyin", def_compress_io);
-       if (io_fds[IOFD_TTYIN].v == NULL)
-           log_error(USE_ERRNO, "Can't create %s", pathbuf);
-    }
-
-    if (def_log_output) {
-       io_fds[IOFD_TTYOUT].v = open_io_fd(pathbuf, len, "/ttyout", def_compress_io);
-       if (io_fds[IOFD_TTYOUT].v == NULL)
-           log_error(USE_ERRNO, "Can't create %s", pathbuf);
-    }
-
-    if (def_log_input) {
-       io_fds[IOFD_STDIN].v = open_io_fd(pathbuf, len, "/stdin", def_compress_io);
-       if (io_fds[IOFD_STDIN].v == NULL)
-           log_error(USE_ERRNO, "Can't create %s", pathbuf);
-    }
-
-    if (def_log_output) {
-       io_fds[IOFD_STDOUT].v = open_io_fd(pathbuf, len, "/stdout", def_compress_io);
-       if (io_fds[IOFD_STDOUT].v == NULL)
-           log_error(USE_ERRNO, "Can't create %s", pathbuf);
-    }
-
-    if (def_log_output) {
-       io_fds[IOFD_STDERR].v = open_io_fd(pathbuf, len, "/stderr", def_compress_io);
-       if (io_fds[IOFD_STDERR].v == NULL)
-           log_error(USE_ERRNO, "Can't create %s", pathbuf);
-    }
-
-    /* So we can block tty-generated signals */
-    sigemptyset(&ttyblock);
-    sigaddset(&ttyblock, SIGINT);
-    sigaddset(&ttyblock, SIGQUIT);
-    sigaddset(&ttyblock, SIGTSTP);
-    sigaddset(&ttyblock, SIGTTIN);
-    sigaddset(&ttyblock, SIGTTOU);
-
-    gettimeofday(&last_time, NULL);
-
-    /* XXX - log more stuff?  window size? environment? */
-    fprintf(io_logfile, "%ld:%s:%s:%s:%s\n", (long)last_time.tv_sec, user_name,
-        runas_pw->pw_name, runas_gr ? runas_gr->gr_name : "", user_tty);
-    fprintf(io_logfile, "%s\n", user_cwd);
-    fprintf(io_logfile, "%s%s%s\n", user_cmnd, user_args ? " " : "",
-        user_args ? user_args : "");
-    fclose(io_logfile);
-
-    return TRUE;
-}
-
-void
-io_log_close()
-{
-    int i;
-
-    for (i = 0; i < IOFD_MAX; i++) {
-       if (io_fds[i].v == NULL)
-           continue;
-#ifdef HAVE_ZLIB_H
-       if (def_compress_io)
-           gzclose(io_fds[i].g);
-       else
-#endif
-           fclose(io_fds[i].f);
-    }
-}
-
-static int
-log_io(buf, len, idx)
-    const char *buf;
-    unsigned int len;
-    int idx;
-{
-    struct timeval now, delay;
-    sigset_t omask;
-
-    gettimeofday(&now, NULL);
-
-    sigprocmask(SIG_BLOCK, &ttyblock, &omask);
-
-#ifdef HAVE_ZLIB_H
-    if (def_compress_io)
-       gzwrite(io_fds[idx].g, buf, len);
-    else
-#endif
-       fwrite(buf, 1, len, io_fds[idx].f);
-    delay.tv_sec = now.tv_sec;
-    delay.tv_usec = now.tv_usec;
-    timevalsub(&delay, &last_time);
-#ifdef HAVE_ZLIB_H
-    if (def_compress_io)
-       gzprintf(io_fds[IOFD_TIMING].g, "%d %f %d\n", idx,
-           delay.tv_sec + ((double)delay.tv_usec / 1000000), len);
-    else
-#endif
-       fprintf(io_fds[IOFD_TIMING].f, "%d %f %d\n", idx,
-           delay.tv_sec + ((double)delay.tv_usec / 1000000), len);
-    last_time.tv_sec = now.tv_sec;
-    last_time.tv_usec = now.tv_usec;
-
-    sigprocmask(SIG_SETMASK, &omask, NULL);
-
-    return TRUE;
-}
-
-int
-log_ttyin(buf, len)
-    const char *buf;
-    unsigned int len;
-{
-    if (!io_fds[IOFD_TTYIN].v)
-       return TRUE;
-    return log_io(buf, len, IOFD_TTYIN);
-}
-
-int
-log_ttyout(buf, len)
-    const char *buf;
-    unsigned int len;
-{
-    if (!io_fds[IOFD_TTYOUT].v)
-       return TRUE;
-    return log_io(buf, len, IOFD_TTYOUT);
-}
-
-int
-log_stdin(buf, len)
-    const char *buf;
-    unsigned int len;
-{
-    if (!io_fds[IOFD_STDIN].v)
-       return TRUE;
-    return log_io(buf, len, IOFD_STDIN);
-}
-
-int
-log_stdout(buf, len)
-    const char *buf;
-    unsigned int len;
-{
-    if (!io_fds[IOFD_STDOUT].v)
-       return TRUE;
-    return log_io(buf, len, IOFD_STDOUT);
-}
-
-int
-log_stderr(buf, len)
-    const char *buf;
-    unsigned int len;
-{
-    if (!io_fds[IOFD_STDOUT].v)
-       return TRUE;
-    return log_io(buf, len, IOFD_STDERR);
-}
diff --git a/isblank.c b/isblank.c
deleted file mode 100644 (file)
index a7f01e2..0000000
--- a/isblank.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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 "missing.h"
-
-#undef isblank
-int
-isblank(ch)
-    int ch;
-{
-    return ch == ' ' || ch == '\t';
-}
diff --git a/lbuf.c b/lbuf.c
deleted file mode 100644 (file)
index bafea18..0000000
--- a/lbuf.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (c) 2007-2011 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
-# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
-#  include <memory.h>
-# endif
-# include <string.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <ctype.h>
-#ifdef HAVE_TERMIOS_H
-# include <termios.h>
-#else
-# ifdef HAVE_TERMIO_H
-#  include <termio.h>
-# endif
-#endif
-
-#include "sudo.h"
-#include "lbuf.h"
-
-/* Compatibility with older tty systems. */
-#if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
-# define TIOCGWINSZ    TIOCGSIZE
-# define winsize       ttysize
-# define ws_col                ts_cols
-#endif
-
-int
-get_ttycols()
-{
-    char *p;
-    int cols;
-#ifdef TIOCGWINSZ
-    struct winsize wsize;
-
-    if (ioctl(STDERR_FILENO, TIOCGWINSZ, &wsize) == 0 && wsize.ws_col != 0)
-       return (int)wsize.ws_col;
-#endif
-
-    /* Fall back on $COLUMNS. */
-    if ((p = getenv("COLUMNS")) == NULL || (cols = atoi(p)) <= 0)
-       cols = 80;
-    return cols;
-}
-
-void
-lbuf_init(lbuf, output, indent, continuation)
-    struct lbuf *lbuf;
-    int (*output)__P((const char *));
-    int indent;
-    const char *continuation;
-{
-    lbuf->output = output;
-    lbuf->continuation = continuation;
-    lbuf->indent = indent;
-    lbuf->cols = get_ttycols();
-    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);
-}
-
-static void
-lbuf_println(lbuf, line, len)
-    struct lbuf *lbuf;
-    char *line;
-    int len;
-{
-    char *cp, save;
-    int i, have, contlen;
-
-    contlen = lbuf->continuation ? strlen(lbuf->continuation) : 0;
-
-    /*
-     * Print the buffer, splitting the line as needed on a word
-     * boundary.
-     */
-    cp = line;
-    have = lbuf->cols;
-    while (cp != NULL && *cp != '\0') {
-       char *ep = NULL;
-       int need = len - (int)(cp - line);
-
-       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 != line) {
-           /* indent continued lines */
-           /* XXX - build up string instead? */
-           for (i = 0; i < lbuf->indent; i++)
-               lbuf->output(" ");
-       }
-       /* NUL-terminate cp for the output function and restore afterwards */
-       save = cp[need];
-       cp[need] = '\0';
-       lbuf->output(cp);
-       cp[need] = save;
-       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 = lbuf->cols - lbuf->indent;
-           ep = line + len;
-           while (cp < ep && isblank((unsigned char)*cp)) {
-               cp++;
-           }
-           if (contlen)
-               lbuf->output(lbuf->continuation);
-       }
-       lbuf->output("\n");
-    }
-}
-
-/*
- * 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, *ep;
-    int len;
-
-    if (lbuf->buf == NULL || lbuf->len == 0)
-       goto done;
-
-    /* For very small widths just give up... */
-    len = lbuf->continuation ? strlen(lbuf->continuation) : 0;
-    if (lbuf->cols <= lbuf->indent + len + 20) {
-       lbuf->buf[lbuf->len] = '\0';
-       lbuf->output(lbuf->buf);
-       goto done;
-    }
-
-    /* Print each line in the buffer */
-    for (cp = lbuf->buf; cp != NULL && *cp != '\0'; ) {
-       if (*cp == '\n') {
-           lbuf->output("\n");
-           cp++;
-       } else {
-           len = lbuf->len - (cp - lbuf->buf);
-           if ((ep = memchr(cp, '\n', len)) != NULL)
-               len = (int)(ep - cp);
-           if (len)
-               lbuf_println(lbuf, cp, len);
-           cp = ep ? ep + 1 : NULL;
-       }
-    }
-
-done:
-    lbuf->len = 0;             /* reset the buffer for re-use. */
-}
diff --git a/lbuf.h b/lbuf.h
deleted file mode 100644 (file)
index db6f964..0000000
--- a/lbuf.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2007, 2010 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.
- */
-
-#ifndef _SUDO_LBUF_H
-#define _SUDO_LBUF_H
-
-/*
- * Line buffer struct.
- */
-struct lbuf {
-    int (*output)__P((const char *));
-    char *buf;
-    const char *continuation;
-    int indent;
-    int len;
-    int size;
-    int cols;
-};
-
-int get_ttycols                __P((void));
-void lbuf_append       __P((struct lbuf *, ...));
-void lbuf_append_quoted        __P((struct lbuf *, const char *, ...));
-void lbuf_destroy      __P((struct lbuf *));
-void lbuf_init         __P((struct lbuf *, int (*)(const char *), int, const char *));
-void lbuf_print                __P((struct lbuf *));
-
-#endif /* _SUDO_LBUF_H */
diff --git a/ldap.c b/ldap.c
deleted file mode 100644 (file)
index 3097af7..0000000
--- a/ldap.c
+++ /dev/null
@@ -1,2561 +0,0 @@
-/*
- * Copyright (c) 2003-2011 Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * This code is derived from software contributed by Aaron Spangler.
- *
- * 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/time.h>
-#include <sys/param.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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-#include <ctype.h>
-#include <pwd.h>
-#include <grp.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#ifdef HAVE_LBER_H
-# include <lber.h>
-#endif
-#include <ldap.h>
-#if defined(HAVE_LDAP_SSL_H)
-# include <ldap_ssl.h>
-#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 LDAP_OPT_SUCCESS
-# define LDAP_OPT_SUCCESS LDAP_SUCCESS
-#endif
-
-#ifndef LDAPS_PORT
-# define LDAPS_PORT 636
-#endif
-
-#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
-# ifdef HAVE_LDAP_SEARCH_ST
-#  define ldap_search_ext_s(a, b, c, d, e, f, g, h, i, j, k)           \
-       ldap_search_st(a, b, c, d, e, f, i, k)
-# else
-#  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
-#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
-#define CONF_STR       2
-#define CONF_LIST_STR  4
-
-#define SUDO_LDAP_SSL          1
-#define SUDO_LDAP_STARTTLS     2
-
-/* The TIMEFILTER_LENGTH includes the filter itself plus the global AND
-   wrapped around the user filter and the time filter when timed entries
-   are used. The length is computed as follows:
-       85       for the filter
-       + 2 * 13 for the now timestamp
-       +      3 for the global AND
-*/
-#define TIMEFILTER_LENGTH      114    
-
-/*
- * The ldap_search structure implements a linked list of ldap and
- * search result pointers, which allows us to remove them after
- * all search results have been combined in memory.
- * XXX - should probably be a tailq since we do appends
- */
-struct ldap_search_list {
-    LDAP *ldap;
-    LDAPMessage *searchresult;
-    struct ldap_search_list *next;
-};
-
-/*
- * The ldap_entry_wrapper structure is used to implement sorted result entries.
- * A double is used for the order to allow for insertion of new entries
- * without having to renumber everything.
- * Note: there is no standard floating point type in LDAP.
- *       As a result, some LDAP servers will only allow an integer.
- */
-struct ldap_entry_wrapper {
-    LDAPMessage        *entry;
-    double order;
-};
-
-/*
- * The ldap_result structure contains the list of matching searches as
- * well as an array of all result entries sorted by the sudoOrder attribute.
- */
-struct ldap_result {
-    struct ldap_search_list *searches;
-    struct ldap_entry_wrapper *entries;
-    int allocated_entries;
-    int nentries;
-    int user_matches;
-    int host_matches;
-};
-#define        ALLOCATION_INCREMENT    100
-
-struct ldap_config_table {
-    const char *conf_str;      /* config file string */
-    short type;                        /* CONF_BOOL, CONF_INT, CONF_STR */
-    short connected;           /* connection-specific value? */
-    int opt_val;               /* LDAP_OPT_* (or -1 for sudo internal) */
-    void *valp;                        /* pointer into ldap_conf */
-};
-
-struct ldap_config_list_str {
-    struct ldap_config_list_str *next;
-    char val[1];
-};
-
-/* LDAP configuration structure */
-static struct ldap_config {
-    int port;
-    int version;
-    int debug;
-    int ldap_debug;
-    int tls_checkpeer;
-    int timelimit;
-    int timeout;
-    int bind_timelimit;
-    int use_sasl;
-    int rootuse_sasl;
-    int ssl_mode;
-    int timed;
-    char *host;
-    struct ldap_config_list_str *uri;
-    char *binddn;
-    char *bindpw;
-    char *rootbinddn;
-    struct ldap_config_list_str *base;
-    char *search_filter;
-    char *ssl;
-    char *tls_cacertfile;
-    char *tls_cacertdir;
-    char *tls_random_file;
-    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;
-
-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 },
-    { "ssl", CONF_STR, FALSE, -1, &ldap_conf.ssl },
-    { "sslpath", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
-    { "uri", CONF_LIST_STR, FALSE, -1, &ldap_conf.uri },
-#ifdef LDAP_OPT_DEBUG_LEVEL
-    { "debug", CONF_INT, FALSE, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug },
-#endif
-#ifdef LDAP_OPT_PROTOCOL_VERSION
-    { "ldap_version", CONF_INT, TRUE, LDAP_OPT_PROTOCOL_VERSION,
-       &ldap_conf.version },
-#endif
-#ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
-    { "tls_checkpeer", CONF_BOOL, FALSE, LDAP_OPT_X_TLS_REQUIRE_CERT,
-       &ldap_conf.tls_checkpeer },
-#else
-    { "tls_checkpeer", CONF_BOOL, FALSE, -1, &ldap_conf.tls_checkpeer },
-#endif
-#ifdef LDAP_OPT_X_TLS_CACERTFILE
-    { "tls_cacertfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE,
-       &ldap_conf.tls_cacertfile },
-    { "tls_cacert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE,
-       &ldap_conf.tls_cacertfile },
-#endif
-#ifdef LDAP_OPT_X_TLS_CACERTDIR
-    { "tls_cacertdir", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTDIR,
-       &ldap_conf.tls_cacertdir },
-#endif
-#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
-    { "tls_randfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_RANDOM_FILE,
-       &ldap_conf.tls_random_file },
-#endif
-#ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
-    { "tls_ciphers", CONF_STR, FALSE, LDAP_OPT_X_TLS_CIPHER_SUITE,
-       &ldap_conf.tls_cipher_suite },
-#endif
-#ifdef LDAP_OPT_X_TLS_CERTFILE
-    { "tls_cert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CERTFILE,
-       &ldap_conf.tls_certfile },
-#else
-    { "tls_cert", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
-#endif
-#ifdef LDAP_OPT_X_TLS_KEYFILE
-    { "tls_key", CONF_STR, FALSE, LDAP_OPT_X_TLS_KEYFILE,
-       &ldap_conf.tls_keyfile },
-#else
-    { "tls_key", CONF_STR, FALSE, -1, &ldap_conf.tls_keyfile },
-#endif
-#ifdef LDAP_OPT_NETWORK_TIMEOUT
-    { "bind_timelimit", CONF_INT, TRUE, -1 /* needs timeval, set manually */,
-       &ldap_conf.bind_timelimit },
-    { "network_timeout", CONF_INT, TRUE, -1 /* needs timeval, set manually */,
-       &ldap_conf.bind_timelimit },
-#elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
-    { "bind_timelimit", CONF_INT, TRUE, LDAP_X_OPT_CONNECT_TIMEOUT,
-       &ldap_conf.bind_timelimit },
-    { "network_timeout", CONF_INT, TRUE, LDAP_X_OPT_CONNECT_TIMEOUT,
-       &ldap_conf.bind_timelimit },
-#endif
-    { "timelimit", CONF_INT, TRUE, LDAP_OPT_TIMELIMIT, &ldap_conf.timelimit },
-#ifdef LDAP_OPT_TIMEOUT
-    { "timeout", CONF_INT, TRUE, -1 /* needs timeval, set manually */,
-       &ldap_conf.timeout },
-#endif
-    { "binddn", CONF_STR, FALSE, -1, &ldap_conf.binddn },
-    { "bindpw", CONF_STR, FALSE, -1, &ldap_conf.bindpw },
-    { "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },
-    { "sudoers_base", CONF_LIST_STR, FALSE, -1, &ldap_conf.base },
-    { "sudoers_timed", CONF_BOOL, FALSE, -1, &ldap_conf.timed },
-    { "sudoers_search_filter", CONF_STR, FALSE, -1, &ldap_conf.search_filter },
-#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 }
-};
-
-/* sudo_nss implementation */
-static int sudo_ldap_open __P((struct sudo_nss *nss));
-static int sudo_ldap_close __P((struct sudo_nss *nss));
-static int sudo_ldap_parse __P((struct sudo_nss *nss));
-static int sudo_ldap_setdefs __P((struct sudo_nss *nss));
-static int sudo_ldap_lookup __P((struct sudo_nss *nss, int ret, int pwflag));
-static int sudo_ldap_display_cmnd __P((struct sudo_nss *nss,
-    struct passwd *pw));
-static int sudo_ldap_display_defaults __P((struct sudo_nss *nss,
-    struct passwd *pw, struct lbuf *lbuf));
-static int sudo_ldap_display_bound_defaults __P((struct sudo_nss *nss,
-    struct passwd *pw, struct lbuf *lbuf));
-static int sudo_ldap_display_privs __P((struct sudo_nss *nss,
-    struct passwd *pw, struct lbuf *lbuf));
-static struct ldap_result *sudo_ldap_result_get __P((struct sudo_nss *nss,
-    struct passwd *pw));
-
-/*
- * LDAP sudo_nss handle.
- * We store the connection to the LDAP server, the cached ldap_result object
- * (if any), and the name of the user the query was performed for.
- * If a new query is launched with sudo_ldap_result_get() that specifies a
- * different user, the old cached result is freed before the new query is run.
- */
-struct sudo_ldap_handle {
-    LDAP *ld;
-    struct ldap_result *result;
-    char *username;
-    GETGROUPS_T *groups;
-};
-
-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((unsigned char)port[1])) {
-           if (strlcat(hostbuf, defport, sizeof(hostbuf)) >= sizeof(hostbuf))
-               goto toobig;
-       }
-    }
-
-    efree(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
-/*
- * For each uri, convert to host:port pairs.  For ldaps:// enable SSL
- * Accepts: uris of the form ldap:/// or ldap://hostname:portnum/
- * where the trailing slash is optional.
- */
-static int
-sudo_ldap_parse_uri(uri_list)
-    const struct ldap_config_list_str *uri_list;
-{
-    char *buf, *uri, *host, *cp, *port;
-    char hostbuf[LINE_MAX];
-    int nldap = 0, nldaps = 0;
-    int rc = -1;
-
-    do {
-       buf = estrdup(uri_list->val);
-       hostbuf[0] = '\0';
-       for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) {
-           if (strncasecmp(uri, "ldap://", 7) == 0) {
-               nldap++;
-               host = uri + 7;
-           } else if (strncasecmp(uri, "ldaps://", 8) == 0) {
-               nldaps++;
-               host = uri + 8;
-           } else {
-               warningx("unsupported LDAP uri type: %s", uri);
-               goto done;
-           }
-
-           /* trim optional trailing slash */
-           if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') {
-               *cp = '\0';
-           }
-
-           if (hostbuf[0] != '\0') {
-               if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
-                   goto toobig;
-           }
-
-           if (*host == '\0')
-               host = "localhost";             /* no host specified, use localhost */
-
-           if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
-               goto toobig;
-
-           /* If using SSL and no port specified, add port 636 */
-           if (nldaps) {
-               if ((port = strrchr(host, ':')) == NULL ||
-                   !isdigit((unsigned char)port[1]))
-                   if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf))
-                       goto toobig;
-           }
-       }
-       if (hostbuf[0] == '\0') {
-           warningx("invalid uri: %s", uri_list);
-           goto done;
-       }
-
-       if (nldaps != 0) {
-           if (nldap != 0) {
-               warningx("cannot mix ldap and ldaps URIs");
-               goto done;
-           }
-           if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
-               warningx("cannot mix ldaps and starttls");
-               goto done;
-           }
-           ldap_conf.ssl_mode = SUDO_LDAP_SSL;
-       }
-
-       efree(ldap_conf.host);
-       ldap_conf.host = estrdup(hostbuf);
-       efree(buf);
-    } while ((uri_list = uri_list->next));
-
-    buf = NULL;
-    rc = 0;
-
-done:
-    efree(buf);
-    return rc;
-
-toobig:
-    errorx(1, "sudo_ldap_parse_uri: out of space building hostbuf");
-}
-#else
-static char *
-sudo_ldap_join_uri(uri_list)
-    struct ldap_config_list_str *uri_list;
-{
-    struct ldap_config_list_str *uri;
-    size_t len = 0;
-    char *buf, *cp;
-
-    /* Usually just a single entry. */
-    if (uri_list->next == NULL)
-       return estrdup(uri_list->val);
-
-    for (uri = uri_list; uri != NULL; uri = uri->next) {
-       len += strlen(uri->val) + 1;
-    }
-    buf = cp = emalloc(len);
-    buf[0] = '\0';
-    for (uri = uri_list; uri != NULL; uri = uri->next) {
-       cp += strlcpy(cp, uri->val, len - (cp - buf));
-       *cp++ = ' ';
-    }
-    cp[-1] = '\0';
-    return buf;
-}
-#endif /* HAVE_LDAP_INITIALIZE */
-
-static int
-sudo_ldap_init(ldp, host, port)
-    LDAP **ldp;
-    const char *host;
-    int port;
-{
-    LDAP *ld = NULL;
-    int rc = LDAP_CONNECT_ERROR;
-
-#ifdef HAVE_LDAPSSL_INIT
-    if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
-       DPRINTF(("ldapssl_clientauth_init(%s, %s)",
-           ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
-           ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
-       rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
-           ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
-       /*
-        * Mozilla-derived SDKs have a bug starting with version 5.0
-        * where the path can no longer be a file name and must be a dir.
-        */
-       if (rc != LDAP_SUCCESS) {
-           char *cp;
-           if (ldap_conf.tls_certfile) {
-               cp = strrchr(ldap_conf.tls_certfile, '/');
-               if (cp != NULL && strncmp(cp + 1, "cert", 4) == 0)
-                   *cp = '\0';
-           }
-           if (ldap_conf.tls_keyfile) {
-               cp = strrchr(ldap_conf.tls_keyfile, '/');
-               if (cp != NULL && strncmp(cp + 1, "key", 3) == 0)
-                   *cp = '\0';
-           }
-           DPRINTF(("ldapssl_clientauth_init(%s, %s)",
-               ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
-               ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
-           rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
-               ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
-           if (rc != LDAP_SUCCESS) {
-               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)
-           rc = LDAP_SUCCESS;
-    } else
-#endif
-    {
-#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
-    }
-
-done:
-    *ldp = ld;
-    return rc;
-}
-
-/*
- * Walk through search results and return TRUE if we have a matching
- * netgroup, else FALSE.
- */
-static int
-sudo_ldap_check_user_netgroup(ld, entry, user)
-    LDAP *ld;
-    LDAPMessage *entry;
-    char *user;
-{
-    struct berval **bv, **p;
-    char *val;
-    int ret = FALSE;
-
-    if (!entry)
-       return ret;
-
-    /* get the values from the entry */
-    bv = ldap_get_values_len(ld, entry, "sudoUser");
-    if (bv == NULL)
-       return ret;
-
-    /* walk through values */
-    for (p = bv; *p != NULL && !ret; p++) {
-       val = (*p)->bv_val;
-       /* match any */
-       if (netgr_matches(val, NULL, NULL, user))
-           ret = TRUE;
-       DPRINTF(("ldap sudoUser netgroup '%s' ... %s", val,
-           ret ? "MATCH!" : "not"), 2 + ((ret) ? 0 : 1));
-    }
-
-    ldap_value_free_len(bv);   /* cleanup */
-
-    return ret;
-}
-
-/*
- * Walk through search results and return TRUE if we have a
- * host match, else FALSE.
- */
-static int
-sudo_ldap_check_host(ld, entry)
-    LDAP *ld;
-    LDAPMessage *entry;
-{
-    struct berval **bv, **p;
-    char *val;
-    int ret = FALSE;
-
-    if (!entry)
-       return ret;
-
-    /* get the values from the entry */
-    bv = ldap_get_values_len(ld, entry, "sudoHost");
-    if (bv == NULL)
-       return ret;
-
-    /* walk through values */
-    for (p = bv; *p != NULL && !ret; p++) {
-       val = (*p)->bv_val;
-       /* match any or address or netgroup or hostname */
-       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", val,
-           ret ? "MATCH!" : "not"), 2);
-    }
-
-    ldap_value_free_len(bv);   /* cleanup */
-
-    return ret;
-}
-
-static int
-sudo_ldap_check_runas_user(ld, entry)
-    LDAP *ld;
-    LDAPMessage *entry;
-{
-    struct berval **bv, **p;
-    char *val;
-    int ret = FALSE;
-
-    if (!runas_pw)
-       return UNSPEC;
-
-    /* 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:
-     * 
-     * if runas is not specified on the command line, the only information
-     * as to which user to run as is in the runas_default option.  We should
-     * check to see if we have the local option present.  Unfortunately we
-     * don't parse these options until after this routine says yes or no.
-     * The query has already returned, so we could peek at the attribute
-     * values here though.
-     * 
-     * 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 (bv == NULL)
-       return !strcasecmp(runas_pw->pw_name, def_runas_default);
-
-    /* walk through values returned, looking for a match */
-    for (p = bv; *p != NULL && !ret; p++) {
-       val = (*p)->bv_val;
-       switch (val[0]) {
-       case '+':
-           if (netgr_matches(val, NULL, NULL, runas_pw->pw_name))
-               ret = TRUE;
-           break;
-       case '%':
-           if (usergr_matches(val, runas_pw->pw_name, runas_pw))
-               ret = TRUE;
-           break;
-       case 'A':
-           if (strcmp(val, "ALL") == 0) {
-               ret = TRUE;
-               break;
-           }
-           /* FALLTHROUGH */
-       default:
-           if (strcasecmp(val, runas_pw->pw_name) == 0)
-               ret = TRUE;
-           break;
-       }
-       DPRINTF(("ldap sudoRunAsUser '%s' ... %s", val,
-           ret ? "MATCH!" : "not"), 2);
-    }
-
-    ldap_value_free_len(bv);   /* cleanup */
-
-    return ret;
-}
-
-static 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 runas match,
- * else FALSE.  RunAs info is optional.
- */
-static 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.
- */
-static int
-sudo_ldap_check_command(ld, entry, setenv_implied)
-    LDAP *ld;
-    LDAPMessage *entry;
-    int *setenv_implied;
-{
-    struct berval **bv, **p;
-    char *allowed_cmnd, *allowed_args, *val;
-    int foundbang, ret = UNSPEC;
-
-    if (!entry)
-       return ret;
-
-    bv = ldap_get_values_len(ld, entry, "sudoCommand");
-    if (bv == NULL)
-       return ret;
-
-    for (p = bv; *p != NULL && ret != FALSE; p++) {
-       val = (*p)->bv_val;
-       /* Match against ALL ? */
-       if (!strcmp(val, "ALL")) {
-           ret = TRUE;
-           if (setenv_implied != NULL)
-               *setenv_implied = TRUE;
-           DPRINTF(("ldap sudoCommand '%s' ... MATCH!", val), 2);
-           continue;
-       }
-
-       /* check for !command */
-       if (*val == '!') {
-           foundbang = TRUE;
-           allowed_cmnd = estrdup(1 + val);    /* !command */
-       } else {
-           foundbang = FALSE;
-           allowed_cmnd = estrdup(val);        /* command */
-       }
-
-       /* split optional args away from command */
-       allowed_args = strchr(allowed_cmnd, ' ');
-       if (allowed_args)
-           *allowed_args++ = '\0';
-
-       /* check the command like normal */
-       if (command_matches(allowed_cmnd, allowed_args)) {
-           /*
-            * If allowed (no bang) set ret but keep on checking.
-            * If disallowed (bang), exit loop.
-            */
-           ret = foundbang ? FALSE : TRUE;
-       }
-       DPRINTF(("ldap sudoCommand '%s' ... %s", val,
-           ret == TRUE ? "MATCH!" : "not"), 2);
-
-       efree(allowed_cmnd);    /* cleanup */
-    }
-
-    ldap_value_free_len(bv);   /* more cleanup */
-
-    return ret;
-}
-
-/*
- * Search for boolean "option" in sudoOption.
- * Returns TRUE if found and allowed, FALSE if negated, else UNSPEC.
- */
-static 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;
-}
-
-/*
- * Read sudoOption and modify the defaults as we go.  This is used once
- * from the cn=defaults entry and also once when a final sudoRole is matched.
- */
-static void
-sudo_ldap_parse_options(ld, entry)
-    LDAP *ld;
-    LDAPMessage *entry;
-{
-    struct berval **bv, **p;
-    char op, *var, *val;
-
-    if (entry == NULL)
-       return;
-
-    bv = ldap_get_values_len(ld, entry, "sudoOption");
-    if (bv == NULL)
-       return;
-
-    /* walk through options */
-    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, '=');
-       if (val > var) {
-           *val++ = '\0';      /* split on = and truncate var */
-           op = *(val - 2);    /* peek for += or -= cases */
-           if (op == '+' || op == '-') {
-               *(val - 2) = '\0';      /* found, remove extra char */
-               /* case var+=val or var-=val */
-               set_default(var, val, (int) op);
-           } else {
-               /* case var=val */
-               set_default(var, val, TRUE);
-           }
-       } else if (*var == '!') {
-           /* case !var Boolean False */
-           set_default(var + 1, NULL, FALSE);
-       } else {
-           /* case var Boolean True */
-           set_default(var, NULL, TRUE);
-       }
-       efree(var);
-    }
-
-    ldap_value_free_len(bv);
-}
-
-/*
- * Build an LDAP timefilter.
- *
- * Stores a filter in the buffer that makes sure only entries
- * are selected that have a sudoNotBefore in the past and a
- * sudoNotAfter in the future, i.e. a filter of the following
- * structure (spaced out a little more for better readability:
- *
- * (&
- *   (|
- *     (!(sudoNotAfter=*))
- *     (sudoNotAfter>__now__)
- *   )
- *   (|
- *     (!(sudoNotBefore=*))
- *     (sudoNotBefore<__now__)
- *   )
- * )
- *
- * If either the sudoNotAfter or sudoNotBefore attributes are missing,
- * no time restriction shall be imposed.
- */
-static int
-sudo_ldap_timefilter(buffer, buffersize)
-    char *buffer;
-    size_t buffersize;
-{
-    struct tm *tp;
-    time_t now;
-    char timebuffer[16];
-    int bytes = 0;
-
-    /* Make sure we have a formatted timestamp for __now__. */
-    time(&now);
-    if ((tp = gmtime(&now)) == NULL) {
-       warning("unable to get GMT");
-       goto done;
-    }
-
-    /* Format the timestamp according to the RFC. */
-    if (strftime(timebuffer, sizeof(timebuffer), "%Y%m%d%H%MZ", tp) == 0) {
-       warning("unable to format timestamp");
-       goto done;
-    }
-
-    /* Build filter. */
-    bytes = snprintf(buffer, buffersize, "(&(|(!(sudoNotAfter=*))(sudoNotAfter>=%s))(|(!(sudoNotBefore=*))(sudoNotBefore<=%s)))",
-       timebuffer, timebuffer);
-    if (bytes < 0 || bytes >= buffersize) {
-       warning("unable to build time filter");
-       bytes = 0;
-    }
-
-done:
-    return bytes;
-}
-
-/*
- * Builds up a filter to search for default settings
- */
-static char *
-sudo_ldap_build_default_filter()
-{
-    char *filt;
-
-    if (ldap_conf.search_filter)
-       easprintf(&filt, "(&%s(cn=defaults))", ldap_conf.search_filter);
-    else
-       filt = estrdup("cn=defaults");
-    return filt;
-}
-
-/*
- * Builds up a filter to check against LDAP.
- */
-static char *
-sudo_ldap_build_pass1(pw)
-    struct passwd *pw;
-{
-    struct group *grp;
-    char *buf, timebuffer[TIMEFILTER_LENGTH];
-    size_t sz = 0;
-    int i;
-
-    /* Start with LDAP search filter length + 3 */
-    if (ldap_conf.search_filter)
-       sz += strlen(ldap_conf.search_filter) + 3;
-
-    /* Then add (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
-    sz += 29 + strlen(pw->pw_name);
-
-    /* Add space for groups */
-    if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
-       sz += 12 + strlen(grp->gr_name);        /* primary group */
-       gr_delref(grp);
-    }
-    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 */
-           gr_delref(grp);
-       }
-    }
-
-    /* If timed, add space for time limits. */
-    if (ldap_conf.timed)
-       sz += TIMEFILTER_LENGTH;
-    buf = emalloc(sz);
-    *buf = '\0';
-
-    /*
-     * If timed or using a search filter, start a global AND clause to
-     * contain the search filter, search criteria, and time restriction.
-     */
-    if (ldap_conf.timed || ldap_conf.search_filter)
-       (void) strlcpy(buf, "(&", sz);
-
-    if (ldap_conf.search_filter)
-       (void) strlcat(buf, ldap_conf.search_filter, sz);
-
-    /* Global OR + sudoUser=user_name filter */
-    (void) strlcat(buf, "(|(sudoUser=", sz);
-    (void) strlcat(buf, pw->pw_name, sz);
-    (void) strlcat(buf, ")", sz);
-
-    /* Append primary group */
-    if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
-       (void) strlcat(buf, "(sudoUser=%", sz);
-       (void) strlcat(buf, grp->gr_name, sz);
-       (void) strlcat(buf, ")", sz);
-       gr_delref(grp);
-    }
-
-    /* Append supplementary groups */
-    for (i = 0; i < user_ngroups; i++) {
-       if (user_groups[i] == pw->pw_gid)
-           continue;
-       if ((grp = sudo_getgrgid(user_groups[i])) != NULL) {
-           (void) strlcat(buf, "(sudoUser=%", sz);
-           (void) strlcat(buf, grp->gr_name, sz);
-           (void) strlcat(buf, ")", sz);
-           gr_delref(grp);
-       }
-    }
-
-    /* Add ALL to list and end the global OR */
-    if (strlcat(buf, "(sudoUser=ALL)", sz) >= sz)
-       errorx(1, "sudo_ldap_build_pass1 allocation mismatch");
-
-    /* Add the time restriction, or simply end the global OR. */
-    if (ldap_conf.timed) {
-       strlcat(buf, ")", sz); /* closes the global OR */
-       sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
-       strlcat(buf, timebuffer, sz);
-    } else if (ldap_conf.search_filter) {
-       strlcat(buf, ")", sz); /* closes the global OR */
-    }
-    strlcat(buf, ")", sz); /* closes the global OR or the global AND */
-
-    return buf;
-}
-
-/*
- * Builds up a filter to check against netgroup entries in LDAP.
- */
-static char *
-sudo_ldap_build_pass2()
-{
-    char *filt, timebuffer[TIMEFILTER_LENGTH];
-
-    if (ldap_conf.timed)
-       sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
-
-    /*
-     * Match all sudoUsers beginning with a '+'.
-     * If a search filter or time restriction is specified, 
-     * those get ANDed in to the expression.
-     */
-    easprintf(&filt, "%s%s(sudoUser=+*)%s%s",
-       (ldap_conf.timed || ldap_conf.search_filter) ? "(&" : "",
-       ldap_conf.search_filter ? ldap_conf.search_filter : "",
-       ldap_conf.timed ? timebuffer : "",
-       (ldap_conf.timed || ldap_conf.search_filter) ? ")" : "");
-
-    return filt;
-}
-
-/*
- * Map yes/true/on to TRUE, no/false/off to FALSE, else -1
- */
-static int
-_atobool(s)
-    const char *s;
-{
-    switch (*s) {
-       case 'y':
-       case 'Y':
-           if (strcasecmp(s, "yes") == 0)
-               return TRUE;
-           break;
-       case 't':
-       case 'T':
-           if (strcasecmp(s, "true") == 0)
-               return TRUE;
-           break;
-       case 'o':
-       case 'O':
-           if (strcasecmp(s, "on") == 0)
-               return TRUE;
-           if (strcasecmp(s, "off") == 0)
-               return FALSE;
-           break;
-       case 'n':
-       case 'N':
-           if (strcasecmp(s, "no") == 0)
-               return FALSE;
-           break;
-       case 'f':
-       case 'F':
-           if (strcasecmp(s, "false") == 0)
-               return FALSE;
-           break;
-    }
-    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);
-    }
-}
-
-static int
-sudo_ldap_read_config()
-{
-    FILE *fp;
-    char *cp, *keyword, *value;
-    struct ldap_config_table *cur;
-
-    /* defaults */
-    ldap_conf.version = 3;
-    ldap_conf.port = -1;
-    ldap_conf.tls_checkpeer = -1;
-    ldap_conf.timelimit = -1;
-    ldap_conf.timeout = -1;
-    ldap_conf.bind_timelimit = -1;
-    ldap_conf.use_sasl = -1;
-    ldap_conf.rootuse_sasl = -1;
-
-    if ((fp = fopen(_PATH_LDAP_CONF, "r")) == NULL)
-       return FALSE;
-
-    while ((cp = sudo_parseln(fp)) != NULL) {
-       if (*cp == '\0')
-           continue;           /* skip empty line */
-
-       /* 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 (isblank((unsigned char) *cp))
-           cp++;
-       value = cp;
-
-       /* Look up keyword in config table. */
-       for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
-           if (strcasecmp(keyword, cur->conf_str) == 0) {
-               switch (cur->type) {
-               case CONF_BOOL:
-                   *(int *)(cur->valp) = _atobool(value);
-                   break;
-               case CONF_INT:
-                   *(int *)(cur->valp) = atoi(value);
-                   break;
-               case CONF_STR:
-                   efree(*(char **)(cur->valp));
-                   *(char **)(cur->valp) = estrdup(value);
-                   break;
-               case CONF_LIST_STR:
-                   {
-                       struct ldap_config_list_str **p;
-                       size_t len = strlen(value);
-
-                       if (len > 0) {
-                           p = (struct ldap_config_list_str **)cur->valp;
-                           while (*p != NULL)
-                               p = &(*p)->next;
-                           *p = emalloc(sizeof(struct ldap_config_list_str) + len);
-                           memcpy((*p)->val, value, len + 1);
-                           (*p)->next = NULL;
-                       }
-                   }
-                   break;
-               }
-               break;
-           }
-       }
-    }
-    fclose(fp);
-
-    if (!ldap_conf.host)
-       ldap_conf.host = estrdup("localhost");
-
-    if (ldap_conf.debug > 1) {
-       fprintf(stderr, "LDAP Config Summary\n");
-       fprintf(stderr, "===================\n");
-       if (ldap_conf.uri) {
-           struct ldap_config_list_str *uri = ldap_conf.uri;
-
-           do {
-               fprintf(stderr, "uri              %s\n", uri->val);
-           } while ((uri = uri->next) != NULL);
-       } else {
-           fprintf(stderr, "host             %s\n", ldap_conf.host ?
-               ldap_conf.host : "(NONE)");
-           fprintf(stderr, "port             %d\n", ldap_conf.port);
-       }
-       fprintf(stderr, "ldap_version     %d\n", ldap_conf.version);
-       if (ldap_conf.base) {
-           struct ldap_config_list_str *base = ldap_conf.base;
-
-           do {
-               fprintf(stderr, "sudoers_base     %s\n", base->val);
-           } while ((base = base->next) != NULL);
-       } else {
-           fprintf(stderr, "sudoers_base     %s\n",
-               "(NONE) <---Sudo will ignore ldap)");
-       }
-       if (ldap_conf.search_filter)
-           fprintf(stderr, "search_filter    %s\n", ldap_conf.search_filter);
-       fprintf(stderr, "binddn           %s\n", ldap_conf.binddn ?
-           ldap_conf.binddn : "(anonymous)");
-       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);
-       if (ldap_conf.timelimit > 0)
-           fprintf(stderr, "timelimit        %d\n", ldap_conf.timelimit);
-       if (ldap_conf.timeout > 0)
-           fprintf(stderr, "timeout          %d\n", ldap_conf.timeout);
-       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 ?
-               "(yes)" : "(no)");
-       if (ldap_conf.tls_cacertfile != NULL)
-           fprintf(stderr, "tls_cacertfile   %s\n", ldap_conf.tls_cacertfile);
-       if (ldap_conf.tls_cacertdir != NULL)
-           fprintf(stderr, "tls_cacertdir    %s\n", ldap_conf.tls_cacertdir);
-       if (ldap_conf.tls_random_file != NULL)
-           fprintf(stderr, "tls_random_file  %s\n", ldap_conf.tls_random_file);
-       if (ldap_conf.tls_cipher_suite != NULL)
-           fprintf(stderr, "tls_cipher_suite %s\n", ldap_conf.tls_cipher_suite);
-       if (ldap_conf.tls_certfile != NULL)
-           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)
-       return FALSE;           /* if no base is defined, ignore LDAP */
-
-    if (ldap_conf.bind_timelimit > 0)
-       ldap_conf.bind_timelimit *= 1000;       /* convert to ms */
-
-    /*
-     * Interpret SSL option
-     */
-    if (ldap_conf.ssl != NULL) {
-       if (strcasecmp(ldap_conf.ssl, "start_tls") == 0)
-           ldap_conf.ssl_mode = SUDO_LDAP_STARTTLS;
-       else if (_atobool(ldap_conf.ssl))
-           ldap_conf.ssl_mode = SUDO_LDAP_SSL;
-    }
-
-#if defined(HAVE_LDAPSSL_SET_STRENGTH) && !defined(LDAP_OPT_X_TLS_REQUIRE_CERT)
-    if (ldap_conf.tls_checkpeer != -1) {
-       ldapssl_set_strength(NULL,
-           ldap_conf.tls_checkpeer ? LDAPSSL_AUTH_CERT : LDAPSSL_AUTH_WEAK);
-    }
-#endif
-
-#ifndef HAVE_LDAP_INITIALIZE
-    /* Convert uri list to host list if no ldap_initialize(). */
-    if (ldap_conf.uri) {
-       struct ldap_config_list_str *uri = ldap_conf.uri;
-       if (sudo_ldap_parse_uri(uri) != 0)
-           return FALSE;
-       do {
-           ldap_conf.uri = uri->next;
-           efree(uri);
-       } while ((uri = ldap_conf.uri));
-       ldap_conf.port = LDAP_PORT;
-    }
-#endif
-
-    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 search filter is not parenthesized, make it so. */
-    if (ldap_conf.search_filter && ldap_conf.search_filter[0] != '(') {
-       size_t len = strlen(ldap_conf.search_filter);
-       cp = ldap_conf.search_filter;
-       ldap_conf.search_filter = emalloc(len + 3);
-       ldap_conf.search_filter[0] = '(';
-       memcpy(ldap_conf.search_filter + 1, cp, len);
-       ldap_conf.search_filter[len + 1] = ')';
-       ldap_conf.search_filter[len + 2] = '\0';
-       efree(cp);
-    }
-
-    /* If rootbinddn set, read in /etc/ldap.secret if it exists. */
-    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;
-           }
-       }
-    }
-#endif
-    return TRUE;
-}
-
-/*
- * Extract the dn from an entry and return the first rdn from it.
- */
-static char *
-sudo_ldap_get_first_rdn(ld, entry)
-    LDAP *ld;
-    LDAPMessage *entry;
-{
-#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
-}
-
-/*
- * Fetch and display the global Options.
- */
-static int
-sudo_ldap_display_defaults(nss, pw, lbuf)
-    struct sudo_nss *nss;
-    struct passwd *pw;
-    struct lbuf *lbuf;
-{
-    struct berval **bv, **p;
-    struct timeval tv, *tvp = NULL;
-    struct ldap_config_list_str *base;
-    struct sudo_ldap_handle *handle = nss->handle;
-    LDAP *ld;
-    LDAPMessage *entry, *result;
-    char *prefix, *filt;
-    int rc, count = 0;
-
-    if (handle == NULL || handle->ld == NULL)
-       goto done;
-    ld = handle->ld;
-
-    filt = sudo_ldap_build_default_filter();
-    for (base = ldap_conf.base; base != NULL; base = base->next) {
-       if (ldap_conf.timeout > 0) {
-           tv.tv_sec = ldap_conf.timeout;
-           tv.tv_usec = 0;
-           tvp = &tv;
-       }
-       result = NULL;
-       rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
-           filt, NULL, 0, NULL, NULL, tvp, 0, &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 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
-                   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);
-    }
-    efree(filt);
-done:
-    return count;
-}
-
-/*
- * STUB
- */
-static int
-sudo_ldap_display_bound_defaults(nss, pw, lbuf)
-    struct sudo_nss *nss;
-    struct passwd *pw;
-    struct lbuf *lbuf;
-{
-    return 0;
-}
-
-/*
- * Print a record in the short form, ala file sudoers.
- */
-static 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);
-       }
-       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_append(lbuf, "\n", NULL);
-
-    return count;
-}
-
-/*
- * Print a record in the long form.
- */
-static int
-sudo_ldap_display_entry_long(ld, entry, lbuf)
-    LDAP *ld;
-    LDAPMessage *entry;
-    struct lbuf *lbuf;
-{
-    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_append(lbuf, "\nLDAP Role: ", rdn ? rdn : "UNKNOWN", "\n", NULL);
-    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_append(lbuf, "\n", NULL);
-
-    /* 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_append(lbuf, "\n", NULL);
-    }
-
-    /* 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_append(lbuf, "\n", NULL);
-    }
-
-    /*
-     * Display order attribute if present.  This attribute is single valued,
-     * so there is no need for a loop.
-     */
-    bv = ldap_get_values_len(ld, entry, "sudoOrder");
-    if (bv != NULL) {
-       if (*bv != NULL) {
-           lbuf_append(lbuf, "    Order: ", (*bv)->bv_val, "\n", NULL);
-       }
-       ldap_value_free_len(bv);
-    }
-
-    /* Get the command values from the entry. */
-    bv = ldap_get_values_len(ld, entry, "sudoCommand");
-    if (bv != NULL) {
-       lbuf_append(lbuf, "    Commands:\n", NULL);
-       for (p = bv; *p != NULL; p++) {
-           lbuf_append(lbuf, "\t", (*p)->bv_val, "\n", NULL);
-           count++;
-       }
-       ldap_value_free_len(bv);
-    }
-
-    return count;
-}
-
-/*
- * Like sudo_ldap_lookup(), except we just print entries.
- */
-static int
-sudo_ldap_display_privs(nss, pw, lbuf)
-    struct sudo_nss *nss;
-    struct passwd *pw;
-    struct lbuf *lbuf;
-{
-    struct sudo_ldap_handle *handle = nss->handle;
-    LDAP *ld;
-    struct ldap_result *lres;
-    LDAPMessage *entry;
-    int i, count = 0;
-
-    if (handle == NULL || handle->ld == NULL)
-       goto done;
-    ld = handle->ld;
-
-    DPRINTF(("ldap search for command list"), 1);
-    lres = sudo_ldap_result_get(nss, pw);
-
-    /* Display all matching entries. */
-    for (i = 0; i < lres->nentries; i++) {
-       entry = lres->entries[i].entry;
-       if (long_list)
-           count += sudo_ldap_display_entry_long(ld, entry, lbuf);
-       else
-           count += sudo_ldap_display_entry_short(ld, entry, lbuf);
-    }
-
-done:
-    return count;
-}
-
-static int
-sudo_ldap_display_cmnd(nss, pw)
-    struct sudo_nss *nss;
-    struct passwd *pw;
-{
-    struct sudo_ldap_handle *handle = nss->handle;
-    LDAP *ld;
-    struct ldap_result *lres;
-    LDAPMessage *entry;
-    int i, found = FALSE;
-
-    if (handle == NULL || handle->ld == NULL)
-       goto done;
-    ld = handle->ld;
-
-    /*
-     * The sudo_ldap_result_get() function returns all nodes that match
-     * the user and the host.
-     */
-    DPRINTF(("ldap search for command list"), 1);
-    lres = sudo_ldap_result_get(nss, pw);
-    for (i = 0; i < lres->nentries; i++) {
-       entry = lres->entries[i].entry;
-       if (sudo_ldap_check_command(ld, entry, NULL) &&
-           sudo_ldap_check_runas(ld, entry)) {
-           found = TRUE;
-           goto done;
-       }
-    }
-
-done:
-    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.
- */
-static int
-sudo_ldap_set_options(ld)
-    LDAP *ld;
-{
-    struct ldap_config_table *cur;
-    int rc;
-
-    /* Set ber options */
-#ifdef LBER_OPT_DEBUG_LEVEL
-    if (ldap_conf.ldap_debug)
-       ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug);
-#endif
-
-    /* Set simple LDAP options */
-    for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
-       LDAP *conn;
-       int ival;
-       char *sval;
-
-       if (cur->opt_val == -1)
-           continue;
-
-       conn = cur->connected ? ld : NULL;
-       switch (cur->type) {
-       case CONF_BOOL:
-       case CONF_INT:
-           ival = *(int *)(cur->valp);
-           if (ival >= 0) {
-               rc = ldap_set_option(conn, cur->opt_val, &ival);
-               if (rc != LDAP_OPT_SUCCESS) {
-                   warningx("ldap_set_option: %s -> %d: %s",
-                       cur->conf_str, ival, ldap_err2string(rc));
-                   return -1;
-               }
-               DPRINTF(("ldap_set_option: %s -> %d", cur->conf_str, ival), 1);
-           }
-           break;
-       case CONF_STR:
-           sval = *(char **)(cur->valp);
-           if (sval != NULL) {
-               rc = ldap_set_option(conn, cur->opt_val, sval);
-               if (rc != LDAP_OPT_SUCCESS) {
-                   warningx("ldap_set_option: %s -> %s: %s",
-                       cur->conf_str, sval, ldap_err2string(rc));
-                   return -1;
-               }
-               DPRINTF(("ldap_set_option: %s -> %s", cur->conf_str, sval), 1);
-           }
-           break;
-       }
-    }
-
-#ifdef LDAP_OPT_TIMEOUT
-    /* Convert timeout to a timeval */
-    if (ldap_conf.timeout > 0) {
-       struct timeval tv;
-       tv.tv_sec = ldap_conf.timeout;
-       tv.tv_usec = 0;
-       rc = ldap_set_option(ld, LDAP_OPT_TIMEOUT, &tv);
-       if (rc != LDAP_OPT_SUCCESS) {
-           warningx("ldap_set_option(TIMEOUT, %ld): %s",
-               (long)tv.tv_sec, ldap_err2string(rc));
-           return -1;
-       }
-       DPRINTF(("ldap_set_option(LDAP_OPT_TIMEOUT, %ld)",
-           (long)tv.tv_sec), 1);
-    }
-#endif
-#ifdef LDAP_OPT_NETWORK_TIMEOUT
-    /* Convert bind_timelimit to a timeval */
-    if (ldap_conf.bind_timelimit > 0) {
-       struct timeval tv;
-       tv.tv_sec = ldap_conf.bind_timelimit / 1000;
-       tv.tv_usec = 0;
-       rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
-       if (rc != LDAP_OPT_SUCCESS) {
-           warningx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",
-               (long)tv.tv_sec, ldap_err2string(rc));
-           return -1;
-       }
-       DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)",
-           (long)tv.tv_sec), 1);
-    }
-#endif
-
-#if defined(LDAP_OPT_X_TLS) && !defined(HAVE_LDAPSSL_INIT)
-    if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
-       int val = LDAP_OPT_X_TLS_HARD;
-       rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val);
-       if (rc != LDAP_SUCCESS) {
-           warningx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",
-               ldap_err2string(rc));
-           return -1;
-       }
-       DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)"), 1);
-    }
-#endif
-    return 0;
-}
-
-/*
- * Create a new sudo_ldap_result structure.
- */
-static struct ldap_result *
-sudo_ldap_result_alloc()
-{
-    struct ldap_result *result;
-
-    result = emalloc(sizeof(*result));
-    result->searches = NULL;
-    result->nentries = 0;
-    result->entries = NULL;
-    result->allocated_entries = 0;
-    result->user_matches = FALSE;
-    result->host_matches = FALSE;
-    return result;
-}
-
-/*
- * Free the ldap result structure
- */
-static void
-sudo_ldap_result_free(lres)
-    struct ldap_result *lres;
-{
-    struct ldap_search_list *s;
-
-    if (lres != NULL) {
-       if (lres->nentries) {
-           efree(lres->entries);
-           lres->entries = NULL;
-       }
-       if (lres->searches) {
-           while ((s = lres->searches) != NULL) {
-               ldap_msgfree(s->searchresult);
-               lres->searches = s->next;
-               efree(s);
-           }
-       }
-       efree(lres);
-    }
-}
-
-/*
- * Add a search result to the ldap_result structure.
- */
-static struct ldap_search_list *
-sudo_ldap_result_add_search(lres, ldap, searchresult)
-    struct ldap_result *lres;
-    LDAP *ldap;
-    LDAPMessage *searchresult;
-{
-    struct ldap_search_list *s, *news;
-
-    news = emalloc(sizeof(struct ldap_search_list));
-    news->next = NULL;
-    news->ldap = ldap;
-    news->searchresult = searchresult;
-
-    /* Add entry to the end of the chain (XXX - tailq instead?). */
-    if (lres->searches) {
-       for (s = lres->searches; s->next != NULL; s = s->next)
-           continue;
-       s->next = news;
-    } else {
-       lres->searches = news;
-    }
-    return news;
-}
-
-/*
- * Connect to the LDAP server specified by ld
- */
-static int
-sudo_ldap_bind_s(ld)
-    LDAP *ld;
-{
-    int rc;
-#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
-    const char *old_ccname = user_ccname;
-# ifdef HAVE_GSS_KRB5_CCACHE_NAME
-    unsigned int status;
-# endif
-#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
-           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)
-               setenv("KRB5CCNAME", old_ccname, TRUE);
-           else
-               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.
- */
-static int
-sudo_ldap_open(nss)
-    struct sudo_nss *nss;
-{
-    LDAP *ld;
-    int rc, ldapnoinit = FALSE;
-    struct sudo_ldap_handle    *handle;
-
-    if (!sudo_ldap_read_config())
-       return -1;
-
-    /* Prevent reading of user ldaprc and system defaults. */
-    if (getenv("LDAPNOINIT") == NULL) {
-       ldapnoinit = TRUE;
-       setenv("LDAPNOINIT", "1", TRUE);
-    }
-
-    /* Connect to LDAP server */
-#ifdef HAVE_LDAP_INITIALIZE
-    if (ldap_conf.uri != NULL) {
-       char *buf = sudo_ldap_join_uri(ldap_conf.uri);
-       DPRINTF(("ldap_initialize(ld, %s)", buf), 2);
-       rc = ldap_initialize(&ld, buf);
-       efree(buf);
-    } else
-#endif
-       rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port);
-    if (rc != LDAP_SUCCESS) {
-       warningx("unable to initialize LDAP: %s", ldap_err2string(rc));
-       return -1;
-    }
-
-    if (ldapnoinit)
-       unsetenv("LDAPNOINIT");
-
-    /* Set LDAP options */
-    if (sudo_ldap_set_options(ld) < 0)
-       return -1;
-
-    if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
-#if defined(HAVE_LDAP_START_TLS_S)
-       rc = ldap_start_tls_s(ld, NULL, NULL);
-       if (rc != LDAP_SUCCESS) {
-           warningx("ldap_start_tls_s(): %s", ldap_err2string(rc));
-           return -1;
-       }
-       DPRINTF(("ldap_start_tls_s() ok"), 1);
-#elif defined(HAVE_LDAP_SSL_CLIENT_INIT) && defined(HAVE_LDAP_START_TLS_S_NP)
-       if (ldap_ssl_client_init(NULL, NULL, 0, &rc) != LDAP_SUCCESS) {
-           warningx("ldap_ssl_client_init(): %s", ldap_err2string(rc));
-           return -1;
-       }
-       rc = ldap_start_tls_s_np(ld, NULL);
-       if (rc != LDAP_SUCCESS) {
-           warningx("ldap_start_tls_s_np(): %s", ldap_err2string(rc));
-           return -1;
-       }
-       DPRINTF(("ldap_start_tls_s_np() ok"), 1);
-#else
-       warningx("start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()");
-#endif /* !HAVE_LDAP_START_TLS_S && !HAVE_LDAP_START_TLS_S_NP */
-    }
-
-    /* Actually connect */
-    if (sudo_ldap_bind_s(ld) != 0)
-       return -1;
-
-    /* Create a handle container. */
-    handle = emalloc(sizeof(struct sudo_ldap_handle));
-    handle->ld = ld;
-    handle->result = NULL;
-    handle->username = NULL;
-    handle->groups = NULL;
-    nss->handle = handle;
-
-    return 0;
-}
-
-static int
-sudo_ldap_setdefs(nss)
-    struct sudo_nss *nss;
-{
-    struct ldap_config_list_str *base;
-    struct sudo_ldap_handle *handle = nss->handle;
-    struct timeval tv, *tvp = NULL;
-    LDAP *ld;
-    LDAPMessage *entry, *result;
-    char *filt;
-    int rc;
-
-    if (handle == NULL || handle->ld == NULL)
-       return -1;
-    ld = handle->ld;
-
-    filt = sudo_ldap_build_default_filter();
-    DPRINTF(("Looking for cn=defaults: %s", filt), 1);
-
-    for (base = ldap_conf.base; base != NULL; base = base->next) {
-       if (ldap_conf.timeout > 0) {
-           tv.tv_sec = ldap_conf.timeout;
-           tv.tv_usec = 0;
-           tvp = &tv;
-       }
-       result = NULL;
-       rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
-           filt, NULL, 0, NULL, NULL, NULL, 0, &result);
-       if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
-           DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
-           sudo_ldap_parse_options(ld, entry);
-       } else
-           DPRINTF(("no default options found in %s", base->val), 1);
-
-       if (result)
-           ldap_msgfree(result);
-    }
-    efree(filt);
-
-    return 0;
-}
-
-/*
- * like sudoers_lookup() - only LDAP style
- */
-static int
-sudo_ldap_lookup(nss, ret, pwflag)
-    struct sudo_nss *nss;
-    int ret;
-    int pwflag;
-{
-    struct sudo_ldap_handle *handle = nss->handle;
-    LDAP *ld;
-    LDAPMessage *entry;
-    int i, rc, setenv_implied, matched = UNSPEC;
-    struct ldap_result *lres = NULL;
-
-    if (handle == NULL || handle->ld == NULL)
-       return ret;
-    ld = handle->ld;
-
-    /* Fetch list of sudoRole entries that match user and host. */
-    lres = sudo_ldap_result_get(nss, sudo_user.pw);
-
-    /*
-     * The following queries are only determine whether or not a
-     * password is required, so the order of the entries doesn't matter.
-     */
-    if (pwflag) {
-       DPRINTF(("perform search for pwflag %d", pwflag), 1);
-       int doauth = UNSPEC;
-       enum def_tupple pwcheck = 
-           (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
-
-       for (i = 0; i < lres->nentries; i++) {
-           entry = lres->entries[i].entry;
-           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 = TRUE;
-               break;
-           }
-       }
-       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;
-    }
-
-    DPRINTF(("searching LDAP for sudoers entries"), 1);
-
-    setenv_implied = FALSE;
-    for (i = 0; i < lres->nentries; i++) {
-       entry = lres->entries[i].entry;
-       if (!sudo_ldap_check_runas(ld, entry))
-           continue;
-       rc = sudo_ldap_check_command(ld, entry, &setenv_implied);
-       if (rc != UNSPEC) {
-           /* We have a match. */
-           DPRINTF(("Command %sallowed", rc == TRUE ? "" : "NOT "), 1);
-           matched = TRUE;
-           if (rc == TRUE) {
-               DPRINTF(("LDAP entry: %p", entry), 1);
-               /* Apply entry-specific 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;
-#endif /* HAVE_SELINUX */
-               SET(ret, VALIDATE_OK);
-               CLR(ret, VALIDATE_NOT_OK);
-           } else {
-               SET(ret, VALIDATE_NOT_OK);
-               CLR(ret, VALIDATE_OK);
-           }
-           break;
-       }
-    }
-
-done:
-    DPRINTF(("done with LDAP searches"), 1);
-    DPRINTF(("user_matches=%d", lres->user_matches), 1);
-    DPRINTF(("host_matches=%d", lres->host_matches), 1);
-
-    if (!ISSET(ret, VALIDATE_OK)) {
-       /* No matching entries. */
-       if (pwflag && list_pw == NULL)
-           SET(ret, FLAG_NO_CHECK);
-    }
-    if (lres->user_matches)
-       CLR(ret, FLAG_NO_USER);
-    if (lres->host_matches)
-       CLR(ret, FLAG_NO_HOST);
-    DPRINTF(("sudo_ldap_lookup(%d)=0x%02x", pwflag, ret), 1);
-
-    return ret;
-}
-
-/*
- * Comparison function for ldap_entry_wrapper structures, descending order.
- */
-static int
-ldap_entry_compare(a, b)
-    const void *a;
-    const void *b;
-{
-    const struct ldap_entry_wrapper *aw = a;
-    const struct ldap_entry_wrapper *bw = b;
-
-    return bw->order < aw->order ? -1 :
-       (bw->order > aw->order ? 1 : 0);
-}
-
-/*
- * Find the last entry in the list of searches, usually the
- * one currently being used to add entries.
- * XXX - use a tailq instead?
- */
-static struct ldap_search_list *
-sudo_ldap_result_last_search(lres)
-    struct ldap_result *lres;
-{
-    struct ldap_search_list *result = lres->searches;
-
-    if (result) {
-       while (result->next)
-           result = result->next;
-    }
-    return result;
-}
-
-/*
- * Add an entry to the result structure.
- */
-static struct ldap_entry_wrapper *
-sudo_ldap_result_add_entry(lres, entry)
-    struct ldap_result *lres;
-    LDAPMessage *entry;
-{
-    struct ldap_search_list *last;
-    struct berval **bv;
-    double order = 0.0;
-    char *ep;
-
-    /* Determine whether the entry has the sudoOrder attribute. */
-    last = sudo_ldap_result_last_search(lres);
-    bv = ldap_get_values_len(last->ldap, entry, "sudoOrder");
-    if (bv != NULL) {
-       if (ldap_count_values_len(bv) > 0) {
-           /* Get the value of this attribute, 0 if not present. */
-           DPRINTF(("order attribute raw: %s", (*bv)->bv_val), 1);
-           order = strtod((*bv)->bv_val, &ep);
-           if (ep == (*bv)->bv_val || *ep != '\0') {
-               warningx("invalid sudoOrder attribute: %s", (*bv)->bv_val);
-               order = 0.0;
-           }
-           DPRINTF(("order attribute: %f", order), 1);
-       }
-       ldap_value_free_len(bv);
-    }
-
-    /*
-     * Enlarge the array of entry wrappers as needed, preallocating blocks
-     * of 100 entries to save on allocation time.
-     */
-    if (++lres->nentries > lres->allocated_entries) {
-       lres->allocated_entries += ALLOCATION_INCREMENT;
-       lres->entries = erealloc3(lres->entries, lres->allocated_entries,
-           sizeof(lres->entries[0]));
-    }
-
-    /* Fill in the new entry and return it. */
-    lres->entries[lres->nentries - 1].entry = entry;
-    lres->entries[lres->nentries - 1].order = order;
-
-    return &lres->entries[lres->nentries - 1];
-}
-
-/*
- * Free the ldap result structure in the sudo_nss handle.
- */
-static void
-sudo_ldap_result_free_nss(nss)
-    struct sudo_nss *nss;
-{
-    struct sudo_ldap_handle *handle = nss->handle;
-
-    if (handle->result != NULL) {
-       DPRINTF(("removing reusable search result"), 1);
-       sudo_ldap_result_free(handle->result);
-       if (handle->username) {
-           efree(handle->username);
-           handle->username = NULL;
-       }
-       handle->groups = NULL;
-       handle->result = NULL;
-    }
-}
-
-/*
- * Perform the LDAP query for the user or return a cached query if
- * there is one for this user.
- */
-static struct ldap_result *
-sudo_ldap_result_get(nss, pw)
-    struct sudo_nss *nss;
-    struct passwd *pw;
-{
-    struct sudo_ldap_handle *handle = nss->handle;
-    struct ldap_config_list_str *base;
-    struct ldap_result *lres;
-    struct timeval tv, *tvp = NULL;
-    LDAPMessage *entry, *result;
-    LDAP *ld = handle->ld;
-    int do_netgr, rc;
-    char *filt;
-
-    /*
-     * If we already have a cached result, return it so we don't have to
-     * have to contact the LDAP server again.
-     */
-    if (handle->result) {
-       if (handle->groups == user_groups &&
-           strcmp(pw->pw_name, handle->username) == 0) {
-           DPRINTF(("reusing previous result (user %s) with %d entries",
-               handle->username, handle->result->nentries), 1);
-           return handle->result;
-       }
-       /* User mismatch, cached result cannot be used. */
-       DPRINTF(("removing result (user %s), new search (user %s)",
-           handle->username, pw->pw_name), 1);
-       sudo_ldap_result_free_nss(nss);
-    }
-
-    /*
-     * 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.
-     *
-     * Since we have to sort the possible entries before we make a
-     * decision, we perform the queries and store all of the results in
-     * an ldap_result object.  The results are then sorted by sudoOrder.
-     */
-    lres = sudo_ldap_result_alloc();
-    for (do_netgr = 0; do_netgr < 2; do_netgr++) {
-       filt = do_netgr ? sudo_ldap_build_pass2() : sudo_ldap_build_pass1(pw);
-       DPRINTF(("ldap search '%s'", filt), 1);
-       for (base = ldap_conf.base; base != NULL; base = base->next) {
-           DPRINTF(("searching from base '%s'", base->val), 1);
-           if (ldap_conf.timeout > 0) {
-               tv.tv_sec = ldap_conf.timeout;
-               tv.tv_usec = 0;
-               tvp = &tv;
-           }
-           result = NULL;
-           rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, filt,
-               NULL, 0, NULL, NULL, NULL, 0, &result);
-           if (rc != LDAP_SUCCESS) {
-               DPRINTF(("nothing found for '%s'", filt), 1);
-               continue;
-           }
-           lres->user_matches = TRUE;
-
-           /* Add the seach result to list of search results. */
-           DPRINTF(("adding search result"), 1);
-           sudo_ldap_result_add_search(lres, ld, result);
-           LDAP_FOREACH(entry, ld, result) {
-               if ((!do_netgr ||
-                   sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
-                   sudo_ldap_check_host(ld, entry)) {
-                   lres->host_matches = TRUE;
-                   sudo_ldap_result_add_entry(lres, entry);
-               }
-           }
-           DPRINTF(("result now has %d entries", lres->nentries), 1);
-       }
-       efree(filt);
-    }
-
-    /* Sort the entries by the sudoOrder attribute. */
-    DPRINTF(("sorting remaining %d entries", lres->nentries), 1);
-    qsort(lres->entries, lres->nentries, sizeof(lres->entries[0]),
-       ldap_entry_compare);
-
-    /* Store everything in the sudo_nss handle. */
-    handle->result = lres;
-    handle->username = estrdup(pw->pw_name);
-    handle->groups = user_groups;
-
-    return lres;
-}
-
-/*
- * Shut down the LDAP connection.
- */
-static int
-sudo_ldap_close(nss)
-    struct sudo_nss *nss;
-{
-    struct sudo_ldap_handle *handle = nss->handle;
-
-    if (handle != NULL) {
-       /* Free the result before unbinding; it may use the LDAP connection. */
-       sudo_ldap_result_free_nss(nss);
-
-       /* Unbind and close the LDAP connection. */
-       if (handle->ld != NULL) {
-           ldap_unbind_ext_s(handle->ld, NULL, NULL);
-           handle->ld = NULL;
-       }
-
-       /* Free the handle container. */
-       efree(nss->handle);
-       nss->handle = NULL;
-    }
-    return 0;
-}
-
-/*
- * STUB
- */
-static int
-sudo_ldap_parse(nss)
-    struct sudo_nss *nss;
-{
-    return 0;
-}
-
-#if 0
-/*
- * Create an ldap_result from an LDAP search result.
- *
- * This function is currently not used anywhere, it is left here as
- * an example of how to use the cached searches.
- */
-static struct ldap_result *
-sudo_ldap_result_from_search(ldap, searchresult)
-    LDAP *ldap;
-    LDAPMessage *searchresult;
-{
-    /*
-     * An ldap_result is built from several search results, which are
-     * organized in a list. The head of the list is maintained in the
-     * ldap_result structure, together with the wrappers that point
-     * to individual entries, this has to be initialized first.
-     */
-    struct ldap_result *result = sudo_ldap_result_alloc();
-
-    /*
-     * Build a new list node for the search result, this creates the
-     * list node.
-     */
-    struct ldap_search_list *last = sudo_ldap_result_add_search(result,
-       ldap, searchresult);
-
-    /*
-     * Now add each entry in the search result to the array of of entries
-     * in the ldap_result object.
-     */
-    LDAPMessage        *entry;
-    LDAP_FOREACH(entry, last->ldap, last->searchresult) {
-       sudo_ldap_result_add_entry(result, entry);
-    }
-    DPRINTF(("sudo_ldap_result_from_search: %d entries found",
-       result->nentries), 2);
-    return result;
-}
-#endif
diff --git a/linux_audit.c b/linux_audit.c
deleted file mode 100644 (file)
index 16e21af..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2010 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 <stdio.h>
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif /* STDC_HEADERS */
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <libaudit.h>
-
-#include "missing.h"
-#include "error.h"
-#include "alloc.h"
-#include "linux_audit.h"
-
-/*
- * Open audit connection if possible.
- * Returns audit fd on success and -1 on failure.
- */
-static int
-linux_audit_open(void)
-{
-    static int au_fd = -1;
-
-    if (au_fd != -1)
-       return au_fd;
-    au_fd = audit_open();
-    if (au_fd == -1) {
-       /* Kernel may not have audit support. */
-       if (errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
-           error(1, "unable to open audit system");
-    } else {
-       (void)fcntl(au_fd, F_SETFD, FD_CLOEXEC);
-    }
-    return au_fd;
-}
-
-int
-linux_audit_command(char *argv[], int result)
-{
-    int au_fd, rc;
-    char *command, *cp, **av;
-    size_t size, n;
-
-    if ((au_fd = linux_audit_open()) == -1)
-       return -1;
-
-    /* Convert argv to a flat string. */
-    for (size = 0, av = argv; *av != NULL; av++)
-       size += strlen(*av) + 1;
-    command = cp = emalloc(size);
-    for (av = argv; *av != NULL; av++) {
-       n = strlcpy(cp, *av, size - (cp - command));
-       if (n >= size - (cp - command))
-           errorx(1, "internal error, linux_audit_command() overflow");
-       cp += n;
-       *cp++ = ' ';
-    }
-    *--cp = '\0';
-
-    /* Log command, ignoring ECONNREFUSED on error. */
-    rc = audit_log_user_command(au_fd, AUDIT_USER_CMD, command, NULL, result);
-    if (rc <= 0 && errno != ECONNREFUSED)
-       warning("unable to send audit message");
-
-    efree(command);
-
-    return rc;
-}
-
-#ifdef HAVE_SELINUX
-int
-linux_audit_role_change(const char *old_context,
-    const char *new_context, const char *ttyn)
-{
-    int au_fd, rc;
-    char *message;
-
-    if ((au_fd = linux_audit_open()) == -1)
-       return -1;
-
-    /* audit role change using the same format as newrole(1) */
-    easprintf(&message, "newrole: old-context=%s new-context=%s",
-       old_context, new_context);
-    rc = audit_log_user_message(au_fd, AUDIT_USER_ROLE_CHANGE,
-       message, NULL, NULL, ttyn, 1);
-    if (rc <= 0)
-       warning("unable to send audit message");
-
-    efree(message);
-
-    return rc;
-}
-#endif /* HAVE_SELINUX */
diff --git a/linux_audit.h b/linux_audit.h
deleted file mode 100644 (file)
index f2574f6..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2010 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.
- */
-
-#ifndef _SUDO_LINUX_AUDIT_H
-#define        _SUDO_LINUX_AUDIT_H
-
-int    linux_audit_command(char *argv[], int result);
-int    linux_audit_role_change(const char *old_context,
-           const char *new_context, const char *ttyn);
-
-#endif /* _SUDO_LINUX_AUDIT_H */
diff --git a/list.c b/list.c
deleted file mode 100644 (file)
index 2fb4967..0000000
--- a/list.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * 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"
-
-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;
-}
-
-/*
- * Remove element from the tail_queue
- */
-void
-tq_remove(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 (h->first == l && h->last == l) {
-       /* Single element in the list. */
-       h->first = NULL;
-       h->last = NULL;
-    } else {
-       /* At least two elements in the list. */
-       if (h->first == l) {
-           h->first = l->next;
-           h->first->prev = h->first;
-       } else if (h->last == l) {
-           h->last = l->prev;
-           h->last->next = NULL;
-       } else {
-           l->prev->next = l->next;
-           l->next->prev = l->prev;
-       }
-    }
-}
diff --git a/list.h b/list.h
deleted file mode 100644 (file)
index 719afa2..0000000
--- a/list.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.
- */
-
-#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 tq_remove         __P((void *, void *));
-void list_append       __P((void *, void *));
-void list2tq           __P((void *, void *));
-
-#endif /* _SUDO_LIST_H */
diff --git a/logging.c b/logging.c
deleted file mode 100644 (file)
index d0aeab9..0000000
--- a/logging.c
+++ /dev/null
@@ -1,785 +0,0 @@
-/*
- * Copyright (c) 1994-1996, 1998-2010 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.
- */
-
-#ifdef __TANDEM
-# include <floss.h>
-#endif
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/wait.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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#ifdef HAVE_SETLOCALE
-# include <locale.h>
-#endif /* HAVE_SETLOCALE */
-#ifdef HAVE_NL_LANGINFO
-# include <langinfo.h>
-#endif /* HAVE_NL_LANGINFO */
-#include <pwd.h>
-#include <grp.h>
-#include <signal.h>
-#include <time.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include "sudo.h"
-
-static void do_syslog          __P((int, char *));
-static void do_logfile         __P((char *));
-static void send_mail          __P((const char *fmt, ...));
-static int should_mail         __P((int));
-static void mysyslog           __P((int, const char *, ...));
-static char *new_logline       __P((const char *, int));
-
-#define MAXSYSLOGTRIES 16      /* num of retries for broken syslogs */
-
-/*
- * We do an openlog(3)/closelog(3) for each message because some
- * authentication methods (notably PAM) use syslog(3) for their
- * own nefarious purposes and may call openlog(3) and closelog(3).
- * Note that because we don't want to assume that all systems have
- * vsyslog(3) (HP-UX doesn't) "%m" will not be expanded.
- * Sadly this is a maze of #ifdefs.
- */
-static void
-#ifdef __STDC__
-mysyslog(int pri, const char *fmt, ...)
-#else
-mysyslog(pri, fmt, va_alist)
-    int pri;
-    const char *fmt;
-    va_dcl
-#endif
-{
-#ifdef BROKEN_SYSLOG
-    int i;
-#endif
-    char buf[MAXSYSLOGLEN+1];
-    va_list ap;
-
-#ifdef __STDC__
-    va_start(ap, fmt);
-#else
-    va_start(ap);
-#endif
-#ifdef LOG_NFACILITIES
-    openlog("sudo", 0, def_syslog);
-#else
-    openlog("sudo", 0);
-#endif
-    vsnprintf(buf, sizeof(buf), fmt, ap);
-#ifdef BROKEN_SYSLOG
-    /*
-     * Some versions of syslog(3) don't guarantee success and return
-     * an int (notably HP-UX < 10.0).  So, if at first we don't succeed,
-     * try, try again...
-     */
-    for (i = 0; i < MAXSYSLOGTRIES; i++)
-       if (syslog(pri, "%s", buf) == 0)
-           break;
-#else
-    syslog(pri, "%s", buf);
-#endif /* BROKEN_SYSLOG */
-    va_end(ap);
-    closelog();
-}
-
-#define FMT_FIRST "%8s : %s"
-#define FMT_CONTD "%8s : (command continued) %s"
-
-/*
- * Log a message to syslog, pre-pending the username and splitting the
- * message into parts if it is longer than MAXSYSLOGLEN.
- */
-static void
-do_syslog(pri, msg)
-    int pri;
-    char *msg;
-{
-    size_t len, maxlen;
-    char *p, *tmp, save;
-    const char *fmt;
-
-#ifdef HAVE_SETLOCALE
-    const char *old_locale = estrdup(setlocale(LC_ALL, NULL));
-    if (!setlocale(LC_ALL, def_sudoers_locale))
-       setlocale(LC_ALL, "C");
-#endif /* HAVE_SETLOCALE */
-
-    /*
-     * Log the full line, breaking into multiple syslog(3) calls if necessary
-     */
-    fmt = FMT_FIRST;
-    maxlen = MAXSYSLOGLEN - (sizeof(FMT_FIRST) - 6 + strlen(user_name));
-    for (p = msg; *p != '\0'; ) {
-       len = strlen(p);
-       if (len > maxlen) {
-           /*
-            * Break up the line into what will fit on one syslog(3) line
-            * Try to avoid breaking words into several lines if possible.
-            */
-           tmp = memrchr(p, ' ', maxlen);
-           if (tmp == NULL)
-               tmp = p + maxlen;
-
-           /* NULL terminate line, but save the char to restore later */
-           save = *tmp;
-           *tmp = '\0';
-
-           mysyslog(pri, fmt, user_name, p);
-
-           *tmp = save;                        /* restore saved character */
-
-           /* Advance p and eliminate leading whitespace */
-           for (p = tmp; *p == ' '; p++)
-               ;
-       } else {
-           mysyslog(pri, fmt, user_name, p);
-           p += len;
-       }
-       fmt = FMT_CONTD;
-       maxlen = MAXSYSLOGLEN - (sizeof(FMT_CONTD) - 6 + strlen(user_name));
-    }
-
-#ifdef HAVE_SETLOCALE
-    setlocale(LC_ALL, old_locale);
-    efree((void *)old_locale);
-#endif /* HAVE_SETLOCALE */
-}
-
-static void
-do_logfile(msg)
-    char *msg;
-{
-    char *full_line;
-    char *beg, *oldend, *end;
-    FILE *fp;
-    mode_t oldmask;
-    size_t maxlen;
-
-    oldmask = umask(077);
-    maxlen = def_loglinelen > 0 ? def_loglinelen : 0;
-    fp = fopen(def_logfile, "a");
-    (void) umask(oldmask);
-    if (fp == NULL) {
-       send_mail("Can't open log file: %s: %s", def_logfile, strerror(errno));
-    } else if (!lock_file(fileno(fp), SUDO_LOCK)) {
-       send_mail("Can't lock log file: %s: %s", def_logfile, strerror(errno));
-    } else {
-       time_t now;
-
-#ifdef HAVE_SETLOCALE
-       const char *old_locale = estrdup(setlocale(LC_ALL, NULL));
-       if (!setlocale(LC_ALL, def_sudoers_locale))
-           setlocale(LC_ALL, "C");
-#endif /* HAVE_SETLOCALE */
-
-       now = time(NULL);
-       if (def_loglinelen == 0) {
-           /* Don't pretty-print long log file lines (hard to grep) */
-           if (def_log_host)
-               (void) fprintf(fp, "%s : %s : HOST=%s : %s\n",
-                   get_timestr(now, def_log_year), user_name, user_shost, msg);
-           else
-               (void) fprintf(fp, "%s : %s : %s\n",
-                   get_timestr(now, def_log_year), user_name, msg);
-       } else {
-           if (def_log_host)
-               easprintf(&full_line, "%s : %s : HOST=%s : %s",
-                   get_timestr(now, def_log_year), user_name, user_shost, msg);
-           else
-               easprintf(&full_line, "%s : %s : %s",
-                   get_timestr(now, def_log_year), user_name, msg);
-
-           /*
-            * Print out full_line with word wrap
-            */
-           beg = end = full_line;
-           while (beg) {
-               oldend = end;
-               end = strchr(oldend, ' ');
-
-               if (maxlen > 0 && end) {
-                   *end = '\0';
-                   if (strlen(beg) > maxlen) {
-                       /* too far, need to back up & print the line */
-
-                       if (beg == (char *)full_line)
-                           maxlen -= 4;        /* don't indent first line */
-
-                       *end = ' ';
-                       if (oldend != beg) {
-                           /* rewind & print */
-                           end = oldend-1;
-                           while (*end == ' ')
-                               --end;
-                           *(++end) = '\0';
-                           (void) fprintf(fp, "%s\n    ", beg);
-                           *end = ' ';
-                       } else {
-                           (void) fprintf(fp, "%s\n    ", beg);
-                       }
-
-                       /* reset beg to point to the start of the new substr */
-                       beg = end;
-                       while (*beg == ' ')
-                           ++beg;
-                   } else {
-                       /* we still have room */
-                       *end = ' ';
-                   }
-
-                   /* remove leading whitespace */
-                   while (*end == ' ')
-                       ++end;
-               } else {
-                   /* final line */
-                   (void) fprintf(fp, "%s\n", beg);
-                   beg = NULL;                 /* exit condition */
-               }
-           }
-           efree(full_line);
-       }
-       (void) fflush(fp);
-       (void) lock_file(fileno(fp), SUDO_UNLOCK);
-       (void) fclose(fp);
-
-#ifdef HAVE_SETLOCALE
-       setlocale(LC_ALL, old_locale);
-       efree((void *)old_locale);
-#endif /* HAVE_SETLOCALE */
-    }
-}
-
-/*
- * Log and mail the denial message, optionally informing the user.
- */
-void
-log_denial(status, inform_user)
-    int status;
-    int inform_user;
-{
-    char *message;
-    char *logline;
-
-    /* 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
-       message = "command not allowed";
-
-    logline = new_logline(message, 0);
-
-    if (should_mail(status))
-       send_mail("%s", logline);       /* send mail based on status */
-
-    /* Inform the user if they failed to authenticate.  */
-    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");
-       else if (ISSET(status, FLAG_NO_HOST))
-           (void) fprintf(stderr, "%s is not allowed to run sudo on %s.  %s",
-               user_name, user_shost, "This incident will be reported.\n");
-       else if (ISSET(status, FLAG_NO_CHECK))
-           (void) fprintf(stderr, "Sorry, user %s may not run sudo on %s.\n",
-               user_name, user_shost);
-       else
-           (void) fprintf(stderr,
-               "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 : "",
-               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(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("%s", 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(logline);
-}
-
-void
-#ifdef __STDC__
-log_error(int flags, const char *fmt, ...)
-#else
-log_error(flags, fmt, va_alist)
-    int flags;
-    const char *fmt;
-    va_dcl
-#endif
-{
-    int serrno = errno;
-    char *message;
-    char *logline;
-    va_list ap;
-#ifdef __STDC__
-    va_start(ap, fmt);
-#else
-    va_start(ap);
-#endif
-
-    /* Become root if we are not already to avoid user interference */
-    set_perms(PERM_ROOT|PERM_NOEXIT);
-
-    /* Expand printf-style format + args. */
-    evasprintf(&message, fmt, ap);
-    va_end(ap);
-
-    if (ISSET(flags, MSG_ONLY))
-       logline = message;
-    else
-       logline = new_logline(message, ISSET(flags, USE_ERRNO) ? serrno : 0);
-
-    /*
-     * Tell the user.
-     */
-    if (!ISSET(flags, NO_STDERR)) {
-       if (ISSET(flags, USE_ERRNO))
-           warning("%s", message);
-       else
-           warningx("%s", message);
-    }
-    if (logline != message)
-        efree(message);
-
-    /*
-     * Send a copy of the error via mail.
-     */
-    if (!ISSET(flags, NO_MAIL))
-       send_mail("%s", logline);
-
-    /*
-     * Log to syslog and/or a file.
-     */
-    if (def_syslog)
-       do_syslog(def_syslog_badpri, logline);
-    if (def_logfile)
-       do_logfile(logline);
-
-    efree(logline);
-
-    if (!ISSET(flags, NO_EXIT)) {
-       cleanup(0);
-       exit(1);
-    }
-}
-
-#define MAX_MAILFLAGS  63
-
-/*
- * Send a message to MAILTO user
- */
-static void
-#ifdef __STDC__
-send_mail(const char *fmt, ...)
-#else
-send_mail(fmt, va_alist)
-    const char *fmt;
-    va_dcl
-#endif
-{
-    FILE *mail;
-    char *p;
-    int fd, pfd[2], status;
-    pid_t pid, rv;
-    sigaction_t sa;
-    va_list ap;
-#ifndef NO_ROOT_MAILER
-    static char *root_envp[] = {
-       "HOME=/",
-       "PATH=/usr/bin:/bin:/usr/sbin:/sbin",
-       "LOGNAME=root",
-       "USERNAME=root",
-       "USER=root",
-       NULL
-    };
-#endif /* NO_ROOT_MAILER */
-
-    /* Just return if mailer is disabled. */
-    if (!def_mailerpath || !def_mailto)
-       return;
-
-    /* Fork and return, child will daemonize. */
-    switch (pid = fork()) {
-       case -1:
-           /* Error. */
-           error(1, "cannot fork");
-           break;
-       case 0:
-           /* Child. */
-           switch (pid = fork()) {
-               case -1:
-                   /* Error. */
-                   mysyslog(LOG_ERR, "cannot fork: %m");
-                   _exit(1);
-               case 0:
-                   /* Grandchild continues below. */
-                   break;
-               default:
-                   /* Parent will wait for us. */
-                   _exit(0);
-           }
-           break;
-       default:
-           /* Parent. */
-           do {
-#ifdef HAVE_WAITPID
-               rv = waitpid(pid, &status, 0);
-#else
-               rv = wait(&status);
-#endif
-           } while (rv == -1 && errno == EINTR);
-           return;
-    }
-
-    /* Daemonize - disassociate from session/tty. */
-    if (setsid() == -1)
-      warning("setsid");
-    if (chdir("/") == -1)
-      warning("chdir(/)");
-    if ((fd = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) {
-       (void) dup2(fd, STDIN_FILENO);
-       (void) dup2(fd, STDOUT_FILENO);
-       (void) dup2(fd, STDERR_FILENO);
-    }
-
-#ifdef HAVE_SETLOCALE
-    if (!setlocale(LC_ALL, def_sudoers_locale)) {
-       setlocale(LC_ALL, "C");
-       efree(def_sudoers_locale);
-       def_sudoers_locale = estrdup("C");
-    }
-#endif /* HAVE_SETLOCALE */
-
-    /* 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 = SA_INTERRUPT;
-    sa.sa_handler = SIG_IGN;
-    (void) sigaction(SIGPIPE, &sa, NULL);
-
-    if (pipe(pfd) == -1) {
-       mysyslog(LOG_ERR, "cannot open pipe: %m");
-       _exit(1);
-    }
-
-    switch (pid = fork()) {
-       case -1:
-           /* Error. */
-           mysyslog(LOG_ERR, "cannot fork: %m");
-           _exit(1);
-           break;
-       case 0:
-           {
-               char *argv[MAX_MAILFLAGS + 1];
-               char *mpath, *mflags;
-               int i;
-
-               /* Child, set stdin to output side of the pipe */
-               if (pfd[0] != STDIN_FILENO) {
-                   if (dup2(pfd[0], STDIN_FILENO) == -1) {
-                       mysyslog(LOG_ERR, "cannot dup stdin: %m");
-                       _exit(127);
-                   }
-                   (void) close(pfd[0]);
-               }
-               (void) close(pfd[1]);
-
-               /* Build up an argv based on the mailer path and flags */
-               mflags = estrdup(def_mailerflags);
-               mpath = estrdup(def_mailerpath);
-               if ((argv[0] = strrchr(mpath, ' ')))
-                   argv[0]++;
-               else
-                   argv[0] = mpath;
-
-               i = 1;
-               if ((p = strtok(mflags, " \t"))) {
-                   do {
-                       argv[i] = p;
-                   } while (++i < MAX_MAILFLAGS && (p = strtok(NULL, " \t")));
-               }
-               argv[i] = NULL;
-
-               /*
-                * Depending on the config, either run the mailer as root
-                * (so user cannot kill it) or as the user (for the paranoid).
-                */
-#ifndef NO_ROOT_MAILER
-               set_perms(PERM_ROOT|PERM_NOEXIT);
-               execve(mpath, argv, root_envp);
-#else
-               set_perms(PERM_FULL_USER|PERM_NOEXIT);
-               execv(mpath, argv);
-#endif /* NO_ROOT_MAILER */
-               mysyslog(LOG_ERR, "cannot execute %s: %m", mpath);
-               _exit(127);
-           }
-           break;
-    }
-
-    (void) close(pfd[0]);
-    mail = fdopen(pfd[1], "w");
-
-    /* Pipes are all setup, send message. */
-    (void) fprintf(mail, "To: %s\nFrom: %s\nAuto-Submitted: %s\nSubject: ",
-       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) != '%') {
-           switch (*(++p)) {
-               case 'h':
-                   (void) fputs(user_host, mail);
-                   break;
-               case 'u':
-                   (void) fputs(user_name, mail);
-                   break;
-               default:
-                   p--;
-                   break;
-           }
-       } else
-           (void) fputc(*p, mail);
-    }
-
-#ifdef HAVE_NL_LANGINFO
-    if (strcmp(def_sudoers_locale, "C") != 0)
-       (void) fprintf(mail, "\nContent-Type: text/plain; charset=\"%s\"\nContent-Transfer-Encoding: 8bit", nl_langinfo(CODESET));
-#endif /* HAVE_NL_LANGINFO */
-
-    (void) fprintf(mail, "\n\n%s : %s : %s : ", user_host,
-       get_timestr(time(NULL), def_log_year), user_name);
-#ifdef __STDC__
-    va_start(ap, fmt);
-#else
-    va_start(ap);
-#endif
-    (void) vfprintf(mail, fmt, ap);
-    va_end(ap);
-    fputs("\n\n", mail);
-
-    fclose(mail);
-    do {
-#ifdef HAVE_WAITPID
-        rv = waitpid(pid, &status, 0);
-#else
-        rv = wait(&status);
-#endif
-    } while (rv == -1 && errno == EINTR);
-    _exit(0);
-}
-
-/*
- * Determine whether we should send mail based on "status" and defaults options.
- */
-static int
-should_mail(status)
-    int status;
-{
-
-    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));
-}
-
-#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="
-#define        LL_TSID_STR     "TSID="
-
-/*
- * 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.sessid[0] != '\0')
-       len += sizeof(LL_TSID_STR) + 2 + strlen(sudo_user.sessid);
-    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;
-    }
-    /* Note: we log "sudo -l command arg ..." as "list command arg ..." */
-    len += sizeof(LL_CMND_STR) - 1 + strlen(user_cmnd);
-    if (ISSET(sudo_mode, MODE_CHECK))
-       len += sizeof("list ") - 1;
-    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 (sudo_user.sessid[0] != '\0') {
-       if (strlcat(line, LL_TSID_STR, len) >= len ||
-           strlcat(line, sudo_user.sessid, 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)
-       goto toobig;
-    if (ISSET(sudo_mode, MODE_CHECK) && strlcat(line, "list ", len) >= len)
-       goto toobig;
-    if (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");
-}
diff --git a/logging.h b/logging.h
deleted file mode 100644 (file)
index c95423e..0000000
--- a/logging.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2009
- *     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.
- */
-
-#ifndef _LOGGING_H
-#define _LOGGING_H
-
-#include <syslog.h>
-#ifdef __STDC__
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
-
-/* Logging types */
-#define SLOG_SYSLOG            0x01
-#define SLOG_FILE              0x02
-#define SLOG_BOTH              0x03
-
-/* Flags for log_error() */
-#define MSG_ONLY               0x01
-#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
- * will log this much, after that, it truncates the log line.
- * We need this here to make sure that we continue with another
- * syslog(3) call if the internal buffer is more than 1023 characters.
- */
-#ifndef MAXSYSLOGLEN
-# define MAXSYSLOGLEN          960
-#endif
-
-void audit_success             __P((char *[]));
-void audit_failure             __P((char *[], char const * const, ...));
-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));
-
-#endif /* _LOGGING_H */
old mode 100644 (file)
new mode 100755 (executable)
index a72f2fd..04eaea4
--- a/ltmain.sh
+++ b/ltmain.sh
@@ -1,9 +1,10 @@
 # Generated from ltmain.m4sh.
 
-# ltmain.sh (GNU libtool) 2.2.6b
+# libtool (GNU libtool) 2.2.10
 # Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
 
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc.
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 # This is free software; see the source for copying conditions.  There is NO
 # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 #
 # Provide generalized library-building support services.
 #
-#     --config             show all configuration variables
-#     --debug              enable verbose shell tracing
-# -n, --dry-run            display commands without modifying any files
-#     --features           display basic configuration information and exit
-#     --mode=MODE          use operation mode MODE
-#     --preserve-dup-deps  don't remove duplicate dependency libraries
-#     --quiet, --silent    don't print informational messages
-#     --tag=TAG            use configuration variables from tag TAG
-# -v, --verbose            print informational messages (default)
-#     --version            print version information
-# -h, --help               print short or long help message
+#       --config             show all configuration variables
+#       --debug              enable verbose shell tracing
+#   -n, --dry-run            display commands without modifying any files
+#       --features           display basic configuration information and exit
+#       --mode=MODE          use operation mode MODE
+#       --preserve-dup-deps  don't remove duplicate dependency libraries
+#       --quiet, --silent    don't print informational messages
+#       --no-quiet, --no-silent
+#                            print informational messages (default)
+#       --tag=TAG            use configuration variables from tag TAG
+#   -v, --verbose            print more informational messages than default
+#       --no-verbose         don't print the extra informational messages
+#       --version            print version information
+#   -h, --help, --help-all   print short, long, or detailed help message
 #
 # MODE must be one of the following:
 #
-#       clean              remove files from the build directory
-#       compile            compile a source file into a libtool object
-#       execute            automatically set library path, then run a program
-#       finish             complete the installation of libtool libraries
-#       install            install libraries or executables
-#       link               create a library or an executable
-#       uninstall          remove libraries from an installed directory
+#         clean              remove files from the build directory
+#         compile            compile a source file into a libtool object
+#         execute            automatically set library path, then run a program
+#         finish             complete the installation of libtool libraries
+#         install            install libraries or executables
+#         link               create a library or an executable
+#         uninstall          remove libraries from an installed directory
 #
-# MODE-ARGS vary depending on the MODE.
+# MODE-ARGS vary depending on the MODE.  When passed as first option,
+# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
 # Try `$progname --help --mode=MODE' for a more detailed description of MODE.
 #
 # When reporting a bug, please describe a test case to reproduce it and
 # include the following information:
 #
-#       host-triplet:  $host
-#       shell:         $SHELL
-#       compiler:              $LTCC
-#       compiler flags:                $LTCFLAGS
-#       linker:                $LD (gnu? $with_gnu_ld)
-#       $progname:             (GNU libtool) 2.2.6b
-#       automake:              $automake_version
-#       autoconf:              $autoconf_version
+#         host-triplet:        $host
+#         shell:               $SHELL
+#         compiler:            $LTCC
+#         compiler flags:              $LTCFLAGS
+#         linker:              $LD (gnu? $with_gnu_ld)
+#         $progname:   (GNU libtool) 2.2.10
+#         automake:    $automake_version
+#         autoconf:    $autoconf_version
 #
 # Report bugs to <bug-libtool@gnu.org>.
 
-PROGRAM=ltmain.sh
+PROGRAM=libtool
 PACKAGE=libtool
-VERSION=2.2.6b
+VERSION=2.2.10
 TIMESTAMP=""
-package_revision=1.3017
+package_revision=1.3175
 
 # Be Bourne compatible
 if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
@@ -91,10 +96,15 @@ fi
 BIN_SH=xpg4; export BIN_SH # for Tru64
 DUALCASE=1; export DUALCASE # for MKS sh
 
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
 # NLS nuisances: We save the old values to restore during execute mode.
-# Only set LANG and LC_ALL to C if already set.
-# These must not be set unconditionally because not all systems understand
-# e.g. LANG=C (notably SCO).
 lt_user_locale=
 lt_safe_locale=
 for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
@@ -107,24 +117,33 @@ do
          lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
        fi"
 done
+LC_ALL=C
+LANGUAGE=C
+export LANGUAGE LC_ALL
 
 $lt_unset CDPATH
 
 
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
 
 
 
 : ${CP="cp -f"}
-: ${ECHO="echo"}
-: ${EGREP="/bin/grep -E"}
-: ${FGREP="/bin/grep -F"}
-: ${GREP="/bin/grep"}
+test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+: ${EGREP="grep -E"}
+: ${FGREP="grep -F"}
+: ${GREP="grep"}
 : ${LN_S="ln -s"}
 : ${MAKE="make"}
 : ${MKDIR="mkdir"}
 : ${MV="mv -f"}
 : ${RM="rm -f"}
-: ${SED="/bin/sed"}
+: ${SED="sed"}
 : ${SHELL="${CONFIG_SHELL-/bin/sh}"}
 : ${Xsed="$SED -e 1s/^X//"}
 
@@ -159,32 +178,168 @@ basename="s,^.*/,,"
 func_dirname_and_basename ()
 {
   # Extract subdirectory from the argument.
-  func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
+  func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
   if test "X$func_dirname_result" = "X${1}"; then
     func_dirname_result="${3}"
   else
     func_dirname_result="$func_dirname_result${2}"
   fi
-  func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
+  func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
 }
 
 # Generated shell functions inserted here.
 
-# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
-# is ksh but when the shell is invoked as "sh" and the current value of
-# the _XPG environment variable is not equal to 1 (one), the special
-# positional parameter $0, within a function call, is the name of the
-# function.
-progpath="$0"
+# These SED scripts presuppose an absolute path with a trailing slash.
+pathcar='s,^/\([^/]*\).*$,\1,'
+pathcdr='s,^/[^/]*,,'
+removedotparts=':dotsl
+               s@/\./@/@g
+               t dotsl
+               s,/\.$,/,'
+collapseslashes='s@/\{1,\}@/@g'
+finalslash='s,/*$,/,'
+
+# func_normal_abspath PATH
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+#             value returned in "$func_normal_abspath_result"
+func_normal_abspath ()
+{
+  # Start from root dir and reassemble the path.
+  func_normal_abspath_result=
+  func_normal_abspath_tpath=$1
+  func_normal_abspath_altnamespace=
+  case $func_normal_abspath_tpath in
+    "")
+      # Empty path, that just means $cwd.
+      func_stripname '' '/' "`pwd`"
+      func_normal_abspath_result=$func_stripname_result
+      return
+    ;;
+    # The next three entries are used to spot a run of precisely
+    # two leading slashes without using negated character classes;
+    # we take advantage of case's first-match behaviour.
+    ///*)
+      # Unusual form of absolute path, do nothing.
+    ;;
+    //*)
+      # Not necessarily an ordinary path; POSIX reserves leading '//'
+      # and for example Cygwin uses it to access remote file shares
+      # over CIFS/SMB, so we conserve a leading double slash if found.
+      func_normal_abspath_altnamespace=/
+    ;;
+    /*)
+      # Absolute path, do nothing.
+    ;;
+    *)
+      # Relative path, prepend $cwd.
+      func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+    ;;
+  esac
+  # Cancel out all the simple stuff to save iterations.  We also want
+  # the path to end with a slash for ease of parsing, so make sure
+  # there is one (and only one) here.
+  func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
+  while :; do
+    # Processed it all yet?
+    if test "$func_normal_abspath_tpath" = / ; then
+      # If we ascended to the root using ".." the result may be empty now.
+      if test -z "$func_normal_abspath_result" ; then
+        func_normal_abspath_result=/
+      fi
+      break
+    fi
+    func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcar"`
+    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcdr"`
+    # Figure out what to do with it
+    case $func_normal_abspath_tcomponent in
+      "")
+        # Trailing empty path component, ignore it.
+      ;;
+      ..)
+        # Parent dir; strip last assembled component from result.
+        func_dirname "$func_normal_abspath_result"
+        func_normal_abspath_result=$func_dirname_result
+      ;;
+      *)
+        # Actual path component, append it.
+        func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
+      ;;
+    esac
+  done
+  # Restore leading double-slash if one was found on entry.
+  func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+# func_relative_path SRCDIR DSTDIR
+# generates a relative path from SRCDIR to DSTDIR, with a trailing
+# slash if non-empty, suitable for immediately appending a filename
+# without needing to append a separator.
+#             value returned in "$func_relative_path_result"
+func_relative_path ()
+{
+  func_relative_path_result=
+  func_normal_abspath "$1"
+  func_relative_path_tlibdir=$func_normal_abspath_result
+  func_normal_abspath "$2"
+  func_relative_path_tbindir=$func_normal_abspath_result
+
+  # Ascend the tree starting from libdir
+  while :; do
+    # check if we have found a prefix of bindir
+    case $func_relative_path_tbindir in
+      $func_relative_path_tlibdir)
+        # found an exact match
+        func_relative_path_tcancelled=
+        break
+        ;;
+      $func_relative_path_tlibdir*)
+        # found a matching prefix
+        func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+        func_relative_path_tcancelled=$func_stripname_result
+        if test -z "$func_relative_path_result"; then
+          func_relative_path_result=.
+        fi
+        break
+        ;;
+      *)
+        func_dirname $func_relative_path_tlibdir
+        func_relative_path_tlibdir=${func_dirname_result}
+        if test "x$func_relative_path_tlibdir" = x ; then
+          # Have to descend all the way to the root!
+          func_relative_path_result=../$func_relative_path_result
+          func_relative_path_tcancelled=$func_relative_path_tbindir
+          break
+        fi
+        func_relative_path_result=../$func_relative_path_result
+        ;;
+    esac
+  done
+
+  # Now calculate path; take care to avoid doubling-up slashes.
+  func_stripname '' '/' "$func_relative_path_result"
+  func_relative_path_result=$func_stripname_result
+  func_stripname '/' '/' "$func_relative_path_tcancelled"
+  if test "x$func_stripname_result" != x ; then
+    func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
+  fi
+
+  # Normalisation. If bindir is libdir, return empty string,
+  # else relative path ending with a slash; either way, target
+  # file name can be directly appended.
+  if test ! -z "$func_relative_path_result"; then
+    func_stripname './' '' "$func_relative_path_result/"
+    func_relative_path_result=$func_stripname_result
+  fi
+}
 
 # The name of this program:
-# In the unlikely event $progname began with a '-', it would play havoc with
-# func_echo (imagine progname=-n), so we prepend ./ in that case:
 func_dirname_and_basename "$progpath"
 progname=$func_basename_result
-case $progname in
-  -*) progname=./$progname ;;
-esac
 
 # Make sure we have an absolute path for reexecution:
 case $progpath in
@@ -258,6 +413,13 @@ func_verbose ()
     :
 }
 
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
 # func_error arg...
 # Echo program name prefixed message to standard error.
 func_error ()
@@ -326,9 +488,9 @@ func_mkdir_p ()
         case $my_directory_path in */*) ;; *) break ;; esac
 
         # ...otherwise throw away the child directory and loop
-        my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"`
+        my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
       done
-      my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'`
+      my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
 
       save_mkdir_p_IFS="$IFS"; IFS=':'
       for my_dir in $my_dir_list; do
@@ -378,7 +540,7 @@ func_mktempdir ()
         func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
     fi
 
-    $ECHO "X$my_tmpdir" | $Xsed
+    $ECHO "$my_tmpdir"
 }
 
 
@@ -392,7 +554,7 @@ func_quote_for_eval ()
 {
     case $1 in
       *[\\\`\"\$]*)
-       func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;;
+       func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
       *)
         func_quote_for_eval_unquoted_result="$1" ;;
     esac
@@ -419,7 +581,7 @@ func_quote_for_expand ()
 {
     case $1 in
       *[\\\`\"]*)
-       my_arg=`$ECHO "X$1" | $Xsed \
+       my_arg=`$ECHO "$1" | $SED \
            -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
       *)
         my_arg="$1" ;;
@@ -489,14 +651,19 @@ func_show_eval_locale ()
 }
 
 
-
-
-
 # func_version
 # Echo version message to standard output and exit.
 func_version ()
 {
-    $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / {
+    $SED -n '/(C)/!b go
+       :more
+       /\./!{
+         N
+         s/\n# / /
+         b more
+       }
+       :go
+       /^# '$PROGRAM' (GNU /,/# warranty; / {
         s/^# //
        s/^# *$//
         s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
@@ -509,19 +676,20 @@ func_version ()
 # Echo short help message to standard output and exit.
 func_usage ()
 {
-    $SED -n '/^# Usage:/,/# -h/ {
+    $SED -n '/^# Usage:/,/^#  *.*--help/ {
         s/^# //
        s/^# *$//
        s/\$progname/'$progname'/
        p
     }' < "$progpath"
-    $ECHO
+    echo
     $ECHO "run \`$progname --help | more' for full usage"
     exit $?
 }
 
-# func_help
-# Echo long help message to standard output and exit.
+# func_help [NOEXIT]
+# Echo long help message to standard output and exit,
+# unless 'noexit' is passed as argument.
 func_help ()
 {
     $SED -n '/^# Usage:/,/# Report bugs to/ {
@@ -538,7 +706,10 @@ func_help ()
        s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/
        p
      }' < "$progpath"
-    exit $?
+    ret=$?
+    if test -z "$1"; then
+      exit $ret
+    fi
 }
 
 # func_missing_arg argname
@@ -546,7 +717,7 @@ func_help ()
 # exit_cmd.
 func_missing_arg ()
 {
-    func_error "missing argument for $1"
+    func_error "missing argument for $1."
     exit_cmd=exit
 }
 
@@ -556,29 +727,6 @@ exit_cmd=:
 
 
 
-# Check that we have a working $ECHO.
-if test "X$1" = X--no-reexec; then
-  # Discard the --no-reexec flag, and continue.
-  shift
-elif test "X$1" = X--fallback-echo; then
-  # Avoid inline document here, it may be left over
-  :
-elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then
-  # Yippee, $ECHO works!
-  :
-else
-  # Restart under the correct shell, and then maybe $ECHO will work.
-  exec $SHELL "$progpath" --no-reexec ${1+"$@"}
-fi
-
-if test "X$1" = X--fallback-echo; then
-  # used as fallback echo
-  shift
-  cat <<EOF
-$*
-EOF
-  exit $EXIT_SUCCESS
-fi
 
 magic="%%%MAGIC variable%%%"
 magic_exe="%%%MAGIC EXE variable%%%"
@@ -636,16 +784,16 @@ func_config ()
 # Display the features supported by this script.
 func_features ()
 {
-    $ECHO "host: $host"
+    echo "host: $host"
     if test "$build_libtool_libs" = yes; then
-      $ECHO "enable shared libraries"
+      echo "enable shared libraries"
     else
-      $ECHO "disable shared libraries"
+      echo "disable shared libraries"
     fi
     if test "$build_old_libs" = yes; then
-      $ECHO "enable static libraries"
+      echo "enable static libraries"
     else
-      $ECHO "disable static libraries"
+      echo "disable static libraries"
     fi
 
     exit $?
@@ -772,10 +920,21 @@ func_enable_tag ()
 
       --quiet|--silent)        preserve_args="$preserve_args $opt"
                        opt_silent=:
+                       opt_verbose=false
+                       ;;
+
+      --no-quiet|--no-silent)
+                       preserve_args="$preserve_args $opt"
+                       opt_silent=false
                        ;;
 
       --verbose| -v)   preserve_args="$preserve_args $opt"
                        opt_silent=false
+                       opt_verbose=:
+                       ;;
+
+      --no-verbose)    preserve_args="$preserve_args $opt"
+                       opt_verbose=false
                        ;;
 
       --tag)           test "$#" -eq 0 && func_missing_arg "$opt" && break
@@ -793,6 +952,7 @@ func_enable_tag ()
 
       -\?|-h)          func_usage                                      ;;
       --help)          opt_help=:                                      ;;
+      --help-all)      opt_help=': help-all'                           ;;
       --version)       func_version                                    ;;
 
       -*)              func_fatal_help "unrecognized option \`$opt'"   ;;
@@ -1016,10 +1176,13 @@ func_infer_tag ()
         func_quote_for_eval "$arg"
        CC_quoted="$CC_quoted $func_quote_for_eval_result"
       done
+      CC_expanded=`func_echo_all $CC`
+      CC_quoted_expanded=`func_echo_all $CC_quoted`
       case $@ in
       # Blanks in the command may have been stripped by the calling shell,
       # but not from the CC environment variable when configure was run.
-      " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;;
+      " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+      " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
       # Blanks at the start of $base_compile will cause this to fail
       # if we don't check for them as well.
       *)
@@ -1033,8 +1196,11 @@ func_infer_tag ()
              func_quote_for_eval "$arg"
              CC_quoted="$CC_quoted $func_quote_for_eval_result"
            done
+           CC_expanded=`func_echo_all $CC`
+           CC_quoted_expanded=`func_echo_all $CC_quoted`
            case "$@ " in
-             " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*)
+           " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+           " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
              # The compiler in the base compile command matches
              # the one in the tagged configuration.
              # Assume this is the tagged configuration we want.
@@ -1213,7 +1379,7 @@ func_mode_compile ()
     *.[cCFSifmso] | \
     *.ada | *.adb | *.ads | *.asm | \
     *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
-    *.[fF][09]? | *.for | *.java | *.obj | *.sx)
+    *.[fF][09]? | *.for | *.java | *.obj | *.sx | *.cu | *.cup)
       func_xform "$libobj"
       libobj=$func_xform_result
       ;;
@@ -1288,7 +1454,7 @@ func_mode_compile ()
     # Calculate the filename of the output object if compiler does
     # not support -o with -c
     if test "$compiler_c_o" = no; then
-      output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
+      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
       lockfile="$output_obj.lock"
     else
       output_obj=
@@ -1445,7 +1611,7 @@ compiler."
 }
 
 $opt_help || {
-test "$mode" = compile && func_mode_compile ${1+"$@"}
+  test "$mode" = compile && func_mode_compile ${1+"$@"}
 }
 
 func_mode_help ()
@@ -1482,10 +1648,11 @@ This mode accepts the following additional options:
 
   -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
   -no-suppress      do not suppress compiler output for multiple passes
-  -prefer-pic       try to building PIC objects only
-  -prefer-non-pic   try to building non-PIC objects only
+  -prefer-pic       try to build PIC objects only
+  -prefer-non-pic   try to build non-PIC objects only
   -shared           do not build a \`.o' file suitable for static linking
   -static           only build a \`.o' file suitable for static linking
+  -Wc,FLAG          pass FLAG directly to the compiler
 
 COMPILE-COMMAND is a command to be used in creating a \`standard' object file
 from the given SOURCEFILE.
@@ -1538,7 +1705,7 @@ either the \`install' or \`cp' program.
 
 The following components of INSTALL-COMMAND are treated specially:
 
-  -inst-prefix PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
+  -inst-prefix-dir PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
 
 The rest of the components are interpreted as arguments to that command (only
 BSD-compatible install options are recognized)."
@@ -1558,6 +1725,8 @@ The following components of LINK-COMMAND are treated specially:
 
   -all-static       do not do any dynamic linking at all
   -avoid-version    do not add a version suffix if possible
+  -bindir BINDIR    specify path to binaries directory (for systems where
+                    libraries must be found in the PATH setting at runtime)
   -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
   -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
   -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
@@ -1586,6 +1755,11 @@ The following components of LINK-COMMAND are treated specially:
   -version-info CURRENT[:REVISION[:AGE]]
                     specify library version info [each variable defaults to 0]
   -weak LIBNAME     declare that the target provides the LIBNAME interface
+  -Wc,FLAG
+  -Xcompiler FLAG   pass linker-specific FLAG directly to the compiler
+  -Wl,FLAG
+  -Xlinker FLAG     pass linker-specific FLAG directly to the linker
+  -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
 
 All other options (arguments beginning with \`-') are ignored.
 
@@ -1623,14 +1797,40 @@ Otherwise, only FILE itself is deleted using RM."
         ;;
     esac
 
-    $ECHO
+    echo
     $ECHO "Try \`$progname --help' for more information about other modes."
-
-    exit $?
 }
 
-  # Now that we've collected a possible --mode arg, show help if necessary
-  $opt_help && func_mode_help
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+  if test "$opt_help" = :; then
+    func_mode_help
+  else
+    {
+      func_help noexit
+      for mode in compile link execute install finish uninstall clean; do
+       func_mode_help
+      done
+    } | sed -n '1p; 2,$s/^Usage:/  or: /p'
+    {
+      func_help noexit
+      for mode in compile link execute install finish uninstall clean; do
+       echo
+       func_mode_help
+      done
+    } |
+    sed '1d
+      /^When reporting/,/^Report/{
+       H
+       d
+      }
+      $x
+      /information about other modes/d
+      /more detailed .*MODE/d
+      s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+  fi
+  exit $?
+fi
 
 
 # func_mode_execute arg...
@@ -1712,7 +1912,7 @@ func_mode_execute ()
     for file
     do
       case $file in
-      -*) ;;
+      -* | *.la | *.lo ) ;;
       *)
        # Do a test to see if this is really a libtool program.
        if func_ltwrapper_script_p "$file"; then
@@ -1754,7 +1954,7 @@ func_mode_execute ()
       # Display what would be done.
       if test -n "$shlibpath_var"; then
        eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
-       $ECHO "export $shlibpath_var"
+       echo "export $shlibpath_var"
       fi
       $ECHO "$cmd$args"
       exit $EXIT_SUCCESS
@@ -1795,23 +1995,23 @@ func_mode_finish ()
     # Exit here if they wanted silent mode.
     $opt_silent && exit $EXIT_SUCCESS
 
-    $ECHO "X----------------------------------------------------------------------" | $Xsed
-    $ECHO "Libraries have been installed in:"
+    echo "----------------------------------------------------------------------"
+    echo "Libraries have been installed in:"
     for libdir in $libdirs; do
       $ECHO "   $libdir"
     done
-    $ECHO
-    $ECHO "If you ever happen to want to link against installed libraries"
-    $ECHO "in a given directory, LIBDIR, you must either use libtool, and"
-    $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'"
-    $ECHO "flag during linking and do at least one of the following:"
+    echo
+    echo "If you ever happen to want to link against installed libraries"
+    echo "in a given directory, LIBDIR, you must either use libtool, and"
+    echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+    echo "flag during linking and do at least one of the following:"
     if test -n "$shlibpath_var"; then
-      $ECHO "   - add LIBDIR to the \`$shlibpath_var' environment variable"
-      $ECHO "     during execution"
+      echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+      echo "     during execution"
     fi
     if test -n "$runpath_var"; then
-      $ECHO "   - add LIBDIR to the \`$runpath_var' environment variable"
-      $ECHO "     during linking"
+      echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+      echo "     during linking"
     fi
     if test -n "$hardcode_libdir_flag_spec"; then
       libdir=LIBDIR
@@ -1823,21 +2023,21 @@ func_mode_finish ()
       $ECHO "   - have your system administrator run these commands:$admincmds"
     fi
     if test -f /etc/ld.so.conf; then
-      $ECHO "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+      echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
     fi
-    $ECHO
+    echo
 
-    $ECHO "See any operating system documentation about shared libraries for"
+    echo "See any operating system documentation about shared libraries for"
     case $host in
       solaris2.[6789]|solaris2.1[0-9])
-        $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual"
-       $ECHO "pages."
+        echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+       echo "pages."
        ;;
       *)
-        $ECHO "more information, such as the ld(1) and ld.so(8) manual pages."
+        echo "more information, such as the ld(1) and ld.so(8) manual pages."
         ;;
     esac
-    $ECHO "X----------------------------------------------------------------------" | $Xsed
+    echo "----------------------------------------------------------------------"
     exit $EXIT_SUCCESS
 }
 
@@ -1852,7 +2052,7 @@ func_mode_install ()
     # install_prog (especially on Windows NT).
     if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
        # Allow the use of GNU shtool's install command.
-       $ECHO "X$nonopt" | $GREP shtool >/dev/null; then
+       case $nonopt in *shtool*) :;; *) false;; esac; then
       # Aesthetically quote it.
       func_quote_for_eval "$nonopt"
       install_prog="$func_quote_for_eval_result "
@@ -1867,6 +2067,11 @@ func_mode_install ()
     # Aesthetically quote it.
     func_quote_for_eval "$arg"
     install_prog="$install_prog$func_quote_for_eval_result"
+    install_shared_prog=$install_prog
+    case " $install_prog " in
+      *[\\\ /]cp\ *) install_cp=: ;;
+      *) install_cp=false ;;
+    esac
 
     # We need to accept at least all the BSD install flags.
     dest=
@@ -1876,8 +2081,10 @@ func_mode_install ()
     install_type=
     isdir=no
     stripme=
+    no_mode=:
     for arg
     do
+      arg2=
       if test -n "$dest"; then
        files="$files $dest"
        dest=$arg
@@ -1887,10 +2094,9 @@ func_mode_install ()
       case $arg in
       -d) isdir=yes ;;
       -f)
-       case " $install_prog " in
-       *[\\\ /]cp\ *) ;;
-       *) prev=$arg ;;
-       esac
+       if $install_cp; then :; else
+         prev=$arg
+       fi
        ;;
       -g | -m | -o)
        prev=$arg
@@ -1904,6 +2110,10 @@ func_mode_install ()
       *)
        # If the previous option needed an argument, then skip it.
        if test -n "$prev"; then
+         if test "x$prev" = x-m && test -n "$install_override_mode"; then
+           arg2=$install_override_mode
+           no_mode=false
+         fi
          prev=
        else
          dest=$arg
@@ -1915,6 +2125,10 @@ func_mode_install ()
       # Aesthetically quote the argument.
       func_quote_for_eval "$arg"
       install_prog="$install_prog $func_quote_for_eval_result"
+      if test -n "$arg2"; then
+       func_quote_for_eval "$arg2"
+      fi
+      install_shared_prog="$install_shared_prog $func_quote_for_eval_result"
     done
 
     test -z "$install_prog" && \
@@ -1923,6 +2137,13 @@ func_mode_install ()
     test -n "$prev" && \
       func_fatal_help "the \`$prev' option requires an argument"
 
+    if test -n "$install_override_mode" && $no_mode; then
+      if $install_cp; then :; else
+       func_quote_for_eval "$install_override_mode"
+       install_shared_prog="$install_shared_prog -m $func_quote_for_eval_result"
+      fi
+    fi
+
     if test -z "$files"; then
       if test -z "$dest"; then
        func_fatal_help "no file or destination specified"
@@ -2010,7 +2231,7 @@ func_mode_install ()
 
        if test -n "$relink_command"; then
          # Determine the prefix the user has applied to our future dir.
-         inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"`
+         inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
 
          # Don't allow the user to place us outside of our expected
          # location b/c this prevents finding dependent libraries that
@@ -2023,9 +2244,9 @@ func_mode_install ()
 
          if test -n "$inst_prefix_dir"; then
            # Stick the inst_prefix_dir data into the link command.
-           relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+           relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
          else
-           relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"`
+           relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
          fi
 
          func_warning "relinking \`$file'"
@@ -2043,7 +2264,7 @@ func_mode_install ()
          test -n "$relink_command" && srcname="$realname"T
 
          # Install the shared library and build the symlinks.
-         func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \
+         func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
              'exit $?'
          tstripme="$stripme"
          case $host_os in
@@ -2183,7 +2404,7 @@ func_mode_install ()
            if test -f "$lib"; then
              func_source "$lib"
            fi
-           libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
+           libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
            if test -n "$libdir" && test ! -f "$libfile"; then
              func_warning "\`$lib' has not been installed in \`$libdir'"
              finalize=no
@@ -2202,7 +2423,7 @@ func_mode_install ()
                file="$func_basename_result"
                outputname="$tmpdir/$file"
                # Replace the output file specification.
-               relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
+               relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
 
                $opt_silent || {
                  func_quote_for_expand "$relink_command"
@@ -2221,7 +2442,7 @@ func_mode_install ()
            }
          else
            # Install the binary that we compiled earlier.
-           file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+           file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
          fi
        fi
 
@@ -2323,6 +2544,10 @@ func_generate_dlsyms ()
 extern \"C\" {
 #endif
 
+#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
 /* External symbol declarations for the compiler. */\
 "
 
@@ -2332,7 +2557,7 @@ extern \"C\" {
          $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
 
          # Add our own program objects to the symbol list.
-         progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+         progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
          for progfile in $progfiles; do
            func_verbose "extracting global C symbols from \`$progfile'"
            $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'"
@@ -2371,7 +2596,7 @@ extern \"C\" {
              eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
              eval '$MV "$nlist"T "$nlist"'
              case $host in
-               *cygwin | *mingw* | *cegcc* )
+               *cygwin* | *mingw* | *cegcc* )
                  eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
                  eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
                  ;;
@@ -2415,10 +2640,10 @@ extern \"C\" {
          if test -f "$nlist"S; then
            eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
          else
-           $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms"
+           echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
          fi
 
-         $ECHO >> "$output_objdir/$my_dlsyms" "\
+         echo >> "$output_objdir/$my_dlsyms" "\
 
 /* The mapping between symbol names and symbols.  */
 typedef struct {
@@ -2428,7 +2653,7 @@ typedef struct {
 "
          case $host in
          *cygwin* | *mingw* | *cegcc* )
-           $ECHO >> "$output_objdir/$my_dlsyms" "\
+           echo >> "$output_objdir/$my_dlsyms" "\
 /* DATA imports from DLLs on WIN32 con't be const, because
    runtime relocations are performed -- see ld's documentation
    on pseudo-relocs.  */"
@@ -2441,7 +2666,7 @@ typedef struct {
            lt_dlsym_const=const ;;
          esac
 
-         $ECHO >> "$output_objdir/$my_dlsyms" "\
+         echo >> "$output_objdir/$my_dlsyms" "\
 extern $lt_dlsym_const lt_dlsymlist
 lt_${my_prefix}_LTX_preloaded_symbols[];
 $lt_dlsym_const lt_dlsymlist
@@ -2457,7 +2682,7 @@ lt_${my_prefix}_LTX_preloaded_symbols[] =
            eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
            ;;
          esac
-         $ECHO >> "$output_objdir/$my_dlsyms" "\
+         echo >> "$output_objdir/$my_dlsyms" "\
   {0, (void *) 0}
 };
 
@@ -2515,16 +2740,16 @@ static const void *lt_preloaded_setup() {
        case $host in
        *cygwin* | *mingw* | *cegcc* )
          if test -f "$output_objdir/$my_outputname.def"; then
-           compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
-           finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+           compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+           finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
          else
-           compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
-           finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
+           compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+           finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
          fi
          ;;
        *)
-         compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
-         finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
+         compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+         finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
          ;;
        esac
        ;;
@@ -2538,8 +2763,8 @@ static const void *lt_preloaded_setup() {
       # really was required.
 
       # Nullify the symbol file.
-      compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
-      finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+      compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+      finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
     fi
 }
 
@@ -2549,6 +2774,7 @@ static const void *lt_preloaded_setup() {
 # Need a lot of goo to handle *both* DLLs and import libs
 # Has to be a shell function in order to 'eat' the argument
 # that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
 func_win32_libid ()
 {
   $opt_debug
@@ -2559,8 +2785,9 @@ func_win32_libid ()
     win32_libid_type="x86 archive import"
     ;;
   *ar\ archive*) # could be an import, or static
+    # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
     if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
-       $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
+       $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
       win32_nmres=`eval $NM -f posix -A $1 |
        $SED -n -e '
            1,100{
@@ -2598,7 +2825,18 @@ func_extract_an_archive ()
     $opt_debug
     f_ex_an_ar_dir="$1"; shift
     f_ex_an_ar_oldlib="$1"
-    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?'
+    if test "$lock_old_archive_extraction" = yes; then
+      lockfile=$f_ex_an_ar_oldlib.lock
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+       func_echo "Waiting for $lockfile to be removed"
+       sleep 2
+      done
+    fi
+    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+                  'stat=$?; rm -f "$lockfile"; exit $stat'
+    if test "$lock_old_archive_extraction" = yes; then
+      $opt_dry_run || rm -f "$lockfile"
+    fi
     if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
      :
     else
@@ -2669,7 +2907,7 @@ func_extract_archives ()
            darwin_file=
            darwin_files=
            for darwin_file in $darwin_filelist; do
-             darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
+             darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
              $LIPO -create -output "$darwin_file" $darwin_files
            done # $darwin_filelist
            $RM -rf unfat-$$
@@ -2684,25 +2922,30 @@ func_extract_archives ()
         func_extract_an_archive "$my_xdir" "$my_xabs"
        ;;
       esac
-      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
     done
 
     func_extract_archives_result="$my_oldobjs"
 }
 
 
-
-# func_emit_wrapper_part1 [arg=no]
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable.  Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
 #
-# Emit the first part of a libtool wrapper script on stdout.
-# For more information, see the description associated with
-# func_emit_wrapper(), below.
-func_emit_wrapper_part1 ()
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take.  If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory.  This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
 {
-       func_emit_wrapper_part1_arg1=no
-       if test -n "$1" ; then
-         func_emit_wrapper_part1_arg1=$1
-       fi
+       func_emit_wrapper_arg1=${1-no}
 
        $ECHO "\
 #! $SHELL
@@ -2718,7 +2961,6 @@ func_emit_wrapper_part1 ()
 
 # Sed substitution that helps us do robust quoting.  It backslashifies
 # metacharacters that are still active within double-quoted strings.
-Xsed='${SED} -e 1s/^X//'
 sed_quote_subst='$sed_quote_subst'
 
 # Be Bourne compatible
@@ -2749,31 +2991,132 @@ if test \"\$libtool_install_magic\" = \"$magic\"; then
 else
   # When we are sourced in execute mode, \$file and \$ECHO are already set.
   if test \"\$libtool_execute_magic\" != \"$magic\"; then
-    ECHO=\"$qecho\"
-    file=\"\$0\"
-    # Make sure echo works.
-    if test \"X\$1\" = X--no-reexec; then
-      # Discard the --no-reexec flag, and continue.
-      shift
-    elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then
-      # Yippee, \$ECHO works!
-      :
-    else
-      # Restart under the correct shell, and then maybe \$ECHO will work.
-      exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
-    fi
-  fi\
+    file=\"\$0\""
+
+    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+    $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+    ECHO=\"$qECHO\"
+  fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ which is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options which match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+  lt_script_arg0=\$0
+  shift
+  for lt_opt
+  do
+    case \"\$lt_opt\" in
+    --lt-debug) lt_option_debug=1 ;;
+    --lt-dump-script)
+        lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+        test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+        lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+        cat \"\$lt_dump_D/\$lt_dump_F\"
+        exit 0
+      ;;
+    --lt-*)
+        \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+        exit 1
+      ;;
+    esac
+  done
+
+  # Print the debug banner immediately:
+  if test -n \"\$lt_option_debug\"; then
+    echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2
+  fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+  lt_dump_args_N=1;
+  for lt_arg
+  do
+    \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\"
+    lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+  done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
 "
-       $ECHO "\
+  case $host in
+  # Backslashes separate directories on plain windows
+  *-*-mingw | *-*-os2* | *-cegcc*)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+    ;;
+
+  *)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+    ;;
+  esac
+  $ECHO "\
+      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+      exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+  for lt_wr_arg
+  do
+    case \$lt_wr_arg in
+    --lt-*) ;;
+    *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+    esac
+    shift
+  done
+  func_exec_program_core \${1+\"\$@\"}
+}
+
+  # Parse options
+  func_parse_lt_options \"\$0\" \${1+\"\$@\"}
 
   # Find the directory that this script lives in.
-  thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+  thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
   test \"x\$thisdir\" = \"x\$file\" && thisdir=.
 
   # Follow symbolic links until we get to the real thisdir.
-  file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\`
+  file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
   while test -n \"\$file\"; do
-    destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+    destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
 
     # If there was a directory component, then change thisdir.
     if test \"x\$destdir\" != \"x\$file\"; then
@@ -2783,30 +3126,13 @@ else
       esac
     fi
 
-    file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
-    file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
+    file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
   done
-"
-}
-# end: func_emit_wrapper_part1
-
-# func_emit_wrapper_part2 [arg=no]
-#
-# Emit the second part of a libtool wrapper script on stdout.
-# For more information, see the description associated with
-# func_emit_wrapper(), below.
-func_emit_wrapper_part2 ()
-{
-       func_emit_wrapper_part2_arg1=no
-       if test -n "$1" ; then
-         func_emit_wrapper_part2_arg1=$1
-       fi
-
-       $ECHO "\
 
   # Usually 'no', except on cygwin/mingw when embedded into
   # the cwrapper.
-  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
   if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
     # special case for '.'
     if test \"\$thisdir\" = \".\"; then
@@ -2814,7 +3140,7 @@ func_emit_wrapper_part2 ()
     fi
     # remove .libs from thisdir
     case \"\$thisdir\" in
-    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;;
+    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
     $objdir )   thisdir=. ;;
     esac
   fi
@@ -2877,7 +3203,7 @@ func_emit_wrapper_part2 ()
 
     # Some systems cannot cope with colon-terminated $shlibpath_var
     # The second colon is a workaround for a bug in BeOS R4 sed
-    $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+    $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
 
     export $shlibpath_var
 "
@@ -2894,64 +3220,18 @@ func_emit_wrapper_part2 ()
        $ECHO "\
     if test \"\$libtool_execute_magic\" != \"$magic\"; then
       # Run the actual program with our arguments.
-"
-       case $host in
-       # Backslashes separate directories on plain windows
-       *-*-mingw | *-*-os2* | *-cegcc*)
-         $ECHO "\
-      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
-"
-         ;;
-
-       *)
-         $ECHO "\
-      exec \"\$progdir/\$program\" \${1+\"\$@\"}
-"
-         ;;
-       esac
-       $ECHO "\
-      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
-      exit 1
+      func_exec_program \${1+\"\$@\"}
     fi
   else
     # The program doesn't exist.
     \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
     \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
-    $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+    \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
     exit 1
   fi
 fi\
 "
 }
-# end: func_emit_wrapper_part2
-
-
-# func_emit_wrapper [arg=no]
-#
-# Emit a libtool wrapper script on stdout.
-# Don't directly open a file because we may want to
-# incorporate the script contents within a cygwin/mingw
-# wrapper executable.  Must ONLY be called from within
-# func_mode_link because it depends on a number of variables
-# set therein.
-#
-# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
-# variable will take.  If 'yes', then the emitted script
-# will assume that the directory in which it is stored is
-# the $objdir directory.  This is a cygwin/mingw-specific
-# behavior.
-func_emit_wrapper ()
-{
-       func_emit_wrapper_arg1=no
-       if test -n "$1" ; then
-         func_emit_wrapper_arg1=$1
-       fi
-
-       # split this up so that func_emit_cwrapperexe_src
-       # can call each part independently.
-       func_emit_wrapper_part1 "${func_emit_wrapper_arg1}"
-       func_emit_wrapper_part2 "${func_emit_wrapper_arg1}"
-}
 
 
 # func_to_host_path arg
@@ -2978,23 +3258,19 @@ func_emit_wrapper ()
 func_to_host_path ()
 {
   func_to_host_path_result="$1"
-  if test -n "$1" ; then
+  if test -n "$1"; then
     case $host in
       *mingw* )
         lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
         case $build in
           *mingw* ) # actually, msys
             # awkward: cmd appends spaces to result
-            lt_sed_strip_trailing_spaces="s/[ ]*\$//"
-            func_to_host_path_tmp1=`( cmd //c echo "$1" |\
-              $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""`
-            func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\
-              $SED -e "$lt_sed_naive_backslashify"`
+            func_to_host_path_result=`( cmd //c echo "$1" ) 2>/dev/null |
+              $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
             ;;
           *cygwin* )
-            func_to_host_path_tmp1=`cygpath -w "$1"`
-            func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\
-              $SED -e "$lt_sed_naive_backslashify"`
+            func_to_host_path_result=`cygpath -w "$1" |
+             $SED -e "$lt_sed_naive_backslashify"`
             ;;
           * )
             # Unfortunately, winepath does not exit with a non-zero
@@ -3006,17 +3282,17 @@ func_to_host_path ()
             # the odd construction:
             func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null`
             if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then
-              func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\
+              func_to_host_path_result=`$ECHO "$func_to_host_path_tmp1" |
                 $SED -e "$lt_sed_naive_backslashify"`
             else
               # Allow warning below.
-              func_to_host_path_result=""
+              func_to_host_path_result=
             fi
             ;;
         esac
         if test -z "$func_to_host_path_result" ; then
           func_error "Could not determine host path corresponding to"
-          func_error "  '$1'"
+          func_error "  \`$1'"
           func_error "Continuing, but uninstalled executables may not work."
           # Fallback:
           func_to_host_path_result="$1"
@@ -3049,30 +3325,24 @@ func_to_host_path ()
 func_to_host_pathlist ()
 {
   func_to_host_pathlist_result="$1"
-  if test -n "$1" ; then
+  if test -n "$1"; then
     case $host in
       *mingw* )
         lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
         # Remove leading and trailing path separator characters from
         # ARG. msys behavior is inconsistent here, cygpath turns them
         # into '.;' and ';.', and winepath ignores them completely.
-        func_to_host_pathlist_tmp2="$1"
-        # Once set for this call, this variable should not be
-        # reassigned. It is used in tha fallback case.
-        func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\
-          $SED -e 's|^:*||' -e 's|:*$||'`
+       func_stripname : : "$1"
+        func_to_host_pathlist_tmp1=$func_stripname_result
         case $build in
           *mingw* ) # Actually, msys.
             # Awkward: cmd appends spaces to result.
-            lt_sed_strip_trailing_spaces="s/[ ]*\$//"
-            func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\
-              $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""`
-            func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\
-              $SED -e "$lt_sed_naive_backslashify"`
+            func_to_host_pathlist_result=`
+             ( cmd //c echo "$func_to_host_pathlist_tmp1" ) 2>/dev/null |
+             $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
             ;;
           *cygwin* )
-            func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"`
-            func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\
+            func_to_host_pathlist_result=`cygpath -w -p "$func_to_host_pathlist_tmp1" |
               $SED -e "$lt_sed_naive_backslashify"`
             ;;
           * )
@@ -3088,18 +3358,17 @@ func_to_host_pathlist ()
                   if test -z "$func_to_host_pathlist_result" ; then
                     func_to_host_pathlist_result="$func_to_host_path_result"
                   else
-                    func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result"
+                    func_append func_to_host_pathlist_result ";$func_to_host_path_result"
                   fi
                 fi
               fi
-              IFS=:
             done
             IFS=$func_to_host_pathlist_oldIFS
             ;;
         esac
-        if test -z "$func_to_host_pathlist_result" ; then
+        if test -z "$func_to_host_pathlist_result"; then
           func_error "Could not determine the host path(s) corresponding to"
-          func_error "  '$1'"
+          func_error "  \`$1'"
           func_error "Continuing, but uninstalled executables may not work."
           # Fallback. This may break if $1 contains DOS-style drive
           # specifications. The fix is not to complicate the expression
@@ -3116,7 +3385,7 @@ func_to_host_pathlist ()
             ;;
         esac
         case "$1" in
-          *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;"
+          *: ) func_append func_to_host_pathlist_result ";"
             ;;
         esac
         ;;
@@ -3141,31 +3410,23 @@ func_emit_cwrapperexe_src ()
 
    This wrapper executable should never be moved out of the build directory.
    If it is, it will not operate correctly.
-
-   Currently, it simply execs the wrapper *script* "$SHELL $output",
-   but could eventually absorb all of the scripts functionality and
-   exec $objdir/$outputname directly.
 */
 EOF
            cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 #ifdef _MSC_VER
 # include <direct.h>
 # include <process.h>
 # include <io.h>
-# define setmode _setmode
 #else
 # include <unistd.h>
 # include <stdint.h>
 # ifdef __CYGWIN__
 #  include <io.h>
-#  define HAVE_SETENV
-#  ifdef __STRICT_ANSI__
-char *realpath (const char *, char *);
-int putenv (char *);
-int setenv (const char *, const char *, int);
-#  endif
 # endif
 #endif
 #include <malloc.h>
@@ -3177,6 +3438,44 @@ int setenv (const char *, const char *, int);
 #include <fcntl.h>
 #include <sys/stat.h>
 
+/* declarations of non-ANSI functions */
+#if defined(__MINGW32__)
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined(__CYGWIN__)
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined (other platforms) ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined(_MSC_VER)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+# define S_IXUSR _S_IEXEC
+# ifndef _INTPTR_T_DEFINED
+#  define _INTPTR_T_DEFINED
+#  define intptr_t int
+# endif
+#elif defined(__MINGW32__)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+#elif defined(__CYGWIN__)
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined (other platforms) ... */
+#endif
+
 #if defined(PATH_MAX)
 # define LT_PATHMAX PATH_MAX
 #elif defined(MAXPATHLEN)
@@ -3192,14 +3491,7 @@ int setenv (const char *, const char *, int);
 # define S_IXGRP 0
 #endif
 
-#ifdef _MSC_VER
-# define S_IXUSR _S_IEXEC
-# define stat _stat
-# ifndef _INTPTR_T_DEFINED
-#  define intptr_t int
-# endif
-#endif
-
+/* path handling portability macros */
 #ifndef DIR_SEPARATOR
 # define DIR_SEPARATOR '/'
 # define PATH_SEPARATOR ':'
@@ -3230,10 +3522,6 @@ int setenv (const char *, const char *, int);
 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
 #endif /* PATH_SEPARATOR_2 */
 
-#ifdef __CYGWIN__
-# define FOPEN_WB "wb"
-#endif
-
 #ifndef FOPEN_WB
 # define FOPEN_WB "w"
 #endif
@@ -3246,22 +3534,13 @@ int setenv (const char *, const char *, int);
   if (stale) { free ((void *) stale); stale = 0; } \
 } while (0)
 
-#undef LTWRAPPER_DEBUGPRINTF
-#if defined DEBUGWRAPPER
-# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args
-static void
-ltwrapper_debugprintf (const char *fmt, ...)
-{
-    va_list args;
-    va_start (args, fmt);
-    (void) vfprintf (stderr, fmt, args);
-    va_end (args);
-}
+#if defined(LT_DEBUGWRAPPER)
+static int lt_debug = 1;
 #else
-# define LTWRAPPER_DEBUGPRINTF(args)
+static int lt_debug = 0;
 #endif
 
-const char *program_name = NULL;
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
 
 void *xmalloc (size_t num);
 char *xstrdup (const char *string);
@@ -3271,31 +3550,17 @@ char *chase_symlinks (const char *pathspec);
 int make_executable (const char *path);
 int check_executable (const char *path);
 char *strendzap (char *str, const char *pat);
-void lt_fatal (const char *message, ...);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
 void lt_setenv (const char *name, const char *value);
 char *lt_extend_str (const char *orig_value, const char *add, int to_end);
-void lt_opt_process_env_set (const char *arg);
-void lt_opt_process_env_prepend (const char *arg);
-void lt_opt_process_env_append (const char *arg);
-int lt_split_name_value (const char *arg, char** name, char** value);
 void lt_update_exe_path (const char *name, const char *value);
 void lt_update_lib_path (const char *name, const char *value);
-
-static const char *script_text_part1 =
-EOF
-
-           func_emit_wrapper_part1 yes |
-               $SED -e 's/\([\\"]\)/\\\1/g' \
-                    -e 's/^/  "/' -e 's/$/\\n"/'
-           echo ";"
-           cat <<EOF
-
-static const char *script_text_part2 =
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
 EOF
-           func_emit_wrapper_part2 yes |
-               $SED -e 's/\([\\"]\)/\\\1/g' \
-                    -e 's/^/  "/' -e 's/$/\\n"/'
-           echo ";"
 
            cat <<EOF
 const char * MAGIC_EXE = "$magic_exe";
@@ -3340,24 +3605,10 @@ EOF
            cat <<"EOF"
 
 #define LTWRAPPER_OPTION_PREFIX         "--lt-"
-#define LTWRAPPER_OPTION_PREFIX_LENGTH  5
 
-static const size_t opt_prefix_len         = LTWRAPPER_OPTION_PREFIX_LENGTH;
 static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
-
 static const char *dumpscript_opt       = LTWRAPPER_OPTION_PREFIX "dump-script";
-
-static const size_t env_set_opt_len     = LTWRAPPER_OPTION_PREFIX_LENGTH + 7;
-static const char *env_set_opt          = LTWRAPPER_OPTION_PREFIX "env-set";
-  /* argument is putenv-style "foo=bar", value of foo is set to bar */
-
-static const size_t env_prepend_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 11;
-static const char *env_prepend_opt      = LTWRAPPER_OPTION_PREFIX "env-prepend";
-  /* argument is putenv-style "foo=bar", new value of foo is bar${foo} */
-
-static const size_t env_append_opt_len  = LTWRAPPER_OPTION_PREFIX_LENGTH + 10;
-static const char *env_append_opt       = LTWRAPPER_OPTION_PREFIX "env-append";
-  /* argument is putenv-style "foo=bar", new value of foo is ${foo}bar */
+static const char *debug_opt            = LTWRAPPER_OPTION_PREFIX "debug";
 
 int
 main (int argc, char *argv[])
@@ -3374,10 +3625,13 @@ main (int argc, char *argv[])
   int i;
 
   program_name = (char *) xstrdup (base_name (argv[0]));
-  LTWRAPPER_DEBUGPRINTF (("(main) argv[0]      : %s\n", argv[0]));
-  LTWRAPPER_DEBUGPRINTF (("(main) program_name : %s\n", program_name));
+  newargz = XMALLOC (char *, argc + 1);
 
-  /* very simple arg parsing; don't want to rely on getopt */
+  /* very simple arg parsing; don't want to rely on getopt
+   * also, copy all non cwrapper options to newargz, except
+   * argz[0], which is handled differently
+   */
+  newargc=0;
   for (i = 1; i < argc; i++)
     {
       if (strcmp (argv[i], dumpscript_opt) == 0)
@@ -3391,25 +3645,57 @@ EOF
              esac
 
            cat <<"EOF"
-         printf ("%s", script_text_part1);
-         printf ("%s", script_text_part2);
+         lt_dump_script (stdout);
          return 0;
        }
+      if (strcmp (argv[i], debug_opt) == 0)
+       {
+          lt_debug = 1;
+          continue;
+       }
+      if (strcmp (argv[i], ltwrapper_option_prefix) == 0)
+        {
+          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+             namespace, but it is not one of the ones we know about and
+             have already dealt with, above (inluding dump-script), then
+             report an error. Otherwise, targets might begin to believe
+             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+             namespace. The first time any user complains about this, we'll
+             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+             or a configure.ac-settable value.
+           */
+          lt_fatal (__FILE__, __LINE__,
+                   "unrecognized %s option: '%s'",
+                    ltwrapper_option_prefix, argv[i]);
+        }
+      /* otherwise ... */
+      newargz[++newargc] = xstrdup (argv[i]);
     }
+  newargz[++newargc] = NULL;
+
+EOF
+           cat <<EOF
+  /* The GNU banner must be the first non-error debug message */
+  lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\n");
+EOF
+           cat <<"EOF"
+  lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
 
-  newargz = XMALLOC (char *, argc + 1);
   tmp_pathspec = find_executable (argv[0]);
   if (tmp_pathspec == NULL)
-    lt_fatal ("Couldn't find %s", argv[0]);
-  LTWRAPPER_DEBUGPRINTF (("(main) found exe (before symlink chase) at : %s\n",
-                         tmp_pathspec));
+    lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (before symlink chase) at: %s\n",
+                 tmp_pathspec);
 
   actual_cwrapper_path = chase_symlinks (tmp_pathspec);
-  LTWRAPPER_DEBUGPRINTF (("(main) found exe (after symlink chase) at : %s\n",
-                         actual_cwrapper_path));
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (after symlink chase) at: %s\n",
+                 actual_cwrapper_path);
   XFREE (tmp_pathspec);
 
-  actual_cwrapper_name = xstrdupbase_name (actual_cwrapper_path));
+  actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
   strendzap (actual_cwrapper_path, actual_cwrapper_name);
 
   /* wrapper name transforms */
@@ -3427,8 +3713,9 @@ EOF
   target_name = tmp_pathspec;
   tmp_pathspec = 0;
 
-  LTWRAPPER_DEBUGPRINTF (("(main) libtool target name: %s\n",
-                         target_name));
+  lt_debugprintf (__FILE__, __LINE__,
+                 "(main) libtool target name: %s\n",
+                 target_name);
 EOF
 
            cat <<EOF
@@ -3481,77 +3768,12 @@ EOF
   lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
   lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
 
-  newargc=0;
-  for (i = 1; i < argc; i++)
-    {
-      if (strncmp (argv[i], env_set_opt, env_set_opt_len) == 0)
-        {
-          if (argv[i][env_set_opt_len] == '=')
-            {
-              const char *p = argv[i] + env_set_opt_len + 1;
-              lt_opt_process_env_set (p);
-            }
-          else if (argv[i][env_set_opt_len] == '\0' && i + 1 < argc)
-            {
-              lt_opt_process_env_set (argv[++i]); /* don't copy */
-            }
-          else
-            lt_fatal ("%s missing required argument", env_set_opt);
-          continue;
-        }
-      if (strncmp (argv[i], env_prepend_opt, env_prepend_opt_len) == 0)
-        {
-          if (argv[i][env_prepend_opt_len] == '=')
-            {
-              const char *p = argv[i] + env_prepend_opt_len + 1;
-              lt_opt_process_env_prepend (p);
-            }
-          else if (argv[i][env_prepend_opt_len] == '\0' && i + 1 < argc)
-            {
-              lt_opt_process_env_prepend (argv[++i]); /* don't copy */
-            }
-          else
-            lt_fatal ("%s missing required argument", env_prepend_opt);
-          continue;
-        }
-      if (strncmp (argv[i], env_append_opt, env_append_opt_len) == 0)
-        {
-          if (argv[i][env_append_opt_len] == '=')
-            {
-              const char *p = argv[i] + env_append_opt_len + 1;
-              lt_opt_process_env_append (p);
-            }
-          else if (argv[i][env_append_opt_len] == '\0' && i + 1 < argc)
-            {
-              lt_opt_process_env_append (argv[++i]); /* don't copy */
-            }
-          else
-            lt_fatal ("%s missing required argument", env_append_opt);
-          continue;
-        }
-      if (strncmp (argv[i], ltwrapper_option_prefix, opt_prefix_len) == 0)
-        {
-          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
-             namespace, but it is not one of the ones we know about and
-             have already dealt with, above (inluding dump-script), then
-             report an error. Otherwise, targets might begin to believe
-             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
-             namespace. The first time any user complains about this, we'll
-             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
-             or a configure.ac-settable value.
-           */
-          lt_fatal ("Unrecognized option in %s namespace: '%s'",
-                    ltwrapper_option_prefix, argv[i]);
-        }
-      /* otherwise ... */
-      newargz[++newargc] = xstrdup (argv[i]);
-    }
-  newargz[++newargc] = NULL;
-
-  LTWRAPPER_DEBUGPRINTF     (("(main) lt_argv_zero : %s\n", (lt_argv_zero ? lt_argv_zero : "<NULL>")));
+  lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+                 nonnull (lt_argv_zero));
   for (i = 0; i < newargc; i++)
     {
-      LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d]   : %s\n", i, (newargz[i] ? newargz[i] : "<NULL>")));
+      lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+                     i, nonnull (newargz[i]));
     }
 
 EOF
@@ -3560,11 +3782,14 @@ EOF
              mingw*)
                cat <<"EOF"
   /* execv doesn't actually work on mingw as expected on unix */
+  newargz = prepare_spawn (newargz);
   rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
   if (rval == -1)
     {
       /* failed to start process */
-      LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno));
+      lt_debugprintf (__FILE__, __LINE__,
+                     "(main) failed to launch target \"%s\": %s\n",
+                     lt_argv_zero, nonnull (strerror (errno)));
       return 127;
     }
   return rval;
@@ -3586,7 +3811,7 @@ xmalloc (size_t num)
 {
   void *p = (void *) malloc (num);
   if (!p)
-    lt_fatal ("Memory exhausted");
+    lt_fatal (__FILE__, __LINE__, "memory exhausted");
 
   return p;
 }
@@ -3620,8 +3845,8 @@ check_executable (const char *path)
 {
   struct stat st;
 
-  LTWRAPPER_DEBUGPRINTF (("(check_executable)  : %s\n",
-                         path ? (*path ? path : "EMPTY!") : "NULL!"));
+  lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+                  nonempty (path));
   if ((!path) || (!*path))
     return 0;
 
@@ -3638,8 +3863,8 @@ make_executable (const char *path)
   int rval = 0;
   struct stat st;
 
-  LTWRAPPER_DEBUGPRINTF (("(make_executable)   : %s\n",
-                         path ? (*path ? path : "EMPTY!") : "NULL!"));
+  lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+                  nonempty (path));
   if ((!path) || (!*path))
     return 0;
 
@@ -3665,8 +3890,8 @@ find_executable (const char *wrapper)
   int tmp_len;
   char *concat_name;
 
-  LTWRAPPER_DEBUGPRINTF (("(find_executable)   : %s\n",
-                         wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"));
+  lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+                  nonempty (wrapper));
 
   if ((wrapper == NULL) || (*wrapper == '\0'))
     return NULL;
@@ -3719,7 +3944,8 @@ find_executable (const char *wrapper)
                {
                  /* empty path: current directory */
                  if (getcwd (tmp, LT_PATHMAX) == NULL)
-                   lt_fatal ("getcwd failed");
+                   lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+                              nonnull (strerror (errno)));
                  tmp_len = strlen (tmp);
                  concat_name =
                    XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
@@ -3744,7 +3970,8 @@ find_executable (const char *wrapper)
     }
   /* Relative path | not found in path: prepend cwd */
   if (getcwd (tmp, LT_PATHMAX) == NULL)
-    lt_fatal ("getcwd failed");
+    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+              nonnull (strerror (errno)));
   tmp_len = strlen (tmp);
   concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
   memcpy (concat_name, tmp, tmp_len);
@@ -3770,8 +3997,9 @@ chase_symlinks (const char *pathspec)
   int has_symlinks = 0;
   while (strlen (tmp_pathspec) && !has_symlinks)
     {
-      LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n",
-                             tmp_pathspec));
+      lt_debugprintf (__FILE__, __LINE__,
+                     "checking path component for symlinks: %s\n",
+                     tmp_pathspec);
       if (lstat (tmp_pathspec, &s) == 0)
        {
          if (S_ISLNK (s.st_mode) != 0)
@@ -3793,8 +4021,9 @@ chase_symlinks (const char *pathspec)
        }
       else
        {
-         char *errstr = strerror (errno);
-         lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr);
+         lt_fatal (__FILE__, __LINE__,
+                   "error accessing file \"%s\": %s",
+                   tmp_pathspec, nonnull (strerror (errno)));
        }
     }
   XFREE (tmp_pathspec);
@@ -3807,7 +4036,8 @@ chase_symlinks (const char *pathspec)
   tmp_pathspec = realpath (pathspec, buf);
   if (tmp_pathspec == 0)
     {
-      lt_fatal ("Could not follow symlinks for %s", pathspec);
+      lt_fatal (__FILE__, __LINE__,
+               "could not follow symlinks for %s", pathspec);
     }
   return xstrdup (tmp_pathspec);
 #endif
@@ -3833,11 +4063,25 @@ strendzap (char *str, const char *pat)
   return str;
 }
 
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+  va_list args;
+  if (lt_debug)
+    {
+      (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+      va_start (args, fmt);
+      (void) vfprintf (stderr, fmt, args);
+      va_end (args);
+    }
+}
+
 static void
-lt_error_core (int exit_status, const char *mode,
+lt_error_core (int exit_status, const char *file,
+              int line, const char *mode,
               const char *message, va_list ap)
 {
-  fprintf (stderr, "%s: %s: ", program_name, mode);
+  fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
   vfprintf (stderr, message, ap);
   fprintf (stderr, ".\n");
 
@@ -3846,20 +4090,32 @@ lt_error_core (int exit_status, const char *mode,
 }
 
 void
-lt_fatal (const char *message, ...)
+lt_fatal (const char *file, int line, const char *message, ...)
 {
   va_list ap;
   va_start (ap, message);
-  lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
+  lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
   va_end (ap);
 }
 
+static const char *
+nonnull (const char *s)
+{
+  return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+  return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
 void
 lt_setenv (const char *name, const char *value)
 {
-  LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n",
-                          (name ? name : "<NULL>"),
-                          (value ? value : "<NULL>")));
+  lt_debugprintf (__FILE__, __LINE__,
+                 "(lt_setenv) setting '%s' to '%s'\n",
+                  nonnull (name), nonnull (value));
   {
 #ifdef HAVE_SETENV
     /* always make a copy, for consistency with !HAVE_SETENV */
@@ -3904,95 +4160,12 @@ lt_extend_str (const char *orig_value, const char *add, int to_end)
   return new_value;
 }
 
-int
-lt_split_name_value (const char *arg, char** name, char** value)
-{
-  const char *p;
-  int len;
-  if (!arg || !*arg)
-    return 1;
-
-  p = strchr (arg, (int)'=');
-
-  if (!p)
-    return 1;
-
-  *value = xstrdup (++p);
-
-  len = strlen (arg) - strlen (*value);
-  *name = XMALLOC (char, len);
-  strncpy (*name, arg, len-1);
-  (*name)[len - 1] = '\0';
-
-  return 0;
-}
-
-void
-lt_opt_process_env_set (const char *arg)
-{
-  char *name = NULL;
-  char *value = NULL;
-
-  if (lt_split_name_value (arg, &name, &value) != 0)
-    {
-      XFREE (name);
-      XFREE (value);
-      lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg);
-    }
-
-  lt_setenv (name, value);
-  XFREE (name);
-  XFREE (value);
-}
-
-void
-lt_opt_process_env_prepend (const char *arg)
-{
-  char *name = NULL;
-  char *value = NULL;
-  char *new_value = NULL;
-
-  if (lt_split_name_value (arg, &name, &value) != 0)
-    {
-      XFREE (name);
-      XFREE (value);
-      lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg);
-    }
-
-  new_value = lt_extend_str (getenv (name), value, 0);
-  lt_setenv (name, new_value);
-  XFREE (new_value);
-  XFREE (name);
-  XFREE (value);
-}
-
-void
-lt_opt_process_env_append (const char *arg)
-{
-  char *name = NULL;
-  char *value = NULL;
-  char *new_value = NULL;
-
-  if (lt_split_name_value (arg, &name, &value) != 0)
-    {
-      XFREE (name);
-      XFREE (value);
-      lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg);
-    }
-
-  new_value = lt_extend_str (getenv (name), value, 1);
-  lt_setenv (name, new_value);
-  XFREE (new_value);
-  XFREE (name);
-  XFREE (value);
-}
-
 void
 lt_update_exe_path (const char *name, const char *value)
 {
-  LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
-                          (name ? name : "<NULL>"),
-                          (value ? value : "<NULL>")));
+  lt_debugprintf (__FILE__, __LINE__,
+                 "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
 
   if (name && *name && value && *value)
     {
@@ -4011,9 +4184,9 @@ lt_update_exe_path (const char *name, const char *value)
 void
 lt_update_lib_path (const char *name, const char *value)
 {
-  LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
-                          (name ? name : "<NULL>"),
-                          (value ? value : "<NULL>")));
+  lt_debugprintf (__FILE__, __LINE__,
+                 "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
 
   if (name && *name && value && *value)
     {
@@ -4023,11 +4196,152 @@ lt_update_lib_path (const char *name, const char *value)
     }
 }
 
+EOF
+           case $host_os in
+             mingw*)
+               cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+   Note that spawn() does not by itself call the command interpreter
+     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+         GetVersionEx(&v);
+         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+      }) ? "cmd.exe" : "command.com").
+   Instead it simply concatenates the arguments, separated by ' ', and calls
+   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
+   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+   special way:
+   - Space and tab are interpreted as delimiters. They are not treated as
+     delimiters if they are surrounded by double quotes: "...".
+   - Unescaped double quotes are removed from the input. Their only effect is
+     that within double quotes, space and tab are treated like normal
+     characters.
+   - Backslashes not followed by double quotes are not special.
+   - But 2*n+1 backslashes followed by a double quote become
+     n backslashes followed by a double quote (n >= 0):
+       \" -> "
+       \\\" -> \"
+       \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+  size_t argc;
+  char **new_argv;
+  size_t i;
+
+  /* Count number of arguments.  */
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  /* Allocate new argument vector.  */
+  new_argv = XMALLOC (char *, argc + 1);
+
+  /* Put quoted arguments into the new argument vector.  */
+  for (i = 0; i < argc; i++)
+    {
+      const char *string = argv[i];
+
+      if (string[0] == '\0')
+       new_argv[i] = xstrdup ("\"\"");
+      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+       {
+         int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+         size_t length;
+         unsigned int backslashes;
+         const char *s;
+         char *quoted_string;
+         char *p;
+
+         length = 0;
+         backslashes = 0;
+         if (quote_around)
+           length++;
+         for (s = string; *s != '\0'; s++)
+           {
+             char c = *s;
+             if (c == '"')
+               length += backslashes + 1;
+             length++;
+             if (c == '\\')
+               backslashes++;
+             else
+               backslashes = 0;
+           }
+         if (quote_around)
+           length += backslashes + 1;
+
+         quoted_string = XMALLOC (char, length + 1);
+
+         p = quoted_string;
+         backslashes = 0;
+         if (quote_around)
+           *p++ = '"';
+         for (s = string; *s != '\0'; s++)
+           {
+             char c = *s;
+             if (c == '"')
+               {
+                 unsigned int j;
+                 for (j = backslashes + 1; j > 0; j--)
+                   *p++ = '\\';
+               }
+             *p++ = c;
+             if (c == '\\')
+               backslashes++;
+             else
+               backslashes = 0;
+           }
+         if (quote_around)
+           {
+             unsigned int j;
+             for (j = backslashes; j > 0; j--)
+               *p++ = '\\';
+             *p++ = '"';
+           }
+         *p = '\0';
+
+         new_argv[i] = quoted_string;
+       }
+      else
+       new_argv[i] = (char *) string;
+    }
+  new_argv[argc] = NULL;
+
+  return new_argv;
+}
+EOF
+               ;;
+           esac
+
+            cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+           func_emit_wrapper yes |
+              $SED -e 's/\([\\"]\)/\\\1/g' \
+                  -e 's/^/  fputs ("/' -e 's/$/\\n", f);/'
 
+            cat <<"EOF"
+}
 EOF
 }
 # end: func_emit_cwrapperexe_src
 
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+    $opt_debug
+    case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+    *import*) : ;;
+    *) false ;;
+    esac
+}
+
 # func_mode_link arg...
 func_mode_link ()
 {
@@ -4072,6 +4386,7 @@ func_mode_link ()
     new_inherited_linker_flags=
 
     avoid_version=no
+    bindir=
     dlfiles=
     dlprefiles=
     dlself=no
@@ -4164,6 +4479,11 @@ func_mode_link ()
        esac
 
        case $prev in
+       bindir)
+         bindir="$arg"
+         prev=
+         continue
+         ;;
        dlfiles|dlprefiles)
          if test "$preload" = no; then
            # Add the symbol object into the linking commands.
@@ -4425,6 +4745,11 @@ func_mode_link ()
        continue
        ;;
 
+      -bindir)
+       prev=bindir
+       continue
+       ;;
+
       -dlopen)
        prev=dlfiles
        continue
@@ -4503,7 +4828,7 @@ func_mode_link ()
        esac
        case $host in
        *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
-         testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'`
+         testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
          case :$dllsearchpath: in
          *":$dir:"*) ;;
          ::) dllsearchpath=$dir;;
@@ -4522,7 +4847,7 @@ func_mode_link ()
       -l*)
        if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
          case $host in
-         *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*)
+         *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
            # These systems don't actually have a C or math library (as such)
            continue
            ;;
@@ -4708,7 +5033,7 @@ func_mode_link ()
        for flag in $args; do
          IFS="$save_ifs"
           func_quote_for_eval "$flag"
-         arg="$arg $wl$func_quote_for_eval_result"
+         arg="$arg $func_quote_for_eval_result"
          compiler_flags="$compiler_flags $func_quote_for_eval_result"
        done
        IFS="$save_ifs"
@@ -4754,18 +5079,19 @@ func_mode_link ()
        arg="$func_quote_for_eval_result"
        ;;
 
-      # -64, -mips[0-9] enable 64-bit mode on the SGI compiler
-      # -r[0-9][0-9]* specifies the processor on the SGI compiler
-      # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler
-      # +DA*, +DD* enable 64-bit mode on the HP compiler
-      # -q* pass through compiler args for the IBM compiler
-      # -m*, -t[45]*, -txscale* pass through architecture-specific
-      # compiler args for GCC
-      # -F/path gives path to uninstalled frameworks, gcc on darwin
-      # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
-      # @file GCC response files
+      # Flags to be passed through unchanged, with rationale:
+      # -64, -mips[0-9]      enable 64-bit mode for the SGI compiler
+      # -r[0-9][0-9]*        specify processor for the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+      # +DA*, +DD*           enable 64-bit mode for the HP compiler
+      # -q*                  compiler args for the IBM compiler
+      # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+      # -F/path              path to uninstalled frameworks, gcc on darwin
+      # -p, -pg, --coverage, -fprofile-*  profiling flags for GCC
+      # @file                GCC response files
+      # -tp=*                Portland pgcc target processor selection
       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
-      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
         func_quote_for_eval "$arg"
        arg="$func_quote_for_eval_result"
         func_append compile_command " $arg"
@@ -4925,7 +5251,7 @@ func_mode_link ()
 
     if test -n "$shlibpath_var"; then
       # get the directories listed in $shlibpath_var
-      eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+      eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
     else
       shlib_search_path=
     fi
@@ -5048,7 +5374,8 @@ func_mode_link ()
          # Collect preopened libtool deplibs, except any this library
          # has declared as weak libs
          for deplib in $dependency_libs; do
-            deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"`
+           func_basename "$deplib"
+            deplib_base=$func_basename_result
            case " $weak_libs " in
            *" $deplib_base "*) ;;
            *) deplibs="$deplibs $deplib" ;;
@@ -5227,7 +5554,7 @@ func_mode_link ()
                match_pattern*)
                  set dummy $deplibs_check_method; shift
                  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
-                 if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \
+                 if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
                    | $EGREP "$match_pattern_regex" > /dev/null; then
                    valid_a_lib=yes
                  fi
@@ -5237,15 +5564,15 @@ func_mode_link ()
                ;;
              esac
              if test "$valid_a_lib" != yes; then
-               $ECHO
+               echo
                $ECHO "*** Warning: Trying to link with static lib archive $deplib."
-               $ECHO "*** I have the capability to make that library automatically link in when"
-               $ECHO "*** you link to this library.  But I can only do this if you have a"
-               $ECHO "*** shared version of the library, which you do not appear to have"
-               $ECHO "*** because the file extensions .$libext of this argument makes me believe"
-               $ECHO "*** that it is just a static archive that I should not use here."
+               echo "*** I have the capability to make that library automatically link in when"
+               echo "*** you link to this library.  But I can only do this if you have a"
+               echo "*** shared version of the library, which you do not appear to have"
+               echo "*** because the file extensions .$libext of this argument makes me believe"
+               echo "*** that it is just a static archive that I should not use here."
              else
-               $ECHO
+               echo
                $ECHO "*** Warning: Linking the shared library $output against the"
                $ECHO "*** static library $deplib is not portable!"
                deplibs="$deplib $deplibs"
@@ -5318,7 +5645,7 @@ func_mode_link ()
 
        # Convert "-framework foo" to "foo.ltframework"
        if test -n "$inherited_linker_flags"; then
-         tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'`
+         tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
          for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
            case " $new_inherited_linker_flags " in
              *" $tmp_inherited_linker_flag "*) ;;
@@ -5326,7 +5653,7 @@ func_mode_link ()
            esac
          done
        fi
-       dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+       dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
        if test "$linkmode,$pass" = "lib,link" ||
           test "$linkmode,$pass" = "prog,scan" ||
           { test "$linkmode" != prog && test "$linkmode" != lib; }; then
@@ -5580,7 +5907,7 @@ func_mode_link ()
            fi
          done
          if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
-           $ECHO
+           echo
            if test "$linkmode" = prog; then
              $ECHO "*** Warning: Linking the executable $output against the loadable module"
            else
@@ -5683,9 +6010,9 @@ func_mode_link ()
                      if test "X$dlopenmodule" != "X$lib"; then
                        $ECHO "*** Warning: lib $linklib is a module, not a shared library"
                        if test -z "$old_library" ; then
-                         $ECHO
-                         $ECHO "*** And there doesn't seem to be a static archive available"
-                         $ECHO "*** The link will probably fail, sorry"
+                         echo
+                         echo "*** And there doesn't seem to be a static archive available"
+                         echo "*** The link will probably fail, sorry"
                        else
                          add="$dir/$old_library"
                        fi
@@ -5825,21 +6152,21 @@ func_mode_link ()
 
            # Just print a warning and add the library to dependency_libs so
            # that the program can be linked against the static library.
-           $ECHO
+           echo
            $ECHO "*** Warning: This system can not link to static lib archive $lib."
-           $ECHO "*** I have the capability to make that library automatically link in when"
-           $ECHO "*** you link to this library.  But I can only do this if you have a"
-           $ECHO "*** shared version of the library, which you do not appear to have."
+           echo "*** I have the capability to make that library automatically link in when"
+           echo "*** you link to this library.  But I can only do this if you have a"
+           echo "*** shared version of the library, which you do not appear to have."
            if test "$module" = yes; then
-             $ECHO "*** But as you try to build a module library, libtool will still create "
-             $ECHO "*** a static module, that should work as long as the dlopening application"
-             $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime."
+             echo "*** But as you try to build a module library, libtool will still create "
+             echo "*** a static module, that should work as long as the dlopening application"
+             echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
              if test -z "$global_symbol_pipe"; then
-               $ECHO
-               $ECHO "*** However, this would only work if libtool was able to extract symbol"
-               $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could"
-               $ECHO "*** not find such a program.  So, this module is probably useless."
-               $ECHO "*** \`nm' from GNU binutils and a full rebuild may help."
+               echo
+               echo "*** However, this would only work if libtool was able to extract symbol"
+               echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+               echo "*** not find such a program.  So, this module is probably useless."
+               echo "*** \`nm' from GNU binutils and a full rebuild may help."
              fi
              if test "$build_old_libs" = no; then
                build_libtool_libs=module
@@ -5893,6 +6220,7 @@ func_mode_link ()
          if test "$link_all_deplibs" != no; then
            # Add the search paths of all dependency libraries
            for deplib in $dependency_libs; do
+             path=
              case $deplib in
              -L*) path="$deplib" ;;
              *.la)
@@ -5958,7 +6286,7 @@ func_mode_link ()
          compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
          finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
        else
-         compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+         compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
        fi
       fi
       dependency_libs="$newdependency_libs"
@@ -6126,7 +6454,7 @@ func_mode_link ()
        if test "$deplibs_check_method" != pass_all; then
          func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
        else
-         $ECHO
+         echo
          $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
          $ECHO "*** objects $objs is not portable!"
          libobjs="$libobjs $objs"
@@ -6194,7 +6522,7 @@ func_mode_link ()
            age="$number_minor"
            revision="$number_revision"
            ;;
-         freebsd-aout|freebsd-elf|sunos)
+         freebsd-aout|freebsd-elf|qnx|sunos)
            current="$number_major"
            revision="$number_minor"
            age="0"
@@ -6428,14 +6756,14 @@ func_mode_link ()
        oldlibs="$oldlibs $output_objdir/$libname.$libext"
 
        # Transform .lo files to .o files.
-       oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+       oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
       fi
 
       # Eliminate all temporary directories.
       #for path in $notinst_path; do
-      #        lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"`
-      #        deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"`
-      #        dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"`
+      #        lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+      #        deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+      #        dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
       #done
 
       if test -n "$xrpath"; then
@@ -6476,7 +6804,7 @@ func_mode_link ()
       if test "$build_libtool_libs" = yes; then
        if test -n "$rpath"; then
          case $host in
-         *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*)
+         *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
            # these systems don't actually have a c library (as such)!
            ;;
          *-*-rhapsody* | *-*-darwin1.[012])
@@ -6561,13 +6889,13 @@ EOF
                    newdeplibs="$newdeplibs $i"
                  else
                    droppeddeps=yes
-                   $ECHO
+                   echo
                    $ECHO "*** Warning: dynamic linker does not accept needed library $i."
-                   $ECHO "*** I have the capability to make that library automatically link in when"
-                   $ECHO "*** you link to this library.  But I can only do this if you have a"
-                   $ECHO "*** shared version of the library, which I believe you do not have"
-                   $ECHO "*** because a test_compile did reveal that the linker did not use it for"
-                   $ECHO "*** its dynamic dependency list that programs get resolved with at runtime."
+                   echo "*** I have the capability to make that library automatically link in when"
+                   echo "*** you link to this library.  But I can only do this if you have a"
+                   echo "*** shared version of the library, which I believe you do not have"
+                   echo "*** because a test_compile did reveal that the linker did not use it for"
+                   echo "*** its dynamic dependency list that programs get resolved with at runtime."
                  fi
                fi
                ;;
@@ -6604,22 +6932,22 @@ EOF
                      newdeplibs="$newdeplibs $i"
                    else
                      droppeddeps=yes
-                     $ECHO
+                     echo
                      $ECHO "*** Warning: dynamic linker does not accept needed library $i."
-                     $ECHO "*** I have the capability to make that library automatically link in when"
-                     $ECHO "*** you link to this library.  But I can only do this if you have a"
-                     $ECHO "*** shared version of the library, which you do not appear to have"
-                     $ECHO "*** because a test_compile did reveal that the linker did not use this one"
-                     $ECHO "*** as a dynamic dependency that programs can get resolved with at runtime."
+                     echo "*** I have the capability to make that library automatically link in when"
+                     echo "*** you link to this library.  But I can only do this if you have a"
+                     echo "*** shared version of the library, which you do not appear to have"
+                     echo "*** because a test_compile did reveal that the linker did not use this one"
+                     echo "*** as a dynamic dependency that programs can get resolved with at runtime."
                    fi
                  fi
                else
                  droppeddeps=yes
-                 $ECHO
+                 echo
                  $ECHO "*** Warning!  Library $i is needed by this library but I was not able to"
-                 $ECHO "*** make it link in!  You will probably need to install it or some"
-                 $ECHO "*** library that it depends on before this library will be fully"
-                 $ECHO "*** functional.  Installing it before continuing would be even better."
+                 echo "*** make it link in!  You will probably need to install it or some"
+                 echo "*** library that it depends on before this library will be fully"
+                 echo "*** functional.  Installing it before continuing would be even better."
                fi
                ;;
              *)
@@ -6665,7 +6993,7 @@ EOF
                        potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
                        case $potliblink in
                        [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
-                       *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+                       *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
                        esac
                      done
                      if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
@@ -6680,12 +7008,12 @@ EOF
              fi
              if test -n "$a_deplib" ; then
                droppeddeps=yes
-               $ECHO
+               echo
                $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
-               $ECHO "*** I have the capability to make that library automatically link in when"
-               $ECHO "*** you link to this library.  But I can only do this if you have a"
-               $ECHO "*** shared version of the library, which you do not appear to have"
-               $ECHO "*** because I did check the linker path looking for a file starting"
+               echo "*** I have the capability to make that library automatically link in when"
+               echo "*** you link to this library.  But I can only do this if you have a"
+               echo "*** shared version of the library, which you do not appear to have"
+               echo "*** because I did check the linker path looking for a file starting"
                if test -z "$potlib" ; then
                  $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
                else
@@ -6723,7 +7051,7 @@ EOF
                  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
                  for potent_lib in $potential_libs; do
                    potlib="$potent_lib" # see symlink-check above in file_magic test
-                   if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \
+                   if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
                       $EGREP "$match_pattern_regex" > /dev/null; then
                      newdeplibs="$newdeplibs $a_deplib"
                      a_deplib=""
@@ -6734,12 +7062,12 @@ EOF
              fi
              if test -n "$a_deplib" ; then
                droppeddeps=yes
-               $ECHO
+               echo
                $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
-               $ECHO "*** I have the capability to make that library automatically link in when"
-               $ECHO "*** you link to this library.  But I can only do this if you have a"
-               $ECHO "*** shared version of the library, which you do not appear to have"
-               $ECHO "*** because I did check the linker path looking for a file starting"
+               echo "*** I have the capability to make that library automatically link in when"
+               echo "*** you link to this library.  But I can only do this if you have a"
+               echo "*** shared version of the library, which you do not appear to have"
+               echo "*** because I did check the linker path looking for a file starting"
                if test -z "$potlib" ; then
                  $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
                else
@@ -6757,25 +7085,25 @@ EOF
          ;;
        none | unknown | *)
          newdeplibs=""
-         tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \
-             -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'`
+         tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
          if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
            for i in $predeps $postdeps ; do
              # can't use Xsed below, because $i might contain '/'
-             tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"`
+             tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
            done
          fi
-         if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[      ]//g' |
-            $GREP . >/dev/null; then
-           $ECHO
+         case $tmp_deplibs in
+         *[!\  \ ]*)
+           echo
            if test "X$deplibs_check_method" = "Xnone"; then
-             $ECHO "*** Warning: inter-library dependencies are not supported in this platform."
+             echo "*** Warning: inter-library dependencies are not supported in this platform."
            else
-             $ECHO "*** Warning: inter-library dependencies are not known to be supported."
+             echo "*** Warning: inter-library dependencies are not known to be supported."
            fi
-           $ECHO "*** All declared inter-library dependencies are being dropped."
+           echo "*** All declared inter-library dependencies are being dropped."
            droppeddeps=yes
-         fi
+           ;;
+         esac
          ;;
        esac
        versuffix=$versuffix_save
@@ -6787,23 +7115,23 @@ EOF
        case $host in
        *-*-rhapsody* | *-*-darwin1.[012])
          # On Rhapsody replace the C library with the System framework
-         newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'`
+         newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
          ;;
        esac
 
        if test "$droppeddeps" = yes; then
          if test "$module" = yes; then
-           $ECHO
-           $ECHO "*** Warning: libtool could not satisfy all declared inter-library"
+           echo
+           echo "*** Warning: libtool could not satisfy all declared inter-library"
            $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
-           $ECHO "*** a static module, that should work as long as the dlopening"
-           $ECHO "*** application is linked with the -dlopen flag."
+           echo "*** a static module, that should work as long as the dlopening"
+           echo "*** application is linked with the -dlopen flag."
            if test -z "$global_symbol_pipe"; then
-             $ECHO
-             $ECHO "*** However, this would only work if libtool was able to extract symbol"
-             $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could"
-             $ECHO "*** not find such a program.  So, this module is probably useless."
-             $ECHO "*** \`nm' from GNU binutils and a full rebuild may help."
+             echo
+             echo "*** However, this would only work if libtool was able to extract symbol"
+             echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+             echo "*** not find such a program.  So, this module is probably useless."
+             echo "*** \`nm' from GNU binutils and a full rebuild may help."
            fi
            if test "$build_old_libs" = no; then
              oldlibs="$output_objdir/$libname.$libext"
@@ -6813,16 +7141,16 @@ EOF
              build_libtool_libs=no
            fi
          else
-           $ECHO "*** The inter-library dependencies that have been dropped here will be"
-           $ECHO "*** automatically added whenever a program is linked with this library"
-           $ECHO "*** or is declared to -dlopen it."
+           echo "*** The inter-library dependencies that have been dropped here will be"
+           echo "*** automatically added whenever a program is linked with this library"
+           echo "*** or is declared to -dlopen it."
 
            if test "$allow_undefined" = no; then
-             $ECHO
-             $ECHO "*** Since this library must not contain undefined symbols,"
-             $ECHO "*** because either the platform does not support them or"
-             $ECHO "*** it was explicitly requested with -no-undefined,"
-             $ECHO "*** libtool will only create a static version of it."
+             echo
+             echo "*** Since this library must not contain undefined symbols,"
+             echo "*** because either the platform does not support them or"
+             echo "*** it was explicitly requested with -no-undefined,"
+             echo "*** libtool will only create a static version of it."
              if test "$build_old_libs" = no; then
                oldlibs="$output_objdir/$libname.$libext"
                build_libtool_libs=module
@@ -6839,9 +7167,9 @@ EOF
       # Time to change all our "foo.ltframework" stuff back to "-framework foo"
       case $host in
        *-*-darwin*)
-         newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
-         new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
-         deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+         newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+         new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+         deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
          ;;
       esac
 
@@ -6963,7 +7291,7 @@ EOF
        done
 
        # Use standard objects if they are pic
-       test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+       test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
        test "X$libobjs" = "X " && libobjs=
 
        delfiles=
@@ -7029,7 +7357,7 @@ EOF
        if test -n "$export_symbols" && test -n "$include_expsyms"; then
          tmp_export_symbols="$export_symbols"
          test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
-         $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"'
+         $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
        fi
 
        if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
@@ -7130,7 +7458,8 @@ EOF
            save_libobjs=$libobjs
          fi
          save_output=$output
-         output_la=`$ECHO "X$output" | $Xsed -e "$basename"`
+         func_basename "$output"
+         output_la=$func_basename_result
 
          # Clear the reloadable object creation command queue and
          # initialize k to one.
@@ -7143,12 +7472,12 @@ EOF
          if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
            output=${output_objdir}/${output_la}.lnkscript
            func_verbose "creating GNU ld script: $output"
-           $ECHO 'INPUT (' > $output
+           echo 'INPUT (' > $output
            for obj in $save_libobjs
            do
              $ECHO "$obj" >> $output
            done
-           $ECHO ')' >> $output
+           echo ')' >> $output
            delfiles="$delfiles $output"
          elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
            output=${output_objdir}/${output_la}.lnk
@@ -7190,17 +7519,19 @@ EOF
                  # command to the queue.
                  if test "$k" -eq 1 ; then
                    # The first file doesn't have a previous command to add.
-                   eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
+                   reload_objs=$objlist
+                   eval concat_cmds=\"$reload_cmds\"
                  else
                    # All subsequent reloadable object files will link in
                    # the last one created.
-                   eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\"
+                   reload_objs="$objlist $last_robj"
+                   eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
                  fi
                  last_robj=$output_objdir/$output_la-${k}.$objext
                  func_arith $k + 1
                  k=$func_arith_result
                  output=$output_objdir/$output_la-${k}.$objext
-                 objlist=$obj
+                 objlist=" $obj"
                  func_len " $last_robj"
                  func_arith $len0 + $func_len_result
                  len=$func_arith_result
@@ -7210,7 +7541,8 @@ EOF
              # reloadable object file.  All subsequent reloadable object
              # files will link in the last one created.
              test -z "$concat_cmds" || concat_cmds=$concat_cmds~
-             eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
+             reload_objs="$objlist $last_robj"
+             eval concat_cmds=\"\${concat_cmds}$reload_cmds\"
              if test -n "$last_robj"; then
                eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
              fi
@@ -7269,7 +7601,7 @@ EOF
            if test -n "$export_symbols" && test -n "$include_expsyms"; then
              tmp_export_symbols="$export_symbols"
              test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
-             $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"'
+             $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
            fi
 
            if test -n "$orig_export_symbols"; then
@@ -7434,7 +7766,7 @@ EOF
       if test -n "$convenience"; then
        if test -n "$whole_archive_flag_spec"; then
          eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
-         reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'`
+         reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
        else
          gentop="$output_objdir/${obj}x"
          generated="$generated $gentop"
@@ -7445,7 +7777,7 @@ EOF
       fi
 
       # Create the old-style object.
-      reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+      reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
 
       output="$obj"
       func_execute_cmds "$reload_cmds" 'exit $?'
@@ -7505,8 +7837,8 @@ EOF
       case $host in
       *-*-rhapsody* | *-*-darwin1.[012])
        # On Rhapsody replace the C library is the System framework
-       compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'`
-       finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'`
+       compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+       finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
        ;;
       esac
 
@@ -7523,8 +7855,8 @@ EOF
          esac
        fi
        # Time to change all our "foo.ltframework" stuff back to "-framework foo"
-       compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
-       finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+       compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+       finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
        ;;
       esac
 
@@ -7661,8 +7993,8 @@ EOF
 
       if test -n "$libobjs" && test "$build_old_libs" = yes; then
        # Transform all the library objects into standard objects.
-       compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
-       finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+       compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+       finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
       fi
 
       func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
@@ -7674,15 +8006,15 @@ EOF
 
       wrappers_required=yes
       case $host in
+      *cegcc* | *mingw32ce*)
+        # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+        wrappers_required=no
+        ;;
       *cygwin* | *mingw* )
         if test "$build_libtool_libs" != yes; then
           wrappers_required=no
         fi
         ;;
-      *cegcc)
-        # Disable wrappers for cegcc, we are cross compiling anyway.
-        wrappers_required=no
-        ;;
       *)
         if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
           wrappers_required=no
@@ -7691,7 +8023,7 @@ EOF
       esac
       if test "$wrappers_required" = no; then
        # Replace the output file specification.
-       compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+       compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
        link_command="$compile_command$compile_rpath"
 
        # We have no uninstalled library dependencies, so finalize right now.
@@ -7738,7 +8070,7 @@ EOF
        # We don't need to create a wrapper script.
        link_command="$compile_var$compile_command$compile_rpath"
        # Replace the output file specification.
-       link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+       link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
        # Delete the old output file.
        $opt_dry_run || $RM $output
        # Link the executable and exit
@@ -7757,7 +8089,7 @@ EOF
        if test "$fast_install" != no; then
          link_command="$finalize_var$compile_command$finalize_rpath"
          if test "$fast_install" = yes; then
-           relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
+           relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
          else
            # fast_install is set to needless
            relink_command=
@@ -7769,7 +8101,7 @@ EOF
       fi
 
       # Replace the output file specification.
-      link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+      link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
 
       # Delete the old output files.
       $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
@@ -7793,18 +8125,7 @@ EOF
          fi
        done
        relink_command="(cd `pwd`; $relink_command)"
-       relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"`
-      fi
-
-      # Quote $ECHO for shipping.
-      if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then
-       case $progpath in
-       [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";;
-       *) qecho="$SHELL `pwd`/$progpath --fallback-echo";;
-       esac
-       qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"`
-      else
-       qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"`
+       relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
       fi
 
       # Only actually do things if not in dry run mode.
@@ -7925,7 +8246,7 @@ EOF
            done | sort | sort -uc >/dev/null 2>&1); then
          :
        else
-         $ECHO "copying selected object files to avoid basename conflicts..."
+         echo "copying selected object files to avoid basename conflicts..."
          gentop="$output_objdir/${outputname}x"
          generated="$generated $gentop"
          func_mkdir_p "$gentop"
@@ -8036,7 +8357,7 @@ EOF
       done
       # Quote the link command for shipping.
       relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
-      relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+      relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
       if test "$hardcode_automatic" = yes ; then
        relink_command=
       fi
@@ -8121,9 +8442,27 @@ EOF
          fi
          $RM $output
          # place dlname in correct position for cygwin
+         # In fact, it would be nice if we could use this code for all target
+         # systems that can't hard-code library paths into their executables
+         # and that have no shared library path variable independent of PATH,
+         # but it turns out we can't easily determine that from inspecting
+         # libtool variables, so we have to hard-code the OSs to which it
+         # applies here; at the moment, that means platforms that use the PE
+         # object format with DLL files.  See the long comment at the top of
+         # tests/bindir.at for full details.
          tdlname=$dlname
          case $host,$output,$installed,$module,$dlname in
-           *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
+           *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+             # If a -bindir argument was supplied, place the dll there.
+             if test "x$bindir" != x ;
+             then
+               func_relative_path "$install_libdir" "$bindir"
+               tdlname=$func_relative_path_result$dlname
+             else
+               # Otherwise fall back on heuristic.
+               tdlname=../bin/$dlname
+             fi
+             ;;
          esac
          $ECHO > $output "\
 # $outputname - a libtool library file
index 39ba996cb960e22873667c57deeff94bf23bef56..22924a86f47d92afd9dd5344b7a5b61a4346f2dc 100644 (file)
@@ -1,7 +1,8 @@
 # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
 #
 #   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-#                 2006, 2007, 2008 Free Software Foundation, Inc.
+#                 2006, 2007, 2008, 2009, 2010 Free Software Foundation,
+#                 Inc.
 #   Written by Gordon Matzigkeit, 1996
 #
 # This file is free software; the Free Software Foundation gives
@@ -10,7 +11,8 @@
 
 m4_define([_LT_COPYING], [dnl
 #   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-#                 2006, 2007, 2008 Free Software Foundation, Inc.
+#                 2006, 2007, 2008, 2009, 2010 Free Software Foundation,
+#                 Inc.
 #   Written by Gordon Matzigkeit, 1996
 #
 #   This file is part of GNU Libtool.
@@ -37,7 +39,7 @@ m4_define([_LT_COPYING], [dnl
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 ])
 
-# serial 56 LT_INIT
+# serial 57 LT_INIT
 
 
 # LT_PREREQ(VERSION)
@@ -66,6 +68,7 @@ esac
 # ------------------
 AC_DEFUN([LT_INIT],
 [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
 AC_BEFORE([$0], [LT_LANG])dnl
 AC_BEFORE([$0], [LT_OUTPUT])dnl
 AC_BEFORE([$0], [LTDL_INIT])dnl
@@ -82,6 +85,8 @@ AC_REQUIRE([LTVERSION_VERSION])dnl
 AC_REQUIRE([LTOBSOLETE_VERSION])dnl
 m4_require([_LT_PROG_LTMAIN])dnl
 
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
 dnl Parse OPTIONS
 _LT_SET_OPTIONS([$0], [$1])
 
@@ -118,7 +123,7 @@ m4_defun([_LT_CC_BASENAME],
     *) break;;
   esac
 done
-cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
 ])
 
 
@@ -138,6 +143,9 @@ m4_defun([_LT_FILEUTILS_DEFAULTS],
 m4_defun([_LT_SETUP],
 [AC_REQUIRE([AC_CANONICAL_HOST])dnl
 AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
 _LT_DECL([], [host_alias], [0], [The host system])dnl
 _LT_DECL([], [host], [0])dnl
 _LT_DECL([], [host_os], [0])dnl
@@ -179,7 +187,6 @@ fi
 _LT_CHECK_OBJDIR
 
 m4_require([_LT_TAG_COMPILER])dnl
-_LT_PROG_ECHO_BACKSLASH
 
 case $host_os in
 aix3*)
@@ -193,23 +200,6 @@ aix3*)
   ;;
 esac
 
-# Sed substitution that helps us do robust quoting.  It backslashifies
-# metacharacters that are still active within double-quoted strings.
-sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
-
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\([["`\\]]\)/\\\1/g'
-
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
-
-# Sed substitution to delay expansion of an escaped single quote.
-delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
-
-# Sed substitution to avoid accidental globbing in evaled expressions
-no_glob_subst='s/\*/\\\*/g'
-
 # Global variables:
 ofile=libtool
 can_build_shared=yes
@@ -250,6 +240,28 @@ _LT_CONFIG_COMMANDS
 ])# _LT_SETUP
 
 
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
 # _LT_PROG_LTMAIN
 # ---------------
 # Note that this code is called both from `configure', and `config.status'
@@ -408,7 +420,7 @@ m4_define([_lt_decl_all_varnames],
 # declaration there will have the same value as in `configure'.  VARNAME
 # must have a single quote delimited value for this to work.
 m4_define([_LT_CONFIG_STATUS_DECLARE],
-[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`'])
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
 
 
 # _LT_CONFIG_STATUS_DECLARATIONS
@@ -418,7 +430,7 @@ m4_define([_LT_CONFIG_STATUS_DECLARE],
 # embedded single quotes properly.  In configure, this macro expands
 # each variable declared with _LT_DECL (and _LT_TAGDECL) into:
 #
-#    <var>='`$ECHO "X$<var>" | $Xsed -e "$delay_single_quote_subst"`'
+#    <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
 m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
 [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
     [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
@@ -517,12 +529,20 @@ LTCC='$LTCC'
 LTCFLAGS='$LTCFLAGS'
 compiler='$compiler_DEFAULT'
 
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
 # Quote evaled strings.
 for var in lt_decl_all_varnames([[ \
 ]], lt_decl_quote_varnames); do
-    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
     *[[\\\\\\\`\\"\\\$]]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
       ;;
     *)
       eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -533,9 +553,9 @@ done
 # Double-quote double-evaled strings.
 for var in lt_decl_all_varnames([[ \
 ]], lt_decl_dquote_varnames); do
-    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
     *[[\\\\\\\`\\"\\\$]]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
       ;;
     *)
       eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -543,16 +563,38 @@ for var in lt_decl_all_varnames([[ \
     esac
 done
 
-# Fix-up fallback echo if it was mangled by the above quoting rules.
-case \$lt_ECHO in
-*'\\\[$]0 --fallback-echo"')dnl "
-  lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\`
-  ;;
-esac
-
 _LT_OUTPUT_LIBTOOL_INIT
 ])
 
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable.  If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins.  After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script.  The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
 
 # LT_OUTPUT
 # ---------
@@ -562,20 +604,11 @@ _LT_OUTPUT_LIBTOOL_INIT
 AC_DEFUN([LT_OUTPUT],
 [: ${CONFIG_LT=./config.lt}
 AC_MSG_NOTICE([creating $CONFIG_LT])
-cat >"$CONFIG_LT" <<_LTEOF
-#! $SHELL
-# Generated by $as_me.
-# Run this file to recreate a libtool stub with the current configuration.
-
-lt_cl_silent=false
-SHELL=\${CONFIG_SHELL-$SHELL}
-_LTEOF
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
 
 cat >>"$CONFIG_LT" <<\_LTEOF
-AS_SHELL_SANITIZE
-_AS_PREPARE
-
-exec AS_MESSAGE_FD>&1
+lt_cl_silent=false
 exec AS_MESSAGE_LOG_FD>>config.log
 {
   echo
@@ -601,7 +634,7 @@ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
 m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
 configured by $[0], generated by m4_PACKAGE_STRING.
 
-Copyright (C) 2008 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
 This config.lt script is free software; the Free Software Foundation
 gives unlimited permision to copy, distribute and modify it."
 
@@ -646,15 +679,13 @@ chmod +x "$CONFIG_LT"
 # appending to config.log, which fails on DOS, as config.log is still kept
 # open by configure.  Here we exec the FD to /dev/null, effectively closing
 # config.log, so it can be properly (re)opened and appended to by config.lt.
-if test "$no_create" != yes; then
-  lt_cl_success=:
-  test "$silent" = yes &&
-    lt_config_lt_args="$lt_config_lt_args --quiet"
-  exec AS_MESSAGE_LOG_FD>/dev/null
-  $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
-  exec AS_MESSAGE_LOG_FD>>config.log
-  $lt_cl_success || AS_EXIT(1)
-fi
+lt_cl_success=:
+test "$silent" = yes &&
+  lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
 ])# LT_OUTPUT
 
 
@@ -831,11 +862,13 @@ AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
 AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
 AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
 AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
 dnl aclocal-1.4 backwards compatibility:
 dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
 dnl AC_DEFUN([AC_LIBTOOL_F77], [])
 dnl AC_DEFUN([AC_LIBTOOL_FC], [])
 dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
 
 
 # _LT_TAG_COMPILER
@@ -940,6 +973,31 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
        [lt_cv_ld_exported_symbols_list=no])
        LDFLAGS="$save_LDFLAGS"
     ])
+    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+      [lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+      echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+      $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then
+       lt_cv_ld_force_load=yes
+      else
+       cat conftest.err >&AS_MESSAGE_LOG_FD
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+    ])
     case $host_os in
     rhapsody* | darwin1.[[012]])
       _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
@@ -967,7 +1025,7 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
     else
       _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
     fi
-    if test "$DSYMUTIL" != ":"; then
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
       _lt_dsymutil='~$DSYMUTIL $lib || :'
     else
       _lt_dsymutil=
@@ -987,7 +1045,11 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES],
   _LT_TAGVAR(hardcode_direct, $1)=no
   _LT_TAGVAR(hardcode_automatic, $1)=yes
   _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
-  _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+  else
+    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+  fi
   _LT_TAGVAR(link_all_deplibs, $1)=yes
   _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
   case $cc_basename in
@@ -995,7 +1057,7 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES],
      *) _lt_dar_can_shared=$GCC ;;
   esac
   if test "$_lt_dar_can_shared" = "yes"; then
-    output_verbose_link_cmd=echo
+    output_verbose_link_cmd=func_echo_all
     _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
     _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
     _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
@@ -1041,170 +1103,65 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
 # _LT_SHELL_INIT(ARG)
 # -------------------
 m4_define([_LT_SHELL_INIT],
-[ifdef([AC_DIVERSION_NOTICE],
-            [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
-        [AC_DIVERT_PUSH(NOTICE)])
-$1
-AC_DIVERT_POP
-])# _LT_SHELL_INIT
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
 
 
 # _LT_PROG_ECHO_BACKSLASH
 # -----------------------
-# Add some code to the start of the generated configure script which
-# will find an echo command which doesn't interpret backslashes.
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
 m4_defun([_LT_PROG_ECHO_BACKSLASH],
-[_LT_SHELL_INIT([
-# Check that we are running under the correct shell.
-SHELL=${CONFIG_SHELL-/bin/sh}
-
-case X$lt_ECHO in
-X*--fallback-echo)
-  # Remove one level of quotation (which was required for Make).
-  ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
-  ;;
-esac
-
-ECHO=${lt_ECHO-echo}
-if test "X[$]1" = X--no-reexec; then
-  # Discard the --no-reexec flag, and continue.
-  shift
-elif test "X[$]1" = X--fallback-echo; then
-  # Avoid inline document here, it may be left over
-  :
-elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then
-  # Yippee, $ECHO works!
-  :
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`print -r -- -n 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
 else
-  # Restart under the correct shell.
-  exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
-fi
-
-if test "X[$]1" = X--fallback-echo; then
-  # used as fallback echo
-  shift
-  cat <<_LT_EOF
-[$]*
-_LT_EOF
-  exit 0
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
 fi
 
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-if test -z "$lt_ECHO"; then
-  if test "X${echo_test_string+set}" != Xset; then
-    # find a string as large as possible, as long as the shell can cope with it
-    for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
-      # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
-      if { echo_test_string=`eval $cmd`; } 2>/dev/null &&
-        { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null
-      then
-        break
-      fi
-    done
-  fi
-
-  if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
-     echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
-     test "X$echo_testing_string" = "X$echo_test_string"; then
-    :
-  else
-    # The Solaris, AIX, and Digital Unix default echo programs unquote
-    # backslashes.  This makes it impossible to quote backslashes using
-    #   echo "$something" | sed 's/\\/\\\\/g'
-    #
-    # So, first we look for a working echo in the user's PATH.
-
-    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
-    for dir in $PATH /usr/ucb; do
-      IFS="$lt_save_ifs"
-      if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
-         test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
-         echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
-         test "X$echo_testing_string" = "X$echo_test_string"; then
-        ECHO="$dir/echo"
-        break
-      fi
-    done
-    IFS="$lt_save_ifs"
-
-    if test "X$ECHO" = Xecho; then
-      # We didn't find a better echo, so look for alternatives.
-      if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' &&
-         echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` &&
-         test "X$echo_testing_string" = "X$echo_test_string"; then
-        # This shell has a builtin print -r that does the trick.
-        ECHO='print -r'
-      elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } &&
-          test "X$CONFIG_SHELL" != X/bin/ksh; then
-        # If we have ksh, try running configure again with it.
-        ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
-        export ORIGINAL_CONFIG_SHELL
-        CONFIG_SHELL=/bin/ksh
-        export CONFIG_SHELL
-        exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
-      else
-        # Try using printf.
-        ECHO='printf %s\n'
-        if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
-          echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
-          test "X$echo_testing_string" = "X$echo_test_string"; then
-         # Cool, printf works
-         :
-        elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
-            test "X$echo_testing_string" = 'X\t' &&
-            echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
-            test "X$echo_testing_string" = "X$echo_test_string"; then
-         CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
-         export CONFIG_SHELL
-         SHELL="$CONFIG_SHELL"
-         export SHELL
-         ECHO="$CONFIG_SHELL [$]0 --fallback-echo"
-        elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
-            test "X$echo_testing_string" = 'X\t' &&
-            echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
-            test "X$echo_testing_string" = "X$echo_test_string"; then
-         ECHO="$CONFIG_SHELL [$]0 --fallback-echo"
-        else
-         # maybe with a smaller string...
-         prev=:
-
-         for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
-           if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null
-           then
-             break
-           fi
-           prev="$cmd"
-         done
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*" 
+}
 
-         if test "$prev" != 'sed 50q "[$]0"'; then
-           echo_test_string=`eval $prev`
-           export echo_test_string
-           exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
-         else
-           # Oops.  We lost completely, so just stick with echo.
-           ECHO=echo
-         fi
-        fi
-      fi
-    fi
-  fi
-fi
+case "$ECHO" in
+  printf*) AC_MSG_RESULT([printf]) ;;
+  print*) AC_MSG_RESULT([print -r]) ;;
+  *) AC_MSG_RESULT([cat]) ;;
+esac
 
-# Copy echo and quote the copy suitably for passing to libtool from
-# the Makefile, instead of quoting the original, which is used later.
-lt_ECHO=$ECHO
-if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
-   lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
-fi
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test "X`printf %s $ECHO`" = "X$ECHO" \
+      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
 
-AC_SUBST(lt_ECHO)
-])
 _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
-_LT_DECL([], [ECHO], [1],
-    [An echo program that does not interpret backslashes])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
 ])# _LT_PROG_ECHO_BACKSLASH
 
 
@@ -1236,7 +1193,7 @@ ia64-*-hpux*)
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
   if AC_TRY_EVAL(ac_compile); then
     if test "$lt_cv_prog_gnu_ld" = yes; then
       case `/usr/bin/file conftest.$ac_objext` in
@@ -1388,10 +1345,19 @@ if test -n "$RANLIB"; then
   esac
   old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
 fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
 _LT_DECL([], [old_postinstall_cmds], [2])
 _LT_DECL([], [old_postuninstall_cmds], [2])
 _LT_TAGDECL([], [old_archive_cmds], [2],
     [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+    [Whether to use a lock for old archive extraction])
 ])# _LT_CMD_OLD_ARCHIVE
 
 
@@ -1416,15 +1382,15 @@ AC_CACHE_CHECK([$1], [$2],
    -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:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&AS_MESSAGE_LOG_FD
-   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
    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.
-     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
      $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
      if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
        $2=yes
@@ -1464,7 +1430,7 @@ AC_CACHE_CHECK([$1], [$2],
      if test -s conftest.err; then
        # Append any errors to the config.log.
        cat conftest.err 1>&AS_MESSAGE_LOG_FD
-       $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
        $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
        if diff conftest.exp conftest.er2 >/dev/null; then
          $2=yes
@@ -1527,6 +1493,11 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
     lt_cv_sys_max_cmd_len=8192;
     ;;
 
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
   amigaos*)
     # On AmigaOS with pdksh, this test takes hours, literally.
     # So we just punt and use a minimum line length of 8192.
@@ -1591,8 +1562,8 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
       # If test is not a shell built-in, we'll probably end up computing a
       # maximum length that is only half of the actual maximum length, but
       # we can't tell.
-      while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \
-                = "XX$teststring$teststring"; } >/dev/null 2>&1 &&
+      while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \
+                = "X$teststring$teststring"; } >/dev/null 2>&1 &&
              test $i != 17 # 1/2 MB should be enough
       do
         i=`expr $i + 1`
@@ -1643,7 +1614,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-[#line __oline__ "configure"
+[#line $LINENO "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -1684,7 +1655,13 @@ else
 #  endif
 #endif
 
-void fnord() { int i=42;}
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
 int main ()
 {
   void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
@@ -1693,7 +1670,11 @@ int main ()
   if (self)
     {
       if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
-      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      else
+        {
+         if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+       }
       /* dlclose (self); */
     }
   else
@@ -1869,16 +1850,16 @@ AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
    -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:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&AS_MESSAGE_LOG_FD
-   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings
-     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
      $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
      if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
        _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
@@ -2037,6 +2018,7 @@ m4_require([_LT_DECL_EGREP])dnl
 m4_require([_LT_FILEUTILS_DEFAULTS])dnl
 m4_require([_LT_DECL_OBJDUMP])dnl
 m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
 AC_MSG_CHECKING([dynamic linker characteristics])
 m4_if([$1],
        [], [
@@ -2045,16 +2027,23 @@ if test "$GCC" = yes; then
     darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
     *) lt_awk_arg="/^libraries:/" ;;
   esac
-  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
-  if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
     # if the path contains ";" then we assume it to be the separator
     # otherwise default to the standard path separator (i.e. ":") - it is
     # assumed that no part of a normal pathname contains ";" but that should
     # okay in the real world where ";" in dirpaths is itself problematic.
-    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'`
-  else
-    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
-  fi
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
   # Ok, now we have the path, separated by spaces, we can step through it
   # and add multilib dir if necessary.
   lt_tmp_lt_search_path_spec=
@@ -2067,7 +2056,7 @@ if test "$GCC" = yes; then
        lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
     fi
   done
-  lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk '
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
 BEGIN {RS=" "; FS="/|\n";} {
   lt_foo="";
   lt_count=0;
@@ -2087,7 +2076,13 @@ BEGIN {RS=" "; FS="/|\n";} {
   if (lt_foo != "") { lt_freq[[lt_foo]]++; }
   if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
 }'`
-  sys_lib_search_path_spec=`$ECHO $lt_search_path_spec`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
 else
   sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
 fi])
@@ -2175,7 +2170,7 @@ amigaos*)
   m68k)
     library_names_spec='$libname.ixlibrary $libname.a'
     # Create ${libname}_ixlibrary.a entries in /sys/libs.
-    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
     ;;
   esac
   ;;
@@ -2228,23 +2223,12 @@ cygwin* | mingw* | pw32* | cegcc*)
     cygwin*)
       # Cygwin DLLs use 'cyg' prefix rather than 'lib'
       soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
-      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+m4_if([$1], [],[
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
       ;;
     mingw* | cegcc*)
       # MinGW DLLs use traditional 'lib' prefix
       soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
-      sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
-      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
-        # It is most probably a Windows format PATH printed by
-        # mingw gcc, but we are running on Cygwin. Gcc prints its search
-        # path with ; separators, and with drive letters. We can handle the
-        # drive letters (cygwin fileutils understands them), so leave them,
-        # especially as we might pass files found there to a mingw objdump,
-        # which wouldn't understand a cygwinified path. Ahh.
-        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
-      else
-        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
-      fi
       ;;
     pw32*)
       # pw32 DLLs use 'pw' prefix rather than 'lib'
@@ -2344,6 +2328,19 @@ gnu*)
   hardcode_into_libs=yes
   ;;
 
+haiku*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
 hpux9* | hpux10* | hpux11*)
   # Give a soname corresponding to the major version so that dld.sl refuses to
   # link against other versions.
@@ -2386,8 +2383,10 @@ hpux9* | hpux10* | hpux11*)
     soname_spec='${libname}${release}${shared_ext}$major'
     ;;
   esac
-  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
   postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
   ;;
 
 interix[[3-9]]*)
@@ -2445,7 +2444,7 @@ linux*oldld* | linux*aout* | linux*coff*)
   ;;
 
 # This must be Linux ELF.
-linux* | k*bsd*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
   version_type=linux
   need_lib_prefix=no
   need_version=no
@@ -2454,16 +2453,21 @@ linux* | k*bsd*-gnu)
   finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
+
   # Some binutils ld are patched to set DT_RUNPATH
-  save_LDFLAGS=$LDFLAGS
-  save_libdir=$libdir
-  eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
-       LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
-  AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
-    [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
-       [shlibpath_overrides_runpath=yes])])
-  LDFLAGS=$save_LDFLAGS
-  libdir=$save_libdir
+  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+    [lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+        LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+      [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+        [lt_cv_shlibpath_overrides_runpath=yes])])
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+    ])
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
 
   # This implies no fast_install, which is unacceptable.
   # Some rework will be needed to allow for fast_install
@@ -2472,7 +2476,7 @@ linux* | k*bsd*-gnu)
 
   # Append ld.so.conf contents to the search path
   if test -f /etc/ld.so.conf; then
-    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[  ]*hwcap[        ]/d;s/[:,      ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[  ]*hwcap[        ]/d;s/[:,      ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
     sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
   fi
 
@@ -2705,6 +2709,8 @@ _LT_DECL([], [library_names_spec], [1],
     The last name is the one that the linker finds with -lNAME]])
 _LT_DECL([], [soname_spec], [1],
     [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+    [Permission mode override for installation of shared libraries])
 _LT_DECL([], [postinstall_cmds], [2],
     [Command to use after installation of a shared archive])
 _LT_DECL([], [postuninstall_cmds], [2],
@@ -2817,6 +2823,7 @@ AC_REQUIRE([AC_CANONICAL_HOST])dnl
 AC_REQUIRE([AC_CANONICAL_BUILD])dnl
 m4_require([_LT_DECL_SED])dnl
 m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
 
 AC_ARG_WITH([gnu-ld],
     [AS_HELP_STRING([--with-gnu-ld],
@@ -2946,8 +2953,8 @@ case $host_os in
     fi
     ;;
 esac
-_LT_DECL([], [reload_flag], [1], [How to create reloadable object files])dnl
-_LT_DECL([], [reload_cmds], [2])dnl
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
 ])# _LT_CMD_RELOAD
 
 
@@ -2999,16 +3006,18 @@ mingw* | pw32*)
   # Base MSYS/MinGW do not provide the 'file' command needed by
   # func_win32_libid shell function, so use a weaker test based on 'objdump',
   # unless we find 'file', for example because we are cross-compiling.
-  if ( file / ) >/dev/null 2>&1; then
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
     lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
     lt_cv_file_magic_cmd='func_win32_libid'
   else
-    lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
     lt_cv_file_magic_cmd='$OBJDUMP -f'
   fi
   ;;
 
-cegcc)
+cegcc*)
   # use the weaker test based on 'objdump'. See mingw*.
   lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
   lt_cv_file_magic_cmd='$OBJDUMP -f'
@@ -3038,6 +3047,10 @@ gnu*)
   lt_cv_deplibs_check_method=pass_all
   ;;
 
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
 hpux10.20* | hpux11*)
   lt_cv_file_magic_cmd=/usr/bin/file
   case $host_cpu in
@@ -3046,11 +3059,11 @@ hpux10.20* | hpux11*)
     lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
     ;;
   hppa*64*)
-    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
     lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
     ;;
   *)
-    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
     lt_cv_file_magic_test_file=/usr/lib/libc.sl
     ;;
   esac
@@ -3072,7 +3085,7 @@ irix5* | irix6* | nonstopux*)
   ;;
 
 # This must be Linux ELF.
-linux* | k*bsd*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
   lt_cv_deplibs_check_method=pass_all
   ;;
 
@@ -3214,7 +3227,19 @@ if test "$lt_cv_path_NM" != "no"; then
   NM="$lt_cv_path_NM"
 else
   # Didn't find any BSD compatible name lister, look for dumpbin.
-  AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :)
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
   AC_SUBST([DUMPBIN])
   if test "$DUMPBIN" != ":"; then
     NM="$DUMPBIN"
@@ -3227,13 +3252,13 @@ _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
 AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
   [lt_cv_nm_interface="BSD nm"
   echo "int some_variable = 0;" > conftest.$ac_ext
-  (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
   (eval "$ac_compile" 2>conftest.err)
   cat conftest.err >&AS_MESSAGE_LOG_FD
-  (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
   (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
   cat conftest.err >&AS_MESSAGE_LOG_FD
-  (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD)
+  (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
   cat conftest.out >&AS_MESSAGE_LOG_FD
   if $GREP 'External.*some_variable' conftest.out > /dev/null; then
     lt_cv_nm_interface="MS dumpbin"
@@ -3256,7 +3281,7 @@ AC_DEFUN([LT_LIB_M],
 [AC_REQUIRE([AC_CANONICAL_HOST])dnl
 LIBM=
 case $host in
-*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
   # These system don't have libm, or don't need it
   ;;
 *-ncr-sysv4.3*)
@@ -3284,7 +3309,12 @@ m4_defun([_LT_COMPILER_NO_RTTI],
 _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
 
 if test "$GCC" = yes; then
-  _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+  case $cc_basename in
+  nvcc*)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+  esac
 
   _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
     lt_cv_prog_compiler_rtti_exceptions,
@@ -3301,6 +3331,7 @@ _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
 m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
 [AC_REQUIRE([AC_CANONICAL_HOST])dnl
 AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
 AC_REQUIRE([LT_PATH_NM])dnl
 AC_REQUIRE([LT_PATH_LD])dnl
 m4_require([_LT_DECL_SED])dnl
@@ -3426,7 +3457,7 @@ _LT_EOF
   if AC_TRY_EVAL(ac_compile); then
     # Now try to grab the symbols.
     nlist=conftest.nm
-    if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
       # Try sorting and uniquifying the output.
       if sort "$nlist" | uniq > "$nlist"T; then
        mv -f "$nlist"T "$nlist"
@@ -3588,6 +3619,11 @@ m4_if([$1], [CXX], [
       # DJGPP does not support shared libraries at all
       _LT_TAGVAR(lt_prog_compiler_pic, $1)=
       ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
     interix[[3-9]]*)
       # Interix 3.x gcc -fpic/-fPIC options generate broken code.
       # Instead, we relocate shared libraries at runtime.
@@ -3693,7 +3729,7 @@ m4_if([$1], [CXX], [
            ;;
        esac
        ;;
-      linux* | k*bsd*-gnu)
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
        case $cc_basename in
          KCC*)
            # KAI C++ Compiler
@@ -3726,8 +3762,8 @@ m4_if([$1], [CXX], [
            _LT_TAGVAR(lt_prog_compiler_pic, $1)=
            _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
            ;;
-         xlc* | xlC*)
-           # IBM XL 8.0 on PPC
+         xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+           # IBM XL 8.0, 9.0 on PPC and BlueGene
            _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
            _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
@@ -3789,7 +3825,7 @@ m4_if([$1], [CXX], [
        ;;
       solaris*)
        case $cc_basename in
-         CC*)
+         CC* | sunCC*)
            # Sun C++ 4.2, 5.x and Centerline C++
            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
            _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
@@ -3893,6 +3929,12 @@ m4_if([$1], [CXX], [
       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
       ;;
 
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+
     hpux*)
       # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
       # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
@@ -3935,6 +3977,13 @@ m4_if([$1], [CXX], [
       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
       ;;
     esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Xcompiler -fPIC'
+      ;;
+    esac
   else
     # PORTME Check for flag to pass linker flags through the system compiler.
     case $host_os in
@@ -3977,7 +4026,7 @@ m4_if([$1], [CXX], [
       _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
       ;;
 
-    linux* | k*bsd*-gnu)
+    linux* | k*bsd*-gnu | kopensolaris*-gnu)
       case $cc_basename in
       # old Intel for x86_64 which still supported -KPIC.
       ecc*)
@@ -3998,7 +4047,7 @@ m4_if([$1], [CXX], [
        _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
        _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
        ;;
-      pgcc* | pgf77* | pgf90* | pgf95*)
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
         # Portland Group compilers (*not* the Pentium gcc compiler,
        # which looks to be a dead project)
        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
@@ -4010,25 +4059,25 @@ m4_if([$1], [CXX], [
         # All Alpha code is PIC.
         _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
         ;;
-      xl*)
-       # IBM XL C 8.0/Fortran 10.1 on PPC
+      xl* | bgxl* | bgf* | mpixl*)
+       # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
        _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
        ;;
       *)
        case `$CC -V 2>&1 | sed 5q` in
-       *Sun\ C*)
-         # Sun C 5.9
+       *Sun\ F* | *Sun*Fortran*)
+         # Sun Fortran 8.3 passes all unrecognized flags to the linker
          _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
          _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+         _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
          ;;
-       *Sun\ F*)
-         # Sun Fortran 8.3 passes all unrecognized flags to the linker
+       *Sun\ C*)
+         # Sun C 5.9
          _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
          _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-         _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
          ;;
        esac
        ;;
@@ -4060,7 +4109,7 @@ m4_if([$1], [CXX], [
       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
       case $cc_basename in
-      f77* | f90* | f95*)
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
       *)
        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
@@ -4170,8 +4219,10 @@ m4_if([$1], [CXX], [
   aix[[4-9]]*)
     # If we're using GNU nm, then we don't want the "-C" option.
     # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    # Also, AIX nm treats weak defined symbols like other global defined
+    # symbols, whereas GNU nm marks them as "W".
     if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
     else
       _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
     fi
@@ -4249,7 +4300,33 @@ dnl Note also adjust exclude_expsyms for C++ above.
   esac
 
   _LT_TAGVAR(ld_shlibs, $1)=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
   if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+       # The AIX port of GNU ld has always aspired to compatibility
+       # with the native linker.  However, as the warning in the GNU ld
+       # block says, versions before 2.19.5* couldn't really create working
+       # shared libraries, regardless of the interface used.
+       case `$LD -v 2>&1` in
+         *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+         *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+         *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+         *)
+           lt_use_gnu_ld_interface=yes
+           ;;
+       esac
+       ;;
+      *)
+       lt_use_gnu_ld_interface=yes
+       ;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
     # If archive_cmds runs LD, not CC, wlarc should be empty
     wlarc='${wl}'
 
@@ -4267,6 +4344,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
     fi
     supports_anon_versioning=no
     case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
       *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
       *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
       *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
@@ -4282,11 +4360,12 @@ dnl Note also adjust exclude_expsyms for C++ above.
        _LT_TAGVAR(ld_shlibs, $1)=no
        cat <<_LT_EOF 1>&2
 
-*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** Warning: the GNU linker, at least up to release 2.19, is reported
 *** to be unable to reliably create shared libraries on AIX.
 *** Therefore, libtool is disabling shared libraries support.  If you
-*** really care for shared libraries, you may want to modify your PATH
-*** so that a non-GNU linker is found, and then restart.
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
 
 _LT_EOF
       fi
@@ -4322,6 +4401,7 @@ _LT_EOF
       # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
       # as there is no search path for DLLs.
       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
       _LT_TAGVAR(always_export_symbols, $1)=no
       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
@@ -4343,6 +4423,11 @@ _LT_EOF
       fi
       ;;
 
+    haiku*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
     interix[[3-9]]*)
       _LT_TAGVAR(hardcode_direct, $1)=no
       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
@@ -4358,7 +4443,7 @@ _LT_EOF
       _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
       ;;
 
-    gnu* | linux* | tpf* | k*bsd*-gnu)
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
       tmp_diet=no
       if test "$host_os" = linux-dietlibc; then
        case $cc_basename in
@@ -4372,11 +4457,12 @@ _LT_EOF
        tmp_sharedflag='-shared'
        case $cc_basename,$host_cpu in
         pgcc*)                         # Portland Group C compiler
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
          tmp_addflag=' $pic_flag'
          ;;
-       pgf77* | pgf90* | pgf95*)       # Portland Group f77 and f90 compilers
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+       pgf77* | pgf90* | pgf95* | pgfortran*)
+                                       # Portland Group f77 and f90 compilers
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
          tmp_addflag=' $pic_flag -Mnomain' ;;
        ecc*,ia64* | icc*,ia64*)        # Intel C compiler on ia64
          tmp_addflag=' -i_dynamic' ;;
@@ -4387,13 +4473,17 @@ _LT_EOF
        lf95*)                          # Lahey Fortran 8.1
          _LT_TAGVAR(whole_archive_flag_spec, $1)=
          tmp_sharedflag='--shared' ;;
-       xl[[cC]]*)                      # IBM XL C 8.0 on PPC (deal with xlf below)
+       xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
          tmp_sharedflag='-qmkshrobj'
          tmp_addflag= ;;
+       nvcc*)  # Cuda Compiler Driver 2.2
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         _LT_TAGVAR(compiler_needs_object, $1)=yes
+         ;;
        esac
        case `$CC -V 2>&1 | sed 5q` in
        *Sun\ C*)                       # Sun C 5.9
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
          _LT_TAGVAR(compiler_needs_object, $1)=yes
          tmp_sharedflag='-G' ;;
        *Sun\ F*)                       # Sun Fortran 8.3
@@ -4409,17 +4499,17 @@ _LT_EOF
         fi
 
        case $cc_basename in
-       xlf*)
+       xlf* | bgf* | bgxlf* | mpixlf*)
          # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
          _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
          _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
-         _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+         _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
          if test "x$supports_anon_versioning" = xyes; then
            _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
              cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
              echo "local: *; };" >> $output_objdir/$libname.ver~
-             $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+             $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
          fi
          ;;
        esac
@@ -4540,8 +4630,10 @@ _LT_EOF
       else
        # If we're using GNU nm, then we don't want the "-C" option.
        # -C means demangle to AIX nm, but means don't demangle with GNU nm
+       # Also, AIX nm treats weak defined symbols like other global
+       # defined symbols, whereas GNU nm marks them as "W".
        if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-         _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+         _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
        else
          _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
        fi
@@ -4630,7 +4722,7 @@ _LT_EOF
         # empty executable.
         _LT_SYS_MODULE_PATH_AIX
         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
-        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
       else
        if test "$host_cpu" = ia64; then
          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
@@ -4645,8 +4737,13 @@ _LT_EOF
          # -berok will link without error, but may produce a broken library.
          _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
          _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
-         # Exported symbols can be pulled into shared objects from archives
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+         if test "$with_gnu_ld" = yes; then
+           # We only use this code for GNU lds that support --whole-archive.
+           _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+         else
+           # Exported symbols can be pulled into shared objects from archives
+           _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+         fi
          _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
          # This is similar to how AIX traditionally builds its shared libraries.
          _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
@@ -4685,7 +4782,7 @@ _LT_EOF
       # Tell ltmain to make .dll files, not .so files.
       shrext_cmds=".dll"
       # FIXME: Setting linknames here is a bad hack.
-      _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames='
+      _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
       # The linker will automatically build a .lib file if we build a DLL.
       _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
       # FIXME: Should let the user specify the lib program.
@@ -4752,7 +4849,7 @@ _LT_EOF
       ;;
 
     hpux10*)
-      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
       else
        _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
@@ -4771,7 +4868,7 @@ _LT_EOF
       ;;
 
     hpux11*)
-      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
        case $host_cpu in
        hppa*64*)
          _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
@@ -4792,7 +4889,14 @@ _LT_EOF
          _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
          ;;
        *)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+       m4_if($1, [], [
+         # Older versions of the 11.00 compiler do not understand -b yet
+         # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+         _LT_LINKER_OPTION([if $CC understands -b],
+           _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+           [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+           [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+         [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
          ;;
        esac
       fi
@@ -4820,19 +4924,19 @@ _LT_EOF
 
     irix5* | irix6* | nonstopux*)
       if test "$GCC" = yes; then
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
        # Try to use the -exported_symbol ld option, if it does not
        # work, assume that -exports_file does not work either and
        # implicitly export all symbols.
         save_LDFLAGS="$LDFLAGS"
         LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
         AC_LINK_IFELSE(int foo(void) {},
-          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
         )
         LDFLAGS="$save_LDFLAGS"
       else
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
       fi
       _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
@@ -4894,17 +4998,17 @@ _LT_EOF
       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
       _LT_TAGVAR(hardcode_minus_L, $1)=yes
       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
       _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
       ;;
 
     osf3*)
       if test "$GCC" = yes; then
        _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
       else
        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
       fi
       _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
@@ -4914,13 +5018,13 @@ _LT_EOF
     osf4* | osf5*)     # as osf3* with the addition of -msym flag
       if test "$GCC" = yes; then
        _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
       else
        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
        _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
-       $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+       $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
 
        # Both c and cxx compiler support -rpath directly
        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
@@ -5111,36 +5215,38 @@ x|xyes)
       # Test whether the compiler implicitly links with -lc since on some
       # systems, -lgcc has to come before -lc. If gcc already passes -lc
       # to ld, don't add -lc before -lgcc.
-      AC_MSG_CHECKING([whether -lc should be explicitly linked in])
-      $RM conftest*
-      echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
-      if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
-        soname=conftest
-        lib=conftest
-        libobjs=conftest.$ac_objext
-        deplibs=
-        wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
-       pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
-        compiler_flags=-v
-        linker_flags=-v
-        verstring=
-        output_objdir=.
-        libname=conftest
-        lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
-        _LT_TAGVAR(allow_undefined_flag, $1)=
-        if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
-        then
-         _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-        else
-         _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-        fi
-        _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
-      else
-        cat conftest.err 1>&5
-      fi
-      $RM conftest*
-      AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)])
+      AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+       [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+       [$RM conftest*
+       echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+       if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+         soname=conftest
+         lib=conftest
+         libobjs=conftest.$ac_objext
+         deplibs=
+         wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+         pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+         compiler_flags=-v
+         linker_flags=-v
+         verstring=
+         output_objdir=.
+         libname=conftest
+         lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+         _LT_TAGVAR(allow_undefined_flag, $1)=
+         if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+         then
+           lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+         else
+           lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+         fi
+         _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+       else
+         cat conftest.err 1>&5
+       fi
+       $RM conftest*
+       ])
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
       ;;
     esac
   fi
@@ -5310,37 +5416,21 @@ CC="$lt_save_CC"
 ])# _LT_LANG_C_CONFIG
 
 
-# _LT_PROG_CXX
-# ------------
-# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++
-# compiler, we have our own version here.
-m4_defun([_LT_PROG_CXX],
-[
-pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes])
-AC_PROG_CXX
-if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
-    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
-    (test "X$CXX" != "Xg++"))) ; then
-  AC_PROG_CXXCPP
-else
-  _lt_caught_CXX_error=yes
-fi
-popdef([AC_MSG_ERROR])
-])# _LT_PROG_CXX
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([_LT_PROG_CXX], [])
-
-
 # _LT_LANG_CXX_CONFIG([TAG])
 # --------------------------
 # Ensure that the configuration variables for a C++ compiler are suitably
 # defined.  These variables are subsequently used by _LT_CONFIG to write
 # the compiler configuration to `libtool'.
 m4_defun([_LT_LANG_CXX_CONFIG],
-[AC_REQUIRE([_LT_PROG_CXX])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
 m4_require([_LT_DECL_EGREP])dnl
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  AC_PROG_CXXCPP
+else
+  _lt_caught_CXX_error=yes
+fi
 
 AC_LANG_PUSH(C++)
 _LT_TAGVAR(archive_cmds_need_lc, $1)=no
@@ -5362,6 +5452,8 @@ _LT_TAGVAR(module_cmds, $1)=
 _LT_TAGVAR(module_expsym_cmds, $1)=
 _LT_TAGVAR(link_all_deplibs, $1)=unknown
 _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
 _LT_TAGVAR(no_undefined_flag, $1)=
 _LT_TAGVAR(whole_archive_flag_spec, $1)=
 _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
@@ -5464,7 +5556,7 @@ if test "$_lt_caught_CXX_error" != yes; then
       # Commands to make compiler produce verbose output that lists
       # what "hidden" libraries, object files and flags are used when
       # linking a shared library.
-      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
 
     else
       GXX=no
@@ -5576,7 +5668,7 @@ if test "$_lt_caught_CXX_error" != yes; then
           _LT_SYS_MODULE_PATH_AIX
           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
 
-          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
         else
           if test "$host_cpu" = ia64; then
            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
@@ -5591,8 +5683,13 @@ if test "$_lt_caught_CXX_error" != yes; then
            # -berok will link without error, but may produce a broken library.
            _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
            _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
-           # Exported symbols can be pulled into shared objects from archives
-           _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+           if test "$with_gnu_ld" = yes; then
+             # We only use this code for GNU lds that support --whole-archive.
+             _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+           else
+             # Exported symbols can be pulled into shared objects from archives
+             _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+           fi
            _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
            # This is similar to how AIX traditionally builds its shared
            # libraries.
@@ -5625,6 +5722,7 @@ if test "$_lt_caught_CXX_error" != yes; then
         # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
         # as there is no search path for DLLs.
         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
         _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
         _LT_TAGVAR(always_export_symbols, $1)=no
         _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
@@ -5685,6 +5783,11 @@ if test "$_lt_caught_CXX_error" != yes; then
       gnu*)
         ;;
 
+      haiku*)
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        ;;
+
       hpux9*)
         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
         _LT_TAGVAR(hardcode_libdir_separator, $1)=:
@@ -5709,7 +5812,7 @@ if test "$_lt_caught_CXX_error" != yes; then
             # explicitly linking system object files so we need to strip them
             # from the output so that they don't get included in the library
             # dependencies.
-            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
             ;;
           *)
             if test "$GXX" = yes; then
@@ -5774,7 +5877,7 @@ if test "$_lt_caught_CXX_error" != yes; then
            # explicitly linking system object files so we need to strip them
            # from the output so that they don't get included in the library
            # dependencies.
-           output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+           output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
            ;;
           *)
            if test "$GXX" = yes; then
@@ -5817,7 +5920,7 @@ if test "$_lt_caught_CXX_error" != yes; then
         case $cc_basename in
           CC*)
            # SGI C++
-           _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+           _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
 
            # Archives containing C++ object files must be created using
            # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
@@ -5828,9 +5931,9 @@ if test "$_lt_caught_CXX_error" != yes; then
           *)
            if test "$GXX" = yes; then
              if test "$with_gnu_ld" = no; then
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
              else
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib'
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
              fi
            fi
            _LT_TAGVAR(link_all_deplibs, $1)=yes
@@ -5841,7 +5944,7 @@ if test "$_lt_caught_CXX_error" != yes; then
         _LT_TAGVAR(inherit_rpath, $1)=yes
         ;;
 
-      linux* | k*bsd*-gnu)
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
         case $cc_basename in
           KCC*)
            # Kuck and Associates, Inc. (KAI) C++ Compiler
@@ -5859,7 +5962,7 @@ if test "$_lt_caught_CXX_error" != yes; then
            # explicitly linking system object files so we need to strip them
            # from the output so that they don't get included in the library
            # dependencies.
-           output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+           output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
 
            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
            _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
@@ -5896,26 +5999,26 @@ if test "$_lt_caught_CXX_error" != yes; then
           pgCC* | pgcpp*)
             # Portland Group C++ compiler
            case `$CC -V` in
-           *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*)
+           *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
              _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
                rm -rf $tpldir~
                $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
-               compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
+               compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
              _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
                rm -rf $tpldir~
                $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
-               $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
+               $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
                $RANLIB $oldlib'
              _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
                rm -rf $tpldir~
                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-               $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+               $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
              _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
                rm -rf $tpldir~
                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-               $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+               $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
              ;;
-           *) # Version 6 will use weak symbols
+           *) # Version 6 and above use weak symbols
              _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
              _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
              ;;
@@ -5923,7 +6026,7 @@ if test "$_lt_caught_CXX_error" != yes; then
 
            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
            _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-           _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+           _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
             ;;
          cxx*)
            # Compaq C++
@@ -5942,9 +6045,9 @@ if test "$_lt_caught_CXX_error" != yes; then
            # explicitly linking system object files so we need to strip them
            # from the output so that they don't get included in the library
            # dependencies.
-           output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+           output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
            ;;
-         xl*)
+         xl* | mpixl* | bgxl*)
            # IBM XL 8.0 on PPC, with GNU ld
            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
            _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
@@ -5964,13 +6067,13 @@ if test "$_lt_caught_CXX_error" != yes; then
              _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
              _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
              _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-             _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+             _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
              _LT_TAGVAR(compiler_needs_object, $1)=yes
 
              # Not sure whether something based on
              # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
              # would be better.
-             output_verbose_link_cmd='echo'
+             output_verbose_link_cmd='func_echo_all'
 
              # Archives containing C++ object files must be created using
              # "CC -xar", where "CC" is the Sun C++ compiler.  This is
@@ -6039,7 +6142,7 @@ if test "$_lt_caught_CXX_error" != yes; then
            _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
            _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
          fi
-         output_verbose_link_cmd=echo
+         output_verbose_link_cmd=func_echo_all
        else
          _LT_TAGVAR(ld_shlibs, $1)=no
        fi
@@ -6074,15 +6177,15 @@ if test "$_lt_caught_CXX_error" != yes; then
            case $host in
              osf3*)
                _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
                _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
                ;;
              *)
                _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
                _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
                  echo "-hidden">> $lib.exp~
-                 $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~
+                 $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
                  $RM $lib.exp'
                _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
                ;;
@@ -6098,17 +6201,17 @@ if test "$_lt_caught_CXX_error" != yes; then
            # explicitly linking system object files so we need to strip them
            # from the output so that they don't get included in the library
            # dependencies.
-           output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+           output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
            ;;
          *)
            if test "$GXX" = yes && test "$with_gnu_ld" = no; then
              _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
              case $host in
                osf3*)
-                 _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+                 _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
                  ;;
                *)
-                 _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+                 _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
                  ;;
              esac
 
@@ -6118,7 +6221,7 @@ if test "$_lt_caught_CXX_error" != yes; then
              # Commands to make compiler produce verbose output that lists
              # what "hidden" libraries, object files and flags are used when
              # linking a shared library.
-             output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+             output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
 
            else
              # FIXME: insert proper C++ library support
@@ -6154,7 +6257,7 @@ if test "$_lt_caught_CXX_error" != yes; then
 
       solaris*)
         case $cc_basename in
-          CC*)
+          CC* | sunCC*)
            # Sun C++ 4.2, 5.x and Centerline C++
             _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
            _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
@@ -6175,7 +6278,7 @@ if test "$_lt_caught_CXX_error" != yes; then
            esac
            _LT_TAGVAR(link_all_deplibs, $1)=yes
 
-           output_verbose_link_cmd='echo'
+           output_verbose_link_cmd='func_echo_all'
 
            # Archives containing C++ object files must be created using
            # "CC -xar", where "CC" is the Sun C++ compiler.  This is
@@ -6202,7 +6305,7 @@ if test "$_lt_caught_CXX_error" != yes; then
                # Commands to make compiler produce verbose output that lists
                # what "hidden" libraries, object files and flags are used when
                # linking a shared library.
-               output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+               output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
              else
                # g++ 2.7 appears to require `-G' NOT `-shared' on this
                # platform.
@@ -6213,7 +6316,7 @@ if test "$_lt_caught_CXX_error" != yes; then
                # Commands to make compiler produce verbose output that lists
                # what "hidden" libraries, object files and flags are used when
                # linking a shared library.
-               output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+               output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
              fi
 
              _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
@@ -6267,6 +6370,10 @@ if test "$_lt_caught_CXX_error" != yes; then
           CC*)
            _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
            _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+           _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+             '"$_LT_TAGVAR(old_archive_cmds, $1)"
+           _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+             '"$_LT_TAGVAR(reload_cmds, $1)"
            ;;
          *)
            _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
@@ -6513,7 +6620,7 @@ linux*)
 
 solaris*)
   case $cc_basename in
-  CC*)
+  CC* | sunCC*)
     # The more standards-conforming stlport4 library is
     # incompatible with the Cstd library. Avoid specifying
     # it if it's in CXXFLAGS. Ignore libCrun as
@@ -6557,32 +6664,16 @@ _LT_TAGDECL([], [compiler_lib_search_path], [1],
 ])# _LT_SYS_HIDDEN_LIBDEPS
 
 
-# _LT_PROG_F77
-# ------------
-# Since AC_PROG_F77 is broken, in that it returns the empty string
-# if there is no fortran compiler, we have our own version here.
-m4_defun([_LT_PROG_F77],
-[
-pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes])
-AC_PROG_F77
-if test -z "$F77" || test "X$F77" = "Xno"; then
-  _lt_disable_F77=yes
-fi
-popdef([AC_MSG_ERROR])
-])# _LT_PROG_F77
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([_LT_PROG_F77], [])
-
-
 # _LT_LANG_F77_CONFIG([TAG])
 # --------------------------
 # Ensure that the configuration variables for a Fortran 77 compiler are
 # suitably defined.  These variables are subsequently used by _LT_CONFIG
 # to write the compiler configuration to `libtool'.
 m4_defun([_LT_LANG_F77_CONFIG],
-[AC_REQUIRE([_LT_PROG_F77])dnl
-AC_LANG_PUSH(Fortran 77)
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+  _lt_disable_F77=yes
+fi
 
 _LT_TAGVAR(archive_cmds_need_lc, $1)=no
 _LT_TAGVAR(allow_undefined_flag, $1)=
@@ -6601,6 +6692,8 @@ _LT_TAGVAR(module_cmds, $1)=
 _LT_TAGVAR(module_expsym_cmds, $1)=
 _LT_TAGVAR(link_all_deplibs, $1)=unknown
 _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
 _LT_TAGVAR(no_undefined_flag, $1)=
 _LT_TAGVAR(whole_archive_flag_spec, $1)=
 _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
@@ -6700,32 +6793,17 @@ AC_LANG_POP
 ])# _LT_LANG_F77_CONFIG
 
 
-# _LT_PROG_FC
-# -----------
-# Since AC_PROG_FC is broken, in that it returns the empty string
-# if there is no fortran compiler, we have our own version here.
-m4_defun([_LT_PROG_FC],
-[
-pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes])
-AC_PROG_FC
-if test -z "$FC" || test "X$FC" = "Xno"; then
-  _lt_disable_FC=yes
-fi
-popdef([AC_MSG_ERROR])
-])# _LT_PROG_FC
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([_LT_PROG_FC], [])
-
-
 # _LT_LANG_FC_CONFIG([TAG])
 # -------------------------
 # Ensure that the configuration variables for a Fortran compiler are
 # suitably defined.  These variables are subsequently used by _LT_CONFIG
 # to write the compiler configuration to `libtool'.
 m4_defun([_LT_LANG_FC_CONFIG],
-[AC_REQUIRE([_LT_PROG_FC])dnl
-AC_LANG_PUSH(Fortran)
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+  _lt_disable_FC=yes
+fi
 
 _LT_TAGVAR(archive_cmds_need_lc, $1)=no
 _LT_TAGVAR(allow_undefined_flag, $1)=
@@ -6744,6 +6822,8 @@ _LT_TAGVAR(module_cmds, $1)=
 _LT_TAGVAR(module_expsym_cmds, $1)=
 _LT_TAGVAR(link_all_deplibs, $1)=unknown
 _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
 _LT_TAGVAR(no_undefined_flag, $1)=
 _LT_TAGVAR(whole_archive_flag_spec, $1)=
 _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
@@ -6889,6 +6969,8 @@ _LT_CC_BASENAME([$compiler])
 _LT_TAGVAR(archive_cmds_need_lc, $1)=no
 
 _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
 
 ## CAVEAT EMPTOR:
 ## There is no encapsulation within the following macros, do not change
@@ -7256,7 +7338,7 @@ _LT_EOF
 func_dirname ()
 {
   # Extract subdirectory from the argument.
-  func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
+  func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
   if test "X$func_dirname_result" = "X${1}"; then
     func_dirname_result="${3}"
   else
@@ -7267,7 +7349,7 @@ func_dirname ()
 # func_basename file
 func_basename ()
 {
-  func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
+  func_basename_result=`$ECHO "${1}" | $SED "$basename"`
 }
 
 dnl func_dirname_and_basename
@@ -7283,10 +7365,8 @@ dnl so there is no need for it here.
 func_stripname ()
 {
   case ${2} in
-    .*) func_stripname_result=`$ECHO "X${3}" \
-           | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;;
-    *)  func_stripname_result=`$ECHO "X${3}" \
-           | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;;
+    .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+    *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
   esac
 }
 
@@ -7297,20 +7377,20 @@ my_sed_long_arg='1s/^-[[^=]]*=//'
 # func_opt_split
 func_opt_split ()
 {
-  func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"`
-  func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"`
+  func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"`
+  func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"`
 }
 
 # func_lo2o object
 func_lo2o ()
 {
-  func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"`
+  func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
 }
 
 # func_xform libobj-or-source
 func_xform ()
 {
-  func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'`
+  func_xform_result=`$ECHO "${1}" | $SED 's/\.[[^.]]*$/.lo/'`
 }
 
 # func_arith arithmetic-term...
index 34151a3ba625f326e6645d6afc79586f10746a3e..17cfd51c0b34ed2f118b8b5d4d28947889eec9c3 100644 (file)
@@ -1,13 +1,14 @@
 # Helper functions for option handling.                    -*- Autoconf -*-
 #
-#   Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+#   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+#   Inc.
 #   Written by Gary V. Vaughan, 2004
 #
 # This file is free software; the Free Software Foundation gives
 # unlimited permission to copy and/or distribute it, with or without
 # modifications, as long as this notice is preserved.
 
-# serial 6 ltoptions.m4
+# serial 7 ltoptions.m4
 
 # This is to help aclocal find these macros, as it can't see m4_define.
 AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
@@ -125,7 +126,7 @@ LT_OPTION_DEFINE([LT_INIT], [win32-dll],
 [enable_win32_dll=yes
 
 case $host in
-*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*)
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
   AC_CHECK_TOOL(AS, as, false)
   AC_CHECK_TOOL(DLLTOOL, dlltool, false)
   AC_CHECK_TOOL(OBJDUMP, objdump, false)
@@ -133,13 +134,13 @@ case $host in
 esac
 
 test -z "$AS" && AS=as
-_LT_DECL([], [AS],      [0], [Assembler program])dnl
+_LT_DECL([], [AS],      [1], [Assembler program])dnl
 
 test -z "$DLLTOOL" && DLLTOOL=dlltool
-_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
 
 test -z "$OBJDUMP" && OBJDUMP=objdump
-_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
 ])# win32-dll
 
 AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
index f3c5309802447a3b341b1a2c5e4d74ec138b311a..93fc77124f7297f0486f533e857e981aaccc40c5 100644 (file)
@@ -9,15 +9,15 @@
 
 # Generated from ltversion.in.
 
-# serial 3017 ltversion.m4
+# serial 3175 ltversion.m4
 # This file is part of GNU Libtool
 
-m4_define([LT_PACKAGE_VERSION], [2.2.6b])
-m4_define([LT_PACKAGE_REVISION], [1.3017])
+m4_define([LT_PACKAGE_VERSION], [2.2.10])
+m4_define([LT_PACKAGE_REVISION], [1.3175])
 
 AC_DEFUN([LTVERSION_VERSION],
-[macro_version='2.2.6b'
-macro_revision='1.3017'
+[macro_version='2.2.10'
+macro_revision='1.3175'
 _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
 _LT_DECL(, macro_revision, 0)
 ])
index 637bb2066c425f79faecd6cc9e4e6b5074c6b55c..c573da90c5ccebffba4dce9a6462036bfa986d5f 100644 (file)
@@ -1,13 +1,13 @@
 # lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
 #
-#   Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
+#   Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
 #   Written by Scott James Remnant, 2004.
 #
 # This file is free software; the Free Software Foundation gives
 # unlimited permission to copy and/or distribute it, with or without
 # modifications, as long as this notice is preserved.
 
-# serial 4 lt~obsolete.m4
+# serial 5 lt~obsolete.m4
 
 # These exist entirely to fool aclocal when bootstrapping libtool.
 #
@@ -77,7 +77,6 @@ m4_ifndef([AC_DISABLE_FAST_INSTALL],  [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
 m4_ifndef([_LT_AC_LANG_CXX],           [AC_DEFUN([_LT_AC_LANG_CXX])])
 m4_ifndef([_LT_AC_LANG_F77],           [AC_DEFUN([_LT_AC_LANG_F77])])
 m4_ifndef([_LT_AC_LANG_GCJ],           [AC_DEFUN([_LT_AC_LANG_GCJ])])
-m4_ifndef([AC_LIBTOOL_RC],             [AC_DEFUN([AC_LIBTOOL_RC])])
 m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],  [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
 m4_ifndef([_LT_AC_LANG_C_CONFIG],      [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
 m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],        [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
@@ -90,3 +89,10 @@ m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG],       [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
 m4_ifndef([_LT_AC_LANG_RC_CONFIG],     [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
 m4_ifndef([AC_LIBTOOL_CONFIG],         [AC_DEFUN([AC_LIBTOOL_CONFIG])])
 m4_ifndef([_LT_AC_FILE_LTDLL_C],       [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],        [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP],                [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],        [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH],   [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77],              [AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC],               [AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX],              [AC_DEFUN([_LT_PROG_CXX])])
diff --git a/match.c b/match.c
deleted file mode 100644 (file)
index ba299e1..0000000
--- a/match.c
+++ /dev/null
@@ -1,920 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-2005, 2007-2011
- *     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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_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 */
-#ifdef USING_NONUNIX_GROUPS
-# include "nonunix.h"
-#endif /* USING_NONUNIX_GROUPS */
-
-static struct member_list empty;
-
-static int command_matches_dir __P((char *, size_t));
-static int command_matches_glob __P((char *, char *));
-static int command_matches_fnmatch __P((char *, char *));
-static int command_matches_normal __P((char *, char *));
-
-/*
- * 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 = alias_find(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;
-    int user_matched = UNSPEC;
-    int group_matched = UNSPEC;
-
-    if (runas_pw != NULL) {
-       /* If no runas user or runas group listed in sudoers, use default. */
-       if (tq_empty(user_list) && tq_empty(group_list))
-           return userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw);
-
-       tq_foreach_rev(user_list, m) {
-           switch (m->type) {
-               case ALL:
-                   user_matched = !m->negated;
-                   break;
-               case NETGROUP:
-                   if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name))
-                       user_matched = !m->negated;
-                   break;
-               case USERGROUP:
-                   if (usergr_matches(m->name, runas_pw->pw_name, runas_pw))
-                       user_matched = !m->negated;
-                   break;
-               case ALIAS:
-                   if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
-                       rval = _runaslist_matches(&a->members, &empty);
-                       if (rval != UNSPEC)
-                           user_matched = m->negated ? !rval : rval;
-                       break;
-                   }
-                   /* FALLTHROUGH */
-               case WORD:
-                   if (userpw_matches(m->name, runas_pw->pw_name, runas_pw))
-                       user_matched = !m->negated;
-                   break;
-           }
-           if (user_matched != UNSPEC)
-               break;
-       }
-    }
-
-    if (runas_gr != NULL) {
-       if (user_matched == UNSPEC) {
-           if (runas_pw == NULL || strcmp(runas_pw->pw_name, user_name) == 0)
-               user_matched = ALLOW;   /* only changing group */
-       }
-       tq_foreach_rev(group_list, m) {
-           switch (m->type) {
-               case ALL:
-                   group_matched = !m->negated;
-                   break;
-               case ALIAS:
-                   if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
-                       rval = _runaslist_matches(&a->members, &empty);
-                       if (rval != UNSPEC)
-                           group_matched = m->negated ? !rval : rval;
-                       break;
-                   }
-                   /* FALLTHROUGH */
-               case WORD:
-                   if (group_matches(m->name, runas_gr))
-                       group_matched = !m->negated;
-                   break;
-           }
-           if (group_matched != UNSPEC)
-               break;
-       }
-    }
-
-    if (user_matched == DENY || group_matched == DENY)
-       return DENY;
-    if (user_matched == group_matched || runas_gr == NULL)
-       return user_matched;
-    return UNSPEC;
-}
-
-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 = alias_find(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 matched = UNSPEC;
-
-    tq_foreach_rev(list, m) {
-       matched = cmnd_matches(m);
-       if (matched != UNSPEC)
-           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 = alias_find(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;
-}
-
-static int
-command_args_match(sudoers_cmnd, sudoers_args)
-    char *sudoers_cmnd;
-    char *sudoers_args;
-{
-    int flags = 0;
-
-    /*
-     * If no args specified in sudoers, any user args are allowed.
-     * If the empty string is specified in sudoers, no user args are allowed.
-     */
-    if (!sudoers_args ||
-       (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)))
-       return TRUE;
-    /*
-     * If args are specified in sudoers, they must match the user args.
-     * If running as sudoedit, all args are assumed to be paths.
-     */
-    if (sudoers_args) {
-       /* For sudoedit, all args are assumed to be pathnames. */
-       if (strcmp(sudoers_cmnd, "sudoedit") == 0)
-           flags = FNM_PATHNAME;
-       if (fnmatch(sudoers_args, user_args ? user_args : "", flags) == 0)
-           return TRUE;
-    }
-    return FALSE;
-}
-
-/*
- * 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;
-{
-    /* Check for pseudo-commands */
-    if (sudoers_cmnd[0] != '/') {
-       /*
-        * 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 (command_args_match(sudoers_cmnd, sudoers_args)) {
-           efree(safe_cmnd);
-           safe_cmnd = estrdup(sudoers_cmnd);
-           return TRUE;
-       } else
-           return FALSE;
-    }
-
-    if (has_meta(sudoers_cmnd)) {
-       /*
-        * If sudoers_cmnd has meta characters in it, we need to
-        * use glob(3) and/or fnmatch(3) to do the matching.
-        */
-       if (def_fast_glob)
-           return command_matches_fnmatch(sudoers_cmnd, sudoers_args);
-       return command_matches_glob(sudoers_cmnd, sudoers_args);
-    }
-    return command_matches_normal(sudoers_cmnd, sudoers_args);
-}
-
-static int
-command_matches_fnmatch(sudoers_cmnd, sudoers_args)
-    char *sudoers_cmnd;
-    char *sudoers_args;
-{
-    /*
-     * Return true if fnmatch(3) succeeds 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.
-     */
-    if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0)
-       return FALSE;
-    if (command_args_match(sudoers_cmnd, sudoers_args)) {
-       if (safe_cmnd)
-           free(safe_cmnd);
-       safe_cmnd = estrdup(user_cmnd);
-       return TRUE;
-    } else
-       return FALSE;
-}
-
-static int
-command_matches_glob(sudoers_cmnd, sudoers_args)
-    char *sudoers_cmnd;
-    char *sudoers_args;
-{
-    struct stat sudoers_stat;
-    size_t dlen;
-    char **ap, *base, *cp;
-    glob_t gl;
-
-    /*
-     * 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.
-     */
-    dlen = strlen(sudoers_cmnd);
-    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 || gl.gl_pathc == 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 (command_args_match(sudoers_cmnd, sudoers_args)) {
-       efree(safe_cmnd);
-       safe_cmnd = estrdup(user_cmnd);
-       return TRUE;
-    }
-    return FALSE;
-}
-
-static int
-command_matches_normal(sudoers_cmnd, sudoers_args)
-    char *sudoers_cmnd;
-    char *sudoers_args;
-{
-    struct stat sudoers_stat;
-    char *base;
-    size_t dlen;
-
-    /* If it ends in '/' it is a directory spec. */
-    dlen = strlen(sudoers_cmnd);
-    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 (command_args_match(sudoers_cmnd, sudoers_args)) {
-       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)) {
-       closedir(dirp);
-       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 == NULL ||
-           (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;
-    union sudo_in_addr_un addr;
-    struct interface *ifp;
-#ifdef HAVE_IN6_ADDR
-    int j;
-#endif
-    int family;
-
-#ifdef HAVE_IN6_ADDR
-    if (inet_pton(AF_INET6, n, &addr.ip6) > 0) {
-       family = AF_INET6;
-    } else
-#endif
-    {
-       family = AF_INET;
-       addr.ip4.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.ip4.s_addr ||
-                   (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr)
-                   == addr.ip4.s_addr)
-                   return TRUE;
-               break;
-#ifdef HAVE_IN6_ADDR
-           case AF_INET6:
-               if (memcmp(ifp->addr.ip6.s6_addr, addr.ip6.s6_addr,
-                   sizeof(addr.ip6.s6_addr)) == 0)
-                   return TRUE;
-               for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) {
-                   if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j])
-                       break;
-               }
-               if (j == sizeof(addr.ip6.s6_addr))
-                   return TRUE;
-#endif
-       }
-    }
-
-    return FALSE;
-}
-
-static int
-addr_matches_if_netmask(n, m)
-    char *n;
-    char *m;
-{
-    int i;
-    union sudo_in_addr_un addr, mask;
-    struct interface *ifp;
-#ifdef HAVE_IN6_ADDR
-    int j;
-#endif
-    int family;
-
-#ifdef HAVE_IN6_ADDR
-    if (inet_pton(AF_INET6, n, &addr.ip6) > 0)
-       family = AF_INET6;
-    else
-#endif
-    {
-       family = AF_INET;
-       addr.ip4.s_addr = inet_addr(n);
-    }
-
-    if (family == AF_INET) {
-       if (strchr(m, '.'))
-           mask.ip4.s_addr = inet_addr(m);
-       else {
-           i = 32 - atoi(m);
-           mask.ip4.s_addr = 0xffffffff;
-           mask.ip4.s_addr >>= i;
-           mask.ip4.s_addr <<= i;
-           mask.ip4.s_addr = htonl(mask.ip4.s_addr);
-       }
-    }
-#ifdef HAVE_IN6_ADDR
-    else {
-       if (inet_pton(AF_INET6, m, &mask.ip6) <= 0) {
-           j = atoi(m);
-           for (i = 0; i < 16; i++) {
-               if (j < i * 8)
-                   mask.ip6.s6_addr[i] = 0;
-               else if (i * 8 + 8 <= j)
-                   mask.ip6.s6_addr[i] = 0xff;
-               else
-                   mask.ip6.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.ip4.s_addr) == addr.ip4.s_addr)
-                   return TRUE;
-#ifdef HAVE_IN6_ADDR
-           case AF_INET6:
-               for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) {
-                   if ((ifp->addr.ip6.s6_addr[j] & mask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j])
-                       break;
-               }
-               if (j == sizeof(addr.ip6.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.
- */
-int
-usergr_matches(group, user, pw)
-    char *group;
-    char *user;
-    struct passwd *pw;
-{
-    int matched = FALSE;
-    struct passwd *pw0 = NULL;
-
-    /* make sure we have a valid usergroup, sudo style */
-    if (*group++ != '%')
-       goto done;
-
-#ifdef USING_NONUNIX_GROUPS
-    if (*group == ':') {
-       matched = sudo_nonunix_groupcheck(++group, user, pw);
-       goto done;
-    }
-#endif /* USING_NONUNIX_GROUPS */
-
-    /* look up user's primary gid in the passwd file */
-    if (pw == NULL) {
-       if ((pw0 = sudo_getpwnam(user)) == NULL)
-           goto done;
-       pw = pw0;
-    }
-
-    if (user_in_group(pw, group)) {
-       matched = TRUE;
-       goto done;
-    }
-
-#ifdef USING_NONUNIX_GROUPS
-    /* not a Unix group, could be an AD group */
-    if (sudo_nonunix_groupcheck_available() &&
-       sudo_nonunix_groupcheck(group, user, pw)) {
-       matched = TRUE;
-       goto done;
-    }
-#endif /* USING_NONUNIX_GROUPS */
-
-done:
-    if (pw0 != NULL)
-       pw_delref(pw0);
-
-    return matched;
-}
-
-/*
- * 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;
-}
diff --git a/memrchr.c b/memrchr.c
deleted file mode 100644 (file)
index 425fcb4..0000000
--- a/memrchr.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-
-#include "missing.h"
-
-/*
- * Reverse memchr()
- * Find the last occurrence of 'c' in the buffer 's' of size 'n'.
- */
-void *
-memrchr(s, c, n)
-    const void *s;
-    int c;
-    size_t n;
-{
-    const unsigned char *cp;
-
-    if (n != 0) {
-       cp = (unsigned char *)s + n;
-       do {
-           if (*(--cp) == (unsigned char)c)
-               return (void *)cp;
-       } while (--n != 0);
-    }
-    return (void *)0;
-}
diff --git a/missing.h b/missing.h
deleted file mode 100644 (file)
index 7b2d29d..0000000
--- a/missing.h
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-2005, 2008-2010
- *     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.
- */
-
-#ifndef _SUDO_MISSING_H
-#define _SUDO_MISSING_H
-
-#include <stdio.h>
-#ifdef __STDC__
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
-
-/*
- * Macros that may be missing on some Operating Systems
- */
-
-/* Deal with ANSI stuff reasonably.  */
-#ifndef  __P
-# if defined (__cplusplus) || defined (__STDC__)
-#  define __P(args)            args
-# else
-#  define __P(args)            ()
-# endif
-#endif /* __P */
-
-/* Define away __attribute__ for non-gcc or old gcc */
-#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__))
-# else
-#  define __unused
-# endif
-#endif
-
-/* 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)))
-# else
-#  define __printflike(f, v)
-# endif
-#endif
-
-/*
- * Some systems lack full limit definitions.
- */
-#ifndef OPEN_MAX
-# define OPEN_MAX      256
-#endif
-
-#ifndef INT_MAX
-# define INT_MAX       0x7fffffff
-#endif
-
-#ifndef PATH_MAX
-# ifdef MAXPATHLEN
-#  define PATH_MAX             MAXPATHLEN
-# else
-#  ifdef _POSIX_PATH_MAX
-#   define PATH_MAX            _POSIX_PATH_MAX
-#  else
-#   define PATH_MAX            1024
-#  endif
-# endif
-#endif
-
-#ifndef MAXHOSTNAMELEN
-# define MAXHOSTNAMELEN                64
-#endif
-
-/*
- * Posix versions for those without...
- */
-#ifndef _S_IFMT
-# define _S_IFMT               S_IFMT
-#endif /* _S_IFMT */
-#ifndef _S_IFREG
-# define _S_IFREG              S_IFREG
-#endif /* _S_IFREG */
-#ifndef _S_IFDIR
-# define _S_IFDIR              S_IFDIR
-#endif /* _S_IFDIR */
-#ifndef _S_IFLNK
-# define _S_IFLNK              S_IFLNK
-#endif /* _S_IFLNK */
-#ifndef S_ISREG
-# define S_ISREG(m)            (((m) & _S_IFMT) == _S_IFREG)
-#endif /* S_ISREG */
-#ifndef S_ISDIR
-# define S_ISDIR(m)            (((m) & _S_IFMT) == _S_IFDIR)
-#endif /* S_ISDIR */
-
-/*
- * Some OS's may not have this.
- */
-#ifndef S_IRWXU
-# define S_IRWXU               0000700         /* rwx for owner */
-#endif /* S_IRWXU */
-
-/*
- * These should be defined in <unistd.h> but not everyone has them.
- */
-#ifndef STDIN_FILENO
-# define       STDIN_FILENO    0
-#endif
-#ifndef STDOUT_FILENO
-# define       STDOUT_FILENO   1
-#endif
-#ifndef STDERR_FILENO
-# define       STDERR_FILENO   2
-#endif
-
-/*
- * These should be defined in <unistd.h> but not everyone has them.
- */
-#ifndef SEEK_SET
-# define       SEEK_SET        0
-#endif
-#ifndef SEEK_CUR
-# define       SEEK_CUR        1
-#endif
-#ifndef SEEK_END
-# define       SEEK_END        2
-#endif
-
-/*
- * BSD defines these in <sys/param.h> but others may not.
- */
-#ifndef MIN
-# define MIN(a,b) (((a)<(b))?(a):(b))
-#endif
-#ifndef MAX
-# define MAX(a,b) (((a)>(b))?(a):(b))
-#endif
-
-/*
- * Simple isblank() macro and function for systems without it.
- */
-#ifndef HAVE_ISBLANK
-int isblank __P((int));
-# define isblank(_x)   ((_x) == ' ' || (_x) == '\t')
-#endif
-
-/*
- * Old BSD systems lack strchr(), strrchr(), memset() and memcpy()
- */
-#if !defined(HAVE_STRCHR) && !defined(strchr)
-# define strchr(_s, _c)        index(_s, _c)
-#endif
-#if !defined(HAVE_STRRCHR) && !defined(strrchr)
-# define strrchr(_s, _c)       rindex(_s, _c)
-#endif
-#if !defined(HAVE_MEMCPY) && !defined(memcpy)
-# define memcpy(_d, _s, _n)    (bcopy(_s, _d, _n))
-#endif
-#if !defined(HAVE_MEMSET) && !defined(memset)
-# define memset(_s, _x, _n)    (bzero(_s, _n))
-#endif
-
-/*
- * NCR's SVr4 has _innetgr(3) instead of innetgr(3) for some reason.
- */
-#ifdef HAVE__INNETGR
-# define innetgr(n, h, u, d)   (_innetgr(n, h, u, d))
-# define HAVE_INNETGR 1
-#endif /* HAVE__INNETGR */
-
-/*
- * On POSIX systems, O_NOCTTY is the default so some OS's may lack this define.
- */
-#ifndef O_NOCTTY
-# define O_NOCTTY      0
-#endif /* O_NOCTTY */
-
-/*
- * Emulate POSIX signals via sigvec(2)
- */
-#ifndef HAVE_SIGACTION
-# define SA_ONSTACK    SV_ONSTACK
-# define SA_RESTART    SV_INTERRUPT            /* opposite effect */
-# define SA_RESETHAND  SV_RESETHAND
-# define sa_handler    sv_handler
-# define sa_mask       sv_mask
-# define sa_flags      sv_flags
-typedef struct sigvec sigaction_t;
-typedef int sigset_t;
-int sigaction __P((int sig, const sigaction_t *act, sigaction_t *oact));
-int sigemptyset __P((sigset_t *));
-int sigfillset __P((sigset_t *));
-int sigaddset __P((sigset_t *, int));
-int sigdelset __P((sigset_t *, int));
-int sigismember __P((sigset_t *, int));
-int sigprocmask __P((int, const sigset_t *, sigset_t *));
-#endif
-
-/*
- * Extra sugar for POSIX signals to deal with the above emulation
- * as well as the fact that SunOS has a SA_INTERRUPT flag.
- */
-#ifdef HAVE_SIGACTION
-# ifndef HAVE_SIGACTION_T
-typedef struct sigaction sigaction_t;
-# endif
-# ifndef SA_INTERRUPT
-#  define SA_INTERRUPT 0
-# endif
-# ifndef SA_RESTART
-#  define SA_RESTART   0
-# endif
-#endif
-
-/*
- * If dirfd() does not exists, hopefully dd_fd does.
- */
-#if !defined(HAVE_DIRFD) && defined(HAVE_DD_FD)
-# define dirfd(_d)     ((_d)->dd_fd)
-# define HAVE_DIRFD
-#endif
-
-/*
- * Define futimes() in terms of futimesat() if needed.
- */
-#if !defined(HAVE_FUTIMES) && defined(HAVE_FUTIMESAT)
-# define futimes(_f, _tv)      futimesat(_f, NULL, _tv)
-# define HAVE_FUTIMES
-#endif
-
-#if !defined(HAVE_KILLPG) && !defined(killpg)
-# define killpg(s)     kill(-(s))
-#endif
-
-/*
- * If we lack getprogname(), emulate with __progname if possible.
- * Otherwise, add a prototype for use with our own getprogname.c.
- */
-#ifndef HAVE_GETPROGNAME
-# ifdef HAVE___PROGNAME
-extern const char *__progname;
-#  define getprogname()          (__progname)
-# else
-const char *getprogname __P((void));
-#endif /* HAVE___PROGNAME */
-#endif /* !HAVE_GETPROGNAME */
-
-#ifndef timevalclear
-# define timevalclear(tv)      ((tv)->tv_sec = (tv)->tv_usec = 0)
-#endif
-#ifndef timevalisset
-# define timevalisset(tv)      ((tv)->tv_sec || (tv)->tv_usec)
-#endif
-#ifndef timevalcmp
-# define timevalcmp(tv1, tv2, op)                                             \
-    (((tv1)->tv_sec == (tv2)->tv_sec) ?                                               \
-       ((tv1)->tv_usec op (tv2)->tv_usec) :                                   \
-       ((tv1)->tv_sec op (tv2)->tv_sec))
-#endif
-#ifndef timevaladd
-# define timevaladd(tv1, tv2)                                                 \
-    do {                                                                      \
-       (tv1)->tv_sec += (tv2)->tv_sec;                                        \
-       (tv1)->tv_usec += (tv2)->tv_usec;                                      \
-       if ((tv1)->tv_usec >= 1000000) {                                       \
-           (tv1)->tv_sec++;                                                   \
-           (tv1)->tv_usec -= 1000000;                                         \
-       }                                                                      \
-    } while (0)
-#endif
-#ifndef timevalsub
-# define timevalsub(tv1, tv2)                                                 \
-    do {                                                                      \
-       (tv1)->tv_sec -= (tv2)->tv_sec;                                        \
-       (tv1)->tv_usec -= (tv2)->tv_usec;                                      \
-       if ((tv1)->tv_usec < 0) {                                              \
-           (tv1)->tv_sec--;                                                   \
-           (tv1)->tv_usec += 1000000;                                         \
-       }                                                                      \
-    } while (0)
-#endif
-
-/* Not all systems define NSIG in signal.h */
-#if !defined(NSIG)
-# if defined(_NSIG)
-#  define NSIG _NSIG
-# elif defined(__NSIG)
-#  define NSIG __NSIG
-# else
-#  define NSIG 64
-# endif
-#endif
-
-#ifndef WCOREDUMP
-# define WCOREDUMP(x)  ((x) & 0x80)
-#endif
-
-/*
- * HP-UX does not declare innetgr() or getdomainname().
- * Solaris does not declare getdomainname().
- */
-#if defined(__hpux)
-int innetgr __P((const char *, const char *, const char *, const char *));
-#endif
-#if defined(__hpux) || defined(__sun)
-int getdomainname __P((char *, size_t));
-#endif
-
-/* Functions "missing" from libc. */
-
-struct timeval;
-struct timespec;
-
-#ifndef HAVE_CLOSEFROM
-void closefrom         __P((int));
-#endif
-#ifndef HAVE_GETCWD
-char *getcwd           __P((char *, size_t size));
-#endif
-#ifndef HAVE_GETLINE
-ssize_t getline                __P((char **, size_t *, FILE *));
-#endif
-#ifndef HAVE_UTIMES
-int utimes             __P((const char *, const struct timeval *));
-#endif
-#ifdef HAVE_FUTIME
-int futimes            __P((int, const struct timeval *));
-#endif
-#ifndef HAVE_SNPRINTF
-int snprintf           __P((char *, size_t, const char *, ...))
-                           __printflike(3, 4);
-#endif
-#ifndef HAVE_VSNPRINTF
-int vsnprintf          __P((char *, size_t, const char *, va_list))
-                           __printflike(3, 0);
-#endif
-#ifndef HAVE_ASPRINTF
-int asprintf           __P((char **, const char *, ...))
-                           __printflike(2, 3);
-#endif
-#ifndef HAVE_VASPRINTF
-int vasprintf          __P((char **, const char *, va_list))
-                           __printflike(2, 0);
-#endif
-#ifndef HAVE_STRCASECMP
-int strcasecmp         __P((const char *, const char *));
-#endif
-#ifndef HAVE_STRLCAT
-size_t strlcat         __P((char *, const char *, size_t));
-#endif
-#ifndef HAVE_STRLCPY
-size_t strlcpy         __P((char *, const char *, size_t));
-#endif
-#ifndef HAVE_MEMRCHR
-void *memrchr          __P((const void *, int, size_t));
-#endif
-#ifndef HAVE_MKSTEMPS
-int mkstemps           __P((char *, int));
-#endif
-#ifndef HAVE_NANOSLEEP
-int nanosleep          __P((const struct timespec *, struct timespec *));
-#endif
-#ifndef HAVE_SETENV
-int setenv             __P((const char *, const char *, int));
-#endif
-#ifndef HAVE_UNSETENV
-int unsetenv           __P((const char *));
-#endif
-#ifndef HAVE_STRSIGNAL
-char *strsignal                __P((int));
-#endif
-#ifndef HAVE_SETSID
-pid_t setsid           __P((void));
-#endif
-
-#endif /* _SUDO_MISSING_H */
diff --git a/mkdefaults b/mkdefaults
deleted file mode 100755 (executable)
index 90f3b0c..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-#!/usr/bin/perl -w
-#
-# Generate sudo_defs_table and associated defines
-#
-# Input should be formatted thusly:
-#
-# var_name
-#      TYPE
-#      description (or NULL)
-#      array of struct def_values if TYPE == T_TUPLE
-
-# Deal with optional -o (output) argument
-if ($#ARGV > 0 && $ARGV[0] eq "-o") {
-    shift;
-    $header = $cfile = shift;
-    $header .= '.h';
-    $cfile .= '.c';
-}
-die "usage: $0 [input_file]\n" unless $#ARGV == -1 || $#ARGV == 0;
-
-$infile = $ARGV[0] || "def_data.in";
-if (!defined($header)) {
-    $header = $infile;
-    $header =~ s/(\.in)?$/.h/;
-}
-if (!defined($cfile)) {
-    $cfile = $infile;
-    $cfile =~ s/(\.in)?$/.c/;
-}
-
-open(IN, "<$infile") || die "$0: can't open $infile: $!\n";
-open(HEADER, ">$header") || die "$0: can't open $header: $!\n";
-open(CFILE, ">$cfile") || die "$0: can't open $cfile: $!\n";
-
-$count = 0;
-@tuple_values = ( "never" );
-@records = ();
-while(<IN>) {
-    chomp;
-    s/\s*#.*$//;
-    next if /^\s*$/;
-
-    if (/^\S/) {
-       # Store previous record and begin new one
-       $records[$count++] = [$var, $type, $desc, $values, $callback] if defined($var);
-
-       $var = $_;
-       $type = '';
-       $desc = undef;
-       $values = undef;
-       $callback = undef;
-       $field = 0;
-    } else {
-       $field++;
-       s/^\s+//;
-       s/\s+$//;
-       if ($field == 1) {
-           # type
-           $type = $_;
-       } elsif ($field == 2) {
-           # description
-           if ($_ eq "NULL") {
-               $desc = "NULL";
-           } else {
-               # Strip leading and trailing double quote and escape the rest
-               s/^"//;
-               s/"$//;
-               s/"/\\"/g;
-               $desc = "\"$_\"";
-           }
-       } elsif ($field == 3 || $field == 4) {
-           if (s/^\*//) {
-               $callback = $_;
-           } else {
-               die "$0: syntax error near line $.\n" if $type !~ /^T_TUPLE/;
-               $values = [ split ];
-               foreach $v (@$values) {
-                   push(@tuple_values, $v) unless grep(/^$v$/, @tuple_values);
-               }
-           }
-       } else {
-           die "$0: syntax error near line $.\n";
-       }
-    }
-}
-$records[$count++] = [$var, $type, $desc, $values, $callback] if defined($var);
-
-# Print out value arrays
-for ($i = 0; $i < $count; $i++) {
-    if (defined($records[$i]->[3])) {
-       die "Values list specified for non-tupple\n" unless
-           $records[$i]->[1] =~ /^T_TUPLE/;
-       printf CFILE "static struct def_values def_data_%s[] = {\n", $records[$i]->[0];
-       foreach (@{$records[$i]->[3]}) {
-           print CFILE "    { \"$_\", $_ },\n";
-       }
-       print CFILE "    { NULL, 0 },\n";
-       print CFILE "};\n\n";
-    }
-}
-
-# Print each record
-print CFILE "struct sudo_defs_types sudo_defs_table[] = {\n    {\n";
-for ($i = 0; $i < $count; $i++) {
-    &print_record($records[$i], $i);
-}
-print CFILE "\tNULL, 0, NULL\n    }\n};\n";
-
-# Print out def_tuple
-if (@tuple_values) {
-    print HEADER "\nenum def_tupple {\n";
-    for ($i = 0; $i <= $#tuple_values; $i++) {
-       printf HEADER "\t%s%s\n", $tuple_values[$i],
-           $i != $#tuple_values ? "," : "";
-    }
-    print HEADER "};\n";
-}
-
-close(IN);
-close(HEADER);
-close(CFILE);
-
-sub print_record {
-    my ($rec, $recnum) = @_;
-    my ($i, $v, $defname);
-    # each variable gets a macro to access its value
-    for ($rec->[1]) {
-       if    (/^T_U?INT/)  { $v = "ival"; }
-       elsif (/^T_STR/)    { $v = "str"; }
-       elsif (/^T_FLAG/)   { $v = "flag"; }
-       elsif (/^T_MODE/)   { $v = "mode"; }
-       elsif (/^T_LIST/)   { $v = "list"; }
-       elsif (/^T_LOGFAC/) { $v = "ival"; }
-       elsif (/^T_LOGPRI/) { $v = "ival"; }
-       elsif (/^T_TUPLE/)  { $v = "tuple"; }
-       elsif (/^T_FLOAT/)  { $v = "fval"; }
-       else { die "$0: unknown defaults type: $_\n"; }
-    }
-    printf HEADER "#define %-23s (sudo_defs_table[$recnum].sd_un.${v})\n",
-       "def_$rec->[0]";
-
-    $defname = "I_" . uc($rec->[0]);
-    printf HEADER "#define %-24s%d", $defname, $recnum;
-    #print HEADER "\t/* $rec->[2] */" if defined($rec->[2]);
-    print HEADER "\n";
-
-    print CFILE "\t\"$rec->[0]\", $rec->[1],\n\t$rec->[2],\n";
-    if (defined($rec->[3])) {
-       printf CFILE "\tdef_data_$rec->[0],\n";
-    } else {
-       printf CFILE "\tNULL,\n";
-    }
-    printf CFILE "\t$rec->[4],\n" if defined($rec->[4]);
-    print CFILE "    }, {\n";
-}
diff --git a/mksiglist.c b/mksiglist.c
deleted file mode 100644 (file)
index f5cfbc1..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2010 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 <stdio.h>
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif /* STDC_HEADERS */
-#include <signal.h>
-
-#include "missing.h"
-
-int
-main(argc, argv)
-    int argc;
-    char *argv[];
-{
-    static char *my_sys_siglist[NSIG];
-    int i;
-
-#include "mksiglist.h"
-
-    printf("#include <config.h>\n");
-    printf("#include <signal.h>\n");
-    printf("#include \"missing.h\"\n\n");
-    printf("const char *const my_sys_siglist[NSIG] = {\n");
-    for (i = 0; i < NSIG; i++) {
-       if (my_sys_siglist[i] != NULL) {
-           printf("    \"%s\",\n", my_sys_siglist[i]);
-       } else {
-           printf("    \"Signal %d\",\n", i);
-       }
-    }
-    printf("};\n");
-
-    exit(0);
-}
diff --git a/mksiglist.h b/mksiglist.h
deleted file mode 100644 (file)
index f9f3294..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/* public domain */
-
-#ifdef SIGHUP
-    if (my_sys_siglist[SIGHUP] == NULL)
-       my_sys_siglist[SIGHUP] = "Hangup";
-#endif
-#ifdef SIGINT
-    if (my_sys_siglist[SIGINT] == NULL)
-       my_sys_siglist[SIGINT] = "Interrupt";
-#endif
-#ifdef SIGQUIT
-    if (my_sys_siglist[SIGQUIT] == NULL)
-       my_sys_siglist[SIGQUIT] = "Quit";
-#endif
-#ifdef SIGILL
-    if (my_sys_siglist[SIGILL] == NULL)
-       my_sys_siglist[SIGILL] = "Illegal instruction";
-#endif
-#ifdef SIGTRAP
-    if (my_sys_siglist[SIGTRAP] == NULL)
-       my_sys_siglist[SIGTRAP] = "Trace trap";
-#endif
-#ifdef SIGABRT
-    if (my_sys_siglist[SIGABRT] == NULL)
-       my_sys_siglist[SIGABRT] = "Abort";
-#endif
-#ifdef SIGIOT
-    if (my_sys_siglist[SIGIOT] == NULL)
-       my_sys_siglist[SIGIOT] = "IOT instruction";
-#endif
-#ifdef SIGEMT
-    if (my_sys_siglist[SIGEMT] == NULL)
-       my_sys_siglist[SIGEMT] = "EMT trap";
-#endif
-#ifdef SIGFPE
-    if (my_sys_siglist[SIGFPE] == NULL)
-       my_sys_siglist[SIGFPE] = "Floating point exception";
-#endif
-#ifdef SIGKILL
-    if (my_sys_siglist[SIGKILL] == NULL)
-       my_sys_siglist[SIGKILL] = "Killed";
-#endif
-#ifdef SIGUNUSED
-    if (my_sys_siglist[SIGUNUSED] == NULL)
-       my_sys_siglist[SIGUNUSED] = "Unused";
-#endif
-#ifdef SIGBUS
-    if (my_sys_siglist[SIGBUS] == NULL)
-       my_sys_siglist[SIGBUS] = "Bus error";
-#endif
-#ifdef SIGSEGV
-    if (my_sys_siglist[SIGSEGV] == NULL)
-       my_sys_siglist[SIGSEGV] = "Memory fault";
-#endif
-#ifdef SIGSYS
-    if (my_sys_siglist[SIGSYS] == NULL)
-       my_sys_siglist[SIGSYS] = "Bad system call";
-#endif
-#ifdef SIGPIPE
-    if (my_sys_siglist[SIGPIPE] == NULL)
-       my_sys_siglist[SIGPIPE] = "Broken pipe";
-#endif
-#ifdef SIGALRM
-    if (my_sys_siglist[SIGALRM] == NULL)
-       my_sys_siglist[SIGALRM] = "Alarm clock";
-#endif
-#ifdef SIGTERM
-    if (my_sys_siglist[SIGTERM] == NULL)
-       my_sys_siglist[SIGTERM] = "Terminated";
-#endif
-#ifdef SIGSTKFLT
-    if (my_sys_siglist[SIGSTKFLT] == NULL)
-       my_sys_siglist[SIGSTKFLT] = "Stack fault";
-#endif
-#ifdef SIGIO
-    if (my_sys_siglist[SIGIO] == NULL)
-       my_sys_siglist[SIGIO] = "I/O possible";
-#endif
-#ifdef SIGXCPU
-    if (my_sys_siglist[SIGXCPU] == NULL)
-       my_sys_siglist[SIGXCPU] = "CPU time limit exceeded";
-#endif
-#ifdef SIGXFSZ
-    if (my_sys_siglist[SIGXFSZ] == NULL)
-       my_sys_siglist[SIGXFSZ] = "File size limit exceeded";
-#endif
-#ifdef SIGVTALRM
-    if (my_sys_siglist[SIGVTALRM] == NULL)
-       my_sys_siglist[SIGVTALRM] = "Virtual timer expired";
-#endif
-#ifdef SIGPROF
-    if (my_sys_siglist[SIGPROF] == NULL)
-       my_sys_siglist[SIGPROF] = "Profiling timer expired";
-#endif
-#ifdef SIGWINCH
-    if (my_sys_siglist[SIGWINCH] == NULL)
-       my_sys_siglist[SIGWINCH] = "Window size change";
-#endif
-#ifdef SIGLOST
-    if (my_sys_siglist[SIGLOST] == NULL)
-       my_sys_siglist[SIGLOST] = "File lock lost";
-#endif
-#ifdef SIGUSR1
-    if (my_sys_siglist[SIGUSR1] == NULL)
-       my_sys_siglist[SIGUSR1] = "User defined signal 1";
-#endif
-#ifdef SIGUSR2
-    if (my_sys_siglist[SIGUSR2] == NULL)
-       my_sys_siglist[SIGUSR2] = "User defined signal 2";
-#endif
-#ifdef SIGPWR
-    if (my_sys_siglist[SIGPWR] == NULL)
-       my_sys_siglist[SIGPWR] = "Power-fail/Restart";
-#endif
-#ifdef SIGPOLL
-    if (my_sys_siglist[SIGPOLL] == NULL)
-       my_sys_siglist[SIGPOLL] = "Pollable event occurred";
-#endif
-#ifdef SIGSTOP
-    if (my_sys_siglist[SIGSTOP] == NULL)
-       my_sys_siglist[SIGSTOP] = "Stopped (signal)";
-#endif
-#ifdef SIGTSTP
-    if (my_sys_siglist[SIGTSTP] == NULL)
-       my_sys_siglist[SIGTSTP] = "Stopped";
-#endif
-#ifdef SIGCONT
-    if (my_sys_siglist[SIGCONT] == NULL)
-       my_sys_siglist[SIGCONT] = "Continued";
-#endif
-#ifdef SIGCHLD
-    if (my_sys_siglist[SIGCHLD] == NULL)
-       my_sys_siglist[SIGCHLD] = "Child exited";
-#endif
-#ifdef SIGCLD
-    if (my_sys_siglist[SIGCLD] == NULL)
-       my_sys_siglist[SIGCLD] = "Child exited";
-#endif
-#ifdef SIGTTIN
-    if (my_sys_siglist[SIGTTIN] == NULL)
-       my_sys_siglist[SIGTTIN] = "Stopped (tty input)";
-#endif
-#ifdef SIGTTOU
-    if (my_sys_siglist[SIGTTOU] == NULL)
-       my_sys_siglist[SIGTTOU] = "Stopped (tty output)";
-#endif
-#ifdef SIGINFO
-    if (my_sys_siglist[SIGINFO] == NULL)
-       my_sys_siglist[SIGINFO] = "Information request";
-#endif
-#ifdef SIGURG
-    if (my_sys_siglist[SIGURG] == NULL)
-       my_sys_siglist[SIGURG] = "Urgent I/O condition";
-#endif
-#ifdef SIGWAITING
-    if (my_sys_siglist[SIGWAITING] == NULL)
-       my_sys_siglist[SIGWAITING] = "No runnable LWPs";
-#endif
-#ifdef SIGLWP
-    if (my_sys_siglist[SIGLWP] == NULL)
-       my_sys_siglist[SIGLWP] = "Inter-LWP signal";
-#endif
-#ifdef SIGFREEZE
-    if (my_sys_siglist[SIGFREEZE] == NULL)
-       my_sys_siglist[SIGFREEZE] = "Checkpoint freeze";
-#endif
-#ifdef SIGTHAW
-    if (my_sys_siglist[SIGTHAW] == NULL)
-       my_sys_siglist[SIGTHAW] = "Checkpoint thaw";
-#endif
-#ifdef SIGCANCEL
-    if (my_sys_siglist[SIGCANCEL] == NULL)
-       my_sys_siglist[SIGCANCEL] = "Thread cancellation";
-#endif
diff --git a/mkstemps.c b/mkstemps.c
deleted file mode 100644 (file)
index b3b688d..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2001, 2003, 2004, 2008-2010
- *     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/time.h>
-#include <sys/stat.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif /* HAVE_STDLIB_H */
-#include <ctype.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-
-#include "sudo.h"
-
-static unsigned int get_random __P((void));
-static void seed_random __P((void));
-
-#define TEMPCHARS      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
-#define NUM_CHARS      (sizeof(TEMPCHARS) - 1)
-
-#ifndef INT_MAX
-#define INT_MAX        0x7fffffff
-#endif
-
-int
-mkstemps(path, slen)
-       char *path;
-       int slen;
-{
-       char *start, *cp, *ep;
-       const char *tempchars = TEMPCHARS;
-       unsigned int r, tries;
-       int fd;
-
-       for (ep = path; *ep; ep++)
-               ;
-       if (path + slen >= ep) {
-               errno = EINVAL;
-               return -1;
-       }
-       ep -= slen;
-
-       tries = 1;
-       for (start = ep; start > path && start[-1] == 'X'; start--) {
-               if (tries < INT_MAX / NUM_CHARS)
-                       tries *= NUM_CHARS;
-       }
-       tries *= 2;
-
-       do {
-               for (cp = start; *cp; cp++) {
-                       r = get_random() % NUM_CHARS;
-                       *cp = tempchars[r];
-               }
-
-               fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
-               if (fd != -1 || errno != EEXIST)
-                       return fd;
-       } while (--tries);
-
-       errno = EEXIST;
-       return -1;
-}
-
-#ifdef HAVE_RANDOM
-# define RAND          random
-# define SRAND         srandom
-# define SEED_T                unsigned int
-#else
-# ifdef HAVE_LRAND48
-#  define RAND         lrand48
-#  define SRAND                srand48
-#  define SEED_T       long
-# else
-#  define RAND         rand
-#  define SRAND                srand
-#  define SEED_T       unsigned int
-# endif
-#endif
-
-static void
-seed_random()
-{
-       SEED_T seed;
-       struct timeval tv;
-
-       /*
-        * Seed from time of day and process id multiplied by small primes.
-        */
-       (void) gettime(&tv);
-       seed = (tv.tv_sec % 10000) * 523 + tv.tv_usec * 13 +
-           (getpid() % 1000) * 983;
-       SRAND(seed);
-}
-
-static unsigned int
-get_random()
-{
-       static int initialized;
-
-       if (!initialized) {
-               seed_random();
-               initialized = 1;
-       }
-
-       return RAND() & 0xffffffff;
-}
diff --git a/nanosleep.c b/nanosleep.c
deleted file mode 100644 (file)
index 1849eb2..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2009-2010 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/time.h>
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif /* HAVE_SYS_SELECT_H */
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-#ifndef HAVE_TIMESPEC
-# include "emul/timespec.h"
-#endif
-#include <errno.h>
-
-#include "missing.h"
-
-int
-nanosleep(ts, rts)
-    const struct timespec *ts;
-    struct timespec *rts;
-{
-    struct timeval timeout, endtime, now;
-    int rval;
-
-    timeout.tv_sec = ts->tv_sec;
-    timeout.tv_usec = ts->tv_nsec / 1000;
-    if (rts != NULL) {
-       gettimeofday(&endtime, NULL);
-       timevaladd(&endtime, &timeout);
-    }
-    rval = select(0, NULL, NULL, NULL, &timeout);
-    if (rts != NULL && rval == -1 && errno == EINTR) {
-       gettimeofday(&now, NULL);
-       timevalsub(&endtime, &now);
-       rts->tv_sec = endtime.tv_sec;
-       rts->tv_nsec = endtime.tv_usec * 1000;
-    }
-    return rval;
-}
diff --git a/nonunix.h b/nonunix.h
deleted file mode 100644 (file)
index 09de9d2..0000000
--- a/nonunix.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * (c) 2006 Quest Software, Inc.  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. Neither the name of Quest Software, Inc. 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 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. 
- */
-
-#ifndef _NONUNIX_H
-#define _NONUNIX_H
-
-void
-sudo_nonunix_groupcheck_init(void);
-
-void
-sudo_nonunix_groupcheck_cleanup(void);
-
-int
-sudo_nonunix_groupcheck( const char* group, const char* user, const struct passwd* pwd );
-
-int
-sudo_nonunix_groupcheck_available(void);
-
-#endif /* _NONUNIX_H */
diff --git a/parse.c b/parse.c
deleted file mode 100644 (file)
index acf8e5f..0000000
--- a/parse.c
+++ /dev/null
@@ -1,684 +0,0 @@
-/*
- * Copyright (c) 2004-2005, 2007-2010 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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <ctype.h>
-#include <pwd.h>
-#include <grp.h>
-
-#include "sudo.h"
-#include "parse.h"
-#include "lbuf.h"
-#include <gram.h>
-
-/* 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
-};
-
-/*
- * Parser externs.
- */
-extern FILE *yyin;
-extern char *errorfile;
-extern int errorlineno, parse_error;
-
-/*
- * Local prototypes.
- */
-static void print_member       __P((struct lbuf *, char *, int, int, int));
-static int display_bound_defaults __P((int, struct lbuf *));
-
-int
-sudo_file_open(nss)
-    struct sudo_nss *nss;
-{
-    if (def_ignore_local_sudoers)
-       return -1;
-    nss->handle = open_sudoers(_PATH_SUDOERS, FALSE, NULL);
-    return nss->handle ? 0 : -1;
-}
-
-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;
-}
-
-/*
- * 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;
-}
-
-/*
- * Wrapper around update_defaults() for nsswitch code.
- */
-int
-sudo_file_setdefs(nss)
-    struct sudo_nss *nss;
-{
-    if (nss->handle == NULL)
-       return -1;
-
-    if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER))
-       return -1;
-    return 0;
-}
-
-/*
- * 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;
-
-    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.
-     */
-    if (pwflag) {
-       int nopass;
-       enum def_tupple pwcheck;
-
-       pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
-       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;
-               }
-           }
-       }
-       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;
-    }
-
-    /* Need to be runas user while stat'ing things. */
-    set_perms(PERM_RUNAS);
-
-    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
-               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 = 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;
-                   }
-               }
-           }
-       }
-    }
-    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;
-           if (tags->log_input != UNSPEC)
-               def_log_input = tags->log_input;
-           if (tags->log_output != UNSPEC)
-               def_log_output = tags->log_output;
-       }
-    } else if (match == DENY) {
-       SET(validated, VALIDATE_NOT_OK);
-       CLR(validated, VALIDATE_OK);
-    }
-    set_perms(PERM_ROOT);
-    return validated;
-}
-
-#define        TAG_CHANGED(t) \
-       (cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags->t)
-
-static void
-sudo_file_append_cmnd(cs, tags, lbuf)
-    struct cmndspec *cs;
-    struct cmndtag *tags;
-    struct lbuf *lbuf;
-{
-    struct member *m;
-
-#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;
-    }
-    if (TAG_CHANGED(log_input)) {
-       lbuf_append(lbuf, cs->tags.log_input ? "LOG_INPUT: " :
-           "NOLOG_INPUT: ", NULL);
-       tags->log_input = cs->tags.log_input;
-    }
-    if (TAG_CHANGED(log_output)) {
-       lbuf_append(lbuf, cs->tags.log_output ? "LOG_OUTPUT: " :
-           "NOLOG_OUTPUT: ", NULL);
-       tags->log_output = cs->tags.log_output;
-    }
-    m = cs->cmnd;
-    print_member(lbuf, m->name, m->type, m->negated,
-       CMNDALIAS);
-}
-
-static int
-sudo_file_display_priv_short(pw, us, lbuf)
-    struct passwd *pw;
-    struct userspec *us;
-    struct lbuf *lbuf;
-{
-    struct cmndspec *cs;
-    struct member *m;
-    struct privilege *priv;
-    struct cmndtag tags;
-    int nfound = 0;
-
-    tq_foreach_fwd(&us->privileges, priv) {
-       if (hostlist_matches(&priv->hostlist) != ALLOW)
-           continue;
-       tags.noexec = UNSPEC;
-       tags.setenv = UNSPEC;
-       tags.nopasswd = UNSPEC;
-       tags.log_input = UNSPEC;
-       tags.log_output = 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);
-               }
-           } else if (tq_empty(&cs->runasgrouplist)) {
-               lbuf_append(lbuf, def_runas_default, NULL);
-           } else {
-               lbuf_append(lbuf, pw->pw_name, 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_append(lbuf, "\n", NULL);
-    }
-    return nfound;
-}
-
-static int
-sudo_file_display_priv_long(pw, us, lbuf)
-    struct passwd *pw;
-    struct userspec *us;
-    struct lbuf *lbuf;
-{
-    struct cmndspec *cs;
-    struct member *m;
-    struct privilege *priv;
-    struct cmndtag tags;
-    int nfound = 0;
-
-    tq_foreach_fwd(&us->privileges, priv) {
-       if (hostlist_matches(&priv->hostlist) != ALLOW)
-           continue;
-       tags.noexec = UNSPEC;
-       tags.setenv = UNSPEC;
-       tags.nopasswd = UNSPEC;
-       tags.log_input = UNSPEC;
-       tags.log_output = UNSPEC;
-       lbuf_append(lbuf, "\nSudoers entry:\n", NULL);
-       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 if (tq_empty(&cs->runasgrouplist)) {
-               lbuf_append(lbuf, def_runas_default, NULL);
-           } else {
-               lbuf_append(lbuf, pw->pw_name, NULL);
-           }
-           lbuf_append(lbuf, "\n", NULL);
-           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);
-               }
-               lbuf_append(lbuf, "\n", NULL);
-           }
-           lbuf_append(lbuf, "    Commands:\n\t", NULL);
-           sudo_file_append_cmnd(cs, &tags, lbuf);
-           lbuf_append(lbuf, "\n", NULL);
-           nfound++;
-       }
-    }
-    return nfound;
-}
-
-int
-sudo_file_display_privs(nss, pw, lbuf)
-    struct sudo_nss *nss;
-    struct passwd *pw;
-    struct lbuf *lbuf;
-{
-    struct userspec *us;
-    int nfound = 0;
-
-    if (nss->handle == NULL)
-       goto done;
-
-    tq_foreach_fwd(&userspecs, us) {
-       if (userlist_matches(pw, &us->users) != ALLOW)
-           continue;
-
-       if (long_list)
-           nfound += sudo_file_display_priv_long(pw, us, lbuf);
-       else
-           nfound += sudo_file_display_priv_short(pw, us, lbuf);
-    }
-done:
-    return nfound;
-}
-
-/*
- * Display matching Defaults entries for the given user on this host.
- */
-int
-sudo_file_display_defaults(nss, pw, lbuf)
-    struct sudo_nss *nss;
-    struct passwd *pw;
-    struct lbuf *lbuf;
-{
-    struct defaults *d;
-    char *prefix;
-    int nfound = 0;
-
-    if (nss->handle == NULL)
-       goto done;
-
-    if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
-       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++;
-    }
-done:
-    return nfound;
-}
-
-/*
- * Display Defaults entries that are per-runas or per-command
- */
-int
-sudo_file_display_bound_defaults(nss, pw, lbuf)
-    struct sudo_nss *nss;
-    struct passwd *pw;
-    struct lbuf *lbuf;
-{
-    int nfound = 0;
-
-    /* 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);
-
-    return nfound;
-}
-
-/*
- * 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;
-    }
-    /* 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);
-           if (nfound != 1)
-               lbuf_append(lbuf, "\n", NULL);
-           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 nfound;
-}
-
-int
-sudo_file_display_cmnd(nss, pw)
-    struct sudo_nss *nss;
-    struct passwd *pw;
-{
-    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)
-       goto done;
-
-    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;
-                   }
-               }
-           }
-       }
-    }
-    matched:
-    if (match != NULL && !match->negated) {
-       printf("%s%s%s\n", safe_cmnd, user_args ? " " : "",
-           user_args ? user_args : "");
-       rval = 0;
-    }
-done:
-    return rval;
-}
-
-/*
- * Print the contents of a struct member to stdout
- */
-static void
-_print_member(lbuf, name, type, negated, alias_type)
-    struct lbuf *lbuf;
-    char *name;
-    int type, negated, alias_type;
-{
-    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 = alias_find(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;
-    }
-}
-
-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
deleted file mode 100644 (file)
index 90595bf..0000000
--- a/parse.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-2000, 2004, 2007-2010
- *     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.
- */
-
-#ifndef _SUDO_PARSE_H
-#define _SUDO_PARSE_H
-
-#undef UNSPEC
-#define UNSPEC -1
-#undef DENY
-#define DENY    0
-#undef ALLOW
-#define ALLOW   1
-#undef IMPLIED
-#define IMPLIED         2
-
-/*
- * 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 int nopasswd: 3;
-    __signed int noexec: 3;
-    __signed int setenv: 3;
-    __signed int log_input: 3;
-    __signed int log_output: 3;
-};
-
-/*
- * SELinux-specific container struct.
- * Currently just contains a role and type.
- */
-struct selinux_info {
-    char *role;
-    char *type;
-};
-
-/*
- * 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 describing a user specification and list thereof.
- */
-struct userspec {
-    struct userspec *prev, *next;
-    struct member_list users;          /* list of users */
-    struct privilege_list privileges;  /* list of privileges */
-};
-
-/*
- * Structure describing a privilege specification.
- */
-struct privilege {
-    struct privilege *prev, *next;
-    struct member_list hostlist;       /* list of hosts */
-    struct cmndspec_list cmndlist;     /* list of Cmnd_Specs */
-};
-
-/*
- * Structure describing a linked list of Cmnd_Specs.
- */
-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
-};
-
-/*
- * 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 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 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 *alias_find __P((char *, int));
-struct alias *alias_remove __P((char *, int));
-void alias_free                __P((void *));
-void alias_apply       __P((int (*)(void *, void *), void *));
-void init_aliases      __P((void));
-void init_lexer                __P((void));
-void init_parser       __P((char *, int));
-int alias_compare      __P((const void *, const void *));
-
-#endif /* _SUDO_PARSE_H */
diff --git a/parse_args.c b/parse_args.c
deleted file mode 100644 (file)
index ee4245b..0000000
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * Copyright (c) 1993-1996, 1998-2010 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/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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <grp.h>
-
-#include "sudo.h"
-#include "lbuf.h"
-#include <sudo_usage.h>
-
-/*
- * Local functions
- */
-static void usage_excl                 __P((int));
-
-/*
- * For sudo.c
- */
-extern int NewArgc;
-extern char **NewArgv;
-extern int user_closefrom;
-extern char *runas_user;
-extern char *runas_group;
-
-/* For getopt(3) */
-extern char *optarg;
-extern int optind;
-
-#ifdef HAVE_BSD_AUTH_H
-char *login_style;
-#endif /* HAVE_BSD_AUTH_H */
-
-/*
- * 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).
- */
-int
-parse_args(argc, argv)
-    int argc;
-    char **argv;
-{
-    int mode = 0;              /* what mode is sudo to be run in? */
-    int flags = 0;             /* mode flags */
-    int valid_flags, ch;
-
-    /* First, check to see if we were invoked as "sudoedit". */
-    if (strcmp(getprogname(), "sudoedit") == 0)
-       mode = MODE_EDIT;
-
-    /* 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')
-
-    /* Returns true if next option is an environment variable */
-#define is_envar (optind < argc && argv[optind][0] != '/' && \
-           strchr(argv[optind], '=') != NULL)
-
-    /* Flags allowed when running a command */
-    valid_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|
-                 MODE_LOGIN_SHELL|MODE_INVALIDATE|MODE_NONINTERACTIVE|
-                 MODE_PRESERVE_GROUPS|MODE_SHELL;
-    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':
-                   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 a number greater than or equal to 3");
-                       usage(1);
-                   }
-                   break;
-#ifdef HAVE_LOGIN_CAP_H
-               case 'c':
-                   login_class = optarg;
-                   def_use_loginclass = TRUE;
-                   break;
-#endif
-               case 'E':
-                   SET(flags, MODE_PRESERVE_ENV);
-                   break;
-               case 'e':
-                   if (mode && mode != MODE_EDIT)
-                       usage_excl(1);
-                   mode = MODE_EDIT;
-                   valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
-                   break;
-               case 'g':
-                   runas_group = optarg;
-                   break;
-               case 'H':
-                   SET(flags, MODE_RESET_HOME);
-                   break;
-               case 'h':
-                   if (mode && mode != MODE_HELP) {
-                       if (strcmp(getprogname(), "sudoedit") != 0)
-                           usage_excl(1);
-                   }
-                   mode = MODE_HELP;
-                   valid_flags = 0;
-                   break;
-               case 'i':
-                   SET(flags, MODE_LOGIN_SHELL);
-                   def_env_reset = TRUE;
-                   break;
-               case 'k':
-                   SET(flags, MODE_INVALIDATE);
-                   break;
-               case 'K':
-                   if (mode && mode != MODE_KILL)
-                       usage_excl(1);
-                   mode = MODE_KILL;
-                   valid_flags = 0;
-                   break;
-               case 'L':
-                   if (mode && mode != MODE_LISTDEFS)
-                       usage_excl(1);
-                   mode = MODE_LISTDEFS;
-                   valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
-                   break;
-               case 'l':
-                   if (mode) {
-                       if (mode == MODE_LIST)
-                           long_list = 1;
-                       else
-                           usage_excl(1);
-                   }
-                   mode = MODE_LIST;
-                   valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
-                   break;
-               case 'n':
-                   SET(flags, MODE_NONINTERACTIVE);
-                   break;
-               case 'P':
-                   SET(flags, MODE_PRESERVE_GROUPS);
-                   break;
-               case 'p':
-                   user_prompt = optarg;
-                   def_passprompt_override = TRUE;
-                   break;
-#ifdef HAVE_SELINUX
-               case 'r':
-                   user_role = optarg;
-                   break;
-               case 't':
-                   user_type = optarg;
-                   break;
-#endif
-               case 'S':
-                   SET(tgetpass_flags, TGP_STDIN);
-                   break;
-               case 's':
-                   SET(flags, MODE_SHELL);
-                   break;
-               case 'U':
-                   if ((list_pw = sudo_getpwnam(optarg)) == NULL)
-                       errorx(1, "unknown user: %s", optarg);
-                   break;
-               case 'u':
-                   runas_user = optarg;
-                   break;
-               case 'v':
-                   if (mode && mode != MODE_VALIDATE)
-                       usage_excl(1);
-                   mode = MODE_VALIDATE;
-                   valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
-                   break;
-               case 'V':
-                   if (mode && mode != MODE_VERSION)
-                       usage_excl(1);
-                   mode = MODE_VERSION;
-                   valid_flags = 0;
-                   break;
-               default:
-                   usage(1);
-           }
-       } else if (!got_end_of_args && is_envar) {
-           struct list_member *ev;
-
-           /* Store environment variable. */
-           ev = emalloc(sizeof(*ev));
-           ev->value = argv[optind];
-           ev->next = sudo_user.env_vars;
-           sudo_user.env_vars = ev;
-
-           /* Crank optind and resume getopt. */
-           optind++;
-       } else {
-           /* Not an option or an environment variable -- we're done. */
-           break;
-       }
-    }
-
-    NewArgc = argc - optind;
-    NewArgv = argv + optind;
-
-    if (!mode) {
-       /* Defer -k mode setting until we know whether it is a flag or not */
-       if (ISSET(flags, MODE_INVALIDATE) && NewArgc == 0) {
-           mode = MODE_INVALIDATE;     /* -k by itself */
-           CLR(flags, MODE_INVALIDATE);
-           valid_flags = 0;
-       } else {
-           mode = MODE_RUN;            /* running a command */
-       }
-    }
-
-    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 ((flags & valid_flags) != flags)
-       usage(1);
-    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)
-           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 | MODE_VALIDATE)) {
-       usage(1);
-    }
-    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 (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 && mode == MODE_EDIT) ||
-       (NewArgc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
-       usage(1);
-    if (NewArgc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL))
-       SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
-
-    return mode | flags;
-}
-
-static int
-usage_err(buf)
-    const char *buf;
-{
-    return fputs(buf, stderr);
-}
-
-static int
-usage_out(buf)
-    const char *buf;
-{
-    return fputs(buf, stdout);
-}
-
-/*
- * Give usage message and exit.
- * The actual usage strings are in sudo_usage.h for configure substitution.
- */
-void
-usage(fatal)
-    int fatal;
-{
-    struct lbuf lbuf;
-    char *uvec[6];
-    int i, ulen;
-
-    /*
-     * Use usage vectors appropriate to the progname.
-     */
-    if (strcmp(getprogname(), "sudoedit") == 0) {
-       uvec[0] = SUDO_USAGE5 + 3;
-       uvec[1] = NULL;
-    } else {
-       uvec[0] = SUDO_USAGE1;
-       uvec[1] = SUDO_USAGE2;
-       uvec[2] = SUDO_USAGE3;
-       uvec[3] = SUDO_USAGE4;
-       uvec[4] = SUDO_USAGE5;
-       uvec[5] = NULL;
-    }
-
-    /*
-     * Print usage and wrap lines as needed, depending on the
-     * tty width.
-     */
-    ulen = (int)strlen(getprogname()) + 8;
-    lbuf_init(&lbuf, fatal ? usage_err : usage_out, ulen, NULL);
-    for (i = 0; uvec[i] != NULL; i++) {
-       lbuf_append(&lbuf, "usage: ", getprogname(), uvec[i], NULL);
-       lbuf_print(&lbuf);
-    }
-    lbuf_destroy(&lbuf);
-    if (fatal)
-       exit(1);
-}
-
-/*
- * Tell which options are mutually exclusive and exit.
- */
-static void
-usage_excl(fatal)
-    int fatal;
-{
-    warningx("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified");
-    usage(fatal);
-}
-
-void
-help()
-{
-    struct lbuf lbuf;
-    int indent = 16;
-    const char *pname = getprogname();
-
-    lbuf_init(&lbuf, usage_out, indent, NULL);
-    if (strcmp(pname, "sudoedit") == 0)
-       lbuf_append(&lbuf, pname,  " - edit files as another user\n\n", NULL);
-    else
-       lbuf_append(&lbuf, pname,  " - execute a command as another user\n\n", NULL);
-    lbuf_print(&lbuf);
-
-    usage(0);
-
-    lbuf_append(&lbuf, "\nOptions:\n", NULL);
-#ifdef HAVE_BSD_AUTH_H
-    lbuf_append(&lbuf,
-       "  -A            use helper program for password prompting\n", NULL);
-#endif
-    lbuf_append(&lbuf,
-       "  -a type       use specified BSD authentication type\n", NULL);
-    lbuf_append(&lbuf,
-       "  -b            run command in the background\n", NULL);
-    lbuf_append(&lbuf,
-       "  -C fd         close all file descriptors >= fd\n", NULL);
-#ifdef HAVE_LOGIN_CAP_H
-    lbuf_append(&lbuf,
-       "  -c class      run command with specified login class\n", NULL);
-#endif
-    lbuf_append(&lbuf,
-       "  -E            preserve user environment when executing command\n",
-       NULL);
-    lbuf_append(&lbuf,
-       "  -e            edit files instead of running a command\n", NULL);
-    lbuf_append(&lbuf,
-       "  -g group      execute command as the specified group\n", NULL);
-    lbuf_append(&lbuf,
-       "  -H            set HOME variable to target user's home dir.\n",
-       NULL);
-    lbuf_append(&lbuf,
-       "  -h            display help message and exit\n", NULL);
-    lbuf_append(&lbuf,
-       "  -i [command]  run a login shell as target user\n", NULL);
-    lbuf_append(&lbuf,
-       "  -K            remove timestamp file completely\n", NULL);
-    lbuf_append(&lbuf,
-       "  -k            invalidate timestamp file\n", NULL);
-    lbuf_append(&lbuf,
-       "  -L            list supported sudoers Defaults values\n", NULL);
-    lbuf_append(&lbuf,
-       "  -l[l] command list user's available commands\n", NULL);
-    lbuf_append(&lbuf,
-       "  -n            non-interactive mode, will not prompt user\n", NULL);
-    lbuf_append(&lbuf,
-       "  -P            preserve group vector instead of setting to target's\n",
-       NULL);
-    lbuf_append(&lbuf,
-       "  -p prompt     use specified password prompt\n", NULL);
-#ifdef HAVE_SELINUX
-    lbuf_append(&lbuf,
-       "  -r role       create SELinux security context with specified role\n",
-       NULL);
-#endif
-    lbuf_append(&lbuf,
-       "  -S            read password from standard input\n", NULL);
-    lbuf_append(&lbuf,
-       "  -s [command]  run a shell as target user\n", NULL);
-#ifdef HAVE_SELINUX
-    lbuf_append(&lbuf,
-       "  -t type       create SELinux security context with specified role\n",
-       NULL);
-#endif
-    lbuf_append(&lbuf,
-       "  -U user       when listing, list specified user's privileges\n",
-       NULL);
-    lbuf_append(&lbuf,
-       "  -u user       run command (or edit file) as specified user\n", NULL);
-    lbuf_append(&lbuf,
-       "  -V            display version information and exit\n", NULL);
-    lbuf_append(&lbuf,
-       "  -v            update user's timestamp without running a command\n",
-       NULL);
-    lbuf_append(&lbuf,
-       "  --            stop processing command line arguments\n", NULL);
-    lbuf_print(&lbuf);
-    lbuf_destroy(&lbuf);
-    exit(0);
-}
index 96c4523000b3db62f781a13590bc1e204e085905..32bff86b77c0d74a3c9474f69d0edd4fc6bbc5a3 100644 (file)
 #define _PATH_ENVIRONMENT      "/etc/environment"
 #endif /* _PATH_ENVIRONMENT */
 
+/*
+ * NOTE: _PATH_SUDO_CONF is usually overridden by the Makefile.
+ */
+#ifndef _PATH_SUDO_CONF
+#define _PATH_SUDO_CONF                "/etc/sudo.conf"
+#endif /* _PATH_SUDO_CONF */
+
 /*
  * NOTE: _PATH_SUDOERS is usually overridden by the Makefile.
  */
 #undef _PATH_SUDO_ASKPASS
 #endif /* _PATH_SUDO_ASKPASS */
 
+#ifndef _PATH_SUDO_PLUGIN_DIR
+#undef _PATH_SUDO_PLUGIN_DIR
+#endif /* _PATH_SUDO_PLUGIN_DIR */
+
 #ifndef _PATH_VI
 #undef _PATH_VI
 #endif /* _PATH_VI */
 #undef _PATH_MAILDIR
 #endif /* _PATH_MAILDIR */
 
+#ifndef _PATH_UTMP
+#undef _PATH_UTMP
+#endif /* _PATH_UTMP */
+
 #ifndef _PATH_SUDO_SESH
 #undef _PATH_SUDO_SESH
 #endif /* _PATH_SUDO_SESH */
diff --git a/plugins/sample/Makefile.in b/plugins/sample/Makefile.in
new file mode 100644 (file)
index 0000000..180dee3
--- /dev/null
@@ -0,0 +1,123 @@
+#
+# Copyright (c) 2011 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.
+#
+# @configure_input@
+#
+
+#### Start of system configuration section. ####
+
+srcdir = @srcdir@
+devdir = @devdir@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+incdir = $(top_srcdir)/include
+
+# Compiler & tools to use
+CC = @CC@
+LIBTOOL = @LIBTOOL@ @LT_STATIC@
+
+# Our install program supports extra flags...
+INSTALL = $(SHELL) $(top_srcdir)/install-sh -c
+
+# Libraries
+LIBS = $(LIBOBJDIR)/libreplace.la
+
+# C preprocessor flags
+CPPFLAGS = -I$(incdir) -I$(top_builddir) @CPPFLAGS@
+
+# Usually -O and/or -g
+CFLAGS = @CFLAGS@
+
+# Flags to pass to the link stage
+LDFLAGS = @LDFLAGS@
+LTLDFLAGS = @LTLDFLAGS@
+
+# Where to install things...
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+sbindir = @sbindir@
+sysconfdir = @sysconfdir@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
+localstatedir = @localstatedir@
+plugindir = @PLUGINDIR@
+soext = @SOEXT@
+
+# OS dependent defines
+DEFS = @OSDEFS@
+
+#### End of system configuration section. ####
+
+SHELL = @SHELL@
+
+OBJS = sample_plugin.lo
+
+LIBOBJDIR = $(top_builddir)/@ac_config_libobj_dir@/
+
+VERSION = @PACKAGE_VERSION@
+
+all: sample_plugin.la
+
+Makefile: $(srcdir)/Makefile.in
+       (cd $(top_builddir) && ./config.status --file plugins/sample/Makefile)
+
+.SUFFIXES: .o .c .h .lo
+
+.c.lo:
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $<
+
+sample_plugin.lo: $(srcdir)/sample_plugin.c
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sample_plugin.c
+
+sample_plugin.la: $(OBJS)
+       $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) $(LTLDFLAGS) -o $@ $(OBJS) $(LIBS) -module -export-symbols $(srcdir)/sample_plugin.sym -avoid-version -rpath $(plugindir)
+
+pre-install:
+
+install: install-dirs install-plugin
+
+install-dirs:
+       $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(plugindir)
+
+install-binaries:
+
+install-includes:
+
+install-doc:
+
+install-plugin: install-dirs sample_plugin.la
+       $(INSTALL) -b~ -M 0755 .libs/sample_plugin$(soext) $(DESTDIR)$(plugindir)
+
+uninstall:
+       -rm -f $(DESTDIR)$(plugindir)/sample_plugin$(soext)
+
+check:
+
+clean:
+       -$(LIBTOOL) --mode=clean rm -f *.lo *.o *.la *.a stamp-* core *.core core.*
+
+mostlyclean: clean
+
+distclean: clean
+       -rm -rf Makefile .libs
+
+clobber: distclean
+
+realclean: distclean
+       rm -f TAGS tags
+
+cleandir: realclean
diff --git a/plugins/sample/sample_plugin.c b/plugins/sample/sample_plugin.c
new file mode 100644 (file)
index 0000000..5ac19a4
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * Copyright (c) 2010-2011 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 <sys/stat.h>
+#include <sys/wait.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <ctype.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdarg.h>
+
+#include <pathnames.h>
+#include "sudo_plugin.h"
+#include "missing.h"
+
+/*
+ * Sample plugin module that allows any user who knows the password
+ * ("test") to run any command as root.  Since there is no credential
+ * caching the validate and invalidate functions are NULL.
+ */
+
+#ifdef __TANDEM
+# define ROOT_UID       65535
+#else
+# define ROOT_UID       0
+#endif
+
+#undef TRUE
+#define TRUE 1
+#undef FALSE
+#define FALSE 0
+#undef ERROR
+#define ERROR -1
+
+static struct plugin_state {
+    char **envp;
+    char * const *settings;
+    char * const *user_info;
+} plugin_state;
+static sudo_conv_t sudo_conv;
+static sudo_printf_t sudo_log;
+static FILE *input, *output;
+static uid_t runas_uid = ROOT_UID;
+static gid_t runas_gid = -1;
+static int use_sudoedit = FALSE;
+
+/*
+ * Allocate storage for a name=value string and return it.
+ */
+static char *
+fmt_string(const char *var, const char *val)
+{
+    size_t var_len = strlen(var);
+    size_t val_len = strlen(val);
+    char *cp, *str;
+
+    cp = str = malloc(var_len + 1 + val_len + 1);
+    if (str != NULL) {
+       memcpy(cp, var, var_len);
+       cp += var_len;
+       *cp++ = '=';
+       memcpy(cp, val, val_len);
+       cp += val_len;
+       *cp = '\0';
+    }
+
+    return str;
+}
+
+/*
+ * Plugin policy open function.
+ */
+static int
+policy_open(unsigned int version, sudo_conv_t conversation,
+    sudo_printf_t sudo_printf, char * const settings[],
+    char * const user_info[], char * const user_env[])
+{
+    char * const *ui;
+    struct passwd *pw;
+    const char *runas_user = NULL;
+    struct group *gr;
+    const char *runas_group = NULL;
+
+    if (!sudo_conv)
+       sudo_conv = conversation;
+    if (!sudo_log)
+       sudo_log = sudo_printf;
+
+    if (SUDO_API_VERSION_GET_MAJOR(version) != SUDO_API_VERSION_MAJOR) {
+       sudo_log(SUDO_CONV_ERROR_MSG,
+           "the sample plugin requires API version %d.x\n",
+           SUDO_API_VERSION_MAJOR);
+       return ERROR;
+    }
+
+    /* Only allow commands to be run as root. */
+    for (ui = settings; *ui != NULL; ui++) {
+       if (strncmp(*ui, "runas_user=", sizeof("runas_user=") - 1) == 0) {
+           runas_user = *ui + sizeof("runas_user=") - 1;
+       }
+       if (strncmp(*ui, "runas_group=", sizeof("runas_group=") - 1) == 0) {
+           runas_group = *ui + sizeof("runas_group=") - 1;
+       }
+#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
+       if (strncmp(*ui, "progname=", sizeof("progname=") - 1) == 0) {
+           setprogname(*ui + sizeof("progname=") - 1);
+       }
+#endif
+       /* Check to see if sudo was called as sudoedit or with -e flag. */
+       if (strncmp(*ui, "sudoedit=", sizeof("sudoedit=") - 1) == 0) {
+           if (strcasecmp(*ui + sizeof("sudoedit=") - 1, "true") == 0)
+               use_sudoedit = TRUE;
+       }
+       /* This plugin doesn't support running sudo with no arguments. */
+       if (strncmp(*ui, "implied_shell=", sizeof("implied_shell=") - 1) == 0) {
+           if (strcasecmp(*ui + sizeof("implied_shell=") - 1, "true") == 0)
+               return -2; /* usage error */
+       }
+    }
+    if (runas_user != NULL) {
+       if ((pw = getpwnam(runas_user)) == NULL) {
+           sudo_log(SUDO_CONV_ERROR_MSG, "unknown user %s\n", runas_user);
+           return 0;
+       }
+       runas_uid = pw->pw_uid;
+    }
+    if (runas_group != NULL) {
+       if ((gr = getgrnam(runas_group)) == NULL) {
+           sudo_log(SUDO_CONV_ERROR_MSG, "unknown group %s\n", runas_group);
+           return 0;
+       }
+       runas_gid = gr->gr_gid;
+    }
+
+    /* Plugin state. */
+    plugin_state.envp = (char **)user_env;
+    plugin_state.settings = settings;
+    plugin_state.user_info = user_info;
+
+    return 1;
+}
+
+static char *
+find_in_path(char *command, char **envp)
+{
+    struct stat sb;
+    char *path, *path0, **ep, *cp;
+    char pathbuf[PATH_MAX], *qualified = NULL;
+
+    if (strchr(command, '/') != NULL)
+       return command;
+
+    path = _PATH_DEFPATH;
+    for (ep = plugin_state.envp; *ep != NULL; ep++) {
+       if (strncmp(*ep, "PATH=", 5) == 0) {
+           path = *ep + 5;
+           break;
+       }
+    }
+    path = path0 = strdup(path);
+    do {
+       if ((cp = strchr(path, ':')))
+           *cp = '\0';
+       snprintf(pathbuf, sizeof(pathbuf), "%s/%s", *path ? path : ".",
+           command);
+       if (stat(pathbuf, &sb) == 0) {
+           if (S_ISREG(sb.st_mode) && (sb.st_mode & 0000111)) {
+               qualified = pathbuf;
+               break;
+           }
+       }
+       path = cp + 1;
+    } while (cp != NULL);
+    free(path0);
+    return qualified ? strdup(qualified) : NULL;
+}
+
+static int
+check_passwd(void)
+{
+    struct sudo_conv_message msg;
+    struct sudo_conv_reply repl;
+
+    /* Prompt user for password via conversation function. */
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_type = SUDO_CONV_PROMPT_ECHO_OFF;
+    msg.msg = "Password: ";
+    memset(&repl, 0, sizeof(repl));
+    sudo_conv(1, &msg, &repl);
+    if (repl.reply == NULL) {
+       sudo_log(SUDO_CONV_ERROR_MSG, "missing password\n");
+       return FALSE;
+    }
+    if (strcmp(repl.reply, "test") != 0) {
+       sudo_log(SUDO_CONV_ERROR_MSG, "incorrect password\n");
+       return FALSE;
+    }
+    return TRUE;
+}
+
+static char **
+build_command_info(char *command)
+{
+    static char **command_info;
+    int i = 0;
+
+    /* Setup command info. */
+    command_info = calloc(32, sizeof(char *));
+    if (command_info == NULL)
+       return NULL;
+    if ((command_info[i++] = fmt_string("command", command)) == NULL ||
+       asprintf(&command_info[i++], "runas_euid=%ld", (long)runas_uid) == -1 ||
+       asprintf(&command_info[i++], "runas_uid=%ld", (long)runas_uid) == -1) {
+       return NULL;
+    }
+    if (runas_gid != -1) {
+       if (asprintf(&command_info[i++], "runas_gid=%ld", (long)runas_gid) == -1 ||
+           asprintf(&command_info[i++], "runas_egid=%ld", (long)runas_gid) == -1) {
+           return NULL;
+       }
+    }
+    if (use_sudoedit) {
+       command_info[i] = strdup("sudoedit=true");
+       if (command_info[i++] == NULL)
+               return NULL;
+    }
+#ifdef USE_TIMEOUT
+    command_info[i++] = "timeout=30";
+#endif
+    return command_info;
+}
+
+static char *
+find_editor(int nfiles, char * const files[], char **argv_out[])
+{
+    char *cp, **ep, **nargv, *editor, *editor_path;
+    int ac, i, nargc, wasblank;
+
+    /* Lookup EDITOR in user's environment. */
+    editor = _PATH_VI;
+    for (ep = plugin_state.envp; *ep != NULL; ep++) {
+       if (strncmp(*ep, "EDITOR=", 7) == 0) {
+           editor = *ep + 7;
+           break;
+       }
+    }
+    editor = strdup(editor);
+    if (editor == NULL) {
+       sudo_log(SUDO_CONV_ERROR_MSG, "unable to allocate memory\n");
+       return NULL;
+    }
+
+    /*
+     * Split editor into an argument vector; editor is reused (do not free).
+     * The EDITOR environment variables may contain command
+     * line args so look for those and alloc space for them too.
+     */
+    nargc = 1;
+    for (wasblank = 0, cp = editor; *cp != '\0'; cp++) {
+       if (isblank((unsigned char) *cp))
+           wasblank = 1;
+       else if (wasblank) {
+           wasblank = 0;
+           nargc++;
+       }
+    }
+    /* If we can't find the editor in the user's PATH, give up. */
+    cp = strtok(editor, " \t");
+    if (cp == NULL ||
+       (editor_path = find_in_path(editor, plugin_state.envp)) == NULL) {
+       return NULL;
+    }
+    nargv = (char **) malloc((nargc + 1 + nfiles + 1) * sizeof(char *));
+    if (nargv == NULL) {
+       sudo_log(SUDO_CONV_ERROR_MSG, "unable to allocate memory\n");
+       return NULL;
+    }
+    for (ac = 0; cp != NULL && ac < nargc; ac++) {
+       nargv[ac] = cp;
+       cp = strtok(NULL, " \t");
+    }
+    nargv[ac++] = "--";
+    for (i = 0; i < nfiles; )
+       nargv[ac++] = files[i++];
+    nargv[ac] = NULL;
+
+    *argv_out = nargv;
+    return editor_path;
+}
+
+/*
+ * Plugin policy check function.
+ * Simple example that prompts for a password, hard-coded to "test".
+ */
+static int 
+policy_check(int argc, char * const argv[],
+    char *env_add[], char **command_info_out[],
+    char **argv_out[], char **user_env_out[])
+{
+    char *command;
+
+    if (!argc || argv[0] == NULL) {
+       sudo_log(SUDO_CONV_ERROR_MSG, "no command specified\n");
+       return FALSE;
+    }
+
+    if (!check_passwd())
+       return FALSE;
+
+    command = find_in_path(argv[0], plugin_state.envp);
+    if (command == NULL) {
+       sudo_log(SUDO_CONV_ERROR_MSG, "%s: command not found\n", argv[0]);
+       return FALSE;
+    }
+
+    /* If "sudo vi" is run, auto-convert to sudoedit.  */
+    if (strcmp(command, _PATH_VI) == 0)
+       use_sudoedit = TRUE;
+
+    if (use_sudoedit) {
+       /* Rebuild argv using editor */
+       command = find_editor(argc - 1, argv + 1, argv_out);
+       if (command == NULL) {
+           sudo_log(SUDO_CONV_ERROR_MSG, "unable to find valid editor\n");
+           return ERROR;
+       }
+       use_sudoedit = TRUE;
+    } else {
+       /* No changes needd to argv */
+       *argv_out = (char **)argv;
+    }
+
+    /* No changes to envp */
+    *user_env_out = plugin_state.envp;
+
+    /* Setup command info. */
+    *command_info_out = build_command_info(command);
+    if (*command_info_out == NULL) {
+       sudo_log(SUDO_CONV_ERROR_MSG, "out of memory\n");
+       return ERROR;
+    }
+
+    return TRUE;
+}
+
+static int
+policy_list(int argc, char * const argv[], int verbose, const char *list_user)
+{
+    /*
+     * List user's capabilities.
+     */
+    sudo_log(SUDO_CONV_INFO_MSG, "Validated users may run any command\n");
+    return TRUE;
+}
+
+static int
+policy_version(int verbose)
+{
+    sudo_log(SUDO_CONV_INFO_MSG, "Sample policy plugin version %s\n", PACKAGE_VERSION);
+    return TRUE;
+}
+
+static void
+policy_close(int exit_status, int error)
+{
+    /*
+     * The policy might log the command exit status here.
+     * In this example, we just print a message.
+     */
+    if (error) {
+       sudo_log(SUDO_CONV_ERROR_MSG, "Command error: %s\n", strerror(error));
+    } else {
+        if (WIFEXITED(exit_status)) {
+           sudo_log(SUDO_CONV_INFO_MSG, "Command exited with status %d\n",
+               WEXITSTATUS(exit_status));
+        } else if (WIFSIGNALED(exit_status)) {
+           sudo_log(SUDO_CONV_INFO_MSG, "Command killed by signal %d\n",
+               WTERMSIG(exit_status));
+       }
+    }
+}
+
+static int
+io_open(unsigned int version, sudo_conv_t conversation,
+    sudo_printf_t sudo_printf, char * const settings[],
+    char * const user_info[], char * const command_info[],
+    int argc, char * const argv[], char * const user_env[])
+{
+    int fd;
+    char path[PATH_MAX];
+
+    if (!sudo_conv)
+       sudo_conv = conversation;
+    if (!sudo_log)
+       sudo_log = sudo_printf;
+
+    /* Open input and output files. */
+    snprintf(path, sizeof(path), "/var/tmp/sample-%u.output",
+       (unsigned int)getpid());
+    fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0644);
+    if (fd == -1)
+       return FALSE;
+    output = fdopen(fd, "w");
+
+    snprintf(path, sizeof(path), "/var/tmp/sample-%u.input",
+       (unsigned int)getpid());
+    fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0644);
+    if (fd == -1)
+       return FALSE;
+    input = fdopen(fd, "w");
+
+    return TRUE;
+}
+
+static void
+io_close(int exit_status, int error)
+{
+    fclose(input);
+    fclose(output);
+}
+
+static int
+io_version(int verbose)
+{
+    sudo_log(SUDO_CONV_INFO_MSG, "Sample I/O plugin version %s\n",
+       PACKAGE_VERSION);
+    return TRUE;
+}
+
+static int
+io_log_input(const char *buf, unsigned int len)
+{
+    fwrite(buf, len, 1, input);
+    return TRUE;
+}
+
+static int
+io_log_output(const char *buf, unsigned int len)
+{
+    fwrite(buf, len, 1, output);
+    return TRUE;
+}
+
+struct policy_plugin sample_policy = {
+    SUDO_POLICY_PLUGIN,
+    SUDO_API_VERSION,
+    policy_open,
+    policy_close,
+    policy_version,
+    policy_check,
+    policy_list,
+    NULL, /* validate */
+    NULL /* invalidate */
+};
+
+/*
+ * Note: This plugin does not differentiate between tty and pipe I/O.
+ *       It all gets logged to the same file.
+ */
+struct io_plugin sample_io = {
+    SUDO_IO_PLUGIN,
+    SUDO_API_VERSION,
+    io_open,
+    io_close,
+    io_version,
+    io_log_input,      /* tty input */
+    io_log_output,     /* tty output */
+    io_log_input,      /* command stdin if not tty */
+    io_log_output,     /* command stdout if not tty */
+    io_log_output      /* command stderr if not tty */
+};
diff --git a/plugins/sample/sample_plugin.sym b/plugins/sample/sample_plugin.sym
new file mode 100644 (file)
index 0000000..9f85094
--- /dev/null
@@ -0,0 +1,2 @@
+sample_policy
+sample_io
diff --git a/plugins/sample_group/Makefile.in b/plugins/sample_group/Makefile.in
new file mode 100644 (file)
index 0000000..eda9f1f
--- /dev/null
@@ -0,0 +1,126 @@
+#
+# Copyright (c) 2011 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.
+#
+# @configure_input@
+#
+
+#### Start of system configuration section. ####
+
+srcdir = @srcdir@
+devdir = @devdir@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+incdir = $(top_srcdir)/include
+
+# Compiler & tools to use
+CC = @CC@
+LIBTOOL = @LIBTOOL@ @LT_STATIC@
+
+# Our install program supports extra flags...
+INSTALL = $(SHELL) $(top_srcdir)/install-sh -c
+
+# Libraries
+LIBS = $(LIBOBJDIR)/libreplace.la
+
+# C preprocessor flags
+CPPFLAGS = -I$(incdir) -I$(top_builddir) @CPPFLAGS@
+
+# Usually -O and/or -g
+CFLAGS = @CFLAGS@
+
+# Flags to pass to the link stage
+LDFLAGS = @LDFLAGS@
+LTLDFLAGS = @LTLDFLAGS@
+
+# Where to install things...
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+sbindir = @sbindir@
+sysconfdir = @sysconfdir@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
+localstatedir = @localstatedir@
+plugindir = @PLUGINDIR@
+soext = @SOEXT@
+
+# OS dependent defines
+DEFS = @OSDEFS@
+
+#### End of system configuration section. ####
+
+SHELL = @SHELL@
+
+OBJS = sample_group.lo getgrent.lo
+
+LIBOBJDIR = $(top_builddir)/@ac_config_libobj_dir@/
+
+VERSION = @PACKAGE_VERSION@
+
+all: sample_group.la
+
+Makefile: $(srcdir)/Makefile.in
+       (cd $(top_builddir) && ./config.status --file plugins/sample_group/Makefile)
+
+.SUFFIXES: .o .c .h .lo
+
+.c.lo:
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $<
+
+getgrent.lo: $(srcdir)/getgrent.c
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/getgrent.c
+
+sample_group.lo: $(srcdir)/sample_group.c
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sample_group.c
+
+sample_group.la: $(OBJS)
+       $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) $(LTLDFLAGS) -o $@ $(OBJS) $(LIBS) -module -export-symbols $(srcdir)/sample_group.sym -avoid-version -rpath $(plugindir)
+
+pre-install:
+
+install: install-dirs install-plugin
+
+install-dirs:
+       $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(plugindir)
+
+install-binaries:
+
+install-includes:
+
+install-doc:
+
+install-plugin: install-dirs sample_group.la
+       $(INSTALL) -b~ -M 0755 .libs/sample_group$(soext) $(DESTDIR)$(plugindir)
+
+uninstall:
+       -rm -f $(DESTDIR)$(plugindir)/sample_group$(soext)
+
+check:
+
+clean:
+       -$(LIBTOOL) --mode=clean rm -f *.lo *.o *.la *.a stamp-* core *.core core.*
+
+mostlyclean: clean
+
+distclean: clean
+       -rm -rf Makefile .libs
+
+clobber: distclean
+
+realclean: distclean
+       rm -f TAGS tags
+
+cleandir: realclean
diff --git a/plugins/sample_group/getgrent.c b/plugins/sample_group/getgrent.c
new file mode 100644 (file)
index 0000000..aa98c14
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2005,2008,2010-2011 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 getgr{uid,nam}() routines.
+ */
+
+#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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <fcntl.h>
+#include <limits.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "missing.h"
+
+#ifndef LINE_MAX
+# define LINE_MAX 2048
+#endif
+
+#undef GRMEM_MAX
+#define GRMEM_MAX 200
+
+static FILE *grf;
+static const char *grfile = "/etc/group";
+static int gr_stayopen;
+
+void mysetgrfile(const char *);
+void mysetgrent(void);
+void myendgrent(void);
+struct group *mygetgrent(void);
+struct group *mygetgrnam(const char *);
+struct group *mygetgrgid(gid_t);
+
+void
+mysetgrfile(const char *file)
+{
+    grfile = file;
+    if (grf != NULL)
+       myendgrent();
+}
+
+void
+mysetgrent(void)
+{
+    if (grf == NULL) {
+       grf = fopen(grfile, "r");
+       if (grf != NULL)
+           fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
+    } else {
+       rewind(grf);
+    }
+    gr_stayopen = 1;
+}
+
+void
+myendgrent(void)
+{
+    if (grf != NULL) {
+       fclose(grf);
+       grf = NULL;
+    }
+    gr_stayopen = 0;
+}
+
+struct group *
+mygetgrent(void)
+{
+    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;
+
+    memset(&gr, 0, 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 *
+mygetgrnam(const char *name)
+{
+    struct group *gr;
+
+    if (grf == NULL) {
+       if ((grf = fopen(grfile, "r")) == NULL)
+           return NULL;
+       fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
+    } else {
+       rewind(grf);
+    }
+    while ((gr = mygetgrent()) != NULL) {
+       if (strcmp(gr->gr_name, name) == 0)
+           break;
+    }
+    if (!gr_stayopen) {
+       fclose(grf);
+       grf = NULL;
+    }
+    return gr;
+}
+
+struct group *
+mygetgrgid(gid_t gid)
+{
+    struct group *gr;
+
+    if (grf == NULL) {
+       if ((grf = fopen(grfile, "r")) == NULL)
+           return NULL;
+       fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
+    } else {
+       rewind(grf);
+    }
+    while ((gr = mygetgrent()) != NULL) {
+       if (gr->gr_gid == gid)
+           break;
+    }
+    if (!gr_stayopen) {
+       fclose(grf);
+       grf = NULL;
+    }
+    return gr;
+}
diff --git a/plugins/sample_group/plugin_test.c b/plugins/sample_group/plugin_test.c
new file mode 100644 (file)
index 0000000..87077a5
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2010-2011 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 <sys/types.h>
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <limits.h>
+#include <pwd.h>
+
+#include "sudo_plugin.h"
+
+/*
+ * Simple driver to test sudoer group plugins.
+ * usage: plugin_test [-p "plugin.so plugin_args ..."] user:group ...
+ */
+
+static void *group_handle;
+static struct sudoers_group_plugin *group_plugin;
+
+static int
+plugin_printf(int msg_type, const char *fmt, ...)
+{
+    va_list ap;
+    FILE *fp;
+           
+    switch (msg_type) {
+    case SUDO_CONV_INFO_MSG:
+       fp = stdout;
+       break;
+    case SUDO_CONV_ERROR_MSG:
+       fp = stderr;
+       break;
+    default:
+       errno = EINVAL;
+       return -1;
+    }
+
+    va_start(ap, fmt);
+    vfprintf(fp, fmt, ap);
+    va_end(ap);
+
+    return 0;
+}
+
+/*
+ * Load the specified plugin and run its init function.
+ * Returns -1 if unable to open the plugin, else it returns
+ * the value from the plugin's init function.
+ */
+static int
+group_plugin_load(char *plugin_info)
+{
+    char *args, path[PATH_MAX], savedch;
+    char **argv = NULL;
+    int rc;
+
+    /*
+     * Fill in .so path and split out args (if any).
+     */
+    if ((args = strpbrk(plugin_info, " \t")) != NULL) {
+       savedch = *args;
+       *args = '\0';
+    }
+    strncpy(path, plugin_info, sizeof(path) - 1);
+    path[sizeof(path) - 1] = '\0';
+    if (args != NULL)
+       *args++ = savedch;
+
+    /* Open plugin and map in symbol. */
+    group_handle = dlopen(path, RTLD_LAZY);
+    if (!group_handle) {
+       fprintf(stderr, "unable to dlopen %s: %s\n", path, dlerror());
+       return -1;
+    }
+    group_plugin = dlsym(group_handle, "group_plugin");
+    if (group_plugin == NULL) {
+       fprintf(stderr, "unable to find symbol \"group_plugin\" in %s\n", path);
+       return -1;
+    }
+
+    if (GROUP_API_VERSION_GET_MAJOR(group_plugin->version) != GROUP_API_VERSION_MAJOR) {
+       fprintf(stderr,
+           "%s: incompatible group plugin major version %d, expected %d\n",
+           path, GROUP_API_VERSION_GET_MAJOR(group_plugin->version),
+           GROUP_API_VERSION_MAJOR);
+       return -1;
+    }
+
+    /*
+     * Split args into a vector if specified.
+     */
+    if (args != NULL) {
+       int ac = 0, wasblank = 1;
+       char *cp;
+
+        for (cp = args; *cp != '\0'; cp++) {
+            if (isblank((unsigned char)*cp)) {
+                wasblank = 1;
+            } else if (wasblank) {
+                wasblank = 0;
+                ac++;
+            }
+        }
+       if (ac != 0)    {
+           argv = malloc(ac * sizeof(char *));
+           if (argv == NULL) {
+               fprintf(stderr, "unable to allocate memory\n");
+               return -1;
+           }
+           ac = 0;
+           for ((cp = strtok(args, " \t")); cp; (cp = strtok(NULL, " \t")))
+               argv[ac++] = cp;
+       }
+    }
+
+    rc = (group_plugin->init)(GROUP_API_VERSION, plugin_printf, argv);
+
+    free(argv);
+
+    return rc;
+}
+
+static void
+group_plugin_unload(void)
+{
+    (group_plugin->cleanup)();
+    dlclose(group_handle);
+    group_handle = NULL;
+}
+
+static int
+group_plugin_query(const char *user, const char *group,
+    const struct passwd *pwd)
+{
+    return group_plugin->query)(user, group, pwd;
+}
+
+static void
+usage(void)
+{
+    fprintf(stderr,
+       "usage: plugin_test [-p \"plugin.so plugin_args ...\"] user:group ...\n");
+    exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+    int ch, i, found;
+    char *plugin = "sample_group.so";
+    char *user, *group;
+    struct passwd *pwd;
+
+    while ((ch = getopt(argc, argv, "p:")) != -1) {
+       switch (ch) {
+       case 'p':
+           plugin = optarg;
+           break;
+       default:
+           usage();
+       }
+    }
+    argc -= optind;
+    argv += optind;
+
+    if (argc < 1)
+       usage();
+
+    if (group_plugin_load(plugin) != 1) {
+       fprintf(stderr, "unable to load plugin: %s\n", plugin);
+       exit(1);
+    }
+
+    for (i = 0; argv[i] != NULL; i++) {
+       user = argv[i];
+       group = strchr(argv[i], ':');
+       if (group == NULL)
+           continue;
+       *group++ = '\0';
+       pwd = getpwnam(user);
+       found = group_plugin_query(user, group, pwd);
+       printf("user %s %s in group %s\n", user, found ? "is" : "NOT ", group);
+    }
+    group_plugin_unload();
+
+    exit(0);
+}
+
diff --git a/plugins/sample_group/sample_group.c b/plugins/sample_group/sample_group.c
new file mode 100644 (file)
index 0000000..dbd1c27
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2010 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 <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
+# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <grp.h>
+#include <pwd.h>
+
+#include "sudo_plugin.h"
+#include "missing.h"
+
+/*
+ * Sample sudoers group plugin that uses an extra group file with the
+ * same format as /etc/group.
+ */
+
+#undef TRUE
+#define TRUE 1
+#undef FALSE
+#define FALSE 0
+#undef ERROR
+#define ERROR -1
+
+static sudo_printf_t sudo_log;
+
+extern void mysetgrfile(const char *);
+extern void mysetgrent(void);
+extern void myendgrent(void);
+extern struct group *mygetgrnam(const char *);
+
+static int
+sample_init(int version, sudo_printf_t sudo_printf, char *const argv[])
+{
+    struct stat sb;
+
+    sudo_log = sudo_printf;
+
+    if (GROUP_API_VERSION_GET_MAJOR(version) != GROUP_API_VERSION_MAJOR) {
+       sudo_log(SUDO_CONV_ERROR_MSG,
+           "sample_group: incompatible major version %d, expected %d\n",
+           GROUP_API_VERSION_GET_MAJOR(version),
+           GROUP_API_VERSION_MAJOR);
+       return ERROR;
+    }
+
+    /* Sanity check the specified group file. */
+    if (argv == NULL || argv[0] == NULL) {
+       sudo_log(SUDO_CONV_ERROR_MSG,
+           "sample_group: path to group file not specified\n");
+       return ERROR;
+    }
+    if (stat(argv[0], &sb) != 0) {
+       sudo_log(SUDO_CONV_ERROR_MSG,
+           "sample_group: %s: %s\n", argv[0], strerror(errno));
+       return ERROR;
+    }
+    if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
+       sudo_log(SUDO_CONV_ERROR_MSG,
+           "%s must be only be writable by owner\n", argv[0]);
+       return ERROR;
+    }
+
+    mysetgrfile(argv[0]);
+    mysetgrent();
+
+    return TRUE;
+}
+
+static void
+sample_cleanup(void)
+{
+    myendgrent();
+}
+
+/*
+ * Returns TRUE if "user" is a member of "group", else FALSE.
+ */
+static int
+sample_query(const char *user, const char *group, const struct passwd *pwd)
+{
+    struct group *grp;
+    char **member;
+
+    grp = mygetgrnam(group);
+    if (grp != NULL) {
+       for (member = grp->gr_mem; *member != NULL; member++) {
+           if (strcasecmp(user, *member) == 0)
+               return TRUE;
+       }
+    }
+
+    return FALSE;
+}
+
+struct sudoers_group_plugin group_plugin = {
+    GROUP_API_VERSION,
+    sample_init,
+    sample_cleanup,
+    sample_query
+};
diff --git a/plugins/sample_group/sample_group.sym b/plugins/sample_group/sample_group.sym
new file mode 100644 (file)
index 0000000..a859d6c
--- /dev/null
@@ -0,0 +1 @@
+group_plugin
diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in
new file mode 100644 (file)
index 0000000..d8c298b
--- /dev/null
@@ -0,0 +1,453 @@
+#
+# Copyright (c) 1996, 1998-2005, 2007-2011
+#       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.
+#
+# 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.
+#
+# @configure_input@
+#
+
+#### Start of system configuration section. ####
+
+srcdir = @srcdir@
+devdir = @devdir@
+authdir = $(srcdir)/auth
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+incdir = $(top_srcdir)/include
+docdir = @docdir@
+timedir = @timedir@
+
+# Compiler & tools to use
+CC = @CC@
+LIBTOOL = @LIBTOOL@
+FLEX = @FLEX@
+YACC = @YACC@
+
+# Our install program supports extra flags...
+INSTALL = $(SHELL) $(top_srcdir)/install-sh -c
+
+# Libraries
+LIBS = $(top_builddir)/common/libcommon.la $(top_builddir)/@ac_config_libobj_dir@/libreplace.la
+NET_LIBS = @NET_LIBS@
+SUDOERS_LIBS = @SUDOERS_LIBS@ @AFS_LIBS@ @GETGROUPS_LIB@ $(LIBS) $(NET_LIBS) @ZLIB@
+REPLAY_LIBS = @REPLAY_LIBS@ @ZLIB@
+
+# C preprocessor flags
+CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(srcdir) -I$(top_srcdir) @CPPFLAGS@
+
+# Usually -O and/or -g
+CFLAGS = @CFLAGS@
+
+# Flags to pass to the link stage
+LDFLAGS = @LDFLAGS@
+SUDOERS_LDFLAGS = $(LDFLAGS) @SUDOERS_LDFLAGS@
+LTLDFLAGS = @LTLDFLAGS@
+
+# Where to install things...
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+sbindir = @sbindir@
+sysconfdir = @sysconfdir@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
+localstatedir = @localstatedir@
+
+# File extension for shared objects
+soext = @SOEXT@
+
+# Directory in which to install the sudoers plugin
+plugindir = @PLUGINDIR@
+
+# Directory in which to install the sudoers file
+sudoersdir = $(sysconfdir)
+
+# Directory in which to install sudoreplay.
+replaydir = $(bindir)
+
+# Directory in which to install visudo
+visudodir = $(sbindir)
+
+# User and group ids the installed files should be "owned" by
+install_uid = 0
+install_gid = 0
+
+# User, group, and mode the sudoers file should be "owned" by (configure)
+sudoers_uid = @SUDOERS_UID@
+sudoers_gid = @SUDOERS_GID@
+sudoers_mode = @SUDOERS_MODE@
+
+# Pass in paths and uid/gid + OS dependent defines
+DEFS = @OSDEFS@ -D_PATH_SUDOERS=\"$(sudoersdir)/sudoers\" -DSUDOERS_UID=$(sudoers_uid) -DSUDOERS_GID=$(sudoers_gid) -DSUDOERS_MODE=$(sudoers_mode)
+
+#### End of system configuration section. ####
+
+SHELL = @SHELL@
+
+PROGS = sudoers.la visudo sudoreplay testsudoers
+
+TEST_PROGS = check_iolog_path check_fill
+
+AUTH_OBJS = sudo_auth.lo @AUTH_OBJS@
+
+LIBSUDOERS_OBJS = alias.lo audit.lo defaults.lo gram.lo match.lo pwutil.lo \
+                 timestr.lo toke.lo toke_util.lo redblack.lo
+
+SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo env.lo goodpath.lo \
+              group_plugin.lo find_path.lo interfaces.lo logging.lo \
+              parse.lo set_perms.lo sudoers.lo sudo_nss.lo iolog.lo \
+              iolog_path.lo @SUDOERS_OBJS@
+
+VISUDO_OBJS = visudo.o goodpath.o find_path.o error.o
+
+REPLAY_OBJS = getdate.o sudoreplay.o error.o
+
+TEST_OBJS = interfaces.o testsudoers.o tsgetgrpw.o error.o group_plugin.o \
+           net_ifs.o
+
+CHECK_IOLOG_PATH_OBJS = check_iolog_path.o error.o iolog_path.lo pwutil.lo \
+                       redblack.lo
+
+VERSION = @PACKAGE_VERSION@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+
+SUDODEP = $(srcdir)/sudoers.h $(srcdir)/defaults.h $(incdir)/error.h \
+         $(incdir)/list.h $(srcdir)/logging.h $(incdir)/missing.h \
+         $(srcdir)/sudo_nss.h $(devdir)/def_data.h \
+         $(top_builddir)/pathnames.h $(top_builddir)/config.h
+
+AUTHDEP = $(SUDODEP) $(authdir)/sudo_auth.h
+
+INSDEP = $(srcdir)/ins_2001.h $(srcdir)/ins_classic.h $(srcdir)/ins_csops.h \
+        $(srcdir)/ins_goons.h $(srcdir)/insults.h
+
+all: $(PROGS)
+
+.SUFFIXES: .o .c .h .l .y .lo
+
+.c.o:
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $<
+
+.c.lo:
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $<
+
+# Prevent default rules from building .c files from .l and .y files
+.l.c:
+
+.y.c:
+
+Makefile: $(srcdir)/Makefile.in
+       (cd $(top_builddir) && ./config.status --file plugins/sudoers/Makefile)
+
+libsudoers.la: $(LIBSUDOERS_OBJS)
+       $(LIBTOOL) --mode=link $(CC) -o $@ $(LIBSUDOERS_OBJS) -no-install
+
+sudoers.la: $(SUDOERS_OBJS) libsudoers.la
+       $(LIBTOOL) @LT_STATIC@ --mode=link $(CC) $(SUDOERS_LDFLAGS) $(LTLDFLAGS) -o $@ $(SUDOERS_OBJS) libsudoers.la $(SUDOERS_LIBS) -module -export-symbols $(srcdir)/sudoers.sym -avoid-version -rpath $(plugindir)
+
+visudo: libsudoers.la $(VISUDO_OBJS) $(LIBS)
+       $(LIBTOOL) --mode=link $(CC) -o $@ $(VISUDO_OBJS) $(LDFLAGS) libsudoers.la $(LIBS) $(NET_LIBS)
+
+sudoreplay: $(REPLAY_OBJS) $(LIBS)
+       $(LIBTOOL) --mode=link $(CC) -o $@ $(REPLAY_OBJS) $(LDFLAGS) timestr.lo $(REPLAY_LIBS) $(LIBS)
+
+testsudoers: libsudoers.la $(TEST_OBJS) $(LIBS)
+       $(LIBTOOL) --mode=link $(CC) -o $@ $(TEST_OBJS) $(LDFLAGS) libsudoers.la $(LIBS) $(NET_LIBS) @LIBDL@
+
+check_iolog_path: $(CHECK_IOLOG_PATH_OBJS) $(LIBS)
+       $(LIBTOOL) --mode=link $(CC) -o $@ $(CHECK_IOLOG_PATH_OBJS) $(LDFLAGS) $(LIBS)
+
+check_fill: check_fill.o toke_util.lo error.o $(LIBS)
+       $(LIBTOOL) --mode=link $(CC) -o $@ check_fill.o toke_util.lo error.o $(LDFLAGS) $(LIBS)
+
+# Uncomment the following if you want "make distclean" to clean the parser
+@DEV@GENERATED = gram.h gram.c toke.c def_data.c def_data.h getdate.c
+
+# Uncomment the lines before -@true if you intend to modify gram.y
+$(devdir)/gram.c $(devdir)/gram.h: $(srcdir)/gram.y
+@DEV@  $(YACC) -d $(srcdir)/gram.y
+@DEV@  echo "#include <config.h>" > $(devdir)/gram.c
+@DEV@  cat y.tab.c >> $(devdir)/gram.c
+@DEV@  rm -f y.tab.c
+@DEV@  mv -f y.tab.h $(devdir)/gram.h
+       -@true
+
+# Uncomment the lines before -@true if you intend to modify toke.l
+$(devdir)/toke.c: $(srcdir)/toke.l
+@DEV@  $(FLEX) $(srcdir)/toke.l
+@DEV@  echo "#include <config.h>" > $(devdir)/toke.c
+@DEV@  cat lex.yy.c >> $(devdir)/toke.c
+@DEV@  rm -f lex.yy.c
+       -@true
+
+# Uncomment the lines before -@true if you intend to modify getdate.y
+$(devdir)/getdate.c: $(srcdir)/getdate.y
+@DEV@  echo "expect 10 shift/reduce conflicts"
+@DEV@  $(YACC) $(srcdir)/getdate.y
+@DEV@  echo "#include <config.h>" > $(devdir)/getdate.c
+@DEV@  cat y.tab.c >> $(devdir)/getdate.c
+@DEV@  rm -f y.tab.c
+       -@true
+
+# Uncomment the following if you intend to modify def_data.in
+@DEV@$(devdir)/def_data.c $(devdir)/def_data.h: $(srcdir)/def_data.in
+@DEV@  perl $(srcdir)/mkdefaults -o $(devdir)/def_data $(srcdir)/def_data.in
+
+sudoers: $(srcdir)/sudoers.in
+       (cd $(top_builddir) && $(SHELL) config.status --file=plugins/sudoers/$@)
+
+# Sudoers dependencies
+alias.lo: $(srcdir)/alias.c $(SUDODEP) $(srcdir)/parse.h $(incdir)/list.h $(srcdir)/redblack.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/alias.c
+audit.lo: $(srcdir)/audit.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/audit.c
+bsm_audit.lo: $(srcdir)/bsm_audit.c $(SUDODEP) $(srcdir)/bsm_audit.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/bsm_audit.c
+boottime.lo: $(srcdir)/boottime.c $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/boottime.c
+check.lo: $(srcdir)/check.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/check.c
+defaults.lo: $(srcdir)/defaults.c $(SUDODEP) $(devdir)/def_data.c $(authdir)/sudo_auth.h $(devdir)/gram.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/defaults.c
+env.lo: $(srcdir)/env.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/env.c
+find_path.lo: $(srcdir)/find_path.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/find_path.c
+getspwuid.lo: $(srcdir)/getspwuid.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/getspwuid.c
+goodpath.lo: $(srcdir)/goodpath.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/goodpath.c
+gram.lo: $(devdir)/gram.c $(SUDODEP) $(srcdir)/parse.h $(incdir)/list.h $(devdir)/gram.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(devdir)/gram.c
+group_plugin.lo: $(srcdir)/group_plugin.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/group_plugin.c
+interfaces.lo: $(srcdir)/interfaces.c $(SUDODEP) $(srcdir)/interfaces.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/interfaces.c
+iolog.lo: $(srcdir)/iolog.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/iolog.c
+iolog_path.lo: $(srcdir)/iolog_path.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/iolog_path.c
+ldap.lo: $(srcdir)/ldap.c $(SUDODEP) $(srcdir)/parse.h $(incdir)/list.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/ldap.c
+linux_audit.lo: $(srcdir)/linux_audit.c $(SUDODEP) $(srcdir)/linux_audit.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/linux_audit.c
+logging.lo: $(srcdir)/logging.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/logging.c
+match.lo: $(srcdir)/match.c $(SUDODEP) $(srcdir)/parse.h $(incdir)/list.h $(srcdir)/interfaces.h $(devdir)/gram.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/match.c
+parse.lo: $(srcdir)/parse.c $(SUDODEP) $(srcdir)/parse.h $(incdir)/list.h $(devdir)/gram.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/parse.c
+pwutil.lo: $(srcdir)/pwutil.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/pwutil.c
+redblack.lo: $(srcdir)/redblack.c $(SUDODEP) $(srcdir)/redblack.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/redblack.c
+set_perms.lo: $(srcdir)/set_perms.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/set_perms.c
+sudo_nss.lo: $(srcdir)/sudo_nss.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudo_nss.c
+sudoers.lo: $(srcdir)/sudoers.c $(SUDODEP) $(srcdir)/interfaces.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudoers.c
+timestr.lo: $(srcdir)/timestr.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/timestr.c
+toke.lo: $(devdir)/toke.c $(SUDODEP) $(srcdir)/parse.h $(incdir)/list.h $(srcdir)/toke.h $(devdir)/gram.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(devdir)/toke.c
+toke_util.lo: $(srcdir)/toke_util.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/toke.h $(devdir)/gram.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/toke_util.c
+tsgetgrpw.lo: $(srcdir)/tsgetgrpw.c $(SUDODEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/tsgetgrpw.c
+plugin_error.lo: $(srcdir)/plugin_error.c $(incdir)/error.h $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/plugin_error.c
+
+# Auth dependencies
+sudo_auth.lo: $(authdir)/sudo_auth.c $(AUTHDEP) $(INSDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/sudo_auth.c
+afs.lo: $(authdir)/afs.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/afs.c
+aix_auth.lo: $(authdir)/aix_auth.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/aix_auth.c
+bsdauth.lo: $(authdir)/bsdauth.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/bsdauth.c
+dce.lo: $(authdir)/dce.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/dce.c
+fwtk.lo: $(authdir)/fwtk.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/fwtk.c
+kerb4.lo: $(authdir)/kerb4.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/kerb4.c
+kerb5.lo: $(authdir)/kerb5.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/kerb5.c
+pam.lo: $(authdir)/pam.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/pam.c
+passwd.lo: $(authdir)/passwd.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/passwd.c
+rfc1938.lo: $(authdir)/rfc1938.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/rfc1938.c
+secureware.lo: $(authdir)/secureware.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/secureware.c
+securid.lo: $(authdir)/securid.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/securid.c
+securid5.lo: $(authdir)/securid5.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/securid5.c
+sia.lo: $(authdir)/sia.c $(AUTHDEP)
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/sia.c
+
+# Command dependencies (sudoreplay, testsudoers, visudo)
+check_iolog_path.o: $(srcdir)/regress/iolog_path/check_iolog_path.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/regress/iolog_path/check_iolog_path.c
+error.o: $(top_srcdir)/src/error.c $(incdir)/error.h $(incdir)/missing.h $(top_builddir)/config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(top_srcdir)/src/error.c
+find_path.o: find_path.lo
+getdate.o: $(devdir)/getdate.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(devdir)/getdate.c
+goodpath.o: goodpath.lo
+interfaces.o: interfaces.lo
+net_ifs.o: $(top_srcdir)/src/net_ifs.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(top_srcdir)/src/net_ifs.c
+sudoreplay.o: $(srcdir)/sudoreplay.c $(incdir)/alloc.h $(incdir)/missing.h $(incdir)/error.h $(incdir)/missing.h $(top_builddir)/config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudoreplay.c
+check_fill.o: $(srcdir)/regress/parser/check_fill.c
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/regress/parser/check_fill.c
+testsudoers.o: $(srcdir)/testsudoers.c $(SUDODEP) $(srcdir)/parse.h $(incdir)/list.h $(srcdir)/interfaces.h $(devdir)/gram.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/testsudoers.c
+tsgetgrpw.o: $(srcdir)/tsgetgrpw.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/tsgetgrpw.c
+visudo.o: $(srcdir)/visudo.c $(SUDODEP) $(devdir)/gram.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/visudo.c
+
+pre-install:
+       @if test -r $(DESTDIR)$(sudoersdir)/sudoers; then \
+           echo "Checking existing sudoers file for syntax errors."; \
+           ./visudo -c -f $(DESTDIR)$(sudoersdir)/sudoers; \
+       fi
+
+install: install-dirs install-plugin install-binaries install-sudoers install-doc
+
+install-dirs:
+       $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(plugindir) \
+           $(DESTDIR)$(visudodir) $(DESTDIR)$(replaydir) \
+           $(DESTDIR)$(sudoersdir) $(DESTDIR)$(docdir)
+       $(SHELL) $(top_srcdir)/mkinstalldirs -m 0700 $(DESTDIR)$(timedir)
+
+install-binaries: visudo sudoreplay install-dirs
+       $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0111 sudoreplay $(DESTDIR)$(replaydir)/sudoreplay
+       $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0111 visudo $(DESTDIR)$(visudodir)/visudo
+
+install-includes:
+
+install-doc: install-dirs
+       @LDAP@$(INSTALL) -O $(install_uid) -G $(install_gid) -M 0555 $(srcdir)/sudoers2ldif $(DESTDIR)$(docdir)
+
+install-plugin: sudoers.la install-dirs
+       $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0755 .libs/sudoers$(soext) $(DESTDIR)$(plugindir)
+
+install-sudoers: install-dirs
+       $(INSTALL) -d -O $(sudoers_uid) -G $(sudoers_gid) -M 0750 \
+           $(DESTDIR)$(sudoersdir)/sudoers.d
+       test -r $(DESTDIR)$(sudoersdir)/sudoers || \
+           $(INSTALL) -O $(sudoers_uid) -G $(sudoers_gid) -M $(sudoers_mode) \
+               sudoers $(DESTDIR)$(sudoersdir)/sudoers
+
+uninstall:
+       -rm -f $(DESTDIR)$(plugindir)/sudoers$(soext)
+       -rm -f $(DESTDIR)$(replaydir)/sudoreplay
+       -rm -f $(DESTDIR)$(visudodir)/visudo
+       -cmp $(DESTDIR)$(sudoersdir)/sudoers $(srcdir)/sudoers >/dev/null && \
+           rm -f $(DESTDIR)$(sudoersdir)/sudoers
+
+check: $(TEST_PROGS) visudo testsudoers
+       @-rval=0; \
+       ./check_iolog_path $(srcdir)/regress/iolog_path/data; \
+       rval=`expr $$rval + $$?`; \
+       ./check_fill; \
+       rval=`expr $$rval + $$?`; \
+       passed=0; failed=0; total=0; \
+           for t in $(srcdir)/regress/sudoers/*.in; do \
+               dir=`dirname $$t`; \
+               dirbase=`basename $$dir`; \
+               base=`basename $$t .in`; \
+               out="$${base}.out"; \
+               toke="$${base}.toke"; \
+               ./testsudoers -dt <$$t >$$out 2>$$toke; \
+               if cmp $$out $$dir/$$out.ok >/dev/null; then \
+                   passed=`expr $$passed + 1`; \
+                   echo "$$dirbase/$$base (parse): OK"; \
+               else \
+                   failed=`expr $$failed + 1`; \
+                   echo "$$dirbase/$$base: FAIL"; \
+                   diff $$out $$dir/$$out.ok; \
+               fi; \
+               total=`expr $$total + 1`; \
+               if cmp $$toke $$dir/$$toke.ok >/dev/null; then \
+                   passed=`expr $$passed + 1`; \
+                   echo "$$dirbase/$$base (toke):  OK"; \
+               else \
+                   failed=`expr $$failed + 1`; \
+                   echo "$$dirbase/$$base (toke):  FAIL"; \
+                   diff $$out $$dir/$$out.ok; \
+               fi; \
+               total=`expr $$total + 1`; \
+           done; \
+           echo "$$dirbase: $$passed/$$total tests passed; $$failed/$$total tests failed"; \
+       rval=$$failed; passed=0; failed=0; total=0; \
+           for t in $(srcdir)/regress/*/*.sh; do \
+               dir=`dirname $$t`; \
+               dirbase=`basename $$dir`; \
+               base=`basename $$t .sh`; \
+               out="$${base}.out"; \
+               err="$${base}.err"; \
+               $(SHELL) $$t >$$out 2>$$err; \
+               if cmp $$out $$dir/$$out.ok >/dev/null; then \
+                   passed=`expr $$passed + 1`; \
+                   echo "$$dirbase/$$base: OK"; \
+               else \
+                   failed=`expr $$failed + 1`; \
+                   echo "$$dirbase/$$base: FAIL"; \
+                   diff $$out $$dir/$$out.ok; \
+               fi; \
+               total=`expr $$total + 1`; \
+               if test -s $$dir/$$err.ok; then \
+                   if cmp $$err $$dir/$$err.ok >/dev/null; then \
+                       passed=`expr $$passed + 1`; \
+                       echo "$$dirbase/$$base (stderr): OK"; \
+                   else \
+                       failed=`expr $$failed + 1`; \
+                       echo "$$dirbase/$$base (stderr): FAIL"; \
+                       diff $$out $$dir/$$out.ok; \
+                   fi; \
+                   total=`expr $$total + 1`; \
+               elif test -s $$err; then \
+                   cat $$err 1>&2; \
+               fi; \
+           done; \
+           echo "$$dirbase: $$passed/$$total tests passed; $$failed/$$total tests failed"; \
+           rval=`expr $$rval + $$failed`; exit $$rval
+
+clean:
+       -$(LIBTOOL) --mode=clean rm -f $(PROGS) *.lo *.o *.la *.a stamp-* core *.core core.* *.out
+
+mostlyclean: clean
+
+distclean: clean
+       -rm -rf Makefile sudoers sudoers.lo .libs $(LINKS)
+
+clobber: distclean
+
+realclean: distclean
+       rm -f TAGS tags
+
+cleandir: realclean
diff --git a/plugins/sudoers/aixcrypt.exp b/plugins/sudoers/aixcrypt.exp
new file mode 100644 (file)
index 0000000..5ee024e
--- /dev/null
@@ -0,0 +1,4 @@
+#!
+__setkey
+__encrypt
+__crypt
diff --git a/plugins/sudoers/alias.c b/plugins/sudoers/alias.c
new file mode 100644 (file)
index 0000000..274b446
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2004-2005, 2007-2011
+ *     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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include "sudoers.h"
+#include "parse.h"
+#include "redblack.h"
+#include <gram.h>
+
+/*
+ * Globals
+ */
+struct rbtree *aliases;
+unsigned int alias_seqno;
+
+/*
+ * Comparison function for the red-black tree.
+ * Aliases are sorted by name with the type used as a tie-breaker.
+ */
+int
+alias_compare(const void *v1, const void *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 *
+alias_find(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(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)) {
+       snprintf(errbuf, sizeof(errbuf), "Alias `%s' already defined", name);
+       alias_free(a);
+       return errbuf;
+    }
+    return NULL;
+}
+
+/*
+ * Apply a function to each alias entry and pass in a cookie.
+ */
+void
+alias_apply(int (*func)(void *, void *), void *cookie)
+{
+    rbapply(aliases, func, cookie, inorder);
+}
+
+/*
+ * Returns TRUE if there are no aliases, else FALSE.
+ */
+int
+no_aliases(void)
+{
+    return rbisempty(aliases);
+}
+
+/*
+ * Free memory used by an alias struct and its members.
+ */
+void
+alias_free(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, remove it from the tree and return it.
+ */
+struct alias *
+alias_remove(char *name, int type)
+{
+    struct rbnode *node;
+    struct alias key;
+
+    key.name = name;
+    key.type = type;
+    if ((node = rbfind(aliases, &key)) == NULL)
+       return NULL;
+    return rbdelete(aliases, node);
+}
+
+void
+init_aliases(void)
+{
+    if (aliases != NULL)
+       rbdestroy(aliases, alias_free);
+    aliases = rbcreate(alias_compare);
+}
diff --git a/plugins/sudoers/audit.c b/plugins/sudoers/audit.c
new file mode 100644 (file)
index 0000000..2cb1130
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009-2010 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 <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#include <stdarg.h>
+
+#include "missing.h"
+#include "logging.h"
+
+#ifdef HAVE_BSM_AUDIT
+# include "bsm_audit.h"
+#endif
+#ifdef HAVE_LINUX_AUDIT
+# include "linux_audit.h"
+#endif
+
+void
+audit_success(char *exec_args[])
+{
+#ifdef HAVE_BSM_AUDIT
+    bsm_audit_success(exec_args);
+#endif
+#ifdef HAVE_LINUX_AUDIT
+    linux_audit_command(exec_args, 1);
+#endif
+}
+
+void
+audit_failure(char **exec_args, char const *const fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+#ifdef HAVE_BSM_AUDIT
+    bsm_audit_failure(exec_args, fmt, ap);
+#endif
+#ifdef HAVE_LINUX_AUDIT
+    linux_audit_command(exec_args, 0);
+#endif
+    va_end(ap);
+}
diff --git a/plugins/sudoers/auth/API b/plugins/sudoers/auth/API
new file mode 100644 (file)
index 0000000..24bd510
--- /dev/null
@@ -0,0 +1,122 @@
+NOTE: the Sudo auth API is subject to change
+
+Purpose: to provide a simple API for authentication methods that
+         encapsulates things nicely without turning into a maze
+        of #ifdef's
+
+The sudo_auth struct looks like this:
+
+typedef struct sudo_auth {
+    int flags;                  /* various flags, see below */
+    int status;                 /* status from verify routine */
+    char *name;                        /* name of the method in string form */
+    void *data;                 /* method-specific data pointer */
+
+    int (*init)(struct passwd *pw, char **prompt, sudo_auth *auth);
+    int (*setup)(struct passwd *pw, char **prompt, sudo_auth *auth);
+    int (*verify)(struct passwd *pw, char *p, sudo_auth *auth);
+    int (*cleanup)(struct passwd *pw, sudo_auth *auth);
+    int (*begin_session)(struct passwd *pw, sudo_auth *auth);
+    int (*end_session)(sudo_auth *auth);
+} sudo_auth;
+
+The variables in the struct are as follows:
+    flags      Bitwise binary flags, see below.
+
+    status     Contains the return value from the last run of
+               the "verify" function.  Starts out as AUTH_FAILURE.
+
+    name       The name of the authentication method as a C string.
+
+    data       A pointer to method-specific data.  This is passed to
+               all the functions of an auth method and is usually
+               initialized in the "init" or "setup" routines.
+
+Possible values of sudo_auth.flags:
+    FLAG_USER          Whether or not the auth functions should run with
+                       the euid of the invoking user instead of 0.
+
+    FLAG_DISABLED      Set if an "init" or "setup" function fails.
+
+    FLAG_STANDALONE    If set, this indicates that the method must
+                       be the only auth method configured, and that
+                       it will prompt for the password itself.
+
+    FLAG_ONEANDONLY    If set, this indicates that the method is the
+                       only one in use.  Can be used by auth functions
+                       to determine whether to return a fatal or nonfatal
+                       error.
+
+The member functions can return the following values:
+    AUTH_SUCCESS       Function succeeded.  For a ``verify'' function
+                       this means the user correctly authenticated.
+
+    AUTH_FAILURE       Function failed.  If this is an ``init'' or
+                       ``setup'' routine, the auth method will be
+                       marked as !configured.
+
+    AUTH_FATAL         A fatal error occurred.  The routine should have
+                       written an error message to stderr and optionally
+                       sent mail to the administrator.  (If log_error()
+                       is called to do this, the NO_EXIT flag must be used.)
+                       When verify_user() gets AUTH_FATAL from an auth
+                       function it does an exit(1).
+
+The functions in the struct are as follows:
+
+    int init(struct passwd *pw, char **prompt, sudo_auth *auth)
+        Function to do any one-time initialization for the auth
+        method.  All of the "init" functions are run before anything
+        else.  A pointer to the prompt string may be used to add
+        method-specific info to the prompt.
+
+    int setup(struct passwd *pw, char **prompt, sudo_auth *auth)
+        Function to do method-specific setup.  All the "setup"
+        routines are run before any of the "verify" routines.  A
+        pointer to the prompt string may be used to add method-specific
+        info to the prompt.
+
+    int verify(struct passwd *pw, char *p, sudo_auth *auth)
+        Function to do user verification for this auth method.  For
+        standalone auth methods ``p'' is the prompt string.  For
+        normal auth methods, ``p'' is the password the user entered.
+        Note that standalone auth methods are responsible for
+        rerading the password themselves.
+
+    int cleanup(struct passwd *pw, sudo_auth *auth)
+        Function to do per-auth method cleanup.  This is only run
+        at the end of the authentication process, after the user
+        has completely failed or succeeded to authenticate.
+       The ``auth->status'' variable contains the result of the
+       last authentication attempt which may be interesting.
+
+A note about standalone methods.  Some authentication methods can't
+coexist with any others.  This may be because they encapsulate other
+methods (pam, sia) or because they have a special way of interacting
+with the user (securid).
+
+Adding a new authentication method:
+
+Each method should live in its own file.  Add prototypes for the functions
+in sudo_auth.h.
+
+Add the method to the ``auth_switch'' in sudo_auth.c.  Note that
+standalone methods must go first.  If ``fooauth'' is a normal auth
+method, its entry would look like:
+
+#ifdef HAVE_FOOAUTH
+AUTH_ENTRY("foo", 0, foo_init, foo_setup, foo_verify,
+    foo_cleanup, foo_begin_session, foo_end_session)
+#endif
+
+If this is a standalone method, it would be:
+
+#ifdef HAVE_FOOAUTH
+AUTH_ENTRY("foo", FLAG_STANDALONE, foo_init, foo_setup, foo_verify,
+    foo_cleanup, foo_begin_session, foo_end_session)
+#endif
+
+If the method needs to run as the user, not root, add FLAG_USER to
+the second argument in the  AUTH_ENTRY line.  If you don't have an
+init/setup/cleanup/begin/end routine, just use a NULL for that
+field.
diff --git a/plugins/sudoers/auth/afs.c b/plugins/sudoers/auth/afs.c
new file mode 100644 (file)
index 0000000..389bd9d
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1999, 2001-2005, 2007, 2010-2011
+ *     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/param.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 */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+
+#include <afs/stds.h>
+#include <afs/kautils.h>
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+int
+afs_verify(struct passwd *pw, char *pass, sudo_auth *auth)
+{
+    struct ktc_encryptionKey afs_key;
+    struct ktc_token afs_token;
+
+    /* Try to just check the password */
+    ka_StringToKey(pass, NULL, &afs_key);
+    if (ka_GetAdminToken(pw->pw_name,          /* name */
+                        NULL,                  /* instance */
+                        NULL,                  /* realm */
+                        &afs_key,              /* key (contains password) */
+                        0,                     /* lifetime */
+                        &afs_token,            /* token */
+                        0) == 0)               /* new */
+       return AUTH_SUCCESS;
+
+    /* Fall back on old method XXX - needed? */
+    setpag();
+    if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
+                                  pw->pw_name, /* name */
+                                  NULL,        /* instance */
+                                  NULL,        /* realm */
+                                  pass,        /* password */
+                                  0,           /* lifetime */
+                                  NULL,        /* expiration ptr (unused) */
+                                  0,           /* spare */
+                                  NULL) == 0)  /* reason */
+       return AUTH_SUCCESS;
+
+    return AUTH_FAILURE;
+}
diff --git a/plugins/sudoers/auth/aix_auth.c b/plugins/sudoers/auth/aix_auth.c
new file mode 100644 (file)
index 0000000..9f54f91
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1999-2005, 2007-2011 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/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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+/*
+ * For a description of the AIX authentication API, see
+ * http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf1/authenticate.htm
+ */
+int
+aixauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
+{
+    char *pass;
+    char *message = NULL;
+    int reenter = 1;
+    int rval = AUTH_FAILURE;
+
+    pass = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF);
+    if (pass) {
+       /* XXX - should probably print message on failure. */
+       if (authenticate(pw->pw_name, pass, &reenter, &message) == 0)
+           rval = AUTH_SUCCESS;
+       free(message);
+       zero_bytes(pass, strlen(pass));
+    }
+    return rval;
+}
+
+int
+aixauth_cleanup(struct passwd *pw, sudo_auth *auth)
+{
+    /* Unset AUTHSTATE as it may not be correct for the runas user. */
+    unsetenv("AUTHSTATE");
+
+    return AUTH_SUCCESS;
+}
diff --git a/plugins/sudoers/auth/bsdauth.c b/plugins/sudoers/auth/bsdauth.c
new file mode 100644 (file)
index 0000000..f70e424
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2000-2005, 2007-2008, 2010-2011
+ *     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/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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <ctype.h>
+#include <pwd.h>
+#include <signal.h>
+
+#include <login_cap.h>
+#include <bsd_auth.h>
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+extern char *login_style;              /* from sudo.c */
+
+int
+bsdauth_init(struct passwd *pw, char **promptp, sudo_auth *auth)
+{
+    static auth_session_t *as;
+    extern login_cap_t *lc;                    /* from sudo.c */
+
+    if ((as = auth_open()) == NULL) {
+       log_error(USE_ERRNO|NO_EXIT|NO_MAIL,
+           "unable to begin bsd authentication");
+       return AUTH_FATAL;
+    }
+
+    /* XXX - maybe sanity check the auth style earlier? */
+    login_style = login_getstyle(lc, login_style, "auth-sudo");
+    if (login_style == NULL) {
+       log_error(NO_EXIT|NO_MAIL, "invalid authentication type");
+       auth_close(as);
+       return AUTH_FATAL;
+    }
+
+     if (auth_setitem(as, AUTHV_STYLE, login_style) < 0 ||
+       auth_setitem(as, AUTHV_NAME, pw->pw_name) < 0 ||
+       auth_setitem(as, AUTHV_CLASS, login_class) < 0) {
+       log_error(NO_EXIT|NO_MAIL, "unable to setup authentication");
+       auth_close(as);
+       return AUTH_FATAL;
+    }
+
+    auth->data = (void *) as;
+    return AUTH_SUCCESS;
+}
+
+int
+bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
+{
+    char *pass;
+    char *s;
+    size_t len;
+    int authok = 0;
+    sigaction_t sa, osa;
+    auth_session_t *as = (auth_session_t *) auth->data;
+
+    /* save old signal handler */
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = SA_RESTART;
+    sa.sa_handler = SIG_DFL;
+    (void) sigaction(SIGCHLD, &sa, &osa);
+
+    /*
+     * If there is a challenge then print that instead of the normal
+     * prompt.  If the user just hits return we prompt again with echo
+     * turned on, which is useful for challenge/response things like
+     * S/Key.
+     */
+    if ((s = auth_challenge(as)) == NULL) {
+       pass = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF);
+    } else {
+       pass = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF);
+       if (pass && *pass == '\0') {
+           if ((prompt = strrchr(s, '\n')))
+               prompt++;
+           else
+               prompt = s;
+
+           /*
+            * Append '[echo on]' to the last line of the challenge and
+            * reprompt with echo turned on.
+            */
+           len = strlen(prompt) - 1;
+           while (isspace(prompt[len]) || prompt[len] == ':')
+               prompt[len--] = '\0';
+           easprintf(&s, "%s [echo on]: ", prompt);
+           pass = auth_getpass(prompt, def_passwd_timeout * 60,
+               SUDO_CONV_PROMPT_ECHO_ON);
+           free(s);
+       }
+    }
+
+    if (pass) {
+       authok = auth_userresponse(as, pass, 1);
+       zero_bytes(pass, strlen(pass));
+    }
+
+    /* restore old signal handler */
+    (void) sigaction(SIGCHLD, &osa, NULL);
+
+    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;
+}
+
+int
+bsdauth_cleanup(struct passwd *pw, sudo_auth *auth)
+{
+    auth_session_t *as = (auth_session_t *) auth->data;
+
+    auth_close(as);
+
+    return AUTH_SUCCESS;
+}
diff --git a/plugins/sudoers/auth/dce.c b/plugins/sudoers/auth/dce.c
new file mode 100644 (file)
index 0000000..a4ffd34
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2010-2011
+ *     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.
+ */
+/*
+ *  The code below basically comes from the examples supplied on
+ *  the OSF DCE 1.0.3 manpages for the sec_login routines, with
+ *  enough additional polishing to make the routine work with the
+ *  rest of sudo.
+ *
+ *  This code is known to work on HP 700 and 800 series systems
+ *  running HP-UX 9.X and 10.X, with either HP's version 1.2.1 of DCE.
+ *  (aka, OSF DCE 1.0.3) or with HP's version 1.4 of DCE (aka, OSF
+ *  DCE 1.1).
+ */
+
+#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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+
+#include <dce/rpc.h>
+#include <dce/sec_login.h>
+#include <dce/dce_error.h> /* required to call dce_error_inq_text routine */
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+static int check_dce_status(error_status_t, char *);
+
+int
+dce_verify(struct passwd *pw, char *plain_pw, sudo_auth *auth)
+{
+    struct passwd              temp_pw;
+    sec_passwd_rec_t           password_rec;
+    sec_login_handle_t         login_context;
+    boolean32                  reset_passwd;
+    sec_login_auth_src_t       auth_src;
+    error_status_t             status;
+
+    /*
+     * Create the local context of the DCE principal necessary
+     * to perform authenticated network operations.  The network
+     * identity set up by this operation cannot be used until it
+     * is validated via sec_login_validate_identity().
+     */
+    if (sec_login_setup_identity((unsigned_char_p_t) pw->pw_name,
+       sec_login_no_flags, &login_context, &status)) {
+
+       if (check_dce_status(status, "sec_login_setup_identity(1):"))
+           return AUTH_FAILURE;
+
+       password_rec.key.key_type = sec_passwd_plain;
+       password_rec.key.tagged_union.plain = (idl_char *) plain_pw;
+       password_rec.pepper = NULL;
+       password_rec.version_number = sec_passwd_c_version_none;
+
+       /* Validate the login context with the password */
+       if (sec_login_validate_identity(login_context, &password_rec,
+           &reset_passwd, &auth_src, &status)) {
+
+           if (check_dce_status(status, "sec_login_validate_identity(1):"))
+               return AUTH_FAILURE;
+
+           /*
+            * Certify that the DCE Security Server used to set
+            * up and validate a login context is legitimate.  Makes
+            * sure that we didn't get spoofed by another DCE server.
+            */
+           if (!sec_login_certify_identity(login_context, &status)) {
+               (void) fprintf(stderr, "Whoa! Bogus authentication server!\n");
+               (void) check_dce_status(status,"sec_login_certify_identity(1):");
+               return AUTH_FAILURE;
+           }
+           if (check_dce_status(status, "sec_login_certify_identity(2):"))
+               return AUTH_FAILURE;
+
+           /*
+            * Sets the network credentials to those specified
+            * by the now validated login context.
+            */
+           sec_login_set_context(login_context, &status);
+           if (check_dce_status(status, "sec_login_set_context:"))
+               return AUTH_FAILURE;
+
+           /*
+            * Oops, your credentials were no good. Possibly
+            * caused by clock times out of adjustment between
+            * DCE client and DCE security server...
+            */
+           if (auth_src != sec_login_auth_src_network) {
+                   (void) fprintf(stderr,
+                       "You have no network credentials.\n");
+                   return AUTH_FAILURE;
+           }
+           /* Check if the password has aged and is thus no good */
+           if (reset_passwd) {
+                   (void) fprintf(stderr,
+                       "Your DCE password needs resetting.\n");
+                   return AUTH_FAILURE;
+           }
+
+           /*
+            * We should be a valid user by this point.  Pull the
+            * user's password structure from the DCE security
+            * server just to make sure.  If we get it with no
+            * problems, then we really are legitimate...
+            */
+           sec_login_get_pwent(login_context, (sec_login_passwd_t) &temp_pw,
+               &status);
+           if (check_dce_status(status, "sec_login_get_pwent:"))
+               return AUTH_FAILURE;
+
+           /*
+            * If we get to here, then the pwent above properly fetched
+            * the password structure from the DCE registry, so the user
+            * must be valid.  We don't really care what the user's
+            * registry password is, just that the user could be
+            * validated.  In fact, if we tried to compare the local
+            * password to the DCE entry at this point, the operation
+            * would fail if the hidden password feature is turned on,
+            * because the password field would contain an asterisk.
+            * Also go ahead and destroy the user's DCE login context
+            * before we leave here (and don't bother checking the
+            * status), in order to clean up credentials files in
+            * /opt/dcelocal/var/security/creds.  By doing this, we are
+            * assuming that the user will not need DCE authentication
+            * later in the program, only local authentication.  If this
+            * is not true, then the login_context will have to be
+            * returned to the calling program, and the context purged
+            * somewhere later in the program.
+            */
+           sec_login_purge_context(&login_context, &status);
+           return AUTH_SUCCESS;
+       } else {
+           if(check_dce_status(status, "sec_login_validate_identity(2):"))
+               return AUTH_FAILURE;
+           sec_login_purge_context(&login_context, &status);
+           if(check_dce_status(status, "sec_login_purge_context:"))
+               return AUTH_FAILURE;
+       }
+    }
+    (void) check_dce_status(status, "sec_login_setup_identity(2):");
+    return AUTH_FAILURE;
+}
+
+/* Returns 0 for DCE "ok" status, 1 otherwise */
+static int
+check_dce_status(error_status_t input_status, char *comment)
+{
+    int error_stat;
+    unsigned char error_string[dce_c_error_string_len];
+
+    if (input_status == rpc_s_ok)
+       return 0;
+    dce_error_inq_text(input_status, error_string, &error_stat);
+    (void) fprintf(stderr, "%s %s\n", comment, error_string);
+    return 1;
+}
diff --git a/plugins/sudoers/auth/fwtk.c b/plugins/sudoers/auth/fwtk.c
new file mode 100644 (file)
index 0000000..a3a5cff
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 1999-2005, 2008, 2010-2011
+ *     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/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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+
+#include <auth.h>
+#include <firewall.h>
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+int
+fwtk_init(struct passwd *pw, char **promptp, sudo_auth *auth)
+{
+    static Cfg *confp;                 /* Configuration entry struct */
+    char resp[128];                    /* Response from the server */
+
+    if ((confp = cfg_read("sudo")) == (Cfg *)-1) {
+       warningx("cannot read fwtk config");
+       return AUTH_FATAL;
+    }
+
+    if (auth_open(confp)) {
+       warningx("cannot connect to authentication server");
+       return AUTH_FATAL;
+    }
+
+    /* Get welcome message from auth server */
+    if (auth_recv(resp, sizeof(resp))) {
+       warningx("lost connection to authentication server");
+       return AUTH_FATAL;
+    }
+    if (strncmp(resp, "Authsrv ready", 13) != 0) {
+       warningx("authentication server error:\n%s", resp);
+       return AUTH_FATAL;
+    }
+
+    return AUTH_SUCCESS;
+}
+
+int
+fwtk_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
+{
+    char *pass;                                /* Password from the user */
+    char buf[SUDO_PASS_MAX + 12];      /* General prupose buffer */
+    char resp[128];                    /* Response from the server */
+    int error;
+
+    /* 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))) {
+       warningx("lost connection to authentication server");
+       return AUTH_FATAL;
+    }
+
+    /* Get the password/response from the user. */
+    if (strncmp(resp, "challenge ", 10) == 0) {
+       (void) snprintf(buf, sizeof(buf), "%s\nResponse: ", &resp[10]);
+       pass = auth_getpass(buf, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF);
+       if (pass && *pass == '\0') {
+           pass = auth_getpass("Response [echo on]: ",
+               def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_ON);
+       }
+    } else if (strncmp(resp, "chalnecho ", 10) == 0) {
+       pass = auth_getpass(&resp[10], def_passwd_timeout * 60,
+           SUDO_CONV_PROMPT_ECHO_OFF);
+    } else if (strncmp(resp, "password", 8) == 0) {
+       pass = auth_getpass(prompt, def_passwd_timeout * 60,
+           SUDO_CONV_PROMPT_ECHO_OFF);
+    } else if (strncmp(resp, "display ", 8) == 0) {
+       fprintf(stderr, "%s\n", &resp[8]);
+       strlcpy(buf, "response dummy", sizeof(buf));
+       goto restart;
+    } else {
+       warningx("%s", resp);
+       return AUTH_FATAL;
+    }
+    if (!pass) {                       /* ^C or error */
+       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))) {
+       warningx("lost connection to authentication server");
+       error = AUTH_FATAL;
+       goto done;
+    }
+
+    if (strncmp(resp, "ok", 2) == 0) {
+       error = AUTH_SUCCESS;
+       goto done;
+    }
+
+    /* Main loop prints "Permission Denied" or insult. */
+    if (strcmp(resp, "Permission Denied.") != 0)
+       warningx("%s", resp);
+    error = AUTH_FAILURE;
+done:
+    zero_bytes(pass, strlen(pass));
+    zero_bytes(buf, strlen(buf));
+    return error;
+}
+
+int
+fwtk_cleanup(struct passwd *pw, sudo_auth *auth)
+{
+
+    auth_close();
+    return AUTH_SUCCESS;
+}
diff --git a/plugins/sudoers/auth/kerb4.c b/plugins/sudoers/auth/kerb4.c
new file mode 100644 (file)
index 0000000..176d6a7
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1999-2005, 2007, 2010-2011
+ *     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/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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#include <krb.h>
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+int
+kerb4_init(struct passwd *pw, char **promptp, sudo_auth *auth)
+{
+    static char realm[REALM_SZ];
+
+    /* Don't try to verify root */
+    if (pw->pw_uid == 0)
+       return AUTH_FAILURE;
+
+    /* Get the local realm, or retrun failure (no krb.conf) */
+    if (krb_get_lrealm(realm, 1) != KSUCCESS)
+       return AUTH_FAILURE;
+
+    /* Stash a pointer to the realm (used in kerb4_verify) */
+    auth->data = (void *) realm;
+
+    return AUTH_SUCCESS;
+}
+
+int
+kerb4_verify(struct passwd *pw, char *pass, sudo_auth *auth)
+{
+    char tkfile[sizeof(_PATH_SUDO_TIMEDIR) + 4 + MAX_UID_T_LEN];
+    char *realm = (char *) auth->data;
+    int error;
+
+    /*
+     * Set the ticket file to be in sudo sudo timedir so we don't
+     * wipe out other (real) kerberos tickets.
+     */
+    (void) snprintf(tkfile, sizeof(tkfile), "%s/tkt%u",
+       _PATH_SUDO_TIMEDIR, (unsigned int) pw->pw_uid);
+    (void) krb_set_tkt_string(tkfile);
+
+    /* Convert the password to a ticket given. */
+    error = krb_get_pw_in_tkt(pw->pw_name, "", realm, "krbtgt", realm,
+       DEFAULT_TKT_LIFE, pass);
+
+    switch (error) {
+       case INTK_OK:
+           dest_tkt();                 /* we are done with the temp ticket */
+           return AUTH_SUCCESS;
+           break;
+       case INTK_BADPW:
+       case KDC_PR_UNKNOWN:
+           break;
+       default:
+           (void) fprintf(stderr, "Warning: Kerberos error: %s\n",
+               krb_err_txt[error]);
+    }
+
+    return AUTH_FAILURE;
+}
diff --git a/plugins/sudoers/auth/kerb5.c b/plugins/sudoers/auth/kerb5.c
new file mode 100644 (file)
index 0000000..38d84cb
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 1999-2005, 2007-2008, 2010-2011
+ *     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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#include <krb5.h>
+#ifdef HAVE_HEIMDAL
+#include <com_err.h>
+#endif
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+#ifdef HAVE_HEIMDAL
+# define extract_name(c, p)            krb5_principal_get_comp_string(c, p, 1)
+# define krb5_free_data_contents(c, d) krb5_data_free(d)
+#else
+# define extract_name(c, p)            (krb5_princ_component(c, p, 1)->data)
+#endif
+
+#ifndef HAVE_KRB5_VERIFY_USER
+static int verify_krb_v5_tgt(krb5_context, krb5_creds *, char *);
+#endif
+static struct _sudo_krb5_data {
+    krb5_context       sudo_context;
+    krb5_principal     princ;
+    krb5_ccache                ccache;
+} 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(krb5_context context,
+    krb5_get_init_creds_opt **opts)
+{
+    *opts = emalloc(sizeof(krb5_get_init_creds_opt));
+    krb5_get_init_creds_opt_init(*opts);
+    return 0;
+}
+
+static void
+krb5_get_init_creds_opt_free(krb5_get_init_creds_opt *opts)
+{
+    free(opts);
+}
+#endif
+
+int
+kerb5_init(struct passwd *pw, char **promptp, sudo_auth *auth)
+{
+    krb5_context       sudo_context;
+    krb5_ccache                ccache;
+    krb5_principal     princ;
+    krb5_error_code    error;
+    char               cache_name[64];
+    char               *pname;
+
+    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));
+#else
+    error = krb5_init_context(&(sudo_krb5_data.sudo_context));
+#endif
+    if (error)
+       return AUTH_FAILURE;
+    sudo_context = sudo_krb5_data.sudo_context;
+
+    if ((error = krb5_parse_name(sudo_context, pw->pw_name,
+       &(sudo_krb5_data.princ)))) {
+       log_error(NO_EXIT|NO_MAIL,
+                 "%s: unable to parse '%s': %s", auth->name, pw->pw_name,
+                 error_message(error));
+       return AUTH_FAILURE;
+    }
+    princ = sudo_krb5_data.princ;
+
+    /*
+     * Really, we need to tell the caller not to prompt for password.
+     * The API does not currently provide this unless the auth is standalone.
+     */
+#if 1
+    if ((error = krb5_unparse_name(sudo_context, princ, &pname))) {
+       log_error(NO_EXIT|NO_MAIL,
+                 "%s: unable to unparse princ ('%s'): %s", auth->name,
+                 pw->pw_name, error_message(error));
+       return AUTH_FAILURE;
+    }
+
+    /* Only rewrite prompt if user didn't specify their own. */
+    /*if (!strcmp(prompt, PASSPROMPT)) { */
+       easprintf(promptp, "Password for %s: ", pname);
+    /*}*/
+    free(pname);
+#endif
+
+    (void) snprintf(cache_name, sizeof(cache_name), "MEMORY:sudocc_%ld",
+                   (long) getpid());
+    if ((error = krb5_cc_resolve(sudo_context, cache_name,
+       &(sudo_krb5_data.ccache)))) {
+       log_error(NO_EXIT|NO_MAIL,
+                 "%s: unable to resolve ccache: %s", auth->name,
+                 error_message(error));
+       return AUTH_FAILURE;
+    }
+    ccache = sudo_krb5_data.ccache;
+
+    return AUTH_SUCCESS;
+}
+
+#ifdef HAVE_KRB5_VERIFY_USER
+int
+kerb5_verify(struct passwd *pw, char *pass, sudo_auth *auth)
+{
+    krb5_context       sudo_context;
+    krb5_principal     princ;
+    krb5_ccache                ccache;
+    krb5_error_code    error;
+
+    sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context;
+    princ = ((sudo_krb5_datap) auth->data)->princ;
+    ccache = ((sudo_krb5_datap) auth->data)->ccache;
+
+    error = krb5_verify_user(sudo_context, princ, ccache, pass, 1, NULL);
+    return error ? AUTH_FAILURE : AUTH_SUCCESS;
+}
+#else
+int
+kerb5_verify(struct passwd *pw, char *pass, sudo_auth *auth)
+{
+    krb5_context       sudo_context;
+    krb5_principal     princ;
+    krb5_creds         credbuf, *creds = NULL;
+    krb5_ccache                ccache;
+    krb5_error_code    error;
+    krb5_get_init_creds_opt *opts = NULL;
+
+    sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context;
+    princ = ((sudo_krb5_datap) auth->data)->princ;
+    ccache = ((sudo_krb5_datap) auth->data)->ccache;
+
+    /* Set default flags based on the local config file. */
+    error = krb5_get_init_creds_opt_alloc(sudo_context, &opts);
+    if (error) {
+       log_error(NO_EXIT|NO_MAIL,
+                 "%s: unable to allocate options: %s", auth->name,
+                 error_message(error));
+       goto done;
+    }
+#ifdef HAVE_HEIMDAL
+    krb5_get_init_creds_opt_set_default_flags(sudo_context, NULL,
+       krb5_principal_get_realm(sudo_context, princ), opts);
+#endif
+
+    /* Note that we always obtain a new TGT to verify the user */
+    if ((error = krb5_get_init_creds_password(sudo_context, &credbuf, princ,
+                                            pass, krb5_prompter_posix,
+                                            NULL, 0, NULL, opts))) {
+       /* Don't print error if just a bad password */
+       if (error != KRB5KRB_AP_ERR_BAD_INTEGRITY)
+           log_error(NO_EXIT|NO_MAIL,
+                     "%s: unable to get credentials: %s", auth->name,
+                     error_message(error));
+       goto done;
+    }
+    creds = &credbuf;
+
+    /* Verify the TGT to prevent spoof attacks. */
+    if ((error = verify_krb_v5_tgt(sudo_context, creds, auth->name)))
+       goto done;
+
+    /* Store cred in cred cache. */
+    if ((error = krb5_cc_initialize(sudo_context, ccache, princ))) {
+       log_error(NO_EXIT|NO_MAIL,
+                 "%s: unable to initialize ccache: %s", auth->name,
+                 error_message(error));
+    } else if ((error = krb5_cc_store_cred(sudo_context, ccache, creds))) {
+       log_error(NO_EXIT|NO_MAIL,
+                 "%s: unable to store cred in ccache: %s", auth->name,
+                 error_message(error));
+    }
+
+done:
+    if (opts) {
+#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)
+       krb5_free_cred_contents(sudo_context, creds);
+    return error ? AUTH_FAILURE : AUTH_SUCCESS;
+}
+#endif
+
+int
+kerb5_cleanup(struct passwd *pw, sudo_auth *auth)
+{
+    krb5_context       sudo_context;
+    krb5_principal     princ;
+    krb5_ccache                ccache;
+
+    sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context;
+    princ = ((sudo_krb5_datap) auth->data)->princ;
+    ccache = ((sudo_krb5_datap) auth->data)->ccache;
+
+    if (sudo_context) {
+       if (ccache)
+           krb5_cc_destroy(sudo_context, ccache);
+       if (princ)
+           krb5_free_principal(sudo_context, princ);
+       krb5_free_context(sudo_context);
+    }
+
+    return AUTH_SUCCESS;
+}
+
+#ifndef HAVE_KRB5_VERIFY_USER
+/*
+ * Verify the Kerberos ticket-granting ticket just retrieved for the
+ * user.  If the Kerberos server doesn't respond, assume the user is
+ * trying to fake us out (since we DID just get a TGT from what is
+ * supposedly our KDC).
+ *
+ * Returns 0 for successful authentication, non-zero for failure.
+ */
+static int
+verify_krb_v5_tgt(krb5_context sudo_context, krb5_creds *cred, char *auth_name)
+{
+    krb5_error_code    error;
+    krb5_principal     server;
+    krb5_verify_init_creds_opt vopt;
+
+    /*
+     * Get the server principal for the local host.
+     * (Use defaults of "host" and canonicalized local name.)
+     */
+    if ((error = krb5_sname_to_principal(sudo_context, NULL, NULL,
+                                       KRB5_NT_SRV_HST, &server))) {
+       log_error(NO_EXIT|NO_MAIL,
+                 "%s: unable to get host principal: %s", auth_name,
+                 error_message(error));
+       return -1;
+    }
+
+    /* Initialize verify opts and set secure mode */
+    krb5_verify_init_creds_opt_init(&vopt);
+    krb5_verify_init_creds_opt_set_ap_req_nofail(&vopt, 1);
+
+    /* verify the Kerberos ticket-granting ticket we just retrieved */
+    error = krb5_verify_init_creds(sudo_context, cred, server, NULL,
+                                  NULL, &vopt);
+    krb5_free_principal(sudo_context, server);
+    if (error)
+       log_error(NO_EXIT|NO_MAIL,
+                 "%s: Cannot verify TGT! Possible attack!: %s", auth_name,
+                 error_message(error));
+    return error;
+}
+#endif
diff --git a/plugins/sudoers/auth/pam.c b/plugins/sudoers/auth/pam.c
new file mode 100644 (file)
index 0000000..4ff4eed
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 1999-2005, 2007-2011 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/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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#include <errno.h>
+
+#ifdef HAVE_PAM_PAM_APPL_H
+# include <pam/pam_appl.h>
+#else
+# include <security/pam_appl.h>
+#endif
+
+#ifdef HAVE_DGETTEXT
+# include <libintl.h>
+# if defined(__LINUX_PAM__)
+#  define PAM_TEXT_DOMAIN      "Linux-PAM"
+# elif defined(__sun__)
+#  define PAM_TEXT_DOMAIN      "SUNW_OST_SYSOSPAM"
+# endif
+#endif
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+/* Only OpenPAM and Linux PAM use const qualifiers. */
+#if defined(_OPENPAM) || defined(OPENPAM_VERSION) || \
+    defined(__LIBPAM_VERSION) || defined(__LINUX_PAM__)
+# define PAM_CONST     const
+#else
+# define PAM_CONST
+#endif
+
+static int converse(int, PAM_CONST struct pam_message **,
+                   struct pam_response **, void *);
+static char *def_prompt = "Password:";
+static int gotintr;
+
+#ifndef PAM_DATA_SILENT
+#define PAM_DATA_SILENT        0
+#endif
+
+static pam_handle_t *pamh;
+
+int
+pam_init(struct passwd *pw, char **promptp, sudo_auth *auth)
+{
+    static struct pam_conv pam_conv;
+    static int pam_status;
+
+    /* Initial PAM setup */
+    if (auth != NULL)
+       auth->data = (void *) &pam_status;
+    pam_conv.conv = converse;
+#ifdef HAVE_PAM_LOGIN
+    if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
+       pam_status = pam_start("sudo-i", pw->pw_name, &pam_conv, &pamh);
+    else
+#endif
+       pam_status = pam_start("sudo", pw->pw_name, &pam_conv, &pamh);
+    if (pam_status != PAM_SUCCESS) {
+       log_error(USE_ERRNO|NO_EXIT|NO_MAIL, "unable to initialize PAM");
+       return AUTH_FATAL;
+    }
+
+    /*
+     * Set PAM_RUSER to the invoking user (the "from" user).
+     * We set PAM_RHOST to avoid a bug in Solaris 7 and below.
+     */
+    (void) pam_set_item(pamh, PAM_RUSER, user_name);
+#ifdef __sun__
+    (void) pam_set_item(pamh, PAM_RHOST, user_host);
+#endif
+
+    /*
+     * 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.
+     */
+    if (user_ttypath == NULL)
+       (void) pam_set_item(pamh, PAM_TTY, "");
+    else
+       (void) pam_set_item(pamh, PAM_TTY, user_ttypath);
+
+    return AUTH_SUCCESS;
+}
+
+int
+pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
+{
+    const char *s;
+    int *pam_status = (int *) auth->data;
+
+    def_prompt = prompt;       /* for converse */
+
+    /* PAM_SILENT prevents the authentication service from generating output. */
+    *pam_status = pam_authenticate(pamh, PAM_SILENT);
+    switch (*pam_status) {
+       case PAM_SUCCESS:
+           *pam_status = pam_acct_mgmt(pamh, PAM_SILENT);
+           switch (*pam_status) {
+               case PAM_SUCCESS:
+                   return AUTH_SUCCESS;
+               case PAM_AUTH_ERR:
+                   log_error(NO_EXIT|NO_MAIL,
+                       "account validation failure, is your account locked?");
+                   return AUTH_FATAL;
+               case PAM_NEW_AUTHTOK_REQD:
+                   log_error(NO_EXIT|NO_MAIL, "%s, %s",
+                       "Account or password is expired",
+                       "reset your password and try again");
+                   *pam_status = pam_chauthtok(pamh,
+                       PAM_CHANGE_EXPIRED_AUTHTOK);
+                   if (*pam_status == PAM_SUCCESS)
+                       return AUTH_SUCCESS;
+                   if ((s = pam_strerror(pamh, *pam_status)))
+                       log_error(NO_EXIT|NO_MAIL, "pam_chauthtok: %s", s);
+                   return AUTH_FAILURE;
+               case PAM_AUTHTOK_EXPIRED:
+                   log_error(NO_EXIT|NO_MAIL,
+                       "Password expired, contact your system administrator");
+                   return AUTH_FATAL;
+               case PAM_ACCT_EXPIRED:
+                   log_error(NO_EXIT|NO_MAIL, "%s %s",
+                       "Account expired or PAM config lacks an \"account\"",
+                       "section for sudo, contact your system administrator");
+                   return AUTH_FATAL;
+           }
+           /* 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;
+       default:
+           if ((s = pam_strerror(pamh, *pam_status)))
+               log_error(NO_EXIT|NO_MAIL, "pam_authenticate: %s", s);
+           return AUTH_FATAL;
+    }
+}
+
+int
+pam_cleanup(struct passwd *pw, sudo_auth *auth)
+{
+    int *pam_status = (int *) auth->data;
+
+    /* If successful, we can't close the session until pam_end_session() */
+    if (auth->status == AUTH_SUCCESS)
+       return AUTH_SUCCESS;
+
+    *pam_status = pam_end(pamh, *pam_status | PAM_DATA_SILENT);
+    return *pam_status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
+}
+
+int
+pam_begin_session(struct passwd *pw, sudo_auth *auth)
+{
+    int status = PAM_SUCCESS;
+
+    /*
+     * If there is no valid user we cannot open a PAM session.
+     * This is not an error as sudo can run commands with arbitrary
+     * uids, it just means we are done from a session management standpoint.
+     */
+    if (pw == NULL) {
+       if (pamh != NULL) {
+           (void) pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
+           pamh = NULL;
+       }
+       goto done;
+    }
+
+    /* If the user did not have to authenticate there is no pam handle yet. */
+    if (pamh == NULL)
+       pam_init(pw, NULL, NULL);
+
+    /*
+     * Update PAM_USER to reference the user we are running the command
+     * as, as opposed to the user we authenticated as.
+     */
+    (void) pam_set_item(pamh, PAM_USER, pw->pw_name);
+
+    /*
+     * Set credentials (may include resource limits, device ownership, etc).
+     * We don't check the return value here because in Linux-PAM 0.75
+     * it 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.
+     * We can't call pam_acct_mgmt() with Linux-PAM for a similar reason.
+     */
+    (void) pam_setcred(pamh, PAM_ESTABLISH_CRED);
+
+#ifndef NO_PAM_SESSION
+    status = pam_open_session(pamh, 0);
+    if (status != PAM_SUCCESS) {
+       (void) pam_end(pamh, status | PAM_DATA_SILENT);
+       pamh = NULL;
+    }
+#endif
+
+done:
+    return status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
+}
+
+int
+pam_end_session(sudo_auth *auth)
+{
+    int status = PAM_SUCCESS;
+
+    if (pamh) {
+#ifndef NO_PAM_SESSION
+       (void) pam_close_session(pamh, PAM_SILENT);
+#endif
+       status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
+    }
+    return status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
+}
+
+/*
+ * ``Conversation function'' for PAM.
+ * XXX - does not handle PAM_BINARY_PROMPT
+ */
+static int
+converse(int num_msg, PAM_CONST struct pam_message **msg,
+    struct pam_response **response, void *appdata_ptr)
+{
+    struct pam_response *pr;
+    PAM_CONST struct pam_message *pm;
+    const char *prompt;
+    char *pass;
+    int n, type, std_prompt;
+
+    if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL)
+       return PAM_SYSTEM_ERR;
+    zero_bytes(*response, num_msg * sizeof(struct pam_response));
+
+    for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) {
+       type = SUDO_CONV_PROMPT_ECHO_OFF;
+       switch (pm->msg_style) {
+           case PAM_PROMPT_ECHO_ON:
+               type = SUDO_CONV_PROMPT_ECHO_ON;
+           case PAM_PROMPT_ECHO_OFF:
+               prompt = def_prompt;
+
+               /* Error out if the last password read was interrupted. */
+               if (gotintr)
+                   goto err;
+
+               /* Is the sudo prompt standard? (If so, we'l just use PAM's) */
+               std_prompt =  strncmp(def_prompt, "Password:", 9) == 0 &&
+                   (def_prompt[9] == '\0' ||
+                   (def_prompt[9] == ' ' && def_prompt[10] == '\0'));
+
+               /* Only override PAM prompt if it matches /^Password: ?/ */
+#if defined(PAM_TEXT_DOMAIN) && defined(HAVE_DGETTEXT)
+               if (!def_passprompt_override && (std_prompt ||
+                   (strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password: ")) &&
+                   strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password:")))))
+                   prompt = pm->msg;
+#else
+               if (!def_passprompt_override && (std_prompt ||
+                   strncmp(pm->msg, "Password:", 9) || (pm->msg[9] != '\0'
+                   && (pm->msg[9] != ' ' || pm->msg[10] != '\0'))))
+                   prompt = pm->msg;
+#endif
+               /* Read the password unless interrupted. */
+               pass = auth_getpass(prompt, def_passwd_timeout * 60, type);
+               if (pass == NULL) {
+                   /* We got ^C instead of a password; abort quickly. */
+                   if (errno == EINTR)
+                       gotintr = 1;
+#if defined(__darwin__) || defined(__APPLE__)
+                   pass = "";
+#else
+                   goto err;
+#endif
+               }
+               pr->resp = estrdup(pass);
+               zero_bytes(pass, strlen(pass));
+               break;
+           case PAM_TEXT_INFO:
+               if (pm->msg)
+                   (void) puts(pm->msg);
+               break;
+           case PAM_ERROR_MSG:
+               if (pm->msg) {
+                   (void) fputs(pm->msg, stderr);
+                   (void) fputc('\n', stderr);
+               }
+               break;
+           default:
+               goto err;
+       }
+    }
+
+    return PAM_SUCCESS;
+
+err:
+    /* Zero and free allocated memory and return an error. */
+    for (pr = *response, n = num_msg; n--; pr++) {
+       if (pr->resp != NULL) {
+           zero_bytes(pr->resp, strlen(pr->resp));
+           free(pr->resp);
+           pr->resp = NULL;
+       }
+    }
+    zero_bytes(*response, num_msg * sizeof(struct pam_response));
+    free(*response);
+    *response = NULL;
+    return gotintr ? PAM_AUTH_ERR : PAM_CONV_ERR;
+}
diff --git a/plugins/sudoers/auth/passwd.c b/plugins/sudoers/auth/passwd.c
new file mode 100644 (file)
index 0000000..ee0e4d3
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1999-2005, 2010-2011 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/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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+#define DESLEN                 13
+#define HAS_AGEINFO(p, l)      (l == 18 && p[DESLEN] == ',')
+
+int
+passwd_init(struct passwd *pw, char **promptp, sudo_auth *auth)
+{
+#ifdef HAVE_SKEYACCESS
+    if (skeyaccess(pw, user_tty, NULL, NULL) == 0)
+       return AUTH_FAILURE;
+#endif
+    sudo_setspent();
+    auth->data = sudo_getepw(pw);
+    sudo_endspent();
+    return AUTH_SUCCESS;
+}
+
+int
+passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth)
+{
+    char sav, *epass;
+    char *pw_epasswd = auth->data;
+    size_t pw_len;
+    int error;
+
+    pw_len = strlen(pw_epasswd);
+
+#ifdef HAVE_GETAUTHUID
+    /* Ultrix shadow passwords may use crypt16() */
+    error = strcmp(pw_epasswd, (char *) crypt16(pass, pw_epasswd));
+    if (!error)
+       return AUTH_SUCCESS;
+#endif /* HAVE_GETAUTHUID */
+
+    /*
+     * Truncate to 8 chars if standard DES since not all crypt()'s do this.
+     * If this turns out not to be safe we will have to use OS #ifdef's (sigh).
+     */
+    sav = pass[8];
+    if (pw_len == DESLEN || HAS_AGEINFO(pw_epasswd, pw_len))
+       pass[8] = '\0';
+
+    /*
+     * Normal UN*X password check.
+     * HP-UX may add aging info (separated by a ',') at the end so
+     * only compare the first DESLEN characters in that case.
+     */
+    epass = (char *) crypt(pass, pw_epasswd);
+    pass[8] = sav;
+    if (HAS_AGEINFO(pw_epasswd, pw_len) && strlen(epass) == DESLEN)
+       error = strncmp(pw_epasswd, epass, DESLEN);
+    else
+       error = strcmp(pw_epasswd, epass);
+
+    return error ? AUTH_FAILURE : AUTH_SUCCESS;
+}
+
+int
+passwd_cleanup(pw, auth)
+    struct passwd *pw;
+    sudo_auth *auth;
+{
+    char *pw_epasswd = auth->data;
+
+    if (pw_epasswd != NULL) {
+       zero_bytes(pw_epasswd, strlen(pw_epasswd));
+       efree(pw_epasswd);
+    }
+    return AUTH_SUCCESS;
+}
diff --git a/plugins/sudoers/auth/rfc1938.c b/plugins/sudoers/auth/rfc1938.c
new file mode 100644 (file)
index 0000000..846b7b2
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 1994-1996, 1998-2005, 2010-2011
+ *     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/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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+
+#if defined(HAVE_SKEY)
+# include <skey.h>
+# define RFC1938                               skey
+#  ifdef HAVE_RFC1938_SKEYCHALLENGE
+#   define rfc1938challenge(a,b,c,d)   skeychallenge((a),(b),(c),(d))
+#  else
+#   define rfc1938challenge(a,b,c,d)   skeychallenge((a),(b),(c))
+#  endif
+# define rfc1938verify(a,b)            skeyverify((a),(b))
+#elif defined(HAVE_OPIE)
+# include <opie.h>
+# define RFC1938                       opie
+# define rfc1938challenge(a,b,c,d)     opiechallenge((a),(b),(c))
+# define rfc1938verify(a,b)            opieverify((a),(b))
+#endif
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+int
+rfc1938_setup(struct passwd *pw, char **promptp, sudo_auth *auth)
+{
+    char challenge[256];
+    static char *orig_prompt = NULL, *new_prompt = NULL;
+    static int op_len, np_size;
+    static struct RFC1938 rfc1938;
+
+    /* Stash a pointer to the rfc1938 struct if we have not initialized */
+    if (!auth->data)
+       auth->data = &rfc1938;
+
+    /* Save the original prompt */
+    if (orig_prompt == NULL) {
+       orig_prompt = *promptp;
+       op_len = strlen(orig_prompt);
+
+       /* Ignore trailing colon (we will add our own) */
+       if (orig_prompt[op_len - 1] == ':')
+           op_len--;
+       else if (op_len >= 2 && orig_prompt[op_len - 1] == ' '
+           && orig_prompt[op_len - 2] == ':')
+           op_len -= 2;
+    }
+
+#ifdef HAVE_SKEY
+    /* Close old stream */
+    if (rfc1938.keyfile)
+       (void) fclose(rfc1938.keyfile);
+#endif
+
+    /*
+     * Look up the user and get the rfc1938 challenge.
+     * If the user is not in the OTP db, only post a fatal error if
+     * we are running alone (since they may just use a normal passwd).
+     */
+    if (rfc1938challenge(&rfc1938, pw->pw_name, challenge, sizeof(challenge))) {
+       if (IS_ONEANDONLY(auth)) {
+           warningx("you do not exist in the %s database", auth->name);
+           return AUTH_FATAL;
+       } else {
+           return AUTH_FAILURE;
+       }
+    }
+
+    /* Get space for new prompt with embedded challenge */
+    if (np_size < op_len + strlen(challenge) + 7) {
+       np_size = op_len + strlen(challenge) + 7;
+       new_prompt = (char *) erealloc(new_prompt, np_size);
+    }
+
+    if (def_long_otp_prompt)
+       (void) snprintf(new_prompt, np_size, "%s\n%s", challenge, orig_prompt);
+    else
+       (void) snprintf(new_prompt, np_size, "%.*s [ %s ]:", op_len,
+           orig_prompt, challenge);
+
+    *promptp = new_prompt;
+    return AUTH_SUCCESS;
+}
+
+int
+rfc1938_verify(struct passwd *pw, char *pass, sudo_auth *auth)
+{
+
+    if (rfc1938verify((struct RFC1938 *) auth->data, pass) == 0)
+       return AUTH_SUCCESS;
+    else
+       return AUTH_FAILURE;
+}
diff --git a/plugins/sudoers/auth/secureware.c b/plugins/sudoers/auth/secureware.c
new file mode 100644 (file)
index 0000000..221889d
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 1998-2005, 2010-2011 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/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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#ifdef __hpux
+#  undef MAXINT
+#  include <hpsecurity.h>
+#else
+#  include <sys/security.h>
+#endif /* __hpux */
+#include <prot.h>
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+int
+secureware_init(struct passwd *pw, char **promptp, sudo_auth *auth)
+{
+#ifdef __alpha
+    extern int crypt_type;
+
+    if (crypt_type == INT_MAX)
+       return AUTH_FAILURE;                    /* no shadow */
+#endif
+    sudo_setspent();
+    auth->data = sudo_getepw(pw);
+    sudo_endspent();
+    return AUTH_SUCCESS;
+}
+
+int
+secureware_verify(struct passwd *pw, char *pass, sudo_auth *auth)
+{
+    char *pw_epasswd = auth->data;
+#ifdef __alpha
+    extern int crypt_type;
+
+#  ifdef HAVE_DISPCRYPT
+    if (strcmp(pw_epasswd, dispcrypt(pass, pw_epasswd, crypt_type)) == 0)
+       return AUTH_SUCCESS;
+#  else
+    if (crypt_type == AUTH_CRYPT_BIGCRYPT) {
+       if (strcmp(pw_epasswd, bigcrypt(pass, pw_epasswd)) == 0)
+           return AUTH_SUCCESS;
+    } else if (crypt_type == AUTH_CRYPT_CRYPT16) {
+       if (strcmp(pw_epasswd, crypt(pass, pw_epasswd)) == 0)
+           return AUTH_SUCCESS;
+    }
+#  endif /* HAVE_DISPCRYPT */
+#elif defined(HAVE_BIGCRYPT)
+    if (strcmp(pw_epasswd, bigcrypt(pass, pw_epasswd)) == 0)
+       return AUTH_SUCCESS;
+#endif /* __alpha */
+
+       return AUTH_FAILURE;
+}
+
+int
+secureware_cleanup(pw, auth)
+    struct passwd *pw;
+    sudo_auth *auth;
+{
+    char *pw_epasswd = auth->data;
+
+    if (pw_epasswd != NULL) {
+       zero_bytes(pw_epasswd, strlen(pw_epasswd));
+       efree(pw_epasswd);
+    }
+    return AUTH_SUCCESS;
+}
diff --git a/plugins/sudoers/auth/securid.c b/plugins/sudoers/auth/securid.c
new file mode 100644 (file)
index 0000000..bcea4e9
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1999-2005, 2007, 2010-2011
+ *     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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+
+#include <sdi_athd.h>
+#include <sdconf.h>
+#include <sdacmvls.h>
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+union config_record configure;
+
+int
+securid_init(struct passwd *pw, char **promptp, sudo_auth *auth)
+{
+    static struct SD_CLIENT sd_dat;            /* SecurID data block */
+
+    auth->data = (void *) &sd_dat;             /* For method-specific data */
+
+    if (creadcfg() == 0)
+       return AUTH_SUCCESS;
+    else
+       return AUTH_FATAL;
+}
+
+int
+securid_setup(struct passwd *pw, char **promptp, sudo_auth *auth)
+{
+    struct SD_CLIENT *sd = (struct SD_CLIENT *) auth->data;
+
+    /* Re-initialize SecurID every time. */
+    if (sd_init(sd) == 0) {
+       /* The programmer's guide says username is 32 bytes */
+       strlcpy(sd->username, pw->pw_name, 32);
+       return AUTH_SUCCESS;
+    } else {
+       warningx("unable to contact the SecurID server");
+       return AUTH_FATAL;
+    }
+}
+
+int
+securid_verify(struct passwd *pw, char *pass, sudo_auth *auth)
+{
+    struct SD_CLIENT *sd = (struct SD_CLIENT *) auth->data;
+    int rval;
+
+    rval = sd_auth(sd);
+    sd_close();
+    if (rval == ACM_OK)
+       return AUTH_SUCCESS;
+    else
+       return AUTH_FAILURE;
+}
diff --git a/plugins/sudoers/auth/securid5.c b/plugins/sudoers/auth/securid5.c
new file mode 100644 (file)
index 0000000..9d0ed4f
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 1999-2005, 2007, 2010-2011
+ *     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
+ * 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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+
+/* Needed for SecurID v5.0 Authentication on UNIX */
+#define UNIX 1
+#include <acexport.h>
+#include <sdacmvls.h>
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+/*
+ * securid_init - Initialises communications with ACE server
+ * Arguments in:
+ *     pw - UNUSED
+ *     promptp - UNUSED
+ *     auth - sudo authentication structure
+ *
+ * Results out:
+ *     auth - auth->data contains pointer to new SecurID handle
+ *     return code - Fatal if initialization unsuccessful, otherwise
+ *                   success.
+ */
+int
+securid_init(struct passwd *pw, char **promptp, sudo_auth *auth)
+{
+    static SDI_HANDLE sd_dat;                  /* SecurID handle */
+
+    auth->data = (void *) &sd_dat;             /* For method-specific data */
+
+    /* Start communications */
+    if (AceInitialize() != SD_FALSE)
+       return AUTH_SUCCESS;
+
+    warningx("failed to initialise the ACE API library");
+    return AUTH_FATAL;
+}
+
+/*
+ * securid_setup - Initialises a SecurID transaction and locks out other
+ *     ACE servers
+ *
+ * Arguments in:
+ *     pw - struct passwd for username
+ *     promptp - UNUSED
+ *     auth - sudo authentication structure for SecurID handle
+ *
+ * Results out:
+ *     return code - Success if transaction started correctly, fatal
+ *                   otherwise
+ */
+int
+securid_setup(struct passwd *pw, char **promptp, sudo_auth *auth)
+{
+    SDI_HANDLE *sd = (SDI_HANDLE *) auth->data;
+    int retval;
+
+    /* Re-initialize SecurID every time. */
+    if (SD_Init(sd) != ACM_OK) {
+       warningx("unable to contact the SecurID server");
+       return AUTH_FATAL;
+    }
+
+    /* Lock new PIN code */
+    retval = SD_Lock(*sd, pw->pw_name);
+
+    switch (retval) {
+       case ACM_OK:
+               warningx("User ID locked for SecurID Authentication");
+               return AUTH_SUCCESS;
+
+        case ACE_UNDEFINED_USERNAME:
+               warningx("invalid username length for SecurID");
+               return AUTH_FATAL;
+
+       case ACE_ERR_INVALID_HANDLE:
+               warningx("invalid Authentication Handle for SecurID");
+               return AUTH_FATAL;
+
+       case ACM_ACCESS_DENIED:
+               warningx("SecurID communication failed");
+               return AUTH_FATAL;
+
+       default:
+               warningx("unknown SecurID error");
+               return AUTH_FATAL;
+       }
+}
+
+/*
+ * securid_verify - Authenticates user and handles ACE responses
+ *
+ * Arguments in:
+ *     pw - struct passwd for username
+ *     pass - UNUSED
+ *     auth - sudo authentication structure for SecurID handle
+ *
+ * Results out:
+ *     return code - Success on successful authentication, failure on
+ *                   incorrect authentication, fatal on errors
+ */
+int
+securid_verify(struct passwd *pw, char *pass, sudo_auth *auth)
+{
+    SDI_HANDLE *sd = (SDI_HANDLE *) auth->data;
+    int rval;
+
+    pass = auth_getpass("Enter your PASSCODE: ",
+       def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF);
+
+    /* Have ACE verify password */
+    switch (SD_Check(*sd, pass, pw->pw_name)) {
+       case ACM_OK:
+               rval = AUTH_SUCESS;
+               break;
+
+       case ACE_UNDEFINED_PASSCODE:
+               warningx("invalid passcode length for SecurID");
+               rval = AUTH_FATAL;
+               break;
+
+       case ACE_UNDEFINED_USERNAME:
+               warningx("invalid username length for SecurID");
+               rval = AUTH_FATAL;
+               break;
+
+       case ACE_ERR_INVALID_HANDLE:
+               warningx("invalid Authentication Handle for SecurID");
+               rval = AUTH_FATAL;
+               break;
+
+       case ACM_ACCESS_DENIED:
+               rval = AUTH_FAILURE;
+               break;
+
+       case ACM_NEXT_CODE_REQUIRED:
+                /* Sometimes (when current token close to expire?)
+                   ACE challenges for the next token displayed
+                   (entered without the PIN) */
+               pass = auth_getpass("\
+!!! ATTENTION !!!\n\
+Wait for the token code to change, \n\
+then enter the new token code.\n", \
+               def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF);
+
+               if (SD_Next(*sd, pass) == ACM_OK) {
+                       rval = AUTH_SUCCESS;
+                       break;
+               }
+
+               rval = AUTH_FAILURE;
+               break;
+
+       case ACM_NEW_PIN_REQUIRED:
+                /*
+                * This user's SecurID has not been activated yet,
+                 * or the pin has been reset
+                */
+               /* XXX - Is setting up a new PIN within sudo's scope? */
+               SD_Pin(*sd, "");
+               fprintf(stderr, "Your SecurID access has not yet been set up.\n");
+               fprintf(stderr, "Please set up a PIN before you try to authenticate.\n");
+               rval = AUTH_FATAL;
+               break;
+
+       default:
+               warningx("unknown SecurID error");
+               rval = AUTH_FATAL;
+               break;
+    }
+
+    /* Free resources */
+    SD_Close(*sd);
+
+    /* Return stored state to calling process */
+    return rval;
+}
diff --git a/plugins/sudoers/auth/sia.c b/plugins/sudoers/auth/sia.c
new file mode 100644 (file)
index 0000000..65c6653
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 1999-2005, 2007, 2010-2011
+ *     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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#include <siad.h>
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+
+static int sudo_collect(int, int, uchar_t *, int, prompt_t *);
+
+static char *def_prompt;
+static char **sudo_argv;
+static int sudo_argc;
+
+/*
+ * Collection routine (callback) for limiting the timeouts in SIA
+ * prompts and (possibly) setting a custom prompt.
+ */
+static int
+sudo_collect(int timeout, int rendition, uchar_t *title, int nprompts,
+    prompt_t *prompts)
+{
+    switch (rendition) {
+       case SIAFORM:
+       case SIAONELINER:
+           if (timeout <= 0 || timeout > def_passwd_timeout * 60)
+               timeout = def_passwd_timeout * 60;
+           /*
+            * Substitute custom prompt if a) the sudo prompt is not "Password:"
+            * and b) the SIA prompt is "Password:" (so we know it is safe).
+            * This keeps us from overwriting things like S/Key challenges.
+            */
+           if (strcmp((char *)prompts[0].prompt, "Password:") == 0 &&
+               strcmp(def_prompt, "Password:") != 0)
+               prompts[0].prompt = (unsigned char *)def_prompt;
+           break;
+       default:
+           break;
+    }
+
+    return sia_collect_trm(timeout, rendition, title, nprompts, prompts);
+}
+
+int
+sia_setup(struct passwd *pw, char **promptp, sudo_auth *auth)
+{
+    SIAENTITY *siah = NULL;
+    int i;
+    extern int NewArgc;
+    extern char **NewArgv;
+
+    /* Rebuild argv for sia_ses_init() */
+    sudo_argc = NewArgc + 1;
+    sudo_argv = emalloc2(sudo_argc + 1, sizeof(char *));
+    sudo_argv[0] = "sudo";
+    for (i = 0; i < NewArgc; i++)
+       sudo_argv[i + 1] = NewArgv[i];
+    sudo_argv[sudo_argc] = NULL;
+
+    if (sia_ses_init(&siah, sudo_argc, sudo_argv, NULL, pw->pw_name, user_ttypath, 1, NULL) != SIASUCCESS) {
+
+       log_error(USE_ERRNO|NO_EXIT|NO_MAIL,
+           "unable to initialize SIA session");
+       return AUTH_FATAL;
+    }
+
+    auth->data = (void *) siah;
+    return AUTH_SUCCESS;
+}
+
+int
+sia_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
+{
+    SIAENTITY *siah = (SIAENTITY *) auth->data;
+
+    def_prompt = prompt;               /* for sudo_collect */
+
+    /* XXX - need a way to detect user hitting return or EOF at prompt */
+    if (sia_ses_reauthent(sudo_collect, siah) == SIASUCCESS)
+       return AUTH_SUCCESS;
+    else
+       return AUTH_FAILURE;
+}
+
+int
+sia_cleanup(struct passwd *pw, sudo_auth *auth)
+{
+    SIAENTITY *siah = (SIAENTITY *) auth->data;
+
+    (void) sia_ses_release(&siah);
+    efree(sudo_argv);
+    return AUTH_SUCCESS;
+}
diff --git a/plugins/sudoers/auth/sudo_auth.c b/plugins/sudoers/auth/sudo_auth.c
new file mode 100644 (file)
index 0000000..fc69716
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 1999-2005, 2008-2010 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/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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#include <time.h>
+#include <signal.h>
+
+#include "sudoers.h"
+#include "sudo_auth.h"
+#include "insults.h"
+
+static sudo_auth auth_switch[] = {
+/* Standalone entries first */
+#ifdef HAVE_PAM
+    AUTH_ENTRY("pam", FLAG_STANDALONE, pam_init, NULL, pam_verify, pam_cleanup, pam_begin_session, pam_end_session)
+#endif
+#ifdef HAVE_SECURID
+    AUTH_ENTRY("SecurId", FLAG_STANDALONE, securid_init, securid_setup, securid_verify, NULL, NULL, NULL)
+#endif
+#ifdef HAVE_SIA_SES_INIT
+    AUTH_ENTRY("sia", FLAG_STANDALONE, NULL, sia_setup, sia_verify, sia_cleanup, NULL, NULL)
+#endif
+#ifdef HAVE_AIXAUTH
+    AUTH_ENTRY("aixauth", FLAG_STANDALONE, NULL, NULL, aixauth_verify, aixauth_cleanup, NULL, NULL)
+#endif
+#ifdef HAVE_FWTK
+    AUTH_ENTRY("fwtk", FLAG_STANDALONE, fwtk_init, NULL, fwtk_verify, fwtk_cleanup, NULL, NULL)
+#endif
+#ifdef HAVE_BSD_AUTH_H
+    AUTH_ENTRY("bsdauth", FLAG_STANDALONE, bsdauth_init, NULL, bsdauth_verify, bsdauth_cleanup, NULL, NULL)
+#endif
+
+/* Non-standalone entries */
+#ifndef WITHOUT_PASSWD
+    AUTH_ENTRY("passwd", 0, passwd_init, NULL, passwd_verify, passwd_cleanup, NULL, NULL)
+#endif
+#if defined(HAVE_GETPRPWNAM) && !defined(WITHOUT_PASSWD)
+    AUTH_ENTRY("secureware", 0, secureware_init, NULL, secureware_verify, secureware_cleanup, NULL, NULL)
+#endif
+#ifdef HAVE_AFS
+    AUTH_ENTRY("afs", 0, NULL, NULL, afs_verify, NULL, NULL, NULL)
+#endif
+#ifdef HAVE_DCE
+    AUTH_ENTRY("dce", 0, NULL, NULL, dce_verify, NULL, NULL, NULL)
+#endif
+#ifdef HAVE_KERB4
+    AUTH_ENTRY("kerb4", 0, kerb4_init, NULL, kerb4_verify, NULL, NULL, NULL)
+#endif
+#ifdef HAVE_KERB5
+    AUTH_ENTRY("kerb5", 0, kerb5_init, NULL, kerb5_verify, kerb5_cleanup, NULL, NULL)
+#endif
+#ifdef HAVE_SKEY
+    AUTH_ENTRY("S/Key", 0, NULL, rfc1938_setup, rfc1938_verify, NULL, NULL, NULL)
+#endif
+#ifdef HAVE_OPIE
+    AUTH_ENTRY("OPIE", 0, NULL, rfc1938_setup, rfc1938_verify, NULL, NULL, NULL)
+#endif
+    AUTH_ENTRY(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL)
+};
+
+extern char **NewArgv; /* XXX - for auditing */
+
+static void pass_warn(void);
+
+int
+verify_user(struct passwd *pw, char *prompt)
+{
+    int counter = def_passwd_tries + 1;
+    int success = AUTH_FAILURE;
+    int flags, status, standalone, rval;
+    char *p;
+    sudo_auth *auth;
+    sigaction_t sa, osa;
+
+    /* Enable suspend during password entry. */
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = SA_RESTART;
+    sa.sa_handler = SIG_DFL;
+    (void) sigaction(SIGTSTP, &sa, &osa);
+
+    /* Make sure we have at least one auth method. */
+    if (auth_switch[0].name == NULL) {
+       audit_failure(NewArgv, "no authentication methods");
+       log_error(0, "%s  %s %s",
+           "There are no authentication methods compiled into sudo!",
+           "If you want to turn off authentication, use the",
+           "--disable-authentication configure option.");
+       return -1;
+    }
+
+    /* Make sure we haven't mixed standalone and shared auth methods. */
+    standalone = IS_STANDALONE(&auth_switch[0]);
+    if (standalone && auth_switch[1].name != NULL) {
+       audit_failure(NewArgv, "invalid authentication methods");
+       log_error(0, "Invalid authentication methods compiled into sudo!  "
+           "You cannot mix standalone and non-standalone authentication.");
+       return -1;
+    }
+
+    /* Set FLAG_ONEANDONLY if there is only one auth method. */
+    if (auth_switch[1].name == NULL)
+       SET(auth_switch[0].flags, FLAG_ONEANDONLY);
+
+    /* Initialize auth methods and unconfigure the method if necessary. */
+    for (auth = auth_switch; auth->name; auth++) {
+       if (auth->init && !IS_DISABLED(auth)) {
+           if (NEEDS_USER(auth))
+               set_perms(PERM_USER);
+
+           status = (auth->init)(pw, &prompt, auth);
+           if (status == AUTH_FAILURE)
+               SET(auth->flags, FLAG_DISABLED);
+           else if (status == AUTH_FATAL) {    /* XXX log */
+               audit_failure(NewArgv, "authentication failure");
+               return -1;              /* assume error msg already printed */
+           }
+
+           if (NEEDS_USER(auth))
+               restore_perms();
+       }
+    }
+
+    while (--counter) {
+       /* Do any per-method setup and unconfigure the method if needed */
+       for (auth = auth_switch; auth->name; auth++) {
+           if (auth->setup && !IS_DISABLED(auth)) {
+               if (NEEDS_USER(auth))
+                   set_perms(PERM_USER);
+
+               status = (auth->setup)(pw, &prompt, auth);
+               if (status == AUTH_FAILURE)
+                   SET(auth->flags, FLAG_DISABLED);
+               else if (status == AUTH_FATAL) {/* XXX log */
+                   audit_failure(NewArgv, "authentication failure");
+                   return -1;          /* assume error msg already printed */
+               }
+
+               if (NEEDS_USER(auth))
+                   restore_perms();
+           }
+       }
+
+       /* Get the password unless the auth function will do it for us */
+       if (standalone) {
+           p = prompt;
+       } else {
+           p = auth_getpass(prompt, def_passwd_timeout * 60,
+               SUDO_CONV_PROMPT_ECHO_OFF);
+           if (p == NULL)
+               break;
+       }
+
+       /* Call authentication functions. */
+       for (auth = auth_switch; auth->name; auth++) {
+           if (IS_DISABLED(auth))
+               continue;
+
+           if (NEEDS_USER(auth))
+               set_perms(PERM_USER);
+
+           success = auth->status = (auth->verify)(pw, p, auth);
+
+           if (NEEDS_USER(auth))
+               restore_perms();
+
+           if (auth->status != AUTH_FAILURE)
+               goto cleanup;
+       }
+       if (!standalone)
+           zero_bytes(p, strlen(p));
+       pass_warn();
+    }
+
+cleanup:
+    /* Call cleanup routines. */
+    for (auth = auth_switch; auth->name; auth++) {
+       if (auth->cleanup && !IS_DISABLED(auth)) {
+           if (NEEDS_USER(auth))
+               set_perms(PERM_USER);
+
+           status = (auth->cleanup)(pw, auth);
+           if (status == AUTH_FATAL) { /* XXX log */
+               audit_failure(NewArgv, "authentication failure");
+               return -1;              /* assume error msg already printed */
+           }
+
+           if (NEEDS_USER(auth))
+               restore_perms();
+       }
+    }
+
+    switch (success) {
+       case AUTH_SUCCESS:
+           (void) sigaction(SIGTSTP, &osa, NULL);
+           rval = TRUE;
+           break;
+       case AUTH_INTR:
+       case AUTH_FAILURE:
+           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");
+           }
+           audit_failure(NewArgv, "authentication failure");
+           rval = FALSE;
+           break;
+       case AUTH_FATAL:
+       default:
+           audit_failure(NewArgv, "authentication failure");
+           rval = -1;
+           break;
+    }
+
+    return rval;
+}
+
+int auth_begin_session(struct passwd *pw)
+{
+    sudo_auth *auth;
+    int status;
+
+    for (auth = auth_switch; auth->name; auth++) {
+       if (auth->begin_session && !IS_DISABLED(auth)) {
+           status = (auth->begin_session)(pw, auth);
+           if (status == AUTH_FATAL) { /* XXX log */
+               audit_failure(NewArgv, "authentication failure");
+               return -1;              /* assume error msg already printed */
+           }
+       }
+    }
+    return TRUE;
+}
+
+int auth_end_session(void)
+{
+    sudo_auth *auth;
+    int status;
+
+    for (auth = auth_switch; auth->name; auth++) {
+       if (auth->end_session && !IS_DISABLED(auth)) {
+           status = (auth->end_session)(auth);
+           if (status == AUTH_FATAL) { /* XXX log */
+               return -1;              /* assume error msg already printed */
+           }
+       }
+    }
+    return TRUE;
+}
+
+static void
+pass_warn(void)
+{
+    const char *warning = def_badpass_message;
+
+#ifdef INSULT
+    if (def_insults)
+       warning = INSULT;
+#endif
+    sudo_printf(SUDO_CONV_ERROR_MSG, "%s\n", warning);
+}
+
+char *
+auth_getpass(const char *prompt, int timeout, int type)
+{
+    struct sudo_conv_message msg;
+    struct sudo_conv_reply repl;
+
+    /* Mask user input if pwfeedback set and echo is off. */
+    if (type == SUDO_CONV_PROMPT_ECHO_OFF && def_pwfeedback)
+       type = SUDO_CONV_PROMPT_MASK;
+
+    /* If visiblepw set, do not error out if there is no tty. */
+    if (def_visiblepw)
+       type |= SUDO_CONV_PROMPT_ECHO_OK;
+
+    /* Call conversation function */
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_type = type;
+    msg.timeout = def_passwd_timeout * 60;
+    msg.msg = prompt;
+    memset(&repl, 0, sizeof(repl));
+    sudo_conv(1, &msg, &repl);
+    /* XXX - check for ENOTTY? */
+    return repl.reply;
+}
+
+void
+dump_auth_methods(void)
+{
+    sudo_auth *auth;
+
+    sudo_printf(SUDO_CONV_INFO_MSG, "Authentication methods:");
+    for (auth = auth_switch; auth->name; auth++)
+       sudo_printf(SUDO_CONV_INFO_MSG, " '%s'", auth->name);
+    sudo_printf(SUDO_CONV_INFO_MSG, "\n");
+}
diff --git a/plugins/sudoers/auth/sudo_auth.h b/plugins/sudoers/auth/sudo_auth.h
new file mode 100644 (file)
index 0000000..91124bf
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1999-2005, 2007-2010 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.
+ */
+
+#ifndef SUDO_AUTH_H
+#define SUDO_AUTH_H
+
+/* Auth function return values.  */
+#define AUTH_SUCCESS   0
+#define AUTH_FAILURE   1
+#define AUTH_INTR      2
+#define AUTH_FATAL     3
+
+typedef struct sudo_auth {
+    int flags;                 /* various flags, see below */
+    int status;                        /* status from verify routine */
+    char *name;                        /* name of the method as a string */
+    void *data;                        /* method-specific data pointer */
+    int (*init)(struct passwd *pw, char **prompt, struct sudo_auth *auth);
+    int (*setup)(struct passwd *pw, char **prompt, struct sudo_auth *auth);
+    int (*verify)(struct passwd *pw, char *p, struct sudo_auth *auth);
+    int (*cleanup)(struct passwd *pw, struct sudo_auth *auth);
+    int (*begin_session)(struct passwd *pw, struct sudo_auth *auth);
+    int (*end_session)(struct sudo_auth *auth);
+} sudo_auth;
+
+/* Values for sudo_auth.flags.  */
+#define FLAG_USER      0x01    /* functions must run as the user, not root */
+#define FLAG_DISABLED  0x02    /* method disabled */
+#define FLAG_STANDALONE        0x04    /* standalone auth method */
+#define FLAG_ONEANDONLY        0x08    /* one and only auth method */
+
+/* Shortcuts for using the flags above. */
+#define NEEDS_USER(x)          ((x)->flags & FLAG_USER)
+#define IS_DISABLED(x)         ((x)->flags & FLAG_DISABLED)
+#define IS_STANDALONE(x)       ((x)->flags & FLAG_STANDALONE)
+#define IS_ONEANDONLY(x)       ((x)->flags & FLAG_ONEANDONLY)
+
+/* Like tgetpass() but uses conversation function */
+char *auth_getpass(const char *prompt, int timeout, int type);
+
+/* Pointer to conversation function to use with auth_getpass(). */
+extern sudo_conv_t sudo_conv;
+
+/* Prototypes for standalone methods */
+int fwtk_init(struct passwd *pw, char **prompt, sudo_auth *auth);
+int fwtk_verify(struct passwd *pw, char *prompt, sudo_auth *auth);
+int fwtk_cleanup(struct passwd *pw, sudo_auth *auth);
+int pam_init(struct passwd *pw, char **prompt, sudo_auth *auth);
+int pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth);
+int pam_cleanup(struct passwd *pw, sudo_auth *auth);
+int pam_begin_session(struct passwd *pw, sudo_auth *auth);
+int pam_end_session(sudo_auth *auth);
+int sia_setup(struct passwd *pw, char **prompt, sudo_auth *auth);
+int sia_verify(struct passwd *pw, char *prompt, sudo_auth *auth);
+int sia_cleanup(struct passwd *pw, sudo_auth *auth);
+int aixauth_verify(struct passwd *pw, char *pass, sudo_auth *auth);
+int aixauth_cleanup(struct passwd *pw, sudo_auth *auth);
+int bsdauth_init(struct passwd *pw, char **prompt, sudo_auth *auth);
+int bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth);
+int bsdauth_cleanup(struct passwd *pw, sudo_auth *auth);
+
+/* Prototypes for normal methods */
+int passwd_init(struct passwd *pw, char **prompt, sudo_auth *auth);
+int passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth);
+int passwd_cleanup(struct passwd *pw, sudo_auth *auth);
+int secureware_init(struct passwd *pw, char **prompt, sudo_auth *auth);
+int secureware_verify(struct passwd *pw, char *pass, sudo_auth *auth);
+int secureware_cleanup(struct passwd *pw, sudo_auth *auth);
+int rfc1938_setup(struct passwd *pw, char **prompt, sudo_auth *auth);
+int rfc1938_verify(struct passwd *pw, char *pass, sudo_auth *auth);
+int afs_verify(struct passwd *pw, char *pass, sudo_auth *auth);
+int dce_verify(struct passwd *pw, char *pass, sudo_auth *auth);
+int kerb4_init(struct passwd *pw, char **prompt, sudo_auth *auth);
+int kerb4_verify(struct passwd *pw, char *pass, sudo_auth *auth);
+int kerb5_init(struct passwd *pw, char **prompt, sudo_auth *auth);
+int kerb5_verify(struct passwd *pw, char *pass, sudo_auth *auth);
+int kerb5_cleanup(struct passwd *pw, sudo_auth *auth);
+int securid_init(struct passwd *pw, char **prompt, sudo_auth *auth);
+int securid_setup(struct passwd *pw, char **prompt, sudo_auth *auth);
+int securid_verify(struct passwd *pw, char *pass, sudo_auth *auth);
+
+/* Fields: name, flags, init, setup, verify, cleanup, begin_sess, end_sess */
+#define AUTH_ENTRY(n, f, i, s, v, c, b, e) \
+       { (f), AUTH_FAILURE, (n), NULL, (i), (s), (v), (c) , (b), (e) },
+
+#endif /* SUDO_AUTH_H */
diff --git a/plugins/sudoers/boottime.c b/plugins/sudoers/boottime.c
new file mode 100644 (file)
index 0000000..96576f8
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2009-2011 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/param.h>
+#include <sys/types.h>
+#include <sys/time.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <limits.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#ifndef __linux__
+# if defined(HAVE_SYSCTL) && defined(KERN_BOOTTIME)
+#  include <sys/sysctl.h>
+# elif defined(HAVE_GETUTXID)
+#  include <utmpx.h>
+# elif defined(HAVE_GETUTID)
+#  include <utmp.h>
+# endif
+#endif /* !__linux__ */
+
+#include "missing.h"
+
+/*
+ * Fill in a struct timeval with the time the system booted.
+ * Returns 1 on success and 0 on failure.
+ */
+
+#if defined(__linux__)
+int
+get_boottime(struct timeval *tv)
+{
+    char *line = NULL;
+    size_t linesize = 0;
+    ssize_t len;
+    FILE * fp;
+
+    /* read btime from /proc/stat */
+    fp = fopen("/proc/stat", "r");
+    if (fp != NULL) {
+       while ((len = getline(&line, &linesize, fp)) != -1) {
+           if (strncmp(line, "btime ", 6) == 0) {
+               tv->tv_sec = atoi(line + 6);
+               tv->tv_usec = 0;
+               return 1;
+           }
+       }
+       fclose(fp);
+       free(line);
+    }
+
+    return 0;
+}
+
+#elif defined(HAVE_SYSCTL) && defined(KERN_BOOTTIME)
+
+int
+get_boottime(struct timeval *tv)
+{
+    size_t size;
+    int mib[2];
+
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_BOOTTIME;
+    size = sizeof(*tv);
+    if (sysctl(mib, 2, tv, &size, NULL, 0) != -1)
+       return 1;
+
+    return 0;
+}
+
+#elif defined(HAVE_GETUTXID)
+
+int
+get_boottime(struct timeval *tv)
+{
+    struct utmpx *ut, key;
+
+    memset(&key, 0, sizeof(key));
+    key.ut_type = BOOT_TIME;
+    setutxent();
+    if ((ut = getutxid(&key)) != NULL) {
+       tv->tv_sec = ut->ut_tv.tv_sec;
+       tv->tv_usec = ut->ut_tv.tv_usec;
+    }
+    endutxent();
+    return ut != NULL;
+}
+
+#elif defined(HAVE_GETUTID)
+
+int
+get_boottime(struct timeval *tv)
+{
+    struct utmp *ut, key;
+
+    memset(&key, 0, sizeof(key));
+    key.ut_type = BOOT_TIME;
+    setutent();
+    if ((ut = getutid(&key)) != NULL) {
+       tv->tv_sec = ut->ut_time;
+       tv->tv_usec = 0;
+    }
+    endutent();
+    return ut != NULL;
+}
+
+#else
+
+int
+get_boottime(struct timeval *tv)
+{
+    return 0;
+}
+#endif
diff --git a/plugins/sudoers/bsm_audit.c b/plugins/sudoers/bsm_audit.c
new file mode 100644 (file)
index 0000000..8354fe3
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2009-2011 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2009 Christian S.J. Peron
+ *
+ * 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 <bsm/audit.h>
+#include <bsm/libbsm.h>
+#include <bsm/audit_uevents.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <pwd.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "bsm_audit.h"
+
+/*
+ * Solaris auditon() returns EINVAL if BSM audit not configured.
+ * OpenBSM returns ENOSYS for unimplemented options.
+ */
+#ifdef __sun
+# define AUDIT_NOT_CONFIGURED  EINVAL
+#else
+# define AUDIT_NOT_CONFIGURED  ENOSYS
+#endif
+
+void log_error(int flags, const char *fmt, ...) __attribute__((__noreturn__));
+
+static int
+audit_sudo_selected(int sf)
+{
+       auditinfo_addr_t ainfo_addr;
+       struct au_mask *mask;
+       auditinfo_t ainfo;
+       int rc, sorf;
+
+       if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) {
+               if (errno == ENOSYS) {
+                       if (getaudit(&ainfo) < 0)
+                               log_error(0, "getaudit: failed");
+                       mask = &ainfo.ai_mask;
+               } else
+                       log_error(0, "getaudit: failed");
+        } else
+               mask = &ainfo_addr.ai_mask;
+       sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE;
+       rc = au_preselect(AUE_sudo, mask, sorf, AU_PRS_REREAD);
+        return rc;
+}
+
+void
+bsm_audit_success(char **exec_args)
+{
+       auditinfo_addr_t ainfo_addr;
+       auditinfo_t ainfo;
+       token_t *tok;
+       au_id_t auid;
+       long au_cond;
+       int aufd;
+       pid_t pid;
+
+       pid = getpid();
+       /*
+        * If we are not auditing, don't cut an audit record; just return.
+        */
+       if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) {
+               if (errno == AUDIT_NOT_CONFIGURED)
+                       return;
+               log_error(0, "Could not determine audit condition");
+       }
+       if (au_cond == AUC_NOAUDIT)
+               return;
+       /*
+        * Check to see if the preselection masks are interested in seeing
+        * this event.
+        */
+       if (!audit_sudo_selected(0))
+               return;
+       if (getauid(&auid) < 0)
+               log_error(0, "getauid failed");
+       if ((aufd = au_open()) == -1)
+               log_error(0, "au_open: failed");
+       if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) {
+               tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
+                   getuid(), pid, pid, &ainfo_addr.ai_termid);
+       } else if (errno == ENOSYS) {
+               /*
+                * NB: We should probably watch out for ERANGE here.
+                */
+               if (getaudit(&ainfo) < 0)
+                       log_error(0, "getaudit: failed");
+               tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
+                   getuid(), pid, pid, &ainfo.ai_termid);
+       } else
+               log_error(0, "getaudit: failed");
+       if (tok == NULL)
+               log_error(0, "au_to_subject: failed");
+       au_write(aufd, tok);
+       tok = au_to_exec_args(exec_args);
+       if (tok == NULL)
+               log_error(0, "au_to_exec_args: failed");
+       au_write(aufd, tok);
+       tok = au_to_return32(0, 0);
+       if (tok == NULL)
+               log_error(0, "au_to_return32: failed");
+       au_write(aufd, tok);
+       if (au_close(aufd, 1, AUE_sudo) == -1)
+               log_error(0, "unable to commit audit record");
+}
+
+void
+bsm_audit_failure(char **exec_args, char const *const fmt, va_list ap)
+{
+       auditinfo_addr_t ainfo_addr;
+       auditinfo_t ainfo;
+       char text[256];
+       token_t *tok;
+       long au_cond;
+       au_id_t auid;
+       pid_t pid;
+       int aufd;
+
+       pid = getpid();
+       /*
+        * If we are not auditing, don't cut an audit record; just return.
+        */
+       if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
+               if (errno == AUDIT_NOT_CONFIGURED)
+                       return;
+               log_error(0, "Could not determine audit condition");
+       }
+       if (au_cond == AUC_NOAUDIT)
+               return;
+       if (!audit_sudo_selected(1))
+               return;
+       if (getauid(&auid) < 0)
+               log_error(0, "getauid: failed");
+       if ((aufd = au_open()) == -1)
+               log_error(0, "au_open: failed");
+       if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) { 
+               tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
+                   getuid(), pid, pid, &ainfo_addr.ai_termid);
+       } else if (errno == ENOSYS) {
+               if (getaudit(&ainfo) < 0) 
+                       log_error(0, "getaudit: failed");
+               tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
+                   getuid(), pid, pid, &ainfo.ai_termid);
+       } else
+               log_error(0, "getaudit: failed");
+       if (tok == NULL)
+               log_error(0, "au_to_subject: failed");
+       au_write(aufd, tok);
+       tok = au_to_exec_args(exec_args);
+       if (tok == NULL)
+               log_error(0, "au_to_exec_args: failed");
+       au_write(aufd, tok);
+       (void) vsnprintf(text, sizeof(text), fmt, ap);
+       tok = au_to_text(text);
+       if (tok == NULL)
+               log_error(0, "au_to_text: failed");
+       au_write(aufd, tok);
+       tok = au_to_return32(EPERM, 1);
+       if (tok == NULL)
+               log_error(0, "au_to_return32: failed");
+       au_write(aufd, tok);
+       if (au_close(aufd, 1, AUE_sudo) == -1)
+               log_error(0, "unable to commit audit record");
+}
diff --git a/plugins/sudoers/bsm_audit.h b/plugins/sudoers/bsm_audit.h
new file mode 100644 (file)
index 0000000..bd29764
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2009 Christian S.J. Peron
+ *
+ * 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.
+ */
+
+#ifndef _SUDO_BSM_AUDIT_H
+#define        _SUDO_BSM_AUDIT_H
+
+void   bsm_audit_success(char **);
+void   bsm_audit_failure(char **, char const * const, va_list);
+
+#endif /* _SUDO_BSM_AUDIT_H */
diff --git a/plugins/sudoers/check.c b/plugins/sudoers/check.c
new file mode 100644 (file)
index 0000000..af2412f
--- /dev/null
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 1993-1996,1998-2005, 2007-2011
+ *     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/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#ifdef __linux__
+# include <sys/vfs.h>
+#endif
+#if defined(__sun) && defined(__SVR4)
+# include <sys/statvfs.h>
+#endif
+#ifndef __TANDEM
+# include <sys/file.h>
+#endif
+#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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "sudoers.h"
+
+/* Status codes for timestamp_status() */
+#define TS_CURRENT             0
+#define TS_OLD                 1
+#define TS_MISSING             2
+#define TS_NOFILE              3
+#define TS_ERROR               4
+
+/* Flags for timestamp_status() */
+#define TS_MAKE_DIRS           1
+#define TS_REMOVE              2
+
+/*
+ * Info stored in tty ticket from stat(2) to help with tty matching.
+ */
+static struct tty_info {
+    dev_t dev;                 /* ID of device tty resides on */
+    dev_t rdev;                        /* tty device ID */
+    ino_t ino;                 /* tty inode number */
+    struct timeval ctime;      /* tty inode change time */
+} tty_info;
+
+static int   build_timestamp(char **, char **);
+static int   timestamp_status(char *, char *, char *, int);
+static char *expand_prompt(char *, char *, char *);
+static void  lecture(int);
+static void  update_timestamp(char *, char *);
+static int   tty_is_devpts(const char *);
+static struct passwd *get_authpw(void);
+
+/*
+ * Returns TRUE if the user successfully authenticates, else FALSE.
+ */
+int
+check_user(int validated, int mode)
+{
+    char *timestampdir = NULL;
+    char *timestampfile = NULL;
+    char *prompt;
+    struct stat sb;
+    int status, rval = TRUE;
+
+    /* Stash the tty's ctime for tty ticket comparison. */
+    if (def_tty_tickets && user_ttypath && stat(user_ttypath, &sb) == 0) {
+       tty_info.dev = sb.st_dev;
+       tty_info.ino = sb.st_ino;
+       tty_info.rdev = sb.st_rdev;
+       if (tty_is_devpts(user_ttypath))
+           ctim_get(&sb, &tty_info.ctime);
+    }
+
+    /* Always prompt for a password when -k was specified with the command. */
+    if (ISSET(mode, MODE_IGNORE_TICKET)) {
+       SET(validated, FLAG_CHECK_USER);
+    } else {
+       /*
+        * Don't prompt for the root passwd or if the user is exempt.
+        * If the user is not changing uid/gid, no need for a password.
+        */
+       if (user_uid == 0 || (user_uid == runas_pw->pw_uid &&
+           (!runas_gr || user_in_group(sudo_user.pw, runas_gr->gr_name))) ||
+           user_is_exempt())
+           return TRUE;
+    }
+
+    if (build_timestamp(&timestampdir, &timestampfile) == -1)
+       return -1;
+
+    status = timestamp_status(timestampdir, timestampfile, user_name,
+       TS_MAKE_DIRS);
+
+    if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) {
+       struct passwd *auth_pw;
+
+       /* Bail out if we are non-interactive and a password is required */
+       if (ISSET(mode, MODE_NONINTERACTIVE)) {
+           warningx("sorry, a password is required to run %s", getprogname());
+           return -1;
+       }
+
+       /* XXX - should not lecture if askpass help is being used. */
+       lecture(status);
+
+       /* Expand any escapes in the prompt. */
+       prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt,
+           user_name, user_shost);
+
+       auth_pw = get_authpw();
+       rval = verify_user(auth_pw, prompt);
+       pw_delref(auth_pw);
+    }
+    /* Only update timestamp if user was validated. */
+    if (rval == TRUE && ISSET(validated, VALIDATE_OK) &&
+       !ISSET(mode, MODE_IGNORE_TICKET) && status != TS_ERROR)
+       update_timestamp(timestampdir, timestampfile);
+    efree(timestampdir);
+    efree(timestampfile);
+
+    return rval;
+}
+
+static const char lecture_text[] = "\n"
+"We trust you have received the usual lecture from the local System\n"
+"Administrator. It usually boils down to these three things:\n\n"
+"    #1) Respect the privacy of others.\n"
+"    #2) Think before you type.\n"
+"    #3) With great power comes great responsibility.\n\n";
+
+/*
+ * Standard sudo lecture.
+ */
+static void
+lecture(int status)
+{
+    FILE *fp;
+    char buf[BUFSIZ];
+    ssize_t nread;
+    struct sudo_conv_message msg;
+    struct sudo_conv_reply repl;
+
+    if (def_lecture == never ||
+       (def_lecture == once && status != TS_MISSING && status != TS_ERROR))
+       return;
+
+    memset(&msg, 0, sizeof(msg));
+    memset(&repl, 0, sizeof(repl));
+
+    if (def_lecture_file && (fp = fopen(def_lecture_file, "r")) != NULL) {
+       while ((nread = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) != 0) {
+           buf[sizeof(buf) - 1] = '\0';
+           msg.msg_type = SUDO_CONV_ERROR_MSG;
+           msg.msg = buf;
+           sudo_conv(1, &msg, &repl);
+       }
+       fclose(fp);
+    } else {
+       msg.msg_type = SUDO_CONV_ERROR_MSG;
+       msg.msg = lecture_text;
+       sudo_conv(1, &msg, &repl);
+    }
+}
+
+/*
+ * Update the time on the timestamp file/dir or create it if necessary.
+ */
+static void
+update_timestamp(char *timestampdir, char *timestampfile)
+{
+    /* If using tty timestamps but we have no tty there is nothing to do. */
+    if (def_tty_tickets && !user_ttypath)
+       return;
+
+    if (timestamp_uid != 0)
+       set_perms(PERM_TIMESTAMP);
+    if (timestampfile) {
+       /*
+        * Store tty info in timestamp file
+        */
+       int fd = open(timestampfile, O_WRONLY|O_CREAT, 0600);
+       if (fd == -1)
+           log_error(NO_EXIT|USE_ERRNO, "Can't open %s", timestampfile);
+       else {
+           lock_file(fd, SUDO_LOCK);
+           if (write(fd, &tty_info, sizeof(tty_info)) != sizeof(tty_info))
+               log_error(NO_EXIT|USE_ERRNO, "Can't write %s", timestampfile);
+           close(fd);
+       }
+    } else {
+       if (touch(-1, timestampdir, NULL) == -1) {
+           if (mkdir(timestampdir, 0700) == -1)
+               log_error(NO_EXIT|USE_ERRNO, "Can't mkdir %s", timestampdir);
+       }
+    }
+    if (timestamp_uid != 0)
+       restore_perms();
+}
+
+/*
+ * Expand %h and %u escapes in the prompt and pass back the dynamically
+ * allocated result.  Returns the same string if there are no escapes.
+ */
+static char *
+expand_prompt(char *old_prompt, char *user, char *host)
+{
+    size_t len, n;
+    int subst;
+    char *p, *np, *new_prompt, *endp;
+
+    /* How much space do we need to malloc for the prompt? */
+    subst = 0;
+    for (p = old_prompt, len = strlen(old_prompt); *p; p++) {
+       if (p[0] =='%') {
+           switch (p[1]) {
+               case 'h':
+                   p++;
+                   len += strlen(user_shost) - 2;
+                   subst = 1;
+                   break;
+               case 'H':
+                   p++;
+                   len += strlen(user_host) - 2;
+                   subst = 1;
+                   break;
+               case 'p':
+                   p++;
+                   if (def_rootpw)
+                           len += 2;
+                   else if (def_targetpw || def_runaspw)
+                           len += strlen(runas_pw->pw_name) - 2;
+                   else
+                           len += strlen(user_name) - 2;
+                   subst = 1;
+                   break;
+               case 'u':
+                   p++;
+                   len += strlen(user_name) - 2;
+                   subst = 1;
+                   break;
+               case 'U':
+                   p++;
+                   len += strlen(runas_pw->pw_name) - 2;
+                   subst = 1;
+                   break;
+               case '%':
+                   p++;
+                   len--;
+                   subst = 1;
+                   break;
+               default:
+                   break;
+           }
+       }
+    }
+
+    if (subst) {
+       new_prompt = emalloc(++len);
+       endp = new_prompt + len;
+       for (p = old_prompt, np = new_prompt; *p; p++) {
+           if (p[0] =='%') {
+               switch (p[1]) {
+                   case 'h':
+                       p++;
+                       n = strlcpy(np, user_shost, np - endp);
+                       if (n >= np - endp)
+                           goto oflow;
+                       np += n;
+                       continue;
+                   case 'H':
+                       p++;
+                       n = strlcpy(np, user_host, np - endp);
+                       if (n >= np - endp)
+                           goto oflow;
+                       np += n;
+                       continue;
+                   case 'p':
+                       p++;
+                       if (def_rootpw)
+                               n = strlcpy(np, "root", np - endp);
+                       else if (def_targetpw || def_runaspw)
+                               n = strlcpy(np, runas_pw->pw_name, np - endp);
+                       else
+                               n = strlcpy(np, user_name, np - endp);
+                       if (n >= np - endp)
+                               goto oflow;
+                       np += n;
+                       continue;
+                   case 'u':
+                       p++;
+                       n = strlcpy(np, user_name, np - endp);
+                       if (n >= np - endp)
+                           goto oflow;
+                       np += n;
+                       continue;
+                   case 'U':
+                       p++;
+                       n = strlcpy(np,  runas_pw->pw_name, np - endp);
+                       if (n >= np - endp)
+                           goto oflow;
+                       np += n;
+                       continue;
+                   case '%':
+                       /* convert %% -> % */
+                       p++;
+                       break;
+                   default:
+                       /* no conversion */
+                       break;
+               }
+           }
+           *np++ = *p;
+           if (np >= endp)
+               goto oflow;
+       }
+       *np = '\0';
+    } else
+       new_prompt = old_prompt;
+
+    return new_prompt;
+
+oflow:
+    /* We pre-allocate enough space, so this should never happen. */
+    errorx(1, "internal error, expand_prompt() overflow");
+}
+
+/*
+ * Checks if the user is exempt from supplying a password.
+ */
+int
+user_is_exempt(void)
+{
+    if (!def_exempt_group)
+       return FALSE;
+    return user_in_group(sudo_user.pw, def_exempt_group);
+}
+
+/*
+ * Fills in timestampdir as well as timestampfile if using tty tickets.
+ */
+static int
+build_timestamp(char **timestampdir, char **timestampfile)
+{
+    char *dirparent;
+    int len;
+
+    dirparent = def_timestampdir;
+    len = easprintf(timestampdir, "%s/%s", dirparent, user_name);
+    if (len >= PATH_MAX) {
+       log_error(0, "timestamp path too long: %s", *timestampdir);
+       return -1;
+    }
+
+    /*
+     * Timestamp file may be a file in the directory or NUL to use
+     * the directory as the timestamp.
+     */
+    if (def_tty_tickets) {
+       char *p;
+
+       if ((p = strrchr(user_tty, '/')))
+           p++;
+       else
+           p = user_tty;
+       if (def_targetpw)
+           len = easprintf(timestampfile, "%s/%s/%s:%s", dirparent, user_name,
+               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);
+           return -1;
+       }
+    } else if (def_targetpw) {
+       len = easprintf(timestampfile, "%s/%s/%s", dirparent, user_name,
+           runas_pw->pw_name);
+       if (len >= PATH_MAX) {
+           log_error(0, "timestamp path too long: %s", *timestampfile);
+           return -1;
+       }
+    } else
+       *timestampfile = NULL;
+
+    return len;
+}
+
+/*
+ * Check the timestamp file and directory and return their status.
+ */
+static int
+timestamp_status(char *timestampdir, char *timestampfile, char *user, int flags)
+{
+    struct stat sb;
+    struct timeval boottime, mtime;
+    time_t now;
+    char *dirparent = def_timestampdir;
+    int status = TS_ERROR;             /* assume the worst */
+
+    if (timestamp_uid != 0)
+       set_perms(PERM_TIMESTAMP);
+
+    /*
+     * Sanity check dirparent and make it if it doesn't already exist.
+     * We start out assuming the worst (that the dir is not sane) and
+     * if it is ok upgrade the status to ``no timestamp file''.
+     * Note that we don't check the parent(s) of dirparent for
+     * sanity since the sudo dir is often just located in /tmp.
+     */
+    if (lstat(dirparent, &sb) == 0) {
+       if (!S_ISDIR(sb.st_mode))
+           log_error(NO_EXIT, "%s exists but is not a directory (0%o)",
+               dirparent, (unsigned int) sb.st_mode);
+       else if (sb.st_uid != timestamp_uid)
+           log_error(NO_EXIT, "%s owned by uid %u, should be uid %u",
+               dirparent, (unsigned int) sb.st_uid,
+               (unsigned int) timestamp_uid);
+       else if ((sb.st_mode & 0000022))
+           log_error(NO_EXIT,
+               "%s writable by non-owner (0%o), should be mode 0700",
+               dirparent, (unsigned int) sb.st_mode);
+       else {
+           if ((sb.st_mode & 0000777) != 0700)
+               (void) chmod(dirparent, 0700);
+           status = TS_MISSING;
+       }
+    } else if (errno != ENOENT) {
+       log_error(NO_EXIT|USE_ERRNO, "can't stat %s", dirparent);
+    } else {
+       /* No dirparent, try to make one. */
+       if (ISSET(flags, TS_MAKE_DIRS)) {
+           if (mkdir(dirparent, S_IRWXU))
+               log_error(NO_EXIT|USE_ERRNO, "can't mkdir %s",
+                   dirparent);
+           else
+               status = TS_MISSING;
+       }
+    }
+    if (status == TS_ERROR)
+       goto done;
+
+    /*
+     * Sanity check the user's ticket dir.  We start by downgrading
+     * the status to TS_ERROR.  If the ticket dir exists and is sane
+     * this will be upgraded to TS_OLD.  If the dir does not exist,
+     * it will be upgraded to TS_MISSING.
+     */
+    status = TS_ERROR;                 /* downgrade status again */
+    if (lstat(timestampdir, &sb) == 0) {
+       if (!S_ISDIR(sb.st_mode)) {
+           if (S_ISREG(sb.st_mode)) {
+               /* convert from old style */
+               if (unlink(timestampdir) == 0)
+                   status = TS_MISSING;
+           } else
+               log_error(NO_EXIT, "%s exists but is not a directory (0%o)",
+                   timestampdir, (unsigned int) sb.st_mode);
+       } else if (sb.st_uid != timestamp_uid)
+           log_error(NO_EXIT, "%s owned by uid %u, should be uid %u",
+               timestampdir, (unsigned int) sb.st_uid,
+               (unsigned int) timestamp_uid);
+       else if ((sb.st_mode & 0000022))
+           log_error(NO_EXIT,
+               "%s writable by non-owner (0%o), should be mode 0700",
+               timestampdir, (unsigned int) sb.st_mode);
+       else {
+           if ((sb.st_mode & 0000777) != 0700)
+               (void) chmod(timestampdir, 0700);
+           status = TS_OLD;            /* do date check later */
+       }
+    } else if (errno != ENOENT) {
+       log_error(NO_EXIT|USE_ERRNO, "can't stat %s", timestampdir);
+    } else
+       status = TS_MISSING;
+
+    /*
+     * If there is no user ticket dir, AND we are in tty ticket mode,
+     * AND the TS_MAKE_DIRS flag is set, create the user ticket dir.
+     */
+    if (status == TS_MISSING && timestampfile && ISSET(flags, TS_MAKE_DIRS)) {
+       if (mkdir(timestampdir, S_IRWXU) == -1) {
+           status = TS_ERROR;
+           log_error(NO_EXIT|USE_ERRNO, "can't mkdir %s", timestampdir);
+       }
+    }
+
+    /*
+     * Sanity check the tty ticket file if it exists.
+     */
+    if (timestampfile && status != TS_ERROR) {
+       if (status != TS_MISSING)
+           status = TS_NOFILE;                 /* dir there, file missing */
+       if (def_tty_tickets && !user_ttypath)
+           goto done;                          /* no tty, always prompt */
+       if (lstat(timestampfile, &sb) == 0) {
+           if (!S_ISREG(sb.st_mode)) {
+               status = TS_ERROR;
+               log_error(NO_EXIT, "%s exists but is not a regular file (0%o)",
+                   timestampfile, (unsigned int) sb.st_mode);
+           } else {
+               /* If bad uid or file mode, complain and kill the bogus file. */
+               if (sb.st_uid != timestamp_uid) {
+                   log_error(NO_EXIT,
+                       "%s owned by uid %u, should be uid %u",
+                       timestampfile, (unsigned int) sb.st_uid,
+                       (unsigned int) timestamp_uid);
+                   (void) unlink(timestampfile);
+               } else if ((sb.st_mode & 0000022)) {
+                   log_error(NO_EXIT,
+                       "%s writable by non-owner (0%o), should be mode 0600",
+                       timestampfile, (unsigned int) sb.st_mode);
+                   (void) unlink(timestampfile);
+               } else {
+                   /* If not mode 0600, fix it. */
+                   if ((sb.st_mode & 0000777) != 0600)
+                       (void) chmod(timestampfile, 0600);
+
+                   /*
+                    * Check for stored tty info.  If the file is zero-sized
+                    * it is an old-style timestamp with no tty info in it.
+                    * If removing, we don't care about the contents.
+                    * The actual mtime check is done later.
+                    */
+                   if (ISSET(flags, TS_REMOVE)) {
+                       status = TS_OLD;
+                   } else if (sb.st_size != 0) {
+                       struct tty_info info;
+                       int fd = open(timestampfile, O_RDONLY, 0644);
+                       if (fd != -1) {
+                           if (read(fd, &info, sizeof(info)) == sizeof(info) &&
+                               memcmp(&info, &tty_info, sizeof(info)) == 0) {
+                               status = TS_OLD;
+                           }
+                           close(fd);
+                       }
+                   }
+               }
+           }
+       } else if (errno != ENOENT) {
+           log_error(NO_EXIT|USE_ERRNO, "can't stat %s", timestampfile);
+           status = TS_ERROR;
+       }
+    }
+
+    /*
+     * If the file/dir exists and we are not removing it, check its mtime.
+     */
+    if (status == TS_OLD && !ISSET(flags, TS_REMOVE)) {
+       mtim_get(&sb, &mtime);
+       /* Negative timeouts only expire manually (sudo -k). */
+       if (def_timestamp_timeout < 0 && mtime.tv_sec != 0)
+           status = TS_CURRENT;
+       else {
+           now = time(NULL);
+           if (def_timestamp_timeout &&
+               now - mtime.tv_sec < 60 * def_timestamp_timeout) {
+               /*
+                * Check for bogus time on the stampfile.  The clock may
+                * have been set back or someone could be trying to spoof us.
+                */
+               if (mtime.tv_sec > now + 60 * def_timestamp_timeout * 2) {
+                   time_t tv_sec = (time_t)mtime.tv_sec;
+                   log_error(NO_EXIT,
+                       "timestamp too far in the future: %20.20s",
+                       4 + ctime(&tv_sec));
+                   if (timestampfile)
+                       (void) unlink(timestampfile);
+                   else
+                       (void) rmdir(timestampdir);
+                   status = TS_MISSING;
+               } else if (get_boottime(&boottime) && timevalcmp(&mtime, &boottime, <)) {
+                   status = TS_OLD;
+               } else {
+                   status = TS_CURRENT;
+               }
+           }
+       }
+    }
+
+done:
+    if (timestamp_uid != 0)
+       restore_perms();
+    return status;
+}
+
+/*
+ * Remove the timestamp ticket file/dir.
+ */
+void
+remove_timestamp(int remove)
+{
+    struct timeval tv;
+    char *timestampdir, *timestampfile, *path;
+    int status;
+
+    if (build_timestamp(&timestampdir, &timestampfile) == -1)
+       return;
+
+    status = timestamp_status(timestampdir, timestampfile, user_name,
+       TS_REMOVE);
+    if (status != TS_MISSING && status != TS_ERROR) {
+       path = timestampfile ? timestampfile : timestampdir;
+       if (remove) {
+           if (timestampfile)
+               status = unlink(timestampfile);
+           else
+               status = rmdir(timestampdir);
+           if (status == -1 && errno != ENOENT) {
+               log_error(NO_EXIT, "can't remove %s (%s), will reset to Epoch",
+                   path, strerror(errno));
+               remove = FALSE;
+           }
+       } else {
+           timevalclear(&tv);
+           if (touch(-1, path, &tv) == -1 && errno != ENOENT)
+               error(1, "can't reset %s to Epoch", path);
+       }
+    }
+
+    efree(timestampdir);
+    efree(timestampfile);
+}
+
+/*
+ * Returns TRUE if tty lives on a devpts or /devices filesystem, else FALSE.
+ * Unlike most filesystems, the ctime of devpts nodes is not updated when
+ * the device node is written to, only when the inode's status changes,
+ * typically via the chmod, chown, link, rename, or utimes system calls.
+ * Since the ctime is "stable" in this case, we can stash it the tty ticket
+ * file and use it to determine whether the tty ticket file is stale.
+ */
+static int
+tty_is_devpts(const char *tty)
+{
+    int retval = FALSE;
+#ifdef __linux__
+    struct statfs sfs;
+
+#ifndef DEVPTS_SUPER_MAGIC
+# define DEVPTS_SUPER_MAGIC 0x1cd1
+#endif
+
+    if (statfs(tty, &sfs) == 0) {
+       if (sfs.f_type == DEVPTS_SUPER_MAGIC)
+           retval = TRUE;
+    }
+#elif defined(__sun) && defined(__SVR4)
+    struct statvfs sfs;
+
+    if (statvfs(tty, &sfs) == 0) {
+       if (strcmp(sfs.f_fstr, "devices") == 0)
+           retval = TRUE;
+    }
+#endif /* __linux__ */
+    return retval;
+}
+
+/*
+ * Get passwd entry for the user we are going to authenticate as.
+ * By default, this is the user invoking sudo.  In the most common
+ * case, this matches sudo_user.pw or runas_pw.
+ */
+static struct passwd *
+get_authpw(void)
+{
+    struct passwd *pw;
+
+    if (def_rootpw) {
+       if ((pw = sudo_getpwuid(0)) == NULL)
+           log_error(0, "unknown uid: 0");
+    } else if (def_runaspw) {
+       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, "unknown uid: %u",
+               (unsigned int) runas_pw->pw_uid);
+       pw_addref(runas_pw);
+       pw = runas_pw;
+    } else {
+       pw_addref(sudo_user.pw);
+       pw = sudo_user.pw;
+    }
+
+    return pw;
+}
diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c
new file mode 100644 (file)
index 0000000..ca02ced
--- /dev/null
@@ -0,0 +1,352 @@
+static struct def_values def_data_lecture[] = {
+    { "never", never },
+    { "once", once },
+    { "always", always },
+    { NULL, 0 },
+};
+
+static struct def_values def_data_listpw[] = {
+    { "never", never },
+    { "any", any },
+    { "all", all },
+    { "always", always },
+    { NULL, 0 },
+};
+
+static struct def_values def_data_verifypw[] = {
+    { "never", never },
+    { "all", all },
+    { "any", any },
+    { "always", always },
+    { NULL, 0 },
+};
+
+struct sudo_defs_types sudo_defs_table[] = {
+    {
+       "syslog", T_LOGFAC|T_BOOL,
+       "Syslog facility if syslog is being used for logging: %s",
+       NULL,
+    }, {
+       "syslog_goodpri", T_LOGPRI,
+       "Syslog priority to use when user authenticates successfully: %s",
+       NULL,
+    }, {
+       "syslog_badpri", T_LOGPRI,
+       "Syslog priority to use when user authenticates unsuccessfully: %s",
+       NULL,
+    }, {
+       "long_otp_prompt", T_FLAG,
+       "Put OTP prompt on its own line",
+       NULL,
+    }, {
+       "ignore_dot", T_FLAG,
+       "Ignore '.' in $PATH",
+       NULL,
+    }, {
+       "mail_always", T_FLAG,
+       "Always send mail when sudo is run",
+       NULL,
+    }, {
+       "mail_badpass", T_FLAG,
+       "Send mail if user authentication fails",
+       NULL,
+    }, {
+       "mail_no_user", T_FLAG,
+       "Send mail if the user is not in sudoers",
+       NULL,
+    }, {
+       "mail_no_host", T_FLAG,
+       "Send mail if the user is not in sudoers for this host",
+       NULL,
+    }, {
+       "mail_no_perms", T_FLAG,
+       "Send mail if the user is not allowed to run a command",
+       NULL,
+    }, {
+       "tty_tickets", T_FLAG,
+       "Use a separate timestamp for each user/tty combo",
+       NULL,
+    }, {
+       "lecture", T_TUPLE|T_BOOL,
+       "Lecture user the first time they run sudo",
+       def_data_lecture,
+    }, {
+       "lecture_file", T_STR|T_PATH|T_BOOL,
+       "File containing the sudo lecture: %s",
+       NULL,
+    }, {
+       "authenticate", T_FLAG,
+       "Require users to authenticate by default",
+       NULL,
+    }, {
+       "root_sudo", T_FLAG,
+       "Root may run sudo",
+       NULL,
+    }, {
+       "log_host", T_FLAG,
+       "Log the hostname in the (non-syslog) log file",
+       NULL,
+    }, {
+       "log_year", T_FLAG,
+       "Log the year in the (non-syslog) log file",
+       NULL,
+    }, {
+       "shell_noargs", T_FLAG,
+       "If sudo is invoked with no arguments, start a shell",
+       NULL,
+    }, {
+       "set_home", T_FLAG,
+       "Set $HOME to the target user when starting a shell with -s",
+       NULL,
+    }, {
+       "always_set_home", T_FLAG,
+       "Always set $HOME to the target user's home directory",
+       NULL,
+    }, {
+       "path_info", T_FLAG,
+       "Allow some information gathering to give useful error messages",
+       NULL,
+    }, {
+       "fqdn", T_FLAG,
+       "Require fully-qualified hostnames in the sudoers file",
+       NULL,
+    }, {
+       "insults", T_FLAG,
+       "Insult the user when they enter an incorrect password",
+       NULL,
+    }, {
+       "requiretty", T_FLAG,
+       "Only allow the user to run sudo if they have a tty",
+       NULL,
+    }, {
+       "env_editor", T_FLAG,
+       "Visudo will honor the EDITOR environment variable",
+       NULL,
+    }, {
+       "rootpw", T_FLAG,
+       "Prompt for root's password, not the users's",
+       NULL,
+    }, {
+       "runaspw", T_FLAG,
+       "Prompt for the runas_default user's password, not the users's",
+       NULL,
+    }, {
+       "targetpw", T_FLAG,
+       "Prompt for the target user's password, not the users's",
+       NULL,
+    }, {
+       "use_loginclass", T_FLAG,
+       "Apply defaults in the target user's login class if there is one",
+       NULL,
+    }, {
+       "set_logname", T_FLAG,
+       "Set the LOGNAME and USER environment variables",
+       NULL,
+    }, {
+       "stay_setuid", T_FLAG,
+       "Only set the effective uid to the target user, not the real uid",
+       NULL,
+    }, {
+       "preserve_groups", T_FLAG,
+       "Don't initialize the group vector to that of the target user",
+       NULL,
+    }, {
+       "loglinelen", T_UINT|T_BOOL,
+       "Length at which to wrap log file lines (0 for no wrap): %d",
+       NULL,
+    }, {
+       "timestamp_timeout", T_FLOAT|T_BOOL,
+       "Authentication timestamp timeout: %.1f minutes",
+       NULL,
+    }, {
+       "passwd_timeout", T_FLOAT|T_BOOL,
+       "Password prompt timeout: %.1f minutes",
+       NULL,
+    }, {
+       "passwd_tries", T_UINT,
+       "Number of tries to enter a password: %d",
+       NULL,
+    }, {
+       "umask", T_MODE|T_BOOL,
+       "Umask to use or 0777 to use user's: 0%o",
+       NULL,
+    }, {
+       "logfile", T_STR|T_BOOL|T_PATH,
+       "Path to log file: %s",
+       NULL,
+    }, {
+       "mailerpath", T_STR|T_BOOL|T_PATH,
+       "Path to mail program: %s",
+       NULL,
+    }, {
+       "mailerflags", T_STR|T_BOOL,
+       "Flags for mail program: %s",
+       NULL,
+    }, {
+       "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",
+       NULL,
+    }, {
+       "badpass_message", T_STR,
+       "Incorrect password message: %s",
+       NULL,
+    }, {
+       "timestampdir", T_STR|T_PATH,
+       "Path to authentication timestamp dir: %s",
+       NULL,
+    }, {
+       "timestampowner", T_STR,
+       "Owner of the authentication timestamp dir: %s",
+       NULL,
+    }, {
+       "exempt_group", T_STR|T_BOOL,
+       "Users in this group are exempt from password and PATH requirements: %s",
+       NULL,
+    }, {
+       "passprompt", T_STR,
+       "Default password prompt: %s",
+       NULL,
+    }, {
+       "passprompt_override", T_FLAG,
+       "If set, passprompt will override system prompt in all cases.",
+       NULL,
+    }, {
+       "runas_default", T_STR,
+       "Default user to run commands as: %s",
+       NULL,
+    }, {
+       "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",
+       NULL,
+    }, {
+       "listpw", T_TUPLE|T_BOOL,
+       "When to require a password for 'list' pseudocommand: %s",
+       def_data_listpw,
+    }, {
+       "verifypw", T_TUPLE|T_BOOL,
+       "When to require a password for 'verify' pseudocommand: %s",
+       def_data_verifypw,
+    }, {
+       "noexec", T_FLAG,
+       "Preload the dummy exec functions contained in 'noexec_file'",
+       NULL,
+    }, {
+       "noexec_file", T_STR|T_PATH,
+       "File containing dummy exec functions: %s",
+       NULL,
+    }, {
+       "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",
+       NULL,
+    }, {
+       "env_reset", T_FLAG,
+       "Reset the environment to a default set of variables",
+       NULL,
+    }, {
+       "env_check", T_LIST|T_BOOL,
+       "Environment variables to check for sanity:",
+       NULL,
+    }, {
+       "env_delete", T_LIST|T_BOOL,
+       "Environment variables to remove:",
+       NULL,
+    }, {
+       "env_keep", T_LIST|T_BOOL,
+       "Environment variables to preserve:",
+       NULL,
+    }, {
+       "role", T_STR,
+       "SELinux role to use in the new security context: %s",
+       NULL,
+    }, {
+       "type", T_STR,
+       "SELinux type to use in the new security context: %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,
+    }, {
+       "pwfeedback", T_FLAG,
+       "Provide visual feedback at the password prompt when there is user input",
+       NULL,
+    }, {
+       "fast_glob", T_FLAG,
+       "Use faster globbing that is less accurate but does not access the filesystem",
+       NULL,
+    }, {
+       "umask_override", T_FLAG,
+       "The umask specified in sudoers will override the user's, even if it is more permissive",
+       NULL,
+    }, {
+       "log_input", T_FLAG,
+       "Log user's input for the command being run",
+       NULL,
+    }, {
+       "log_output", T_FLAG,
+       "Log the output of the command being run",
+       NULL,
+    }, {
+       "compress_io", T_FLAG,
+       "Compress I/O logs using zlib",
+       NULL,
+    }, {
+       "use_pty", T_FLAG,
+       "Always run commands in a pseudo-tty",
+       NULL,
+    }, {
+       "group_plugin", T_STR,
+       "Plugin for non-Unix group support",
+       NULL,
+    }, {
+       "iolog_dir", T_STR|T_PATH,
+       "Directory in which to store input/output logs",
+       NULL,
+    }, {
+       "iolog_file", T_STR,
+       "File in which to store the input/output log",
+       NULL,
+    }, {
+       "set_utmp", T_FLAG,
+       "Add an entry to the utmp/utmpx file when allocating a pty",
+       NULL,
+    }, {
+       "utmp_runas", T_FLAG,
+       "Set the user in utmp to the runas user, not the invoking user",
+       NULL,
+    }, {
+       NULL, 0, NULL
+    }
+};
diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h
new file mode 100644 (file)
index 0000000..f41f7cd
--- /dev/null
@@ -0,0 +1,170 @@
+#define def_syslog              (sudo_defs_table[0].sd_un.ival)
+#define I_SYSLOG                0
+#define def_syslog_goodpri      (sudo_defs_table[1].sd_un.ival)
+#define I_SYSLOG_GOODPRI        1
+#define def_syslog_badpri       (sudo_defs_table[2].sd_un.ival)
+#define I_SYSLOG_BADPRI         2
+#define def_long_otp_prompt     (sudo_defs_table[3].sd_un.flag)
+#define I_LONG_OTP_PROMPT       3
+#define def_ignore_dot          (sudo_defs_table[4].sd_un.flag)
+#define I_IGNORE_DOT            4
+#define def_mail_always         (sudo_defs_table[5].sd_un.flag)
+#define I_MAIL_ALWAYS           5
+#define def_mail_badpass        (sudo_defs_table[6].sd_un.flag)
+#define I_MAIL_BADPASS          6
+#define def_mail_no_user        (sudo_defs_table[7].sd_un.flag)
+#define I_MAIL_NO_USER          7
+#define def_mail_no_host        (sudo_defs_table[8].sd_un.flag)
+#define I_MAIL_NO_HOST          8
+#define def_mail_no_perms       (sudo_defs_table[9].sd_un.flag)
+#define I_MAIL_NO_PERMS         9
+#define def_tty_tickets         (sudo_defs_table[10].sd_un.flag)
+#define I_TTY_TICKETS           10
+#define def_lecture             (sudo_defs_table[11].sd_un.tuple)
+#define I_LECTURE               11
+#define def_lecture_file        (sudo_defs_table[12].sd_un.str)
+#define I_LECTURE_FILE          12
+#define def_authenticate        (sudo_defs_table[13].sd_un.flag)
+#define I_AUTHENTICATE          13
+#define def_root_sudo           (sudo_defs_table[14].sd_un.flag)
+#define I_ROOT_SUDO             14
+#define def_log_host            (sudo_defs_table[15].sd_un.flag)
+#define I_LOG_HOST              15
+#define def_log_year            (sudo_defs_table[16].sd_un.flag)
+#define I_LOG_YEAR              16
+#define def_shell_noargs        (sudo_defs_table[17].sd_un.flag)
+#define I_SHELL_NOARGS          17
+#define def_set_home            (sudo_defs_table[18].sd_un.flag)
+#define I_SET_HOME              18
+#define def_always_set_home     (sudo_defs_table[19].sd_un.flag)
+#define I_ALWAYS_SET_HOME       19
+#define def_path_info           (sudo_defs_table[20].sd_un.flag)
+#define I_PATH_INFO             20
+#define def_fqdn                (sudo_defs_table[21].sd_un.flag)
+#define I_FQDN                  21
+#define def_insults             (sudo_defs_table[22].sd_un.flag)
+#define I_INSULTS               22
+#define def_requiretty          (sudo_defs_table[23].sd_un.flag)
+#define I_REQUIRETTY            23
+#define def_env_editor          (sudo_defs_table[24].sd_un.flag)
+#define I_ENV_EDITOR            24
+#define def_rootpw              (sudo_defs_table[25].sd_un.flag)
+#define I_ROOTPW                25
+#define def_runaspw             (sudo_defs_table[26].sd_un.flag)
+#define I_RUNASPW               26
+#define def_targetpw            (sudo_defs_table[27].sd_un.flag)
+#define I_TARGETPW              27
+#define def_use_loginclass      (sudo_defs_table[28].sd_un.flag)
+#define I_USE_LOGINCLASS        28
+#define def_set_logname         (sudo_defs_table[29].sd_un.flag)
+#define I_SET_LOGNAME           29
+#define def_stay_setuid         (sudo_defs_table[30].sd_un.flag)
+#define I_STAY_SETUID           30
+#define def_preserve_groups     (sudo_defs_table[31].sd_un.flag)
+#define I_PRESERVE_GROUPS       31
+#define def_loglinelen          (sudo_defs_table[32].sd_un.ival)
+#define I_LOGLINELEN            32
+#define def_timestamp_timeout   (sudo_defs_table[33].sd_un.fval)
+#define I_TIMESTAMP_TIMEOUT     33
+#define def_passwd_timeout      (sudo_defs_table[34].sd_un.fval)
+#define I_PASSWD_TIMEOUT        34
+#define def_passwd_tries        (sudo_defs_table[35].sd_un.ival)
+#define I_PASSWD_TRIES          35
+#define def_umask               (sudo_defs_table[36].sd_un.mode)
+#define I_UMASK                 36
+#define def_logfile             (sudo_defs_table[37].sd_un.str)
+#define I_LOGFILE               37
+#define def_mailerpath          (sudo_defs_table[38].sd_un.str)
+#define I_MAILERPATH            38
+#define def_mailerflags         (sudo_defs_table[39].sd_un.str)
+#define I_MAILERFLAGS           39
+#define def_mailto              (sudo_defs_table[40].sd_un.str)
+#define I_MAILTO                40
+#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_env_file            (sudo_defs_table[66].sd_un.str)
+#define I_ENV_FILE              66
+#define def_sudoers_locale      (sudo_defs_table[67].sd_un.str)
+#define I_SUDOERS_LOCALE        67
+#define def_visiblepw           (sudo_defs_table[68].sd_un.flag)
+#define I_VISIBLEPW             68
+#define def_pwfeedback          (sudo_defs_table[69].sd_un.flag)
+#define I_PWFEEDBACK            69
+#define def_fast_glob           (sudo_defs_table[70].sd_un.flag)
+#define I_FAST_GLOB             70
+#define def_umask_override      (sudo_defs_table[71].sd_un.flag)
+#define I_UMASK_OVERRIDE        71
+#define def_log_input           (sudo_defs_table[72].sd_un.flag)
+#define I_LOG_INPUT             72
+#define def_log_output          (sudo_defs_table[73].sd_un.flag)
+#define I_LOG_OUTPUT            73
+#define def_compress_io         (sudo_defs_table[74].sd_un.flag)
+#define I_COMPRESS_IO           74
+#define def_use_pty             (sudo_defs_table[75].sd_un.flag)
+#define I_USE_PTY               75
+#define def_group_plugin        (sudo_defs_table[76].sd_un.str)
+#define I_GROUP_PLUGIN          76
+#define def_iolog_dir           (sudo_defs_table[77].sd_un.str)
+#define I_IOLOG_DIR             77
+#define def_iolog_file          (sudo_defs_table[78].sd_un.str)
+#define I_IOLOG_FILE            78
+#define def_set_utmp            (sudo_defs_table[79].sd_un.flag)
+#define I_SET_UTMP              79
+#define def_utmp_runas          (sudo_defs_table[80].sd_un.flag)
+#define I_UTMP_RUNAS            80
+
+enum def_tuple {
+       never,
+       once,
+       always,
+       any,
+       all
+};
diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in
new file mode 100644 (file)
index 0000000..340a5e4
--- /dev/null
@@ -0,0 +1,258 @@
+#
+# Format:
+#
+# var_name
+#      TYPE
+#      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
+       "Syslog facility if syslog is being used for logging: %s"
+syslog_goodpri
+       T_LOGPRI
+       "Syslog priority to use when user authenticates successfully: %s"
+syslog_badpri
+       T_LOGPRI
+       "Syslog priority to use when user authenticates unsuccessfully: %s"
+long_otp_prompt
+       T_FLAG
+       "Put OTP prompt on its own line"
+ignore_dot
+       T_FLAG
+       "Ignore '.' in $PATH"
+mail_always
+       T_FLAG
+       "Always send mail when sudo is run"
+mail_badpass
+       T_FLAG
+       "Send mail if user authentication fails"
+mail_no_user
+       T_FLAG
+       "Send mail if the user is not in sudoers"
+mail_no_host
+       T_FLAG
+       "Send mail if the user is not in sudoers for this host"
+mail_no_perms
+       T_FLAG
+       "Send mail if the user is not allowed to run a command"
+tty_tickets
+       T_FLAG
+       "Use a separate timestamp for each user/tty combo"
+lecture
+       T_TUPLE|T_BOOL
+       "Lecture user the first time they run sudo"
+       never once always
+lecture_file
+       T_STR|T_PATH|T_BOOL
+       "File containing the sudo lecture: %s"
+authenticate
+       T_FLAG
+       "Require users to authenticate by default"
+root_sudo
+       T_FLAG
+       "Root may run sudo"
+log_host
+       T_FLAG
+       "Log the hostname in the (non-syslog) log file"
+log_year
+       T_FLAG
+       "Log the year in the (non-syslog) log file"
+shell_noargs
+       T_FLAG
+       "If sudo is invoked with no arguments, start a shell"
+set_home
+       T_FLAG
+       "Set $HOME to the target user when starting a shell with -s"
+always_set_home
+       T_FLAG
+       "Always set $HOME to the target user's home directory"
+path_info
+       T_FLAG
+       "Allow some information gathering to give useful error messages"
+fqdn
+       T_FLAG
+       "Require fully-qualified hostnames in the sudoers file"
+insults
+       T_FLAG
+       "Insult the user when they enter an incorrect password"
+requiretty
+       T_FLAG
+       "Only allow the user to run sudo if they have a tty"
+env_editor
+       T_FLAG
+       "Visudo will honor the EDITOR environment variable"
+rootpw
+       T_FLAG
+       "Prompt for root's password, not the users's"
+runaspw
+       T_FLAG
+       "Prompt for the runas_default user's password, not the users's"
+targetpw
+       T_FLAG
+       "Prompt for the target user's password, not the users's"
+use_loginclass
+       T_FLAG
+       "Apply defaults in the target user's login class if there is one"
+set_logname
+       T_FLAG
+       "Set the LOGNAME and USER environment variables"
+stay_setuid
+       T_FLAG
+       "Only set the effective uid to the target user, not the real uid"
+preserve_groups
+       T_FLAG
+       "Don't initialize the group vector to that of the target user"
+loglinelen
+       T_UINT|T_BOOL
+       "Length at which to wrap log file lines (0 for no wrap): %d"
+timestamp_timeout
+       T_FLOAT|T_BOOL
+       "Authentication timestamp timeout: %.1f minutes"
+passwd_timeout
+       T_FLOAT|T_BOOL
+       "Password prompt timeout: %.1f minutes"
+passwd_tries
+       T_UINT
+       "Number of tries to enter a password: %d"
+umask
+       T_MODE|T_BOOL
+       "Umask to use or 0777 to use user's: 0%o"
+logfile
+       T_STR|T_BOOL|T_PATH
+       "Path to log file: %s"
+mailerpath
+       T_STR|T_BOOL|T_PATH
+       "Path to mail program: %s"
+mailerflags
+       T_STR|T_BOOL
+       "Flags for mail program: %s"
+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"
+badpass_message
+       T_STR
+       "Incorrect password message: %s"
+timestampdir
+       T_STR|T_PATH
+       "Path to authentication timestamp dir: %s"
+timestampowner
+       T_STR
+       "Owner of the authentication timestamp dir: %s"
+exempt_group
+       T_STR|T_BOOL
+       "Users in this group are exempt from password and PATH requirements: %s"
+passprompt
+       T_STR
+       "Default password prompt: %s"
+passprompt_override
+       T_FLAG
+       "If set, passprompt will override system prompt in all cases."
+runas_default
+       T_STR
+       "Default user to run commands as: %s"
+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"
+listpw
+       T_TUPLE|T_BOOL
+       "When to require a password for 'list' pseudocommand: %s"
+       never any all always
+verifypw
+       T_TUPLE|T_BOOL
+       "When to require a password for 'verify' pseudocommand: %s"
+       never all any always
+noexec
+       T_FLAG
+       "Preload the dummy exec functions contained in 'noexec_file'"
+noexec_file
+       T_STR|T_PATH
+       "File containing dummy exec functions: %s"
+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"
+env_reset
+       T_FLAG
+       "Reset the environment to a default set of variables"
+env_check
+       T_LIST|T_BOOL
+       "Environment variables to check for sanity:"
+env_delete
+       T_LIST|T_BOOL
+       "Environment variables to remove:"
+env_keep
+       T_LIST|T_BOOL
+       "Environment variables to preserve:"
+role
+       T_STR
+       "SELinux role to use in the new security context: %s"
+type
+       T_STR
+       "SELinux type to use in the new security context: %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"
+pwfeedback
+       T_FLAG
+       "Provide visual feedback at the password prompt when there is user input"
+fast_glob
+       T_FLAG
+       "Use faster globbing that is less accurate but does not access the filesystem"
+umask_override
+       T_FLAG
+       "The umask specified in sudoers will override the user's, even if it is more permissive"
+log_input
+       T_FLAG
+       "Log user's input for the command being run"
+log_output
+       T_FLAG
+       "Log the output of the command being run"
+compress_io
+       T_FLAG
+       "Compress I/O logs using zlib"
+use_pty
+       T_FLAG
+       "Always run commands in a pseudo-tty"
+group_plugin
+       T_STR
+       "Plugin for non-Unix group support"
+iolog_dir
+       T_STR|T_PATH
+       "Directory in which to store input/output logs"
+iolog_file
+       T_STR
+       "File in which to store the input/output log"
+set_utmp
+       T_FLAG
+       "Add an entry to the utmp/utmpx file when allocating a pty"
+utmp_runas
+       T_FLAG
+       "Set the user in utmp to the runas user, not the invoking user"
diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c
new file mode 100644 (file)
index 0000000..f9e9961
--- /dev/null
@@ -0,0 +1,812 @@
+/*
+ * Copyright (c) 1999-2005, 2007-2011
+ *     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/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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+# ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#include <ctype.h>
+
+#include "sudoers.h"
+#include "parse.h"
+#include <gram.h>
+
+/*
+ * For converting between syslog numbers and strings.
+ */
+struct strmap {
+    char *name;
+    int num;
+};
+
+#ifdef LOG_NFACILITIES
+static struct strmap facilities[] = {
+#ifdef LOG_AUTHPRIV
+       { "authpriv",   LOG_AUTHPRIV },
+#endif
+       { "auth",       LOG_AUTH },
+       { "daemon",     LOG_DAEMON },
+       { "user",       LOG_USER },
+       { "local0",     LOG_LOCAL0 },
+       { "local1",     LOG_LOCAL1 },
+       { "local2",     LOG_LOCAL2 },
+       { "local3",     LOG_LOCAL3 },
+       { "local4",     LOG_LOCAL4 },
+       { "local5",     LOG_LOCAL5 },
+       { "local6",     LOG_LOCAL6 },
+       { "local7",     LOG_LOCAL7 },
+       { NULL,         -1 }
+};
+#endif /* LOG_NFACILITIES */
+
+static struct strmap priorities[] = {
+       { "alert",      LOG_ALERT },
+       { "crit",       LOG_CRIT },
+       { "debug",      LOG_DEBUG },
+       { "emerg",      LOG_EMERG },
+       { "err",        LOG_ERR },
+       { "info",       LOG_INFO },
+       { "notice",     LOG_NOTICE },
+       { "warning",    LOG_WARNING },
+       { NULL,         -1 }
+};
+
+/*
+ * Local prototypes.
+ */
+static int store_int(char *, struct sudo_defs_types *, int);
+static int store_list(char *, struct sudo_defs_types *, int);
+static int store_mode(char *, struct sudo_defs_types *, int);
+static int store_str(char *, struct sudo_defs_types *, int);
+static int store_syslogfac(char *, struct sudo_defs_types *, int);
+static int store_syslogpri(char *, struct sudo_defs_types *, int);
+static int store_tuple(char *, struct sudo_defs_types *, int);
+static int store_uint(char *, struct sudo_defs_types *, int);
+static int store_float(char *, struct sudo_defs_types *, int);
+static void list_op(char *, size_t, struct sudo_defs_types *, enum list_ops);
+static const char *logfac2str(int);
+static const char *logpri2str(int);
+
+/*
+ * Table describing compile-time and run-time options.
+ */
+#include <def_data.c>
+
+/*
+ * Print version and configure info.
+ */
+void
+dump_defaults(void)
+{
+    struct sudo_defs_types *cur;
+    struct list_member *item;
+    struct def_values *def;
+
+    for (cur = sudo_defs_table; cur->name; cur++) {
+       if (cur->desc) {
+           switch (cur->type & T_MASK) {
+               case T_FLAG:
+                   if (cur->sd_un.flag)
+                       sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", cur->desc);
+                   break;
+               case T_STR:
+                   if (cur->sd_un.str) {
+                       sudo_printf(SUDO_CONV_INFO_MSG,
+                           cur->desc, cur->sd_un.str);
+                       sudo_printf(SUDO_CONV_INFO_MSG, "\n");
+                   }
+                   break;
+               case T_LOGFAC:
+                   if (cur->sd_un.ival) {
+                       sudo_printf(SUDO_CONV_INFO_MSG,
+                           cur->desc, logfac2str(cur->sd_un.ival));
+                       sudo_printf(SUDO_CONV_INFO_MSG, "\n");
+                   }
+                   break;
+               case T_LOGPRI:
+                   if (cur->sd_un.ival) {
+                       sudo_printf(SUDO_CONV_INFO_MSG,
+                           cur->desc, logpri2str(cur->sd_un.ival));
+                       sudo_printf(SUDO_CONV_INFO_MSG, "\n");
+                   }
+                   break;
+               case T_UINT:
+               case T_INT:
+                   sudo_printf(SUDO_CONV_INFO_MSG, cur->desc, cur->sd_un.ival);
+                   sudo_printf(SUDO_CONV_INFO_MSG, "\n");
+                   break;
+               case T_FLOAT:
+                   sudo_printf(SUDO_CONV_INFO_MSG, cur->desc, cur->sd_un.fval);
+                   sudo_printf(SUDO_CONV_INFO_MSG, "\n");
+                   break;
+               case T_MODE:
+                   sudo_printf(SUDO_CONV_INFO_MSG, cur->desc, cur->sd_un.mode);
+                   sudo_printf(SUDO_CONV_INFO_MSG, "\n");
+                   break;
+               case T_LIST:
+                   if (cur->sd_un.list) {
+                       sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", cur->desc);
+                       for (item = cur->sd_un.list; item; item = item->next) {
+                           sudo_printf(SUDO_CONV_INFO_MSG,
+                               "\t%s\n", item->value);
+                       }
+                   }
+                   break;
+               case T_TUPLE:
+                   for (def = cur->values; def->sval; def++) {
+                       if (cur->sd_un.ival == def->ival) {
+                           sudo_printf(SUDO_CONV_INFO_MSG,
+                               cur->desc, def->sval);
+                           break;
+                       }
+                   }
+                   sudo_printf(SUDO_CONV_INFO_MSG, "\n");
+                   break;
+           }
+       }
+    }
+}
+
+/*
+ * List each option along with its description.
+ */
+void
+list_options(void)
+{
+    struct sudo_defs_types *cur;
+    char *p;
+
+    sudo_printf(SUDO_CONV_INFO_MSG,
+       "Available options in a sudoers ``Defaults'' line:\n\n");
+    for (cur = sudo_defs_table; cur->name; cur++) {
+       if (cur->name && cur->desc) {
+           switch (cur->type & T_MASK) {
+               case T_FLAG:
+                   sudo_printf(SUDO_CONV_INFO_MSG,
+                       "%s: %s\n", cur->name, cur->desc);
+                   break;
+               default:
+                   p = strrchr(cur->desc, ':');
+                   if (p) {
+                       sudo_printf(SUDO_CONV_INFO_MSG, "%s: %.*s\n",
+                           cur->name, (int) (p - cur->desc), cur->desc);
+                   } else {
+                       sudo_printf(SUDO_CONV_INFO_MSG,
+                           "%s: %s\n", cur->name, cur->desc);
+                   }
+                   break;
+           }
+       }
+    }
+}
+
+/*
+ * Sets/clears an entry in the defaults structure
+ * If a variable that takes a value is used in a boolean
+ * context with op == 0, disable that variable.
+ * Eg. you may want to turn off logging to a file for some hosts.
+ * This is only meaningful for variables that are *optional*.
+ */
+int
+set_default(char *var, char *val, int op)
+{
+    struct sudo_defs_types *cur;
+    int num;
+
+    for (cur = sudo_defs_table, num = 0; cur->name; cur++, num++) {
+       if (strcmp(var, cur->name) == 0)
+           break;
+    }
+    if (!cur->name) {
+       warningx("unknown defaults entry `%s'", var);
+       return FALSE;
+    }
+
+    switch (cur->type & T_MASK) {
+       case T_LOGFAC:
+           if (!store_syslogfac(val, cur, op)) {
+               if (val)
+                   warningx("value `%s' is invalid for option `%s'", val, var);
+               else
+                   warningx("no value specified for `%s'", var);
+               return FALSE;
+           }
+           break;
+       case T_LOGPRI:
+           if (!store_syslogpri(val, cur, op)) {
+               if (val)
+                   warningx("value `%s' is invalid for option `%s'", val, var);
+               else
+                   warningx("no value specified for `%s'", var);
+               return FALSE;
+           }
+           break;
+       case T_STR:
+           if (!val) {
+               /* Check for bogus boolean usage or lack of a value. */
+               if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
+                   warningx("no value specified for `%s'", var);
+                   return FALSE;
+               }
+           }
+           if (ISSET(cur->type, T_PATH) && val && *val != '/') {
+               warningx("values for `%s' must start with a '/'", var);
+               return FALSE;
+           }
+           if (!store_str(val, cur, op)) {
+               warningx("value `%s' is invalid for option `%s'", val, var);
+               return FALSE;
+           }
+           break;
+       case T_INT:
+           if (!val) {
+               /* Check for bogus boolean usage or lack of a value. */
+               if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
+                   warningx("no value specified for `%s'", var);
+                   return FALSE;
+               }
+           }
+           if (!store_int(val, cur, op)) {
+               warningx("value `%s' is invalid for option `%s'", val, var);
+               return FALSE;
+           }
+           break;
+       case T_UINT:
+           if (!val) {
+               /* Check for bogus boolean usage or lack of a value. */
+               if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
+                   warningx("no value specified for `%s'", var);
+                   return FALSE;
+               }
+           }
+           if (!store_uint(val, cur, op)) {
+               warningx("value `%s' is invalid for option `%s'", val, var);
+               return FALSE;
+           }
+           break;
+       case T_FLOAT:
+           if (!val) {
+               /* Check for bogus boolean usage or lack of a value. */
+               if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
+                   warningx("no value specified for `%s'", var);
+                   return FALSE;
+               }
+           }
+           if (!store_float(val, cur, op)) {
+               warningx("value `%s' is invalid for option `%s'", val, var);
+               return FALSE;
+           }
+           break;
+       case T_MODE:
+           if (!val) {
+               /* Check for bogus boolean usage or lack of a value. */
+               if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
+                   warningx("no value specified for `%s'", var);
+                   return FALSE;
+               }
+           }
+           if (!store_mode(val, cur, op)) {
+               warningx("value `%s' is invalid for option `%s'", val, var);
+               return FALSE;
+           }
+           break;
+       case T_FLAG:
+           if (val) {
+               warningx("option `%s' does not take a value", var);
+               return FALSE;
+           }
+           cur->sd_un.flag = op;
+           break;
+       case T_LIST:
+           if (!val) {
+               /* Check for bogus boolean usage or lack of a value. */
+               if (!ISSET(cur->type, T_BOOL) || op != FALSE) {
+                   warningx("no value specified for `%s'", var);
+                   return FALSE;
+               }
+           }
+           if (!store_list(val, cur, op)) {
+               warningx("value `%s' is invalid for option `%s'", val, var);
+               return FALSE;
+           }
+           break;
+       case T_TUPLE:
+           if (!val && !ISSET(cur->type, T_BOOL)) {
+               warningx("no value specified for `%s'", var);
+               return FALSE;
+           }
+           if (!store_tuple(val, cur, op)) {
+               warningx("value `%s' is invalid for option `%s'", val, var);
+               return FALSE;
+           }
+           break;
+    }
+
+    return TRUE;
+}
+
+/*
+ * Set default options to compiled-in values.
+ * Any of these may be overridden at runtime by a "Defaults" file.
+ */
+void
+init_defaults(void)
+{
+    static int firsttime = 1;
+    struct sudo_defs_types *def;
+
+    /* Clear any old settings. */
+    if (!firsttime) {
+       for (def = sudo_defs_table; def->name; def++) {
+           switch (def->type & T_MASK) {
+               case T_STR:
+                   efree(def->sd_un.str);
+                   def->sd_un.str = NULL;
+                   break;
+               case T_LIST:
+                   list_op(NULL, 0, def, freeall);
+                   break;
+           }
+           zero_bytes(&def->sd_un, sizeof(def->sd_un));
+       }
+    }
+
+    /* First initialize the flags. */
+#ifdef LONG_OTP_PROMPT
+    def_long_otp_prompt = TRUE;
+#endif
+#ifdef IGNORE_DOT_PATH
+    def_ignore_dot = TRUE;
+#endif
+#ifdef ALWAYS_SEND_MAIL
+    def_mail_always = TRUE;
+#endif
+#ifdef SEND_MAIL_WHEN_NO_USER
+    def_mail_no_user = TRUE;
+#endif
+#ifdef SEND_MAIL_WHEN_NO_HOST
+    def_mail_no_host = TRUE;
+#endif
+#ifdef SEND_MAIL_WHEN_NOT_OK
+    def_mail_no_perms = TRUE;
+#endif
+#ifndef NO_TTY_TICKETS
+    def_tty_tickets = TRUE;
+#endif
+#ifndef NO_LECTURE
+    def_lecture = once;
+#endif
+#ifndef NO_AUTHENTICATION
+    def_authenticate = TRUE;
+#endif
+#ifndef NO_ROOT_SUDO
+    def_root_sudo = TRUE;
+#endif
+#ifdef HOST_IN_LOG
+    def_log_host = TRUE;
+#endif
+#ifdef SHELL_IF_NO_ARGS
+    def_shell_noargs = TRUE;
+#endif
+#ifdef SHELL_SETS_HOME
+    def_set_home = TRUE;
+#endif
+#ifndef DONT_LEAK_PATH_INFO
+    def_path_info = TRUE;
+#endif
+#ifdef FQDN
+    def_fqdn = TRUE;
+#endif
+#ifdef USE_INSULTS
+    def_insults = TRUE;
+#endif
+#ifdef ENV_EDITOR
+    def_env_editor = TRUE;
+#endif
+#ifdef UMASK_OVERRIDE
+    def_umask_override = TRUE;
+#endif
+    def_iolog_file = estrdup("%{seq}");
+    def_iolog_dir = estrdup(_PATH_SUDO_IO_LOGDIR);
+    def_sudoers_locale = estrdup("C");
+    def_env_reset = ENV_RESET;
+    def_set_logname = TRUE;
+    def_closefrom = STDERR_FILENO + 1;
+
+    /* Syslog options need special care since they both strings and ints */
+#if (LOGGING & SLOG_SYSLOG)
+    (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG], TRUE);
+    (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI],
+       TRUE);
+    (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI],
+       TRUE);
+#endif
+
+    /* Password flags also have a string and integer component. */
+    (void) store_tuple("any", &sudo_defs_table[I_LISTPW], TRUE);
+    (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], TRUE);
+
+    /* Then initialize the int-like things. */
+#ifdef SUDO_UMASK
+    def_umask = SUDO_UMASK;
+#else
+    def_umask = 0777;
+#endif
+    def_loglinelen = MAXLOGFILELEN;
+    def_timestamp_timeout = TIMEOUT;
+    def_passwd_timeout = PASSWORD_TIMEOUT;
+    def_passwd_tries = TRIES_FOR_PASSWORD;
+#ifdef HAVE_ZLIB_H
+    def_compress_io = TRUE;
+#endif
+
+    /* Now do the strings */
+    def_mailto = estrdup(MAILTO);
+    def_mailsub = estrdup(MAILSUBJECT);
+    def_badpass_message = estrdup(INCORRECT_PASSWORD);
+    def_timestampdir = estrdup(_PATH_SUDO_TIMEDIR);
+    def_passprompt = estrdup(PASSPROMPT);
+    def_runas_default = estrdup(RUNAS_DEFAULT);
+#ifdef _PATH_SUDO_SENDMAIL
+    def_mailerpath = estrdup(_PATH_SUDO_SENDMAIL);
+    def_mailerflags = estrdup("-t");
+#endif
+#if (LOGGING & SLOG_FILE)
+    def_logfile = estrdup(_PATH_SUDO_LOGFILE);
+#endif
+#ifdef EXEMPTGROUP
+    def_exempt_group = estrdup(EXEMPTGROUP);
+#endif
+#ifdef SECURE_PATH
+    def_secure_path = estrdup(SECURE_PATH);
+#endif
+    def_editor = estrdup(EDITOR);
+    def_set_utmp = TRUE;
+
+    /* Finally do the lists (currently just environment tables). */
+    init_envtables();
+
+    firsttime = 0;
+}
+
+/*
+ * Update the defaults based on what was set by sudoers.
+ * Pass in an OR'd list of which default types to update.
+ */
+int
+update_defaults(int what)
+{
+    struct defaults *def;
+    int rc = TRUE;
+
+    tq_foreach_fwd(&defaults, def) {
+       switch (def->type) {
+           case DEFAULTS:
+               if (ISSET(what, SETDEF_GENERIC) &&
+                   !set_default(def->var, def->val, def->op))
+                   rc = 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))
+                   rc = FALSE;
+               break;
+           case DEFAULTS_RUNAS:
+               if (ISSET(what, SETDEF_RUNAS) &&
+                   runaslist_matches(&def->binding, NULL) == ALLOW &&
+                   !set_default(def->var, def->val, def->op))
+                   rc = FALSE;
+               break;
+           case DEFAULTS_HOST:
+               if (ISSET(what, SETDEF_HOST) &&
+                   hostlist_matches(&def->binding) == ALLOW &&
+                   !set_default(def->var, def->val, def->op))
+                   rc = FALSE;
+               break;
+           case DEFAULTS_CMND:
+               if (ISSET(what, SETDEF_CMND) &&
+                   cmndlist_matches(&def->binding) == ALLOW &&
+                   !set_default(def->var, def->val, def->op))
+                   rc = FALSE;
+               break;
+       }
+    }
+    return rc;
+}
+
+static int
+store_int(char *val, struct sudo_defs_types *def, int op)
+{
+    char *endp;
+    long l;
+
+    if (op == FALSE) {
+       def->sd_un.ival = 0;
+    } else {
+       l = strtol(val, &endp, 10);
+       if (*endp != '\0')
+           return FALSE;
+       /* XXX - should check against INT_MAX */
+       def->sd_un.ival = (int)l;
+    }
+    if (def->callback)
+       return def->callback(val);
+    return TRUE;
+}
+
+static int
+store_uint(char *val, struct sudo_defs_types *def, int op)
+{
+    char *endp;
+    long l;
+
+    if (op == FALSE) {
+       def->sd_un.ival = 0;
+    } else {
+       l = strtol(val, &endp, 10);
+       if (*endp != '\0' || l < 0)
+           return FALSE;
+       /* XXX - should check against INT_MAX */
+       def->sd_un.ival = (unsigned int)l;
+    }
+    if (def->callback)
+       return def->callback(val);
+    return TRUE;
+}
+
+static int
+store_float(char *val, struct sudo_defs_types *def, int op)
+{
+    char *endp;
+    double d;
+
+    if (op == FALSE) {
+       def->sd_un.fval = 0.0;
+    } else {
+       d = strtod(val, &endp);
+       if (*endp != '\0')
+           return FALSE;
+       /* XXX - should check against HUGE_VAL */
+       def->sd_un.fval = d;
+    }
+    if (def->callback)
+       return def->callback(val);
+    return TRUE;
+}
+
+static int
+store_tuple(char *val, struct sudo_defs_types *def, int op)
+{
+    struct def_values *v;
+
+    /*
+     * Since enums are really just ints we store the value as an ival.
+     * In the future, there may be multiple enums for different tuple
+     * types we want to avoid and special knowledge of the tuple type.
+     * This does assume that the first entry in the tuple enum will
+     * be the equivalent to a boolean "false".
+     */
+    if (!val) {
+       def->sd_un.ival = (op == FALSE) ? 0 : 1;
+    } else {
+       for (v = def->values; v->sval != NULL; v++) {
+           if (strcmp(v->sval, val) == 0) {
+               def->sd_un.ival = v->ival;
+               break;
+           }
+       }
+       if (v->sval == NULL)
+           return FALSE;
+    }
+    if (def->callback)
+       return def->callback(val);
+    return TRUE;
+}
+
+static int
+store_str(char *val, struct sudo_defs_types *def, int op)
+{
+
+    efree(def->sd_un.str);
+    if (op == FALSE)
+       def->sd_un.str = NULL;
+    else
+       def->sd_un.str = estrdup(val);
+    if (def->callback)
+       return def->callback(val);
+    return TRUE;
+}
+
+static int
+store_list(char *str, struct sudo_defs_types *def, int op)
+{
+    char *start, *end;
+
+    /* Remove all old members. */
+    if (op == FALSE || op == TRUE)
+       list_op(NULL, 0, def, freeall);
+
+    /* Split str into multiple space-separated words and act on each one. */
+    if (op != FALSE) {
+       end = str;
+       do {
+           /* Remove leading blanks, if nothing but blanks we are done. */
+           for (start = end; isblank((unsigned char)*start); start++)
+               ;
+           if (*start == '\0')
+               break;
+
+           /* Find end position and perform operation. */
+           for (end = start; *end && !isblank((unsigned char)*end); end++)
+               ;
+           list_op(start, end - start, def, op == '-' ? delete : add);
+       } while (*end++ != '\0');
+    }
+    return TRUE;
+}
+
+static int
+store_syslogfac(char *val, struct sudo_defs_types *def, int op)
+{
+    struct strmap *fac;
+
+    if (op == FALSE) {
+       def->sd_un.ival = FALSE;
+       return TRUE;
+    }
+#ifdef LOG_NFACILITIES
+    if (!val)
+       return FALSE;
+    for (fac = facilities; fac->name && strcmp(val, fac->name); fac++)
+       ;
+    if (fac->name == NULL)
+       return FALSE;                           /* not found */
+
+    def->sd_un.ival = fac->num;
+#else
+    def->sd_un.ival = -1;
+#endif /* LOG_NFACILITIES */
+    return TRUE;
+}
+
+static const char *
+logfac2str(int n)
+{
+#ifdef LOG_NFACILITIES
+    struct strmap *fac;
+
+    for (fac = facilities; fac->name && fac->num != n; fac++)
+       ;
+    return fac->name;
+#else
+    return "default";
+#endif /* LOG_NFACILITIES */
+}
+
+static int
+store_syslogpri(char *val, struct sudo_defs_types *def, int op)
+{
+    struct strmap *pri;
+
+    if (op == FALSE || !val)
+       return FALSE;
+
+    for (pri = priorities; pri->name && strcmp(val, pri->name); pri++)
+       ;
+    if (pri->name == NULL)
+       return FALSE;                           /* not found */
+
+    def->sd_un.ival = pri->num;
+    return TRUE;
+}
+
+static const char *
+logpri2str(int n)
+{
+    struct strmap *pri;
+
+    for (pri = priorities; pri->name && pri->num != n; pri++)
+       ;
+    return pri->name;
+}
+
+static int
+store_mode(char *val, struct sudo_defs_types *def, int op)
+{
+    char *endp;
+    long l;
+
+    if (op == FALSE) {
+       def->sd_un.mode = (mode_t)0777;
+    } else {
+       l = strtol(val, &endp, 8);
+       if (*endp != '\0' || l < 0 || l > 0777)
+           return FALSE;
+       def->sd_un.mode = (mode_t)l;
+    }
+    if (def->callback)
+       return def->callback(val);
+    return TRUE;
+}
+
+static void
+list_op(char *val, size_t len, struct sudo_defs_types *def, enum list_ops op)
+{
+    struct list_member *cur, *prev, *tmp;
+
+    if (op == freeall) {
+       for (cur = def->sd_un.list; cur; ) {
+           tmp = cur;
+           cur = tmp->next;
+           efree(tmp->value);
+           efree(tmp);
+       }
+       def->sd_un.list = NULL;
+       return;
+    }
+
+    for (cur = def->sd_un.list, prev = NULL; cur; prev = cur, cur = cur->next) {
+       if ((strncmp(cur->value, val, len) == 0 && cur->value[len] == '\0')) {
+
+           if (op == add)
+               return;                 /* already exists */
+
+           /* Delete node */
+           if (prev != NULL)
+               prev->next = cur->next;
+           else
+               def->sd_un.list = cur->next;
+           efree(cur->value);
+           efree(cur);
+           break;
+       }
+    }
+
+    /* Add new node to the head of the list. */
+    if (op == add) {
+       cur = emalloc(sizeof(struct list_member));
+       cur->value = emalloc(len + 1);
+       (void) memcpy(cur->value, val, len);
+       cur->value[len] = '\0';
+       cur->next = def->sd_un.list;
+       def->sd_un.list = cur;
+    }
+}
diff --git a/plugins/sudoers/defaults.h b/plugins/sudoers/defaults.h
new file mode 100644 (file)
index 0000000..1329124
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1999-2005, 2008-2010
+ *     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.
+ */
+
+#ifndef _SUDO_DEFAULTS_H
+#define _SUDO_DEFAULTS_H
+
+#include <def_data.h>
+
+struct list_member {
+    char *value;
+    struct list_member *next;
+};
+
+struct def_values {
+    char *sval;                /* string value */
+    int ival;          /* actually an enum */
+};
+
+enum list_ops {
+    add,
+    delete,
+    freeall
+};
+
+/*
+ * Structure describing compile-time and run-time options.
+ */
+struct sudo_defs_types {
+    char *name;
+    int type;
+    char *desc;
+    struct def_values *values;
+    int (*callback)(char *);
+    union {
+       int flag;
+       int ival;
+       double fval;
+       enum def_tuple tuple;
+       char *str;
+       mode_t mode;
+       struct list_member *list;
+    } sd_un;
+};
+
+/*
+ * Four types of defaults: strings, integers, and flags.
+ * Also, T_INT, T_FLOAT or T_STR may be ANDed with T_BOOL to indicate that
+ * a value is not required.  Flags are boolean by nature...
+ */
+#undef T_INT
+#define T_INT          0x001
+#undef T_UINT
+#define T_UINT         0x002
+#undef T_STR
+#define T_STR          0x003
+#undef T_FLAG
+#define T_FLAG         0x004
+#undef T_MODE
+#define T_MODE         0x005
+#undef T_LIST
+#define T_LIST         0x006
+#undef T_LOGFAC
+#define T_LOGFAC       0x007
+#undef T_LOGPRI
+#define T_LOGPRI       0x008
+#undef T_TUPLE
+#define T_TUPLE                0x009
+#undef T_FLOAT
+#define T_FLOAT                0x010
+#undef T_MASK
+#define T_MASK         0x0FF
+#undef T_BOOL
+#define T_BOOL         0x100
+#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(void);
+void init_defaults(void);
+void list_options(void);
+int  set_default(char *, char *, int);
+int  update_defaults(int);
+
+extern struct sudo_defs_types sudo_defs_table[];
+
+#endif /* _SUDO_DEFAULTS_H */
diff --git a/plugins/sudoers/env.c b/plugins/sudoers/env.c
new file mode 100644 (file)
index 0000000..9d1201f
--- /dev/null
@@ -0,0 +1,786 @@
+/*
+ * Copyright (c) 2000-2005, 2007-2011
+ *     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/param.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <ctype.h>
+#include <errno.h>
+#include <pwd.h>
+
+#include "sudoers.h"
+
+/*
+ * Flags used in rebuild_env()
+ */
+#undef DID_TERM
+#define DID_TERM       0x0001
+#undef DID_PATH
+#define DID_PATH       0x0002
+#undef DID_HOME
+#define DID_HOME       0x0004
+#undef DID_SHELL
+#define DID_SHELL      0x0008
+#undef DID_LOGNAME
+#define DID_LOGNAME    0x0010
+#undef DID_USER
+#define DID_USER       0x0020
+#undef DID_USERNAME
+#define DID_USERNAME           0x0040
+#undef DID_MAIL
+#define DID_MAIL       0x0080
+#undef DID_MAX
+#define DID_MAX        0x00ff
+
+#undef KEPT_TERM
+#define KEPT_TERM      0x0100
+#undef KEPT_PATH
+#define KEPT_PATH      0x0200
+#undef KEPT_HOME
+#define KEPT_HOME      0x0400
+#undef KEPT_SHELL
+#define KEPT_SHELL     0x0800
+#undef KEPT_LOGNAME
+#define KEPT_LOGNAME   0x1000
+#undef KEPT_USER
+#define KEPT_USER      0x2000
+#undef KEPT_USERNAME
+#define KEPT_USERNAME  0x4000
+#undef KEPT_MAIL
+#define KEPT_MAIL      0x8000
+#undef KEPT_MAX
+#define KEPT_MAX       0xff00
+
+struct environment {
+    char **envp;               /* pointer to the new environment */
+    size_t env_size;           /* size of new_environ in char **'s */
+    size_t env_len;            /* number of slots used, not counting NULL */
+};
+
+/*
+ * Prototypes
+ */
+static void sudo_setenv(const char *, const char *, int);
+static void sudo_putenv(char *, int, int);
+
+/*
+ * Copy of the sudo-managed environment.
+ */
+static struct environment env;
+
+/*
+ * Default table of "bad" variables to remove from the environment.
+ * XXX - how to omit TERMCAP if it starts with '/'?
+ */
+static const char *initial_badenv_table[] = {
+    "IFS",
+    "CDPATH",
+    "LOCALDOMAIN",
+    "RES_OPTIONS",
+    "HOSTALIASES",
+    "NLSPATH",
+    "PATH_LOCALE",
+    "LD_*",
+    "_RLD*",
+#ifdef __hpux
+    "SHLIB_PATH",
+#endif /* __hpux */
+#ifdef _AIX
+    "LDR_*",
+    "LIBPATH",
+    "AUTHSTATE",
+#endif
+#ifdef __APPLE__
+    "DYLD_*",
+#endif
+#ifdef HAVE_KERB4
+    "KRB_CONF*",
+    "KRBCONFDIR",
+    "KRBTKFILE",
+#endif /* HAVE_KERB4 */
+#ifdef HAVE_KERB5
+    "KRB5_CONFIG*",
+    "KRB5_KTNAME",
+#endif /* HAVE_KERB5 */
+#ifdef HAVE_SECURID
+    "VAR_ACE",
+    "USR_ACE",
+    "DLC_ACE",
+#endif /* HAVE_SECURID */
+    "TERMINFO",                        /* terminfo, exclusive path to terminfo files */
+    "TERMINFO_DIRS",           /* terminfo, path(s) to terminfo files */
+    "TERMPATH",                        /* termcap, path(s) to termcap files */
+    "TERMCAP",                 /* XXX - only if it starts with '/' */
+    "ENV",                     /* ksh, file to source before script runs */
+    "BASH_ENV",                        /* bash, file to source before script runs */
+    "PS4",                     /* bash, prefix for lines in xtrace mode */
+    "GLOBIGNORE",              /* bash, globbing patterns to ignore */
+    "SHELLOPTS",               /* bash, extra command line options */
+    "JAVA_TOOL_OPTIONS",       /* java, extra command line options */
+    "PERLIO_DEBUG ",           /* perl, debugging output file */
+    "PERLLIB",                 /* perl, search path for modules/includes */
+    "PERL5LIB",                        /* perl 5, search path for modules/includes */
+    "PERL5OPT",                        /* perl 5, extra command line options */
+    "PERL5DB",                 /* perl 5, command used to load debugger */
+    "FPATH",                   /* ksh, search path for functions */
+    "NULLCMD",                 /* zsh, command for null file redirection */
+    "READNULLCMD",             /* zsh, command for null file redirection */
+    "ZDOTDIR",                 /* zsh, search path for dot files */
+    "TMPPREFIX",               /* zsh, prefix for temporary files */
+    "PYTHONHOME",              /* python, module search path */
+    "PYTHONPATH",              /* python, search path */
+    "PYTHONINSPECT",           /* python, allow inspection */
+    "PYTHONUSERBASE",          /* python, per user site-packages directory */
+    "RUBYLIB",                 /* ruby, library load path */
+    "RUBYOPT",                 /* ruby, extra command line options */
+    NULL
+};
+
+/*
+ * Default table of variables to check for '%' and '/' characters.
+ */
+static const char *initial_checkenv_table[] = {
+    "COLORTERM",
+    "LANG",
+    "LANGUAGE",
+    "LC_*",
+    "LINGUAS",
+    "TERM",
+    NULL
+};
+
+/*
+ * Default table of variables to preserve in the environment.
+ */
+static const char *initial_keepenv_table[] = {
+    "COLORS",
+    "DISPLAY",
+    "HOSTNAME",
+    "KRB5CCNAME",
+    "LS_COLORS",
+    "PATH",
+    "PS1",
+    "PS2",
+    "TZ",
+    "XAUTHORITY",
+    "XAUTHORIZATION",
+#ifdef _AIX
+    "ODMDIR",
+#endif
+    NULL
+};
+
+/*
+ * Initialize env based on envp.
+ */
+void
+env_init(char * const envp[])
+{
+    char * const *ep;
+    size_t len;
+
+    for (ep = envp; *ep != NULL; ep++)
+       continue;
+    len = (size_t)(ep - envp);
+
+    env.env_len = len;
+    env.env_size = len + 1 + 128;
+    env.envp = emalloc2(env.env_size, sizeof(char *));
+#ifdef ENV_DEBUG
+    memset(env.envp, 0, env.env_size * sizeof(char *));
+#endif
+    memcpy(env.envp, envp, len * sizeof(char *));
+    env.envp[len] = '\0';
+}
+
+char **
+env_get(void)
+{
+    return env.envp;
+}
+
+/*
+ * Similar to setenv(3) but operates on sudo's private copy of the environment
+ * (not environ) and it always overwrites.  The dupcheck param determines
+ * whether we need to verify that the variable is not already set.
+ */
+static void
+sudo_setenv(const char *var, const char *val, int dupcheck)
+{
+    char *estring;
+    size_t esize;
+
+    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");
+    }
+    sudo_putenv(estring, dupcheck, TRUE);
+}
+
+/*
+ * Similar to putenv(3) but operates on sudo's private copy of the
+ * environment (not environ) and it always overwrites.  The dupcheck param
+ * determines whether we need to verify that the variable is not already set.
+ * Will only overwrite an existing variable if overwrite is set.
+ */
+static void
+sudo_putenv(char *str, int dupcheck, int overwrite)
+{
+    char **ep;
+    size_t len;
+    int found = FALSE;
+
+    /* Make sure there is room for the new entry plus a NULL. */
+    if (env.env_len + 2 > env.env_size) {
+       env.env_size += 128;
+       env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
+#ifdef ENV_DEBUG
+       memset(env.envp + env.env_len, 0,
+           (env.env_size - env.env_len) * sizeof(char *));
+#endif
+    }
+
+#ifdef ENV_DEBUG
+    if (env.envp[env.env_len] != NULL)
+       errorx(1, "sudo_putenv: corrupted envp, len mismatch");
+#endif
+
+    if (dupcheck) {
+       len = (strchr(str, '=') - str) + 1;
+       for (ep = env.envp; !found && *ep != NULL; ep++) {
+           if (strncmp(str, *ep, len) == 0) {
+               if (overwrite)
+                   *ep = str;
+               found = TRUE;
+           }
+       }
+       /* Prune out duplicate variables. */
+       if (found && overwrite) {
+           while (*ep != NULL) {
+               if (strncmp(str, *ep, len) == 0) {
+                   char **cur = ep;
+                   while ((*cur = *(cur + 1)) != NULL)
+                       cur++;
+               } else {
+                   ep++;
+               }
+           }
+           env.env_len = ep - env.envp;
+       }
+    }
+
+    if (!found) {
+       ep = env.envp + env.env_len;
+       env.env_len++;
+       *ep++ = str;
+       *ep = NULL;
+    }
+}
+
+/*
+ * Check the env_delete blacklist.
+ * Returns TRUE if the variable was found, else false.
+ */
+static int
+matches_env_delete(const char *var)
+{
+    struct list_member *cur;
+    size_t len;
+    int iswild, match = FALSE;
+
+    /* Skip anything listed in env_delete. */
+    for (cur = def_env_delete; cur; cur = cur->next) {
+       len = strlen(cur->value);
+       /* Deal with '*' wildcard */
+       if (cur->value[len - 1] == '*') {
+           len--;
+           iswild = TRUE;
+       } else
+           iswild = FALSE;
+       if (strncmp(cur->value, var, len) == 0 &&
+           (iswild || var[len] == '=')) {
+           match = TRUE;
+           break;
+       }
+    }
+    return match;
+}
+
+/*
+ * Apply the env_check list.
+ * Returns TRUE if the variable is allowed, FALSE if denied
+ * or -1 if no match.
+ */
+static int
+matches_env_check(const char *var)
+{
+    struct list_member *cur;
+    size_t len;
+    int iswild, keepit = -1;
+
+    for (cur = def_env_check; cur; cur = cur->next) {
+       len = strlen(cur->value);
+       /* Deal with '*' wildcard */
+       if (cur->value[len - 1] == '*') {
+           len--;
+           iswild = TRUE;
+       } else
+           iswild = FALSE;
+       if (strncmp(cur->value, var, len) == 0 &&
+           (iswild || var[len] == '=')) {
+           keepit = !strpbrk(var, "/%");
+           break;
+       }
+    }
+    return keepit;
+}
+
+/*
+ * Check the env_keep list.
+ * Returns TRUE if the variable is allowed else FALSE.
+ */
+static int
+matches_env_keep(const char *var)
+{
+    struct list_member *cur;
+    size_t len;
+    int iswild, keepit = FALSE;
+
+    for (cur = def_env_keep; cur; cur = cur->next) {
+       len = strlen(cur->value);
+       /* Deal with '*' wildcard */
+       if (cur->value[len - 1] == '*') {
+           len--;
+           iswild = TRUE;
+       } else
+           iswild = FALSE;
+       if (strncmp(cur->value, var, len) == 0 &&
+           (iswild || var[len] == '=')) {
+           keepit = TRUE;
+           break;
+       }
+    }
+    return keepit;
+}
+
+/*
+ * Build a new environment and ether clear potentially dangerous
+ * variables from the old one or start with a clean slate.
+ * Also adds sudo-specific variables (SUDO_*).
+ */
+void
+rebuild_env(void)
+{
+    char **old_envp, **ep, *cp, *ps1;
+    char idbuf[MAX_UID_T_LEN];
+    unsigned int didvar;
+    int reset_home = FALSE;
+
+    /*
+     * Either clean out the environment or reset to a safe default.
+     */
+    ps1 = NULL;
+    didvar = 0;
+    env.env_len = 0;
+    env.env_size = 128;
+    old_envp = env.envp;
+    env.envp = emalloc2(env.env_size, sizeof(char *));
+#ifdef ENV_DEBUG
+    memset(env.envp, 0, env.env_size * sizeof(char *));
+#endif
+
+    /* Reset HOME based on target user if configured to. */
+    if (ISSET(sudo_mode, MODE_RUN)) {
+       if (def_always_set_home ||
+           ISSET(sudo_mode, MODE_RESET_HOME | MODE_LOGIN_SHELL) || 
+           (ISSET(sudo_mode, MODE_SHELL) && def_set_home))
+           reset_home = TRUE;
+    }
+
+    if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
+       /* Pull in vars we want to keep from the old environment. */
+       for (ep = old_envp; *ep; ep++) {
+           int keepit;
+
+           /* Skip variables with values beginning with () (bash functions) */
+           if ((cp = strchr(*ep, '=')) != NULL) {
+               if (strncmp(cp, "=() ", 3) == 0)
+                   continue;
+           }
+
+           /*
+            * First check certain variables for '%' and '/' characters.
+            * If no match there, check the keep list.
+            * If nothing matched, we remove it from the environment.
+            */
+           keepit = matches_env_check(*ep);
+           if (keepit == -1)
+               keepit = matches_env_keep(*ep);
+
+           /* For SUDO_PS1 -> PS1 conversion. */
+           if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
+               ps1 = *ep + 5;
+
+           if (keepit) {
+               /* Preserve variable. */
+               switch (**ep) {
+                   case 'H':
+                       if (strncmp(*ep, "HOME=", 5) == 0)
+                           SET(didvar, DID_HOME);
+                       break;
+                   case 'L':
+                       if (strncmp(*ep, "LOGNAME=", 8) == 0)
+                           SET(didvar, DID_LOGNAME);
+                       break;
+                   case 'M':
+                       if (strncmp(*ep, "MAIL=", 5) == 0)
+                           SET(didvar, DID_MAIL);
+                       break;
+                   case 'P':
+                       if (strncmp(*ep, "PATH=", 5) == 0)
+                           SET(didvar, DID_PATH);
+                       break;
+                   case 'S':
+                       if (strncmp(*ep, "SHELL=", 6) == 0)
+                           SET(didvar, DID_SHELL);
+                       break;
+                   case 'T':
+                       if (strncmp(*ep, "TERM=", 5) == 0)
+                           SET(didvar, DID_TERM);
+                       break;
+                   case 'U':
+                       if (strncmp(*ep, "USER=", 5) == 0)
+                           SET(didvar, DID_USER);
+                       if (strncmp(*ep, "USERNAME=", 5) == 0)
+                           SET(didvar, DID_USERNAME);
+                       break;
+               }
+               sudo_putenv(*ep, FALSE, FALSE);
+           }
+       }
+       didvar |= didvar << 8;          /* convert DID_* to KEPT_* */
+
+       /*
+        * Add in defaults.  In -i mode these come from the runas user,
+        * otherwise they may be from the user's environment (depends
+        * on sudoers options).
+        */
+       if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
+           sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL));
+           sudo_setenv("LOGNAME", runas_pw->pw_name,
+               ISSET(didvar, DID_LOGNAME));
+           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_SHELL))
+               sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE);
+           if (!ISSET(didvar, DID_LOGNAME))
+               sudo_setenv("LOGNAME", user_name, FALSE);
+           if (!ISSET(didvar, DID_USER))
+               sudo_setenv("USER", user_name, FALSE);
+           if (!ISSET(didvar, DID_USERNAME))
+               sudo_setenv("USERNAME", user_name, FALSE);
+       }
+
+       /* If we didn't keep HOME, reset it based on target user. */
+       if (!ISSET(didvar, KEPT_HOME))
+           reset_home = TRUE;
+
+       /*
+        * Set MAIL to target user in -i mode or if MAIL is not preserved
+        * from user's environment.
+        */
+       if (ISSET(sudo_mode, MODE_LOGIN_SHELL) || !ISSET(didvar, KEPT_MAIL)) {
+           cp = _PATH_MAILDIR;
+           if (cp[sizeof(_PATH_MAILDIR) - 2] == '/')
+               easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name);
+           else
+               easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name);
+           sudo_putenv(cp, ISSET(didvar, DID_MAIL), TRUE);
+       }
+    } else {
+       /*
+        * Copy environ entries as long as they don't match env_delete or
+        * env_check.
+        */
+       for (ep = old_envp; *ep; ep++) {
+           int okvar;
+
+           /* Skip variables with values beginning with () (bash functions) */
+           if ((cp = strchr(*ep, '=')) != NULL) {
+               if (strncmp(cp, "=() ", 3) == 0)
+                   continue;
+           }
+
+           /*
+            * First check variables against the blacklist in env_delete.
+            * If no match there check for '%' and '/' characters.
+            */
+           okvar = matches_env_delete(*ep) != TRUE;
+           if (okvar)
+               okvar = matches_env_check(*ep) != FALSE;
+
+           if (okvar) {
+               if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
+                   ps1 = *ep + 5;
+               else if (strncmp(*ep, "PATH=", 5) == 0)
+                   SET(didvar, DID_PATH);
+               else if (strncmp(*ep, "TERM=", 5) == 0)
+                   SET(didvar, DID_TERM);
+               sudo_putenv(*ep, FALSE, FALSE);
+           }
+       }
+    }
+    /* 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);
+    }
+
+    /* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is true. */
+    if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
+       if (!ISSET(didvar, KEPT_LOGNAME))
+           sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE);
+       if (!ISSET(didvar, KEPT_USER))
+           sudo_setenv("USER", runas_pw->pw_name, TRUE);
+       if (!ISSET(didvar, KEPT_USERNAME))
+           sudo_setenv("USERNAME", runas_pw->pw_name, TRUE);
+    }
+
+    /* Set $HOME to target user if not preserving user's value. */
+    if (reset_home)
+       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))
+       sudo_putenv("TERM=unknown", FALSE, FALSE);
+    if (!ISSET(didvar, DID_PATH))
+       sudo_setenv("PATH", _PATH_STDPATH, FALSE);
+
+    /* Set PS1 if SUDO_PS1 is set. */
+    if (ps1 != NULL)
+       sudo_putenv(ps1, TRUE, TRUE);
+
+    /* Add the SUDO_COMMAND envariable (cmnd + args). */
+    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. */
+    sudo_setenv("SUDO_USER", user_name, TRUE);
+    snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_uid);
+    sudo_setenv("SUDO_UID", idbuf, TRUE);
+    snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_gid);
+    sudo_setenv("SUDO_GID", idbuf, TRUE);
+
+    /* Free old environment. */
+    efree(old_envp);
+}
+
+void
+insert_env_vars(char * const envp[])
+{
+    char * const *ep;
+
+    if (envp == NULL)
+       return;
+
+    /* Add user-specified environment variables. */
+    for (ep = envp; *ep != NULL; ep++)
+       sudo_putenv(*ep, TRUE, TRUE);
+}
+
+/*
+ * Validate the list of environment variables passed in on the command
+ * line against env_delete, env_check, and env_keep.
+ * Calls log_error() if any specified variables are not allowed.
+ */
+void
+validate_env_vars(char * const env_vars[])
+{
+    char * const *ep;
+    char *eq, *bad = NULL;
+    size_t len, blen = 0, bsize = 0;
+    int okvar;
+
+    if (env_vars == NULL)
+       return;
+
+    /* Add user-specified environment variables. */
+    for (ep = env_vars; *ep != NULL; ep++) {
+       if (def_secure_path && !user_is_exempt() &&
+           strncmp(*ep, "PATH=", 5) == 0) {
+           okvar = FALSE;
+       } else if (def_env_reset) {
+           okvar = matches_env_check(*ep);
+           if (okvar == -1)
+               okvar = matches_env_keep(*ep);
+       } else {
+           okvar = matches_env_delete(*ep) == FALSE;
+           if (okvar == FALSE)
+               okvar = matches_env_check(*ep) != FALSE;
+       }
+       if (okvar == FALSE) {
+           /* Not allowed, add to error string, allocating as needed. */
+           if ((eq = strchr(*ep, '=')) != NULL)
+               *eq = '\0';
+           len = strlen(*ep) + 2;
+           if (blen + len >= bsize) {
+               do {
+                   bsize += 1024;
+               } while (blen + len >= bsize);
+               bad = erealloc(bad, bsize);
+               bad[blen] = '\0';
+           }
+           strlcat(bad, *ep, bsize);
+           strlcat(bad, ", ", bsize);
+           blen += len;
+           if (eq != NULL)
+               *eq = '=';
+       }
+    }
+    if (bad != NULL) {
+       bad[blen - 2] = '\0';           /* remove trailing ", " */
+       log_error(NO_MAIL,
+           "sorry, you are not allowed to set the following environment variables: %s", bad);
+       /* NOTREACHED */
+       efree(bad);
+    }
+}
+
+/*
+ * Read in /etc/environment ala AIX and Linux.
+ * Lines may be in either of three formats:
+ *  NAME=VALUE
+ *  NAME="VALUE"
+ *  NAME='VALUE'
+ * with an optional "export" prefix so the shell can source the file.
+ * Invalid lines, blank lines, or lines consisting solely of a comment
+ * character are skipped.
+ */
+void
+read_env_file(const char *path, int overwrite)
+{
+    FILE *fp;
+    char *cp, *var, *val;
+    size_t var_len, val_len;
+
+    if ((fp = fopen(path, "r")) == NULL)
+       return;
+
+    while ((var = sudo_parseln(fp)) != NULL) {
+       /* Skip blank or comment lines */
+       if (*var == '\0')
+           continue;
+
+       /* Skip optional "export " */
+       if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) {
+           var += 7;
+           while (isspace((unsigned char) *var)) {
+               var++;
+           }
+       }
+
+       /* Must be of the form name=["']value['"] */
+       for (val = var; *val != '\0' && *val != '='; val++)
+           ;
+       if (var == val || *val != '=')
+           continue;
+       var_len = (size_t)(val - var);
+       val_len = strlen(++val);
+
+       /* Strip leading and trailing single/double quotes */
+       if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
+           val[val_len - 1] = '\0';
+           val++;
+           val_len -= 2;
+       }
+
+       cp = emalloc(var_len + 1 + val_len + 1);
+       memcpy(cp, var, var_len + 1); /* includes '=' */
+       memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */
+
+       sudo_putenv(cp, TRUE, overwrite);
+    }
+    fclose(fp);
+}
+
+void
+init_envtables(void)
+{
+    struct list_member *cur;
+    const char **p;
+
+    /* Fill in the "env_delete" list. */
+    for (p = initial_badenv_table; *p; p++) {
+       cur = emalloc(sizeof(struct list_member));
+       cur->value = estrdup(*p);
+       cur->next = def_env_delete;
+       def_env_delete = cur;
+    }
+
+    /* Fill in the "env_check" list. */
+    for (p = initial_checkenv_table; *p; p++) {
+       cur = emalloc(sizeof(struct list_member));
+       cur->value = estrdup(*p);
+       cur->next = def_env_check;
+       def_env_check = cur;
+    }
+
+    /* Fill in the "env_keep" list. */
+    for (p = initial_keepenv_table; *p; p++) {
+       cur = emalloc(sizeof(struct list_member));
+       cur->value = estrdup(*p);
+       cur->next = def_env_keep;
+       def_env_keep = cur;
+    }
+}
diff --git a/plugins/sudoers/find_path.c b/plugins/sudoers/find_path.c
new file mode 100644 (file)
index 0000000..2566733
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2010-2011
+ *     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/param.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include "sudoers.h"
+
+/*
+ * This function finds the full pathname for a command and
+ * stores it in a statically allocated array, filling in a pointer
+ * to the array.  Returns FOUND if the command was found, NOT_FOUND
+ * if it was not found, or NOT_FOUND_DOT if it would have been found
+ * but it is in '.' and IGNORE_DOT is set.
+ */
+int
+find_path(char *infile, char **outfile, struct stat *sbp, char *path,
+    int ignore_dot)
+{
+    static char command[PATH_MAX]; /* qualified filename */
+    char *n;                   /* for traversing path */
+    char *origpath;            /* so we can free path later */
+    char *result = NULL;       /* result of path/file lookup */
+    int checkdot = 0;          /* check current dir? */
+    int len;                   /* length parameter */
+
+    if (strlen(infile) >= PATH_MAX)
+       errorx(1, "%s: File name too long", infile);
+
+    /*
+     * If we were given a fully qualified or relative path
+     * there is no need to look at $PATH.
+     */
+    if (strchr(infile, '/')) {
+       strlcpy(command, infile, sizeof(command));      /* paranoia */
+       if (sudo_goodpath(command, sbp)) {
+           *outfile = command;
+           return FOUND;
+       } else
+           return NOT_FOUND;
+    }
+
+    if (path == NULL)
+       return NOT_FOUND;
+    path = estrdup(path);
+    origpath = path;
+
+    do {
+       if ((n = strchr(path, ':')))
+           *n = '\0';
+
+       /*
+        * Search current dir last if it is in PATH This will miss sneaky
+        * things like using './' or './/'
+        */
+       if (*path == '\0' || (*path == '.' && *(path + 1) == '\0')) {
+           checkdot = 1;
+           path = n + 1;
+           continue;
+       }
+
+       /*
+        * Resolve the path and exit the loop if found.
+        */
+       len = snprintf(command, sizeof(command), "%s/%s", path, infile);
+       if (len <= 0 || len >= sizeof(command))
+           errorx(1, "%s: File name too long", infile);
+       if ((result = sudo_goodpath(command, sbp)))
+           break;
+
+       path = n + 1;
+
+    } while (n);
+    efree(origpath);
+
+    /*
+     * Check current dir if dot was in the PATH
+     */
+    if (!result && checkdot) {
+       len = snprintf(command, sizeof(command), "./%s", infile);
+       if (len <= 0 || len >= sizeof(command))
+           errorx(1, "%s: File name too long", infile);
+       result = sudo_goodpath(command, sbp);
+       if (result && ignore_dot)
+           return NOT_FOUND_DOT;
+    }
+
+    if (result) {
+       *outfile = result;
+       return FOUND;
+    } else
+       return NOT_FOUND;
+}
diff --git a/plugins/sudoers/getdate.c b/plugins/sudoers/getdate.c
new file mode 100644 (file)
index 0000000..cb6aac5
--- /dev/null
@@ -0,0 +1,1596 @@
+#include <config.h>
+#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 "getdate.y"
+/*
+**  Originally written by Steven M. Bellovin <smb@research.att.com> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+**
+**  This grammar has 10 shift/reduce conflicts.
+**
+**  This code is in the public domain and has no copyright.
+*/
+/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
+/* SUPPRESS 288 on yyerrlab *//* Label unused */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/time.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#include <ctype.h>
+
+#include "missing.h"
+
+
+#define EPOCH          1970
+#define HOUR(x)                ((time_t)(x) * 60)
+#define SECSPERDAY     (24L * 60L * 60L)
+
+
+/*
+**  An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+    char       *name;
+    int                type;
+    time_t     value;
+} TABLE;
+
+
+/*
+**  Daylight-savings mode:  on, off, or not yet known.
+*/
+typedef enum _DSTMODE {
+    DSTon, DSToff, DSTmaybe
+} DSTMODE;
+
+/*
+**  Meridian:  am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+    MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+**  Global variables.  We could get rid of most of these by using a good
+**  union as the yacc stack.  (This routine was originally written before
+**  yacc had the %union construct.)  Maybe someday; right now we only use
+**  the %union very rarely.
+*/
+static char    *yyInput;
+static DSTMODE yyDSTmode;
+static time_t  yyDayOrdinal;
+static time_t  yyDayNumber;
+static int     yyHaveDate;
+static int     yyHaveDay;
+static int     yyHaveRel;
+static int     yyHaveTime;
+static int     yyHaveZone;
+static time_t  yyTimezone;
+static time_t  yyDay;
+static time_t  yyHour;
+static time_t  yyMinutes;
+static time_t  yyMonth;
+static time_t  yySeconds;
+static time_t  yyYear;
+static MERIDIAN        yyMeridian;
+static time_t  yyRelMonth;
+static time_t  yyRelSeconds;
+
+static int     yyerror(char *s);
+static int     yylex(void);
+static int     yyparse(void);
+
+#line 107 "getdate.y"
+#ifndef YYSTYPE_DEFINED
+#define YYSTYPE_DEFINED
+typedef union {
+    time_t             Number;
+    enum _MERIDIAN     Meridian;
+} YYSTYPE;
+#endif /* YYSTYPE_DEFINED */
+#line 125 "y.tab.c"
+#define tAGO 257
+#define tDAY 258
+#define tDAYZONE 259
+#define tID 260
+#define tMERIDIAN 261
+#define tMINUTE_UNIT 262
+#define tMONTH 263
+#define tMONTH_UNIT 264
+#define tSEC_UNIT 265
+#define tSNUMBER 266
+#define tUNUMBER 267
+#define tZONE 268
+#define tDST 269
+#define YYERRCODE 256
+#if defined(__cplusplus) || defined(__STDC__)
+const short yylhs[] =
+#else
+short yylhs[] =
+#endif
+       {                                        -1,
+    0,    0,    2,    2,    2,    2,    2,    2,    3,    3,
+    3,    3,    3,    4,    4,    4,    6,    6,    6,    5,
+    5,    5,    5,    5,    5,    5,    5,    7,    7,    9,
+    9,    9,    9,    9,    9,    9,    9,    9,    8,    1,
+    1,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yylen[] =
+#else
+short yylen[] =
+#endif
+       {                                         2,
+    0,    2,    1,    1,    1,    1,    1,    1,    2,    4,
+    4,    6,    6,    1,    1,    2,    1,    2,    2,    3,
+    5,    3,    3,    2,    4,    2,    3,    2,    1,    2,
+    2,    1,    2,    2,    1,    2,    2,    1,    1,    0,
+    1,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yydefred[] =
+#else
+short yydefred[] =
+#endif
+       {                                      1,
+    0,    0,   15,   32,    0,   38,   35,    0,    0,    0,
+    2,    3,    4,    5,    6,    7,    8,    0,   18,    0,
+   31,   36,   33,   19,    9,   30,    0,   37,   34,    0,
+    0,    0,   16,   28,    0,   23,   27,   22,    0,    0,
+   25,   41,   11,    0,   10,    0,    0,   21,   13,   12,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yydgoto[] =
+#else
+short yydgoto[] =
+#endif
+       {                                       1,
+   45,   11,   12,   13,   14,   15,   16,   17,   18,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yysindex[] =
+#else
+short yysindex[] =
+#endif
+       {                                      0,
+ -249,  -38,    0,    0, -260,    0,    0, -240,  -47, -248,
+    0,    0,    0,    0,    0,    0,    0, -237,    0,  -18,
+    0,    0,    0,    0,    0,    0, -262,    0,    0, -239,
+ -238, -236,    0,    0, -235,    0,    0,    0,  -56,  -19,
+    0,    0,    0, -234,    0, -232, -258,    0,    0,    0,};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yyrindex[] =
+#else
+short yyrindex[] =
+#endif
+       {                                      0,
+    0,    1,    0,    0,    0,    0,    0,    0,   69,   12,
+    0,    0,    0,    0,    0,    0,    0,   23,    0,   34,
+    0,    0,    0,    0,    0,    0,   67,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   56,   45,
+    0,    0,    0,    0,    0,    0,   56,    0,    0,    0,};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yygindex[] =
+#else
+short yygindex[] =
+#endif
+       {                                      0,
+  -17,    0,    0,    0,    0,    0,    0,    0,    0,
+};
+#define YYTABLESIZE 337
+#if defined(__cplusplus) || defined(__STDC__)
+const short yytable[] =
+#else
+short yytable[] =
+#endif
+       {                                      32,
+   17,   44,   42,   36,   37,   19,   20,   49,    2,    3,
+   31,   14,    4,    5,    6,    7,    8,    9,   10,   34,
+   33,   21,   29,   22,   23,   35,   38,   46,   39,   50,
+   40,   41,   47,   24,   48,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,   20,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   40,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   26,    0,   39,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,   42,    0,    0,    0,    0,   43,
+   24,    0,    0,   25,   26,   27,   28,   29,   30,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   17,   17,
+    0,    0,   17,   17,   17,   17,   17,   17,   17,   14,
+   14,    0,    0,   14,   14,   14,   14,   14,   14,   14,
+   29,   29,    0,    0,   29,   29,   29,   29,   29,   29,
+   29,   24,   24,    0,    0,   24,   24,   24,   24,   24,
+   24,   24,   20,   20,    0,    0,   20,   20,   20,   20,
+   20,   20,   20,   40,   40,    0,    0,   40,   40,   40,
+   40,    0,   40,   40,   26,   26,    0,   39,   26,   26,
+   26,   26,    0,    0,   26,   39,   39,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yycheck[] =
+#else
+short yycheck[] =
+#endif
+       {                                      47,
+    0,   58,  261,  266,  267,   44,  267,  266,  258,  259,
+   58,    0,  262,  263,  264,  265,  266,  267,  268,  257,
+  269,  262,    0,  264,  265,   44,  266,   47,  267,   47,
+  267,  267,  267,    0,  267,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,    0,   -1,    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,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,  261,   -1,   -1,   -1,   -1,  266,
+  258,   -1,   -1,  261,  262,  263,  264,  265,  266,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  258,  259,
+   -1,   -1,  262,  263,  264,  265,  266,  267,  268,  258,
+  259,   -1,   -1,  262,  263,  264,  265,  266,  267,  268,
+  258,  259,   -1,   -1,  262,  263,  264,  265,  266,  267,
+  268,  258,  259,   -1,   -1,  262,  263,  264,  265,  266,
+  267,  268,  258,  259,   -1,   -1,  262,  263,  264,  265,
+  266,  267,  268,  258,  259,   -1,   -1,  262,  263,  264,
+  265,   -1,  267,  268,  258,  259,   -1,  259,  262,  263,
+  264,  265,   -1,   -1,  268,  267,  268,
+};
+#define YYFINAL 1
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 269
+#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,0,0,0,"tAGO","tDAY",
+"tDAYZONE","tID","tMERIDIAN","tMINUTE_UNIT","tMONTH","tMONTH_UNIT","tSEC_UNIT",
+"tSNUMBER","tUNUMBER","tZONE","tDST",
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const char * const yyrule[] =
+#else
+char *yyrule[] =
+#endif
+       {"$accept : spec",
+"spec :",
+"spec : spec item",
+"item : time",
+"item : zone",
+"item : date",
+"item : day",
+"item : rel",
+"item : number",
+"time : tUNUMBER tMERIDIAN",
+"time : tUNUMBER ':' tUNUMBER o_merid",
+"time : tUNUMBER ':' tUNUMBER tSNUMBER",
+"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid",
+"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER",
+"zone : tZONE",
+"zone : tDAYZONE",
+"zone : tZONE tDST",
+"day : tDAY",
+"day : tDAY ','",
+"day : tUNUMBER tDAY",
+"date : tUNUMBER '/' tUNUMBER",
+"date : tUNUMBER '/' tUNUMBER '/' tUNUMBER",
+"date : tUNUMBER tSNUMBER tSNUMBER",
+"date : tUNUMBER tMONTH tSNUMBER",
+"date : tMONTH tUNUMBER",
+"date : tMONTH tUNUMBER ',' tUNUMBER",
+"date : tUNUMBER tMONTH",
+"date : tUNUMBER tMONTH tUNUMBER",
+"rel : relunit tAGO",
+"rel : relunit",
+"relunit : tUNUMBER tMINUTE_UNIT",
+"relunit : tSNUMBER tMINUTE_UNIT",
+"relunit : tMINUTE_UNIT",
+"relunit : tSNUMBER tSEC_UNIT",
+"relunit : tUNUMBER tSEC_UNIT",
+"relunit : tSEC_UNIT",
+"relunit : tSNUMBER tMONTH_UNIT",
+"relunit : tUNUMBER tMONTH_UNIT",
+"relunit : tMONTH_UNIT",
+"number : tUNUMBER",
+"o_merid :",
+"o_merid : tMERIDIAN",
+};
+#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 326 "getdate.y"
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+    { "january",       tMONTH,  1 },
+    { "february",      tMONTH,  2 },
+    { "march",         tMONTH,  3 },
+    { "april",         tMONTH,  4 },
+    { "may",           tMONTH,  5 },
+    { "june",          tMONTH,  6 },
+    { "july",          tMONTH,  7 },
+    { "august",                tMONTH,  8 },
+    { "september",     tMONTH,  9 },
+    { "sept",          tMONTH,  9 },
+    { "october",       tMONTH, 10 },
+    { "november",      tMONTH, 11 },
+    { "december",      tMONTH, 12 },
+    { "sunday",                tDAY, 0 },
+    { "monday",                tDAY, 1 },
+    { "tuesday",       tDAY, 2 },
+    { "tues",          tDAY, 2 },
+    { "wednesday",     tDAY, 3 },
+    { "wednes",                tDAY, 3 },
+    { "thursday",      tDAY, 4 },
+    { "thur",          tDAY, 4 },
+    { "thurs",         tDAY, 4 },
+    { "friday",                tDAY, 5 },
+    { "saturday",      tDAY, 6 },
+    { NULL }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+    { "year",          tMONTH_UNIT,    12 },
+    { "month",         tMONTH_UNIT,    1 },
+    { "fortnight",     tMINUTE_UNIT,   14 * 24 * 60 },
+    { "week",          tMINUTE_UNIT,   7 * 24 * 60 },
+    { "day",           tMINUTE_UNIT,   1 * 24 * 60 },
+    { "hour",          tMINUTE_UNIT,   60 },
+    { "minute",                tMINUTE_UNIT,   1 },
+    { "min",           tMINUTE_UNIT,   1 },
+    { "second",                tSEC_UNIT,      1 },
+    { "sec",           tSEC_UNIT,      1 },
+    { NULL }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+    { "tomorrow",      tMINUTE_UNIT,   1 * 24 * 60 },
+    { "yesterday",     tMINUTE_UNIT,   -1 * 24 * 60 },
+    { "today",         tMINUTE_UNIT,   0 },
+    { "now",           tMINUTE_UNIT,   0 },
+    { "last",          tUNUMBER,       -1 },
+    { "this",          tMINUTE_UNIT,   0 },
+    { "next",          tUNUMBER,       2 },
+    { "first",         tUNUMBER,       1 },
+/*  { "second",                tUNUMBER,       2 }, */
+    { "third",         tUNUMBER,       3 },
+    { "fourth",                tUNUMBER,       4 },
+    { "fifth",         tUNUMBER,       5 },
+    { "sixth",         tUNUMBER,       6 },
+    { "seventh",       tUNUMBER,       7 },
+    { "eighth",                tUNUMBER,       8 },
+    { "ninth",         tUNUMBER,       9 },
+    { "tenth",         tUNUMBER,       10 },
+    { "eleventh",      tUNUMBER,       11 },
+    { "twelfth",       tUNUMBER,       12 },
+    { "ago",           tAGO,   1 },
+    { NULL }
+};
+
+/* The timezone table. */
+/* Some of these are commented out because a time_t can't store a float. */
+static TABLE const TimezoneTable[] = {
+    { "gmt",   tZONE,     HOUR( 0) },  /* Greenwich Mean */
+    { "ut",    tZONE,     HOUR( 0) },  /* Universal (Coordinated) */
+    { "utc",   tZONE,     HOUR( 0) },
+    { "wet",   tZONE,     HOUR( 0) },  /* Western European */
+    { "bst",   tDAYZONE,  HOUR( 0) },  /* British Summer */
+    { "wat",   tZONE,     HOUR( 1) },  /* West Africa */
+    { "at",    tZONE,     HOUR( 2) },  /* Azores */
+#if    0
+    /* For completeness.  BST is also British Summer, and GST is
+     * also Guam Standard. */
+    { "bst",   tZONE,     HOUR( 3) },  /* Brazil Standard */
+    { "gst",   tZONE,     HOUR( 3) },  /* Greenland Standard */
+#endif
+#if 0
+    { "nft",   tZONE,     HOUR(3.5) }, /* Newfoundland */
+    { "nst",   tZONE,     HOUR(3.5) }, /* Newfoundland Standard */
+    { "ndt",   tDAYZONE,  HOUR(3.5) }, /* Newfoundland Daylight */
+#endif
+    { "ast",   tZONE,     HOUR( 4) },  /* Atlantic Standard */
+    { "adt",   tDAYZONE,  HOUR( 4) },  /* Atlantic Daylight */
+    { "est",   tZONE,     HOUR( 5) },  /* Eastern Standard */
+    { "edt",   tDAYZONE,  HOUR( 5) },  /* Eastern Daylight */
+    { "cst",   tZONE,     HOUR( 6) },  /* Central Standard */
+    { "cdt",   tDAYZONE,  HOUR( 6) },  /* Central Daylight */
+    { "mst",   tZONE,     HOUR( 7) },  /* Mountain Standard */
+    { "mdt",   tDAYZONE,  HOUR( 7) },  /* Mountain Daylight */
+    { "pst",   tZONE,     HOUR( 8) },  /* Pacific Standard */
+    { "pdt",   tDAYZONE,  HOUR( 8) },  /* Pacific Daylight */
+    { "yst",   tZONE,     HOUR( 9) },  /* Yukon Standard */
+    { "ydt",   tDAYZONE,  HOUR( 9) },  /* Yukon Daylight */
+    { "hst",   tZONE,     HOUR(10) },  /* Hawaii Standard */
+    { "hdt",   tDAYZONE,  HOUR(10) },  /* Hawaii Daylight */
+    { "cat",   tZONE,     HOUR(10) },  /* Central Alaska */
+    { "ahst",  tZONE,     HOUR(10) },  /* Alaska-Hawaii Standard */
+    { "nt",    tZONE,     HOUR(11) },  /* Nome */
+    { "idlw",  tZONE,     HOUR(12) },  /* International Date Line West */
+    { "cet",   tZONE,     -HOUR(1) },  /* Central European */
+    { "met",   tZONE,     -HOUR(1) },  /* Middle European */
+    { "mewt",  tZONE,     -HOUR(1) },  /* Middle European Winter */
+    { "mest",  tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
+    { "swt",   tZONE,     -HOUR(1) },  /* Swedish Winter */
+    { "sst",   tDAYZONE,  -HOUR(1) },  /* Swedish Summer */
+    { "fwt",   tZONE,     -HOUR(1) },  /* French Winter */
+    { "fst",   tDAYZONE,  -HOUR(1) },  /* French Summer */
+    { "eet",   tZONE,     -HOUR(2) },  /* Eastern Europe, USSR Zone 1 */
+    { "bt",    tZONE,     -HOUR(3) },  /* Baghdad, USSR Zone 2 */
+#if 0
+    { "it",    tZONE,     -HOUR(3.5) },/* Iran */
+#endif
+    { "zp4",   tZONE,     -HOUR(4) },  /* USSR Zone 3 */
+    { "zp5",   tZONE,     -HOUR(5) },  /* USSR Zone 4 */
+#if 0
+    { "ist",   tZONE,     -HOUR(5.5) },/* Indian Standard */
+#endif
+    { "zp6",   tZONE,     -HOUR(6) },  /* USSR Zone 5 */
+#if    0
+    /* For completeness.  NST is also Newfoundland Stanard, and SST is
+     * also Swedish Summer. */
+    { "nst",   tZONE,     -HOUR(6.5) },/* North Sumatra */
+    { "sst",   tZONE,     -HOUR(7) },  /* South Sumatra, USSR Zone 6 */
+#endif /* 0 */
+    { "wast",  tZONE,     -HOUR(7) },  /* West Australian Standard */
+    { "wadt",  tDAYZONE,  -HOUR(7) },  /* West Australian Daylight */
+#if 0
+    { "jt",    tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
+#endif
+    { "cct",   tZONE,     -HOUR(8) },  /* China Coast, USSR Zone 7 */
+    { "jst",   tZONE,     -HOUR(9) },  /* Japan Standard, USSR Zone 8 */
+#if 0
+    { "cast",  tZONE,     -HOUR(9.5) },/* Central Australian Standard */
+    { "cadt",  tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
+#endif
+    { "east",  tZONE,     -HOUR(10) }, /* Eastern Australian Standard */
+    { "eadt",  tDAYZONE,  -HOUR(10) }, /* Eastern Australian Daylight */
+    { "gst",   tZONE,     -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
+    { "nzt",   tZONE,     -HOUR(12) }, /* New Zealand */
+    { "nzst",  tZONE,     -HOUR(12) }, /* New Zealand Standard */
+    { "nzdt",  tDAYZONE,  -HOUR(12) }, /* New Zealand Daylight */
+    { "idle",  tZONE,     -HOUR(12) }, /* International Date Line East */
+    {  NULL  }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+    { "a",     tZONE,  HOUR(  1) },
+    { "b",     tZONE,  HOUR(  2) },
+    { "c",     tZONE,  HOUR(  3) },
+    { "d",     tZONE,  HOUR(  4) },
+    { "e",     tZONE,  HOUR(  5) },
+    { "f",     tZONE,  HOUR(  6) },
+    { "g",     tZONE,  HOUR(  7) },
+    { "h",     tZONE,  HOUR(  8) },
+    { "i",     tZONE,  HOUR(  9) },
+    { "k",     tZONE,  HOUR( 10) },
+    { "l",     tZONE,  HOUR( 11) },
+    { "m",     tZONE,  HOUR( 12) },
+    { "n",     tZONE,  HOUR(- 1) },
+    { "o",     tZONE,  HOUR(- 2) },
+    { "p",     tZONE,  HOUR(- 3) },
+    { "q",     tZONE,  HOUR(- 4) },
+    { "r",     tZONE,  HOUR(- 5) },
+    { "s",     tZONE,  HOUR(- 6) },
+    { "t",     tZONE,  HOUR(- 7) },
+    { "u",     tZONE,  HOUR(- 8) },
+    { "v",     tZONE,  HOUR(- 9) },
+    { "w",     tZONE,  HOUR(-10) },
+    { "x",     tZONE,  HOUR(-11) },
+    { "y",     tZONE,  HOUR(-12) },
+    { "z",     tZONE,  HOUR(  0) },
+    { NULL }
+};
+
+\f
+
+
+/* ARGSUSED */
+static int
+yyerror(s)
+    char       *s;
+{
+  return 0;
+}
+
+
+static time_t
+ToSeconds(Hours, Minutes, Seconds, Meridian)
+    time_t     Hours;
+    time_t     Minutes;
+    time_t     Seconds;
+    MERIDIAN   Meridian;
+{
+    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
+       return -1;
+    switch (Meridian) {
+    case MER24:
+       if (Hours < 0 || Hours > 23)
+           return -1;
+       return (Hours * 60L + Minutes) * 60L + Seconds;
+    case MERam:
+       if (Hours < 1 || Hours > 12)
+           return -1;
+       if (Hours == 12)
+           Hours = 0;
+       return (Hours * 60L + Minutes) * 60L + Seconds;
+    case MERpm:
+       if (Hours < 1 || Hours > 12)
+           return -1;
+       if (Hours == 12)
+           Hours = 0;
+       return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
+    default:
+       abort ();
+    }
+    /* NOTREACHED */
+}
+
+
+/* Year is either
+   * A negative number, which means to use its absolute value (why?)
+   * A number from 0 to 99, which means a year from 1900 to 1999, or
+   * The actual year (>=100).  */
+static time_t
+Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
+    time_t     Month;
+    time_t     Day;
+    time_t     Year;
+    time_t     Hours;
+    time_t     Minutes;
+    time_t     Seconds;
+    MERIDIAN   Meridian;
+    DSTMODE    DSTmode;
+{
+    static int DaysInMonth[12] = {
+       31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+    };
+    time_t     tod;
+    time_t     Julian;
+    int                i;
+
+    if (Year < 0)
+       Year = -Year;
+    if (Year < 69)
+       Year += 2000;
+    else if (Year < 100) {
+       Year += 1900;
+       if (Year < EPOCH)
+               Year += 100;
+    }
+    DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+                   ? 29 : 28;
+    /* Checking for 2038 bogusly assumes that time_t is 32 bits.  But
+       I'm too lazy to try to check for time_t overflow in another way.  */
+    if (Year < EPOCH || Year > 2038
+     || Month < 1 || Month > 12
+     /* Lint fluff:  "conversion from long may lose accuracy" */
+     || Day < 1 || Day > DaysInMonth[(int)--Month])
+       return -1;
+
+    for (Julian = Day - 1, i = 0; i < Month; i++)
+       Julian += DaysInMonth[i];
+    for (i = EPOCH; i < Year; i++)
+       Julian += 365 + (i % 4 == 0);
+    Julian *= SECSPERDAY;
+    Julian += yyTimezone * 60L;
+    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
+       return -1;
+    Julian += tod;
+    if (DSTmode == DSTon
+     || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
+       Julian -= 60 * 60;
+    return Julian;
+}
+
+
+static time_t
+DSTcorrect(Start, Future)
+    time_t     Start;
+    time_t     Future;
+{
+    time_t     StartDay;
+    time_t     FutureDay;
+
+    StartDay = (localtime(&Start)->tm_hour + 1) % 24;
+    FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
+    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
+}
+
+
+static time_t
+RelativeDate(Start, DayOrdinal, DayNumber)
+    time_t     Start;
+    time_t     DayOrdinal;
+    time_t     DayNumber;
+{
+    struct tm  *tm;
+    time_t     now;
+
+    now = Start;
+    tm = localtime(&now);
+    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
+    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+    return DSTcorrect(Start, now);
+}
+
+
+static time_t
+RelativeMonth(Start, RelMonth)
+    time_t     Start;
+    time_t     RelMonth;
+{
+    struct tm  *tm;
+    time_t     Month;
+    time_t     Year;
+
+    if (RelMonth == 0)
+       return 0;
+    tm = localtime(&Start);
+    Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
+    Year = Month / 12;
+    Month = Month % 12 + 1;
+    return DSTcorrect(Start,
+           Convert(Month, (time_t)tm->tm_mday, Year,
+               (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
+               MER24, DSTmaybe));
+}
+
+
+static int
+LookupWord(buff)
+    char               *buff;
+{
+    char               *p;
+    char               *q;
+    const TABLE                *tp;
+    int                        i;
+    int                        abbrev;
+
+    /* Make it lowercase. */
+    for (p = buff; *p; p++)
+       if (isupper((unsigned char)*p))
+           *p = tolower((unsigned char)*p);
+
+    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
+       yylval.Meridian = MERam;
+       return tMERIDIAN;
+    }
+    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
+       yylval.Meridian = MERpm;
+       return tMERIDIAN;
+    }
+
+    /* See if we have an abbreviation for a month. */
+    if (strlen(buff) == 3)
+       abbrev = 1;
+    else if (strlen(buff) == 4 && buff[3] == '.') {
+       abbrev = 1;
+       buff[3] = '\0';
+    }
+    else
+       abbrev = 0;
+
+    for (tp = MonthDayTable; tp->name; tp++) {
+       if (abbrev) {
+           if (strncmp(buff, tp->name, 3) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+       }
+       else if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+    }
+
+    for (tp = TimezoneTable; tp->name; tp++)
+       if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+
+    if (strcmp(buff, "dst") == 0) 
+       return tDST;
+
+    for (tp = UnitsTable; tp->name; tp++)
+       if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+
+    /* Strip off any plural and try the units table again. */
+    i = strlen(buff) - 1;
+    if (buff[i] == 's') {
+       buff[i] = '\0';
+       for (tp = UnitsTable; tp->name; tp++)
+           if (strcmp(buff, tp->name) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+       buff[i] = 's';          /* Put back for "this" in OtherTable. */
+    }
+
+    for (tp = OtherTable; tp->name; tp++)
+       if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+
+    /* Military timezones. */
+    if (buff[1] == '\0' && isalpha((unsigned char)*buff)) {
+       for (tp = MilitaryTable; tp->name; tp++)
+           if (strcmp(buff, tp->name) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+    }
+
+    /* Drop out any periods and try the timezone table again. */
+    for (i = 0, p = q = buff; *q; q++)
+       if (*q != '.')
+           *p++ = *q;
+       else
+           i++;
+    *p = '\0';
+    if (i)
+       for (tp = TimezoneTable; tp->name; tp++)
+           if (strcmp(buff, tp->name) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+
+    return tID;
+}
+
+
+static int
+yylex()
+{
+    char               c;
+    char               *p;
+    char               buff[20];
+    int                        Count;
+    int                        sign;
+
+    for ( ; ; ) {
+       while (isspace((unsigned char)*yyInput))
+           yyInput++;
+
+       if (isdigit((unsigned char)(c = *yyInput)) || c == '-' || c == '+') {
+           if (c == '-' || c == '+') {
+               sign = c == '-' ? -1 : 1;
+               if (!isdigit((unsigned char)*++yyInput))
+                   /* skip the '-' sign */
+                   continue;
+           }
+           else
+               sign = 0;
+           for (yylval.Number = 0; isdigit((unsigned char)(c = *yyInput++)); )
+               yylval.Number = 10 * yylval.Number + c - '0';
+           yyInput--;
+           if (sign < 0)
+               yylval.Number = -yylval.Number;
+           return sign ? tSNUMBER : tUNUMBER;
+       }
+       if (isalpha((unsigned char)c)) {
+           for (p = buff; isalpha((unsigned char)(c = *yyInput++)) || c == '.'; )
+               if (p < &buff[sizeof buff - 1])
+                   *p++ = c;
+           *p = '\0';
+           yyInput--;
+           return LookupWord(buff);
+       }
+       if (c != '(')
+           return *yyInput++;
+       Count = 0;
+       do {
+           c = *yyInput++;
+           if (c == '\0')
+               return c;
+           if (c == '(')
+               Count++;
+           else if (c == ')')
+               Count--;
+       } while (Count > 0);
+    }
+}
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds.  */
+static long
+difftm (a, b)
+     struct tm *a, *b;
+{
+  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+  int days = (
+             /* difference in day of year */
+             a->tm_yday - b->tm_yday
+             /* + intervening leap days */
+             +  ((ay >> 2) - (by >> 2))
+             -  (ay/100 - by/100)
+             +  ((ay/100 >> 2) - (by/100 >> 2))
+             /* + difference in years * 365 */
+             +  (long)(ay-by) * 365
+             );
+  return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
+             + (a->tm_min - b->tm_min))
+         + (a->tm_sec - b->tm_sec));
+}
+
+time_t
+get_date(p)
+    char               *p;
+{
+    struct tm          *tm, *gmt, gmtbuf;
+    time_t             Start;
+    time_t             tod;
+    time_t             now;
+    time_t             timezone;
+
+    yyInput = p;
+    (void)time (&now);
+
+    gmt = gmtime (&now);
+    if (gmt != NULL)
+    {
+       /* Make a copy, in case localtime modifies *tm (I think
+          that comment now applies to *gmt, but I am too
+          lazy to dig into how gmtime and locatime allocate the
+          structures they return pointers to).  */
+       gmtbuf = *gmt;
+       gmt = &gmtbuf;
+    }
+
+    if (! (tm = localtime (&now)))
+       return -1;
+
+    if (gmt != NULL)
+       timezone = difftm (gmt, tm) / 60;
+    else
+       /* We are on a system like VMS, where the system clock is
+          in local time and the system has no concept of timezones.
+          Hopefully we can fake this out (for the case in which the
+          user specifies no timezone) by just saying the timezone
+          is zero.  */
+       timezone = 0;
+
+    if(tm->tm_isdst)
+       timezone += 60;
+
+    tm = localtime(&now);
+    yyYear = tm->tm_year + 1900;
+    yyMonth = tm->tm_mon + 1;
+    yyDay = tm->tm_mday;
+    yyTimezone = timezone;
+    yyDSTmode = DSTmaybe;
+    yyHour = 0;
+    yyMinutes = 0;
+    yySeconds = 0;
+    yyMeridian = MER24;
+    yyRelSeconds = 0;
+    yyRelMonth = 0;
+    yyHaveDate = 0;
+    yyHaveDay = 0;
+    yyHaveRel = 0;
+    yyHaveTime = 0;
+    yyHaveZone = 0;
+
+    if (yyparse()
+     || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+       return -1;
+
+    if (yyHaveDate || yyHaveTime || yyHaveDay) {
+       Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
+                   yyMeridian, yyDSTmode);
+       if (Start < 0)
+           return -1;
+    }
+    else {
+       Start = now;
+       if (!yyHaveRel)
+           Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
+    }
+
+    Start += yyRelSeconds;
+    Start += RelativeMonth(Start, yyRelMonth);
+
+    if (yyHaveDay && !yyHaveDate) {
+       tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
+       Start += tod;
+    }
+
+    /* Have to do *something* with a legitimate -1 so it's distinguishable
+     * from the error return value.  (Alternately could set errno on error.) */
+    return Start == -1 ? 0 : Start;
+}
+
+
+#if    defined(TEST)
+
+/* ARGSUSED */
+int
+main(ac, av)
+    int                ac;
+    char       *av[];
+{
+    char       buff[128];
+    time_t     d;
+
+    (void)printf("Enter date, or blank line to exit.\n\t> ");
+    (void)fflush(stdout);
+    while (gets(buff) && buff[0]) {
+       d = get_date(buff);
+       if (d == -1)
+           (void)printf("Bad format - couldn't convert.\n");
+       else
+           (void)printf("%s", ctime(&d));
+       (void)printf("\t> ");
+       (void)fflush(stdout);
+    }
+    exit(0);
+    /* NOTREACHED */
+}
+#endif /* defined(TEST) */
+#line 979 "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 3:
+#line 125 "getdate.y"
+{
+           yyHaveTime++;
+       }
+break;
+case 4:
+#line 128 "getdate.y"
+{
+           yyHaveZone++;
+       }
+break;
+case 5:
+#line 131 "getdate.y"
+{
+           yyHaveDate++;
+       }
+break;
+case 6:
+#line 134 "getdate.y"
+{
+           yyHaveDay++;
+       }
+break;
+case 7:
+#line 137 "getdate.y"
+{
+           yyHaveRel++;
+       }
+break;
+case 9:
+#line 143 "getdate.y"
+{
+           yyHour = yyvsp[-1].Number;
+           yyMinutes = 0;
+           yySeconds = 0;
+           yyMeridian = yyvsp[0].Meridian;
+       }
+break;
+case 10:
+#line 149 "getdate.y"
+{
+           yyHour = yyvsp[-3].Number;
+           yyMinutes = yyvsp[-1].Number;
+           yySeconds = 0;
+           yyMeridian = yyvsp[0].Meridian;
+       }
+break;
+case 11:
+#line 155 "getdate.y"
+{
+           yyHour = yyvsp[-3].Number;
+           yyMinutes = yyvsp[-1].Number;
+           yyMeridian = MER24;
+           yyDSTmode = DSToff;
+           yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60);
+       }
+break;
+case 12:
+#line 162 "getdate.y"
+{
+           yyHour = yyvsp[-5].Number;
+           yyMinutes = yyvsp[-3].Number;
+           yySeconds = yyvsp[-1].Number;
+           yyMeridian = yyvsp[0].Meridian;
+       }
+break;
+case 13:
+#line 168 "getdate.y"
+{
+           yyHour = yyvsp[-5].Number;
+           yyMinutes = yyvsp[-3].Number;
+           yySeconds = yyvsp[-1].Number;
+           yyMeridian = MER24;
+           yyDSTmode = DSToff;
+           yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60);
+       }
+break;
+case 14:
+#line 178 "getdate.y"
+{
+           yyTimezone = yyvsp[0].Number;
+           yyDSTmode = DSToff;
+       }
+break;
+case 15:
+#line 182 "getdate.y"
+{
+           yyTimezone = yyvsp[0].Number;
+           yyDSTmode = DSTon;
+       }
+break;
+case 16:
+#line 187 "getdate.y"
+{
+           yyTimezone = yyvsp[-1].Number;
+           yyDSTmode = DSTon;
+       }
+break;
+case 17:
+#line 193 "getdate.y"
+{
+           yyDayOrdinal = 1;
+           yyDayNumber = yyvsp[0].Number;
+       }
+break;
+case 18:
+#line 197 "getdate.y"
+{
+           yyDayOrdinal = 1;
+           yyDayNumber = yyvsp[-1].Number;
+       }
+break;
+case 19:
+#line 201 "getdate.y"
+{
+           yyDayOrdinal = yyvsp[-1].Number;
+           yyDayNumber = yyvsp[0].Number;
+       }
+break;
+case 20:
+#line 207 "getdate.y"
+{
+           yyMonth = yyvsp[-2].Number;
+           yyDay = yyvsp[0].Number;
+       }
+break;
+case 21:
+#line 211 "getdate.y"
+{
+           if (yyvsp[-4].Number >= 100) {
+               yyYear = yyvsp[-4].Number;
+               yyMonth = yyvsp[-2].Number;
+               yyDay = yyvsp[0].Number;
+           } else {
+               yyMonth = yyvsp[-4].Number;
+               yyDay = yyvsp[-2].Number;
+               yyYear = yyvsp[0].Number;
+           }
+       }
+break;
+case 22:
+#line 222 "getdate.y"
+{
+           /* ISO 8601 format.  yyyy-mm-dd.  */
+           yyYear = yyvsp[-2].Number;
+           yyMonth = -yyvsp[-1].Number;
+           yyDay = -yyvsp[0].Number;
+       }
+break;
+case 23:
+#line 228 "getdate.y"
+{
+           /* e.g. 17-JUN-1992.  */
+           yyDay = yyvsp[-2].Number;
+           yyMonth = yyvsp[-1].Number;
+           yyYear = -yyvsp[0].Number;
+       }
+break;
+case 24:
+#line 234 "getdate.y"
+{
+           yyMonth = yyvsp[-1].Number;
+           yyDay = yyvsp[0].Number;
+       }
+break;
+case 25:
+#line 238 "getdate.y"
+{
+           yyMonth = yyvsp[-3].Number;
+           yyDay = yyvsp[-2].Number;
+           yyYear = yyvsp[0].Number;
+       }
+break;
+case 26:
+#line 243 "getdate.y"
+{
+           yyMonth = yyvsp[0].Number;
+           yyDay = yyvsp[-1].Number;
+       }
+break;
+case 27:
+#line 247 "getdate.y"
+{
+           yyMonth = yyvsp[-1].Number;
+           yyDay = yyvsp[-2].Number;
+           yyYear = yyvsp[0].Number;
+       }
+break;
+case 28:
+#line 254 "getdate.y"
+{
+           yyRelSeconds = -yyRelSeconds;
+           yyRelMonth = -yyRelMonth;
+       }
+break;
+case 30:
+#line 261 "getdate.y"
+{
+           yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L;
+       }
+break;
+case 31:
+#line 264 "getdate.y"
+{
+           yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L;
+       }
+break;
+case 32:
+#line 267 "getdate.y"
+{
+           yyRelSeconds += yyvsp[0].Number * 60L;
+       }
+break;
+case 33:
+#line 270 "getdate.y"
+{
+           yyRelSeconds += yyvsp[-1].Number;
+       }
+break;
+case 34:
+#line 273 "getdate.y"
+{
+           yyRelSeconds += yyvsp[-1].Number;
+       }
+break;
+case 35:
+#line 276 "getdate.y"
+{
+           yyRelSeconds++;
+       }
+break;
+case 36:
+#line 279 "getdate.y"
+{
+           yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
+       }
+break;
+case 37:
+#line 282 "getdate.y"
+{
+           yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
+       }
+break;
+case 38:
+#line 285 "getdate.y"
+{
+           yyRelMonth += yyvsp[0].Number;
+       }
+break;
+case 39:
+#line 290 "getdate.y"
+{
+           if (yyHaveTime && yyHaveDate && !yyHaveRel)
+               yyYear = yyvsp[0].Number;
+           else {
+               if(yyvsp[0].Number>10000) {
+                   yyHaveDate++;
+                   yyDay= (yyvsp[0].Number)%100;
+                   yyMonth= (yyvsp[0].Number/100)%100;
+                   yyYear = yyvsp[0].Number/10000;
+               }
+               else {
+                   yyHaveTime++;
+                   if (yyvsp[0].Number < 100) {
+                       yyHour = yyvsp[0].Number;
+                       yyMinutes = 0;
+                   }
+                   else {
+                       yyHour = yyvsp[0].Number / 100;
+                       yyMinutes = yyvsp[0].Number % 100;
+                   }
+                   yySeconds = 0;
+                   yyMeridian = MER24;
+               }
+           }
+       }
+break;
+case 40:
+#line 317 "getdate.y"
+{
+           yyval.Meridian = MER24;
+       }
+break;
+case 41:
+#line 320 "getdate.y"
+{
+           yyval.Meridian = yyvsp[0].Meridian;
+       }
+break;
+#line 1474 "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/plugins/sudoers/getdate.y b/plugins/sudoers/getdate.y
new file mode 100644 (file)
index 0000000..13483ff
--- /dev/null
@@ -0,0 +1,962 @@
+%{
+/*
+**  Originally written by Steven M. Bellovin <smb@research.att.com> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+**
+**  This grammar has 10 shift/reduce conflicts.
+**
+**  This code is in the public domain and has no copyright.
+*/
+/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
+/* SUPPRESS 288 on yyerrlab *//* Label unused */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/time.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#include <ctype.h>
+
+#include "missing.h"
+
+
+#define EPOCH          1970
+#define HOUR(x)                ((time_t)(x) * 60)
+#define SECSPERDAY     (24L * 60L * 60L)
+
+
+/*
+**  An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+    char       *name;
+    int                type;
+    time_t     value;
+} TABLE;
+
+
+/*
+**  Daylight-savings mode:  on, off, or not yet known.
+*/
+typedef enum _DSTMODE {
+    DSTon, DSToff, DSTmaybe
+} DSTMODE;
+
+/*
+**  Meridian:  am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+    MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+**  Global variables.  We could get rid of most of these by using a good
+**  union as the yacc stack.  (This routine was originally written before
+**  yacc had the %union construct.)  Maybe someday; right now we only use
+**  the %union very rarely.
+*/
+static char    *yyInput;
+static DSTMODE yyDSTmode;
+static time_t  yyDayOrdinal;
+static time_t  yyDayNumber;
+static int     yyHaveDate;
+static int     yyHaveDay;
+static int     yyHaveRel;
+static int     yyHaveTime;
+static int     yyHaveZone;
+static time_t  yyTimezone;
+static time_t  yyDay;
+static time_t  yyHour;
+static time_t  yyMinutes;
+static time_t  yyMonth;
+static time_t  yySeconds;
+static time_t  yyYear;
+static MERIDIAN        yyMeridian;
+static time_t  yyRelMonth;
+static time_t  yyRelSeconds;
+
+static int     yyerror(char *s);
+static int     yylex(void);
+static int     yyparse(void);
+
+%}
+
+%union {
+    time_t             Number;
+    enum _MERIDIAN     Meridian;
+}
+
+%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
+%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
+
+%type  <Number>        tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
+%type  <Number>        tSEC_UNIT tSNUMBER tUNUMBER tZONE
+%type  <Meridian>      tMERIDIAN o_merid
+
+%%
+
+spec   : /* NULL */
+       | spec item
+       ;
+
+item   : time {
+           yyHaveTime++;
+       }
+       | zone {
+           yyHaveZone++;
+       }
+       | date {
+           yyHaveDate++;
+       }
+       | day {
+           yyHaveDay++;
+       }
+       | rel {
+           yyHaveRel++;
+       }
+       | number
+       ;
+
+time   : tUNUMBER tMERIDIAN {
+           yyHour = $1;
+           yyMinutes = 0;
+           yySeconds = 0;
+           yyMeridian = $2;
+       }
+       | tUNUMBER ':' tUNUMBER o_merid {
+           yyHour = $1;
+           yyMinutes = $3;
+           yySeconds = 0;
+           yyMeridian = $4;
+       }
+       | tUNUMBER ':' tUNUMBER tSNUMBER {
+           yyHour = $1;
+           yyMinutes = $3;
+           yyMeridian = MER24;
+           yyDSTmode = DSToff;
+           yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
+       }
+       | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
+           yyHour = $1;
+           yyMinutes = $3;
+           yySeconds = $5;
+           yyMeridian = $6;
+       }
+       | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
+           yyHour = $1;
+           yyMinutes = $3;
+           yySeconds = $5;
+           yyMeridian = MER24;
+           yyDSTmode = DSToff;
+           yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
+       }
+       ;
+
+zone   : tZONE {
+           yyTimezone = $1;
+           yyDSTmode = DSToff;
+       }
+       | tDAYZONE {
+           yyTimezone = $1;
+           yyDSTmode = DSTon;
+       }
+       |
+         tZONE tDST {
+           yyTimezone = $1;
+           yyDSTmode = DSTon;
+       }
+       ;
+
+day    : tDAY {
+           yyDayOrdinal = 1;
+           yyDayNumber = $1;
+       }
+       | tDAY ',' {
+           yyDayOrdinal = 1;
+           yyDayNumber = $1;
+       }
+       | tUNUMBER tDAY {
+           yyDayOrdinal = $1;
+           yyDayNumber = $2;
+       }
+       ;
+
+date   : tUNUMBER '/' tUNUMBER {
+           yyMonth = $1;
+           yyDay = $3;
+       }
+       | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
+           if ($1 >= 100) {
+               yyYear = $1;
+               yyMonth = $3;
+               yyDay = $5;
+           } else {
+               yyMonth = $1;
+               yyDay = $3;
+               yyYear = $5;
+           }
+       }
+       | tUNUMBER tSNUMBER tSNUMBER {
+           /* ISO 8601 format.  yyyy-mm-dd.  */
+           yyYear = $1;
+           yyMonth = -$2;
+           yyDay = -$3;
+       }
+       | tUNUMBER tMONTH tSNUMBER {
+           /* e.g. 17-JUN-1992.  */
+           yyDay = $1;
+           yyMonth = $2;
+           yyYear = -$3;
+       }
+       | tMONTH tUNUMBER {
+           yyMonth = $1;
+           yyDay = $2;
+       }
+       | tMONTH tUNUMBER ',' tUNUMBER {
+           yyMonth = $1;
+           yyDay = $2;
+           yyYear = $4;
+       }
+       | tUNUMBER tMONTH {
+           yyMonth = $2;
+           yyDay = $1;
+       }
+       | tUNUMBER tMONTH tUNUMBER {
+           yyMonth = $2;
+           yyDay = $1;
+           yyYear = $3;
+       }
+       ;
+
+rel    : relunit tAGO {
+           yyRelSeconds = -yyRelSeconds;
+           yyRelMonth = -yyRelMonth;
+       }
+       | relunit
+       ;
+
+relunit        : tUNUMBER tMINUTE_UNIT {
+           yyRelSeconds += $1 * $2 * 60L;
+       }
+       | tSNUMBER tMINUTE_UNIT {
+           yyRelSeconds += $1 * $2 * 60L;
+       }
+       | tMINUTE_UNIT {
+           yyRelSeconds += $1 * 60L;
+       }
+       | tSNUMBER tSEC_UNIT {
+           yyRelSeconds += $1;
+       }
+       | tUNUMBER tSEC_UNIT {
+           yyRelSeconds += $1;
+       }
+       | tSEC_UNIT {
+           yyRelSeconds++;
+       }
+       | tSNUMBER tMONTH_UNIT {
+           yyRelMonth += $1 * $2;
+       }
+       | tUNUMBER tMONTH_UNIT {
+           yyRelMonth += $1 * $2;
+       }
+       | tMONTH_UNIT {
+           yyRelMonth += $1;
+       }
+       ;
+
+number : tUNUMBER {
+           if (yyHaveTime && yyHaveDate && !yyHaveRel)
+               yyYear = $1;
+           else {
+               if($1>10000) {
+                   yyHaveDate++;
+                   yyDay= ($1)%100;
+                   yyMonth= ($1/100)%100;
+                   yyYear = $1/10000;
+               }
+               else {
+                   yyHaveTime++;
+                   if ($1 < 100) {
+                       yyHour = $1;
+                       yyMinutes = 0;
+                   }
+                   else {
+                       yyHour = $1 / 100;
+                       yyMinutes = $1 % 100;
+                   }
+                   yySeconds = 0;
+                   yyMeridian = MER24;
+               }
+           }
+       }
+       ;
+
+o_merid        : /* NULL */ {
+           $$ = MER24;
+       }
+       | tMERIDIAN {
+           $$ = $1;
+       }
+       ;
+
+%%
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+    { "january",       tMONTH,  1 },
+    { "february",      tMONTH,  2 },
+    { "march",         tMONTH,  3 },
+    { "april",         tMONTH,  4 },
+    { "may",           tMONTH,  5 },
+    { "june",          tMONTH,  6 },
+    { "july",          tMONTH,  7 },
+    { "august",                tMONTH,  8 },
+    { "september",     tMONTH,  9 },
+    { "sept",          tMONTH,  9 },
+    { "october",       tMONTH, 10 },
+    { "november",      tMONTH, 11 },
+    { "december",      tMONTH, 12 },
+    { "sunday",                tDAY, 0 },
+    { "monday",                tDAY, 1 },
+    { "tuesday",       tDAY, 2 },
+    { "tues",          tDAY, 2 },
+    { "wednesday",     tDAY, 3 },
+    { "wednes",                tDAY, 3 },
+    { "thursday",      tDAY, 4 },
+    { "thur",          tDAY, 4 },
+    { "thurs",         tDAY, 4 },
+    { "friday",                tDAY, 5 },
+    { "saturday",      tDAY, 6 },
+    { NULL }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+    { "year",          tMONTH_UNIT,    12 },
+    { "month",         tMONTH_UNIT,    1 },
+    { "fortnight",     tMINUTE_UNIT,   14 * 24 * 60 },
+    { "week",          tMINUTE_UNIT,   7 * 24 * 60 },
+    { "day",           tMINUTE_UNIT,   1 * 24 * 60 },
+    { "hour",          tMINUTE_UNIT,   60 },
+    { "minute",                tMINUTE_UNIT,   1 },
+    { "min",           tMINUTE_UNIT,   1 },
+    { "second",                tSEC_UNIT,      1 },
+    { "sec",           tSEC_UNIT,      1 },
+    { NULL }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+    { "tomorrow",      tMINUTE_UNIT,   1 * 24 * 60 },
+    { "yesterday",     tMINUTE_UNIT,   -1 * 24 * 60 },
+    { "today",         tMINUTE_UNIT,   0 },
+    { "now",           tMINUTE_UNIT,   0 },
+    { "last",          tUNUMBER,       -1 },
+    { "this",          tMINUTE_UNIT,   0 },
+    { "next",          tUNUMBER,       2 },
+    { "first",         tUNUMBER,       1 },
+/*  { "second",                tUNUMBER,       2 }, */
+    { "third",         tUNUMBER,       3 },
+    { "fourth",                tUNUMBER,       4 },
+    { "fifth",         tUNUMBER,       5 },
+    { "sixth",         tUNUMBER,       6 },
+    { "seventh",       tUNUMBER,       7 },
+    { "eighth",                tUNUMBER,       8 },
+    { "ninth",         tUNUMBER,       9 },
+    { "tenth",         tUNUMBER,       10 },
+    { "eleventh",      tUNUMBER,       11 },
+    { "twelfth",       tUNUMBER,       12 },
+    { "ago",           tAGO,   1 },
+    { NULL }
+};
+
+/* The timezone table. */
+/* Some of these are commented out because a time_t can't store a float. */
+static TABLE const TimezoneTable[] = {
+    { "gmt",   tZONE,     HOUR( 0) },  /* Greenwich Mean */
+    { "ut",    tZONE,     HOUR( 0) },  /* Universal (Coordinated) */
+    { "utc",   tZONE,     HOUR( 0) },
+    { "wet",   tZONE,     HOUR( 0) },  /* Western European */
+    { "bst",   tDAYZONE,  HOUR( 0) },  /* British Summer */
+    { "wat",   tZONE,     HOUR( 1) },  /* West Africa */
+    { "at",    tZONE,     HOUR( 2) },  /* Azores */
+#if    0
+    /* For completeness.  BST is also British Summer, and GST is
+     * also Guam Standard. */
+    { "bst",   tZONE,     HOUR( 3) },  /* Brazil Standard */
+    { "gst",   tZONE,     HOUR( 3) },  /* Greenland Standard */
+#endif
+#if 0
+    { "nft",   tZONE,     HOUR(3.5) }, /* Newfoundland */
+    { "nst",   tZONE,     HOUR(3.5) }, /* Newfoundland Standard */
+    { "ndt",   tDAYZONE,  HOUR(3.5) }, /* Newfoundland Daylight */
+#endif
+    { "ast",   tZONE,     HOUR( 4) },  /* Atlantic Standard */
+    { "adt",   tDAYZONE,  HOUR( 4) },  /* Atlantic Daylight */
+    { "est",   tZONE,     HOUR( 5) },  /* Eastern Standard */
+    { "edt",   tDAYZONE,  HOUR( 5) },  /* Eastern Daylight */
+    { "cst",   tZONE,     HOUR( 6) },  /* Central Standard */
+    { "cdt",   tDAYZONE,  HOUR( 6) },  /* Central Daylight */
+    { "mst",   tZONE,     HOUR( 7) },  /* Mountain Standard */
+    { "mdt",   tDAYZONE,  HOUR( 7) },  /* Mountain Daylight */
+    { "pst",   tZONE,     HOUR( 8) },  /* Pacific Standard */
+    { "pdt",   tDAYZONE,  HOUR( 8) },  /* Pacific Daylight */
+    { "yst",   tZONE,     HOUR( 9) },  /* Yukon Standard */
+    { "ydt",   tDAYZONE,  HOUR( 9) },  /* Yukon Daylight */
+    { "hst",   tZONE,     HOUR(10) },  /* Hawaii Standard */
+    { "hdt",   tDAYZONE,  HOUR(10) },  /* Hawaii Daylight */
+    { "cat",   tZONE,     HOUR(10) },  /* Central Alaska */
+    { "ahst",  tZONE,     HOUR(10) },  /* Alaska-Hawaii Standard */
+    { "nt",    tZONE,     HOUR(11) },  /* Nome */
+    { "idlw",  tZONE,     HOUR(12) },  /* International Date Line West */
+    { "cet",   tZONE,     -HOUR(1) },  /* Central European */
+    { "met",   tZONE,     -HOUR(1) },  /* Middle European */
+    { "mewt",  tZONE,     -HOUR(1) },  /* Middle European Winter */
+    { "mest",  tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
+    { "swt",   tZONE,     -HOUR(1) },  /* Swedish Winter */
+    { "sst",   tDAYZONE,  -HOUR(1) },  /* Swedish Summer */
+    { "fwt",   tZONE,     -HOUR(1) },  /* French Winter */
+    { "fst",   tDAYZONE,  -HOUR(1) },  /* French Summer */
+    { "eet",   tZONE,     -HOUR(2) },  /* Eastern Europe, USSR Zone 1 */
+    { "bt",    tZONE,     -HOUR(3) },  /* Baghdad, USSR Zone 2 */
+#if 0
+    { "it",    tZONE,     -HOUR(3.5) },/* Iran */
+#endif
+    { "zp4",   tZONE,     -HOUR(4) },  /* USSR Zone 3 */
+    { "zp5",   tZONE,     -HOUR(5) },  /* USSR Zone 4 */
+#if 0
+    { "ist",   tZONE,     -HOUR(5.5) },/* Indian Standard */
+#endif
+    { "zp6",   tZONE,     -HOUR(6) },  /* USSR Zone 5 */
+#if    0
+    /* For completeness.  NST is also Newfoundland Stanard, and SST is
+     * also Swedish Summer. */
+    { "nst",   tZONE,     -HOUR(6.5) },/* North Sumatra */
+    { "sst",   tZONE,     -HOUR(7) },  /* South Sumatra, USSR Zone 6 */
+#endif /* 0 */
+    { "wast",  tZONE,     -HOUR(7) },  /* West Australian Standard */
+    { "wadt",  tDAYZONE,  -HOUR(7) },  /* West Australian Daylight */
+#if 0
+    { "jt",    tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
+#endif
+    { "cct",   tZONE,     -HOUR(8) },  /* China Coast, USSR Zone 7 */
+    { "jst",   tZONE,     -HOUR(9) },  /* Japan Standard, USSR Zone 8 */
+#if 0
+    { "cast",  tZONE,     -HOUR(9.5) },/* Central Australian Standard */
+    { "cadt",  tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
+#endif
+    { "east",  tZONE,     -HOUR(10) }, /* Eastern Australian Standard */
+    { "eadt",  tDAYZONE,  -HOUR(10) }, /* Eastern Australian Daylight */
+    { "gst",   tZONE,     -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
+    { "nzt",   tZONE,     -HOUR(12) }, /* New Zealand */
+    { "nzst",  tZONE,     -HOUR(12) }, /* New Zealand Standard */
+    { "nzdt",  tDAYZONE,  -HOUR(12) }, /* New Zealand Daylight */
+    { "idle",  tZONE,     -HOUR(12) }, /* International Date Line East */
+    {  NULL  }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+    { "a",     tZONE,  HOUR(  1) },
+    { "b",     tZONE,  HOUR(  2) },
+    { "c",     tZONE,  HOUR(  3) },
+    { "d",     tZONE,  HOUR(  4) },
+    { "e",     tZONE,  HOUR(  5) },
+    { "f",     tZONE,  HOUR(  6) },
+    { "g",     tZONE,  HOUR(  7) },
+    { "h",     tZONE,  HOUR(  8) },
+    { "i",     tZONE,  HOUR(  9) },
+    { "k",     tZONE,  HOUR( 10) },
+    { "l",     tZONE,  HOUR( 11) },
+    { "m",     tZONE,  HOUR( 12) },
+    { "n",     tZONE,  HOUR(- 1) },
+    { "o",     tZONE,  HOUR(- 2) },
+    { "p",     tZONE,  HOUR(- 3) },
+    { "q",     tZONE,  HOUR(- 4) },
+    { "r",     tZONE,  HOUR(- 5) },
+    { "s",     tZONE,  HOUR(- 6) },
+    { "t",     tZONE,  HOUR(- 7) },
+    { "u",     tZONE,  HOUR(- 8) },
+    { "v",     tZONE,  HOUR(- 9) },
+    { "w",     tZONE,  HOUR(-10) },
+    { "x",     tZONE,  HOUR(-11) },
+    { "y",     tZONE,  HOUR(-12) },
+    { "z",     tZONE,  HOUR(  0) },
+    { NULL }
+};
+
+\f
+
+
+/* ARGSUSED */
+static int
+yyerror(s)
+    char       *s;
+{
+  return 0;
+}
+
+
+static time_t
+ToSeconds(Hours, Minutes, Seconds, Meridian)
+    time_t     Hours;
+    time_t     Minutes;
+    time_t     Seconds;
+    MERIDIAN   Meridian;
+{
+    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
+       return -1;
+    switch (Meridian) {
+    case MER24:
+       if (Hours < 0 || Hours > 23)
+           return -1;
+       return (Hours * 60L + Minutes) * 60L + Seconds;
+    case MERam:
+       if (Hours < 1 || Hours > 12)
+           return -1;
+       if (Hours == 12)
+           Hours = 0;
+       return (Hours * 60L + Minutes) * 60L + Seconds;
+    case MERpm:
+       if (Hours < 1 || Hours > 12)
+           return -1;
+       if (Hours == 12)
+           Hours = 0;
+       return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
+    default:
+       abort ();
+    }
+    /* NOTREACHED */
+}
+
+
+/* Year is either
+   * A negative number, which means to use its absolute value (why?)
+   * A number from 0 to 99, which means a year from 1900 to 1999, or
+   * The actual year (>=100).  */
+static time_t
+Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
+    time_t     Month;
+    time_t     Day;
+    time_t     Year;
+    time_t     Hours;
+    time_t     Minutes;
+    time_t     Seconds;
+    MERIDIAN   Meridian;
+    DSTMODE    DSTmode;
+{
+    static int DaysInMonth[12] = {
+       31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+    };
+    time_t     tod;
+    time_t     Julian;
+    int                i;
+
+    if (Year < 0)
+       Year = -Year;
+    if (Year < 69)
+       Year += 2000;
+    else if (Year < 100) {
+       Year += 1900;
+       if (Year < EPOCH)
+               Year += 100;
+    }
+    DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+                   ? 29 : 28;
+    /* Checking for 2038 bogusly assumes that time_t is 32 bits.  But
+       I'm too lazy to try to check for time_t overflow in another way.  */
+    if (Year < EPOCH || Year > 2038
+     || Month < 1 || Month > 12
+     /* Lint fluff:  "conversion from long may lose accuracy" */
+     || Day < 1 || Day > DaysInMonth[(int)--Month])
+       return -1;
+
+    for (Julian = Day - 1, i = 0; i < Month; i++)
+       Julian += DaysInMonth[i];
+    for (i = EPOCH; i < Year; i++)
+       Julian += 365 + (i % 4 == 0);
+    Julian *= SECSPERDAY;
+    Julian += yyTimezone * 60L;
+    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
+       return -1;
+    Julian += tod;
+    if (DSTmode == DSTon
+     || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
+       Julian -= 60 * 60;
+    return Julian;
+}
+
+
+static time_t
+DSTcorrect(Start, Future)
+    time_t     Start;
+    time_t     Future;
+{
+    time_t     StartDay;
+    time_t     FutureDay;
+
+    StartDay = (localtime(&Start)->tm_hour + 1) % 24;
+    FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
+    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
+}
+
+
+static time_t
+RelativeDate(Start, DayOrdinal, DayNumber)
+    time_t     Start;
+    time_t     DayOrdinal;
+    time_t     DayNumber;
+{
+    struct tm  *tm;
+    time_t     now;
+
+    now = Start;
+    tm = localtime(&now);
+    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
+    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+    return DSTcorrect(Start, now);
+}
+
+
+static time_t
+RelativeMonth(Start, RelMonth)
+    time_t     Start;
+    time_t     RelMonth;
+{
+    struct tm  *tm;
+    time_t     Month;
+    time_t     Year;
+
+    if (RelMonth == 0)
+       return 0;
+    tm = localtime(&Start);
+    Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
+    Year = Month / 12;
+    Month = Month % 12 + 1;
+    return DSTcorrect(Start,
+           Convert(Month, (time_t)tm->tm_mday, Year,
+               (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
+               MER24, DSTmaybe));
+}
+
+
+static int
+LookupWord(buff)
+    char               *buff;
+{
+    char               *p;
+    char               *q;
+    const TABLE                *tp;
+    int                        i;
+    int                        abbrev;
+
+    /* Make it lowercase. */
+    for (p = buff; *p; p++)
+       if (isupper((unsigned char)*p))
+           *p = tolower((unsigned char)*p);
+
+    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
+       yylval.Meridian = MERam;
+       return tMERIDIAN;
+    }
+    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
+       yylval.Meridian = MERpm;
+       return tMERIDIAN;
+    }
+
+    /* See if we have an abbreviation for a month. */
+    if (strlen(buff) == 3)
+       abbrev = 1;
+    else if (strlen(buff) == 4 && buff[3] == '.') {
+       abbrev = 1;
+       buff[3] = '\0';
+    }
+    else
+       abbrev = 0;
+
+    for (tp = MonthDayTable; tp->name; tp++) {
+       if (abbrev) {
+           if (strncmp(buff, tp->name, 3) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+       }
+       else if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+    }
+
+    for (tp = TimezoneTable; tp->name; tp++)
+       if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+
+    if (strcmp(buff, "dst") == 0) 
+       return tDST;
+
+    for (tp = UnitsTable; tp->name; tp++)
+       if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+
+    /* Strip off any plural and try the units table again. */
+    i = strlen(buff) - 1;
+    if (buff[i] == 's') {
+       buff[i] = '\0';
+       for (tp = UnitsTable; tp->name; tp++)
+           if (strcmp(buff, tp->name) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+       buff[i] = 's';          /* Put back for "this" in OtherTable. */
+    }
+
+    for (tp = OtherTable; tp->name; tp++)
+       if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+
+    /* Military timezones. */
+    if (buff[1] == '\0' && isalpha((unsigned char)*buff)) {
+       for (tp = MilitaryTable; tp->name; tp++)
+           if (strcmp(buff, tp->name) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+    }
+
+    /* Drop out any periods and try the timezone table again. */
+    for (i = 0, p = q = buff; *q; q++)
+       if (*q != '.')
+           *p++ = *q;
+       else
+           i++;
+    *p = '\0';
+    if (i)
+       for (tp = TimezoneTable; tp->name; tp++)
+           if (strcmp(buff, tp->name) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+
+    return tID;
+}
+
+
+static int
+yylex()
+{
+    char               c;
+    char               *p;
+    char               buff[20];
+    int                        Count;
+    int                        sign;
+
+    for ( ; ; ) {
+       while (isspace((unsigned char)*yyInput))
+           yyInput++;
+
+       if (isdigit((unsigned char)(c = *yyInput)) || c == '-' || c == '+') {
+           if (c == '-' || c == '+') {
+               sign = c == '-' ? -1 : 1;
+               if (!isdigit((unsigned char)*++yyInput))
+                   /* skip the '-' sign */
+                   continue;
+           }
+           else
+               sign = 0;
+           for (yylval.Number = 0; isdigit((unsigned char)(c = *yyInput++)); )
+               yylval.Number = 10 * yylval.Number + c - '0';
+           yyInput--;
+           if (sign < 0)
+               yylval.Number = -yylval.Number;
+           return sign ? tSNUMBER : tUNUMBER;
+       }
+       if (isalpha((unsigned char)c)) {
+           for (p = buff; isalpha((unsigned char)(c = *yyInput++)) || c == '.'; )
+               if (p < &buff[sizeof buff - 1])
+                   *p++ = c;
+           *p = '\0';
+           yyInput--;
+           return LookupWord(buff);
+       }
+       if (c != '(')
+           return *yyInput++;
+       Count = 0;
+       do {
+           c = *yyInput++;
+           if (c == '\0')
+               return c;
+           if (c == '(')
+               Count++;
+           else if (c == ')')
+               Count--;
+       } while (Count > 0);
+    }
+}
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds.  */
+static long
+difftm (a, b)
+     struct tm *a, *b;
+{
+  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+  int days = (
+             /* difference in day of year */
+             a->tm_yday - b->tm_yday
+             /* + intervening leap days */
+             +  ((ay >> 2) - (by >> 2))
+             -  (ay/100 - by/100)
+             +  ((ay/100 >> 2) - (by/100 >> 2))
+             /* + difference in years * 365 */
+             +  (long)(ay-by) * 365
+             );
+  return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
+             + (a->tm_min - b->tm_min))
+         + (a->tm_sec - b->tm_sec));
+}
+
+time_t
+get_date(p)
+    char               *p;
+{
+    struct tm          *tm, *gmt, gmtbuf;
+    time_t             Start;
+    time_t             tod;
+    time_t             now;
+    time_t             timezone;
+
+    yyInput = p;
+    (void)time (&now);
+
+    gmt = gmtime (&now);
+    if (gmt != NULL)
+    {
+       /* Make a copy, in case localtime modifies *tm (I think
+          that comment now applies to *gmt, but I am too
+          lazy to dig into how gmtime and locatime allocate the
+          structures they return pointers to).  */
+       gmtbuf = *gmt;
+       gmt = &gmtbuf;
+    }
+
+    if (! (tm = localtime (&now)))
+       return -1;
+
+    if (gmt != NULL)
+       timezone = difftm (gmt, tm) / 60;
+    else
+       /* We are on a system like VMS, where the system clock is
+          in local time and the system has no concept of timezones.
+          Hopefully we can fake this out (for the case in which the
+          user specifies no timezone) by just saying the timezone
+          is zero.  */
+       timezone = 0;
+
+    if(tm->tm_isdst)
+       timezone += 60;
+
+    tm = localtime(&now);
+    yyYear = tm->tm_year + 1900;
+    yyMonth = tm->tm_mon + 1;
+    yyDay = tm->tm_mday;
+    yyTimezone = timezone;
+    yyDSTmode = DSTmaybe;
+    yyHour = 0;
+    yyMinutes = 0;
+    yySeconds = 0;
+    yyMeridian = MER24;
+    yyRelSeconds = 0;
+    yyRelMonth = 0;
+    yyHaveDate = 0;
+    yyHaveDay = 0;
+    yyHaveRel = 0;
+    yyHaveTime = 0;
+    yyHaveZone = 0;
+
+    if (yyparse()
+     || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+       return -1;
+
+    if (yyHaveDate || yyHaveTime || yyHaveDay) {
+       Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
+                   yyMeridian, yyDSTmode);
+       if (Start < 0)
+           return -1;
+    }
+    else {
+       Start = now;
+       if (!yyHaveRel)
+           Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
+    }
+
+    Start += yyRelSeconds;
+    Start += RelativeMonth(Start, yyRelMonth);
+
+    if (yyHaveDay && !yyHaveDate) {
+       tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
+       Start += tod;
+    }
+
+    /* Have to do *something* with a legitimate -1 so it's distinguishable
+     * from the error return value.  (Alternately could set errno on error.) */
+    return Start == -1 ? 0 : Start;
+}
+
+
+#if    defined(TEST)
+
+/* ARGSUSED */
+int
+main(ac, av)
+    int                ac;
+    char       *av[];
+{
+    char       buff[128];
+    time_t     d;
+
+    (void)printf("Enter date, or blank line to exit.\n\t> ");
+    (void)fflush(stdout);
+    while (gets(buff) && buff[0]) {
+       d = get_date(buff);
+       if (d == -1)
+           (void)printf("Bad format - couldn't convert.\n");
+       else
+           (void)printf("%s", ctime(&d));
+       (void)printf("\t> ");
+       (void)fflush(stdout);
+    }
+    exit(0);
+    /* NOTREACHED */
+}
+#endif /* defined(TEST) */
diff --git a/plugins/sudoers/getspwuid.c b/plugins/sudoers/getspwuid.c
new file mode 100644 (file)
index 0000000..01f4885
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2010
+ *     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
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#include <grp.h>
+#ifdef HAVE_GETSPNAM
+# include <shadow.h>
+#endif /* HAVE_GETSPNAM */
+#ifdef HAVE_GETPRPWNAM
+# ifdef __hpux
+#  undef MAXINT
+#  include <hpsecurity.h>
+# else
+#  include <sys/security.h>
+# endif /* __hpux */
+# include <prot.h>
+#endif /* HAVE_GETPRPWNAM */
+#ifdef HAVE_GETPWANAM
+# include <sys/label.h>
+# include <sys/audit.h>
+# include <pwdadj.h>
+#endif /* HAVE_GETPWANAM */
+#ifdef HAVE_GETAUTHUID
+# include <auth.h>
+#endif /* HAVE_GETAUTHUID */
+
+#include "sudoers.h"
+
+/*
+ * 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.
+ */
+char *
+sudo_getepw(const struct passwd *pw)
+{
+    char *epw = NULL;
+
+    /* If there is a function to check for shadow enabled, use it... */
+#ifdef HAVE_ISCOMSEC
+    if (!iscomsec())
+       goto done;
+#endif /* HAVE_ISCOMSEC */
+#ifdef HAVE_ISSECURE
+    if (!issecure())
+       goto done;
+#endif /* HAVE_ISSECURE */
+
+#ifdef HAVE_GETPRPWNAM
+    {
+       struct pr_passwd *spw;
+
+       if ((spw = getprpwnam(pw->pw_name)) && spw->ufld.fd_encrypt) {
+# ifdef __alpha
+           crypt_type = spw->ufld.fd_oldcrypt;
+# endif /* __alpha */
+           epw = spw->ufld.fd_encrypt;
+       }
+    }
+#endif /* HAVE_GETPRPWNAM */
+#ifdef HAVE_GETSPNAM
+    {
+       struct spwd *spw;
+
+       if ((spw = getspnam(pw->pw_name)) && spw->sp_pwdp)
+           epw = spw->sp_pwdp;
+    }
+#endif /* HAVE_GETSPNAM */
+#ifdef HAVE_GETSPWUID
+    {
+       struct s_passwd *spw;
+
+       if ((spw = getspwuid(pw->pw_uid)) && spw->pw_passwd)
+           epw = spw->pw_passwd;
+    }
+#endif /* HAVE_GETSPWUID */
+#ifdef HAVE_GETPWANAM
+    {
+       struct passwd_adjunct *spw;
+
+       if ((spw = getpwanam(pw->pw_name)) && spw->pwa_passwd)
+           epw = spw->pwa_passwd;
+    }
+#endif /* HAVE_GETPWANAM */
+#ifdef HAVE_GETAUTHUID
+    {
+       AUTHORIZATION *spw;
+
+       if ((spw = getauthuid(pw->pw_uid)) && spw->a_password)
+           epw = spw->a_password;
+    }
+#endif /* HAVE_GETAUTHUID */
+
+#if defined(HAVE_ISCOMSEC) || defined(HAVE_ISSECURE)
+done:
+#endif
+    /* If no shadow password, fall back on regular password. */
+    return estrdup(epw ? epw : pw->pw_passwd);
+}
+
+void
+sudo_setspent(void)
+{
+#ifdef HAVE_GETPRPWNAM
+    setprpwent();
+#endif
+#ifdef HAVE_GETSPNAM
+    setspent();
+#endif
+#ifdef HAVE_GETSPWUID
+    setspwent();
+#endif
+#ifdef HAVE_GETPWANAM
+    setpwaent();
+#endif
+#ifdef HAVE_GETAUTHUID
+    setauthent();
+#endif
+}
+
+void
+sudo_endspent(void)
+{
+#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
+}
diff --git a/plugins/sudoers/goodpath.c b/plugins/sudoers/goodpath.c
new file mode 100644 (file)
index 0000000..8d02028
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2010-2011
+ *     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 HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <errno.h>
+
+#include "sudoers.h"
+
+/*
+ * Verify that path is a normal file and executable by root.
+ */
+char *
+sudo_goodpath(const char *path, struct stat *sbp)
+{
+    struct stat sb;
+
+    /* Check for brain damage */
+    if (path == NULL || path[0] == '\0')
+       return NULL;
+
+    if (stat(path, &sb))
+       return NULL;
+
+    /* Make sure path describes an executable regular file. */
+    if (!S_ISREG(sb.st_mode) || !(sb.st_mode & 0000111)) {
+       errno = EACCES;
+       return NULL;
+    }
+
+    if (sbp != NULL)
+       (void) memcpy(sbp, &sb, sizeof(struct stat));
+    return (char *)path;
+}
diff --git a/plugins/sudoers/gram.c b/plugins/sudoers/gram.c
new file mode 100644 (file)
index 0000000..d95b834
--- /dev/null
@@ -0,0 +1,1651 @@
+#include <config.h>
+#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-2011
+ *     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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_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 "sudoers.h" /* XXX */
+#include "parse.h"
+#include "toke.h"
+
+/*
+ * 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(int, struct member *, struct defaults *);
+static void  add_userspec(struct member *, struct privilege *);
+static struct defaults *new_default(char *, char *, int);
+static struct member *new_member(char *, int);
+       void  yyerror(const char *);
+
+void
+yyerror(const char *s)
+{
+    /* Save the line the first error occurred on. */
+    if (errorlineno == -1) {
+       errorlineno = sudolineno ? sudolineno - 1 : 0;
+       errorfile = estrdup(sudoers);
+    }
+    if (trace_print != NULL) {
+       LEXTRACE("<*> ");
+    } else if (verbose && s != NULL) {
+       warningx(">>> %s: %s near line %d <<<", sudoers, s,
+           sudolineno ? sudolineno - 1 : 0);
+    }
+    parse_error = TRUE;
+}
+#line 110 "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 136 "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 LOG_INPUT 275
+#define NOLOG_INPUT 276
+#define LOG_OUTPUT 277
+#define NOLOG_OUTPUT 278
+#define ALL 279
+#define COMMENT 280
+#define HOSTALIAS 281
+#define CMNDALIAS 282
+#define USERALIAS 283
+#define RUNASALIAS 284
+#define ERROR 285
+#define TYPE 286
+#define ROLE 287
+#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,   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,    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,   85,   87,   88,   89,    0,    0,    0,    0,    0,
+   86,    5,    0,    0,    0,    0,    0,    0,   81,   83,
+    0,    0,    3,    6,    0,    0,   17,    0,   29,   32,
+   31,   33,   30,    0,   27,    0,   68,    0,    0,   64,
+   63,   62,    0,   37,   73,    0,    0,    0,   65,    0,
+    0,   70,    0,    0,   78,    0,    0,   75,   84,    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,   82,    0,    0,   21,   22,
+   23,   18,   69,   74,    0,   66,    0,   71,    0,   79,
+    0,   76,    0,   34,    0,    0,   25,    0,    0,    0,
+    0,    0,    0,   51,    0,    0,   94,   96,   95,    0,
+   90,   92,    0,    0,   47,   35,    0,    0,    0,   44,
+   45,   93,    0,    0,   40,   39,   52,   53,   54,   55,
+   56,   57,   58,   59,   60,   61,   36,   91,
+};
+#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
+       {                                    475,
+ -270,    0,    0,    0,    0,  -29,  567,  594,  594,   -2,
+    0,    0, -240, -222, -216, -212, -241,    0,    0,    0,
+  -25,  475,    0,    0,  -10, -207,    0,    9,    0,    0,
+    0,    0,    0, -235,    0,  -33,    0,  -31,  -31,    0,
+    0,    0, -242,    0,    0,  -30,   -7,    3,    0,   -6,
+    4,    0,   -5,    6,    0,   -1,    8,    0,    0,  594,
+  -20,    0,   10,    0, -205, -196, -194,    0,  -29,    0,
+  567,    9,    9,    9,    0,   -2,    9,  567, -240,   -2,
+ -222,  594, -216,  594, -212,    0,   31,  567,    0,    0,
+    0,    0,    0,    0,   26,    0,   28,    0,   29,    0,
+   29,    0,  541,    0,   32, -247,    0,   86,  -15,   33,
+   31,   14,   16,    0, -208, -204,    0,    0,    0, -231,
+    0,    0,   38,   86,    0,    0, -179, -178,  491,    0,
+    0,    0,   86,   38,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yyrindex[] =
+#else
+short yyrindex[] =
+#endif
+       {                                     87,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,   90,    0,    0,    1,    0,    0,  177,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,  207,    0,    0,
+  237,    0,    0,  271,    0,    0,  300,    0,    0,    0,
+    0,    0,  329,    0,    0,    0,    0,    0,    0,    0,
+    0,  358,  387,  417,    0,    0,  446,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,  -26,    0,    0,    0,
+    0,    0,    0,    0,   30,    0,   59,    0,   89,    0,
+  118,    0,    0,    0,  148,  514,    0,    0,   45,    0,
+  -26,    0,    0,    0,  537,  565,    0,    0,    0,    0,
+    0,    0,   50,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,   52,    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,
+  -17,    0,   27,   11,   54,  -64,   15,   64,    2,   34,
+   39,   84,   -3,  -27,  -18,  -21,    0,    0,   19,    0,
+    0,    0,  -12,   -4,    0,   88,    0,    0,    0,    0,
+   35,   40,   23,   37,
+};
+#define YYTABLESIZE 873
+#if defined(__cplusplus) || defined(__STDC__)
+const short yytable[] =
+#else
+short yytable[] =
+#endif
+       {                                      26,
+   19,   26,   26,   26,   38,   39,   46,   34,   36,   24,
+   71,   94,   60,   76,   40,   41,    2,   47,   60,    3,
+    4,    5,   29,   71,   30,   31,  117,   32,   60,   67,
+   43,  118,   66,   19,   67,   50,   42,   11,  112,  113,
+   87,   53,  124,   33,   19,   56,   72,  119,   73,   74,
+   65,   68,   69,   78,   80,   82,   77,   89,   72,   84,
+   79,   81,   67,   83,  147,   85,   90,   88,   91,   71,
+  103,   76,   60,  125,  127,  111,  128,  112,   99,   95,
+  101,  133,  113,  135,  136,   48,    1,   67,   80,    2,
+   50,   72,   49,  126,   97,   92,   75,   70,   86,  109,
+   59,  132,  134,  131,   93,  148,  107,  102,    0,   64,
+  130,    0,    0,   96,    0,    0,   72,   77,  120,  100,
+   98,   80,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   80,   26,    0,    0,
+   77,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   77,   12,    0,    0,    0,
+   26,    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,    9,    0,    0,   12,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   25,    0,   25,   25,   25,
+   46,   46,   29,    0,   30,   31,   10,   32,    0,    9,
+    0,    0,   46,   46,   46,   46,   46,   46,   46,   46,
+   46,   46,   46,   33,   40,   41,   19,    0,   19,   46,
+   46,   19,   19,   19,   19,   19,   19,   19,   19,   10,
+    8,    0,    0,    0,    0,    0,   42,    0,    0,   19,
+   19,   19,   19,   19,   19,   67,    0,   67,    0,    0,
+   67,   67,   67,   67,   67,   67,   67,   67,    0,   11,
+    0,    0,    0,    8,    0,    0,    0,    0,   67,   67,
+   67,   67,   67,   67,   72,    0,   72,    0,    0,   72,
+   72,   72,   72,   72,   72,   72,   72,    0,    7,    0,
+    0,    0,   11,    0,    0,    0,    0,   72,   72,   72,
+   72,   72,   72,  117,   80,    0,   80,    0,  118,   80,
+   80,   80,   80,   80,   80,   80,   80,   15,    0,    0,
+    0,    7,    0,    0,  119,    0,    0,   80,   80,   80,
+   80,   80,   80,   77,    0,   77,    0,    0,   77,   77,
+   77,   77,   77,   77,   77,   77,   13,    0,    0,    0,
+   15,    0,    0,    0,    0,    0,   77,   77,   77,   77,
+   77,   77,    0,   26,    0,   26,    0,    0,   26,   26,
+   26,   26,   26,   26,   26,   26,   14,    0,    0,   13,
+    0,    0,    0,    0,    0,    0,   26,   26,   26,   26,
+   26,   26,   12,    0,   12,    0,    0,   12,   12,   12,
+   12,   12,   12,   12,   12,   16,    0,    0,    0,   14,
+    0,    0,    0,    0,    0,   12,   12,   12,   12,   12,
+   12,    0,    9,    0,    9,    0,    0,    9,    9,    9,
+    9,    9,    9,    9,    9,    0,    0,    0,   16,    0,
+    0,    0,    0,    0,    0,    9,    9,    9,    9,    9,
+    9,    0,   10,    0,   10,    0,    0,   10,   10,   10,
+   10,   10,   10,   10,   10,    0,    0,   17,    0,    0,
+    0,    0,    0,    0,    0,   10,   10,   10,   10,   10,
+   10,    0,    0,   43,    0,    0,    8,    0,    8,    0,
+    0,    8,    8,    8,    8,    8,    8,    8,    8,    0,
+    0,    0,    0,    0,    0,    0,   41,    0,    0,    8,
+    8,    8,    8,    8,    8,   11,    0,   11,    0,    0,
+   11,   11,   11,   11,   11,   11,   11,   11,    0,   42,
+    0,    0,    0,   17,    0,    0,    0,    0,   11,   11,
+   11,   11,   11,   11,    7,    0,    7,    0,    0,    7,
+    7,    7,    7,    7,    7,    7,    7,   43,  108,   34,
+    0,    0,    0,    0,    0,    0,    0,    7,    7,    7,
+    7,    7,    7,   15,    0,   15,    0,    0,   15,   15,
+   15,   15,   15,   15,   15,   15,   17,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   15,   15,   15,   15,
+   15,   15,   13,    0,   13,    0,    0,   13,   13,   13,
+   13,   13,   13,   13,   13,    0,    0,    0,    0,    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,    0,    0,    0,    0,   14,   14,   14,   14,   14,
+   14,   16,    0,   16,    0,    0,   16,   16,   16,   16,
+   16,   16,   16,   16,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,   16,   16,   16,   16,   16,   16,
+    1,    0,    2,    0,    0,    3,    4,    5,    6,    7,
+    8,    9,   10,    0,    0,    0,    0,   40,   41,    0,
+    0,    0,    0,   11,   12,   13,   14,   15,   16,  137,
+  138,  139,  140,  141,  142,  143,  144,  145,  146,   42,
+   41,   41,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,   41,   41,   41,   41,   41,   41,   41,   41,
+   41,   41,   41,   42,   42,    0,    0,    0,    2,    0,
+    0,    3,    4,    5,    0,   42,   42,   42,   42,   42,
+   42,   42,   42,   42,   42,   42,    0,    0,    0,   11,
+    0,   43,   43,    0,   29,    0,   30,   31,    0,   32,
+    0,    0,    0,   43,   43,   43,   43,   43,   43,   43,
+   43,   43,   43,   43,    0,   33,    0,    0,    0,    0,
+    0,    2,    0,    0,    3,    4,    5,    0,    0,    0,
+    0,    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,   33,   33,   33,    8,    9,   33,   33,    7,  280,
+   44,   76,   44,   44,  257,  258,  258,  258,   44,  261,
+  262,  263,  258,   44,  260,  261,  258,  263,   44,    0,
+   33,  263,   43,   33,   45,  258,  279,  279,  286,  287,
+   61,  258,   58,  279,   44,  258,   36,  279,   38,   39,
+   61,  259,   44,   61,   61,   61,   46,  263,    0,   61,
+   58,   58,   33,   58,  129,   58,  263,   58,  263,   44,
+   40,   44,   44,   41,   61,   44,   61,  286,   82,   78,
+   84,   44,  287,  263,  263,   41,    0,   58,    0,    0,
+   41,   33,   41,  111,   80,   69,   43,   34,   60,  103,
+   17,  120,  124,  116,   71,  133,   88,   85,   -1,   22,
+  115,   -1,   -1,   79,   -1,   -1,   58,    0,   33,   83,
+   81,   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   58,    0,   -1,   -1,
+   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   58,    0,   -1,   -1,   -1,
+   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   58,    0,   -1,   -1,   33,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  259,   -1,  259,  259,  259,
+  257,  258,  258,   -1,  260,  261,    0,  263,   -1,   33,
+   -1,   -1,  269,  270,  271,  272,  273,  274,  275,  276,
+  277,  278,  279,  279,  257,  258,  256,   -1,  258,  286,
+  287,  261,  262,  263,  264,  265,  266,  267,  268,   33,
+    0,   -1,   -1,   -1,   -1,   -1,  279,   -1,   -1,  279,
+  280,  281,  282,  283,  284,  256,   -1,  258,   -1,   -1,
+  261,  262,  263,  264,  265,  266,  267,  268,   -1,    0,
+   -1,   -1,   -1,   33,   -1,   -1,   -1,   -1,  279,  280,
+  281,  282,  283,  284,  256,   -1,  258,   -1,   -1,  261,
+  262,  263,  264,  265,  266,  267,  268,   -1,    0,   -1,
+   -1,   -1,   33,   -1,   -1,   -1,   -1,  279,  280,  281,
+  282,  283,  284,  258,  256,   -1,  258,   -1,  263,  261,
+  262,  263,  264,  265,  266,  267,  268,    0,   -1,   -1,
+   -1,   33,   -1,   -1,  279,   -1,   -1,  279,  280,  281,
+  282,  283,  284,  256,   -1,  258,   -1,   -1,  261,  262,
+  263,  264,  265,  266,  267,  268,    0,   -1,   -1,   -1,
+   33,   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,
+  283,  284,   -1,  256,   -1,  258,   -1,   -1,  261,  262,
+  263,  264,  265,  266,  267,  268,    0,   -1,   -1,   33,
+   -1,   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,
+  283,  284,  256,   -1,  258,   -1,   -1,  261,  262,  263,
+  264,  265,  266,  267,  268,    0,   -1,   -1,   -1,   33,
+   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,  283,
+  284,   -1,  256,   -1,  258,   -1,   -1,  261,  262,  263,
+  264,  265,  266,  267,  268,   -1,   -1,   -1,   33,   -1,
+   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,  283,
+  284,   -1,  256,   -1,  258,   -1,   -1,  261,  262,  263,
+  264,  265,  266,  267,  268,   -1,   -1,   33,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,  283,
+  284,   -1,   -1,   33,   -1,   -1,  256,   -1,  258,   -1,
+   -1,  261,  262,  263,  264,  265,  266,  267,  268,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   33,   -1,   -1,  279,
+  280,  281,  282,  283,  284,  256,   -1,  258,   -1,   -1,
+  261,  262,  263,  264,  265,  266,  267,  268,   -1,   33,
+   -1,   -1,   -1,   33,   -1,   -1,   -1,   -1,  279,  280,
+  281,  282,  283,  284,  256,   -1,  258,   -1,   -1,  261,
+  262,  263,  264,  265,  266,  267,  268,   33,   58,   33,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,  279,  280,  281,
+  282,  283,  284,  256,   -1,  258,   -1,   -1,  261,  262,
+  263,  264,  265,  266,  267,  268,   33,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,
+  283,  284,  256,   -1,  258,   -1,   -1,  261,  262,  263,
+  264,  265,  266,  267,  268,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,  283,
+  284,   -1,  256,   -1,  258,   -1,   -1,  261,  262,  263,
+  264,  265,  266,  267,  268,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  279,  280,  281,  282,  283,
+  284,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
+  265,  266,  267,  268,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,  279,  280,  281,  282,  283,  284,
+  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,  265,
+  266,  267,  268,   -1,   -1,   -1,   -1,  257,  258,   -1,
+   -1,   -1,   -1,  279,  280,  281,  282,  283,  284,  269,
+  270,  271,  272,  273,  274,  275,  276,  277,  278,  279,
+  257,  258,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,  269,  270,  271,  272,  273,  274,  275,  276,
+  277,  278,  279,  257,  258,   -1,   -1,   -1,  258,   -1,
+   -1,  261,  262,  263,   -1,  269,  270,  271,  272,  273,
+  274,  275,  276,  277,  278,  279,   -1,   -1,   -1,  279,
+   -1,  257,  258,   -1,  258,   -1,  260,  261,   -1,  263,
+   -1,   -1,   -1,  269,  270,  271,  272,  273,  274,  275,
+  276,  277,  278,  279,   -1,  279,   -1,   -1,   -1,   -1,
+   -1,  258,   -1,   -1,  261,  262,  263,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,  279,
+};
+#define YYFINAL 18
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 287
+#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","LOG_INPUT","NOLOG_INPUT",
+"LOG_OUTPUT","NOLOG_OUTPUT","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",
+"cmndtag : cmndtag LOG_INPUT",
+"cmndtag : cmndtag NOLOG_INPUT",
+"cmndtag : cmndtag LOG_OUTPUT",
+"cmndtag : cmndtag NOLOG_OUTPUT",
+"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 604 "gram.y"
+static struct defaults *
+new_default(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(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(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(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(const 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();
+
+    init_lexer();
+
+    efree(sudoers);
+    sudoers = path ? estrdup(path) : NULL;
+
+    parse_error = FALSE;
+    errorlineno = -1;
+    errorfile = NULL;
+    verbose = !quiet;
+}
+#line 760 "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 185 "gram.y"
+{ ; }
+break;
+case 5:
+#line 193 "gram.y"
+{
+                           ;
+                       }
+break;
+case 6:
+#line 196 "gram.y"
+{
+                           yyerrok;
+                       }
+break;
+case 7:
+#line 199 "gram.y"
+{
+                           add_userspec(yyvsp[-1].member, yyvsp[0].privilege);
+                       }
+break;
+case 8:
+#line 202 "gram.y"
+{
+                           ;
+                       }
+break;
+case 9:
+#line 205 "gram.y"
+{
+                           ;
+                       }
+break;
+case 10:
+#line 208 "gram.y"
+{
+                           ;
+                       }
+break;
+case 11:
+#line 211 "gram.y"
+{
+                           ;
+                       }
+break;
+case 12:
+#line 214 "gram.y"
+{
+                           add_defaults(DEFAULTS, NULL, yyvsp[0].defaults);
+                       }
+break;
+case 13:
+#line 217 "gram.y"
+{
+                           add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults);
+                       }
+break;
+case 14:
+#line 220 "gram.y"
+{
+                           add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults);
+                       }
+break;
+case 15:
+#line 223 "gram.y"
+{
+                           add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults);
+                       }
+break;
+case 16:
+#line 226 "gram.y"
+{
+                           add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults);
+                       }
+break;
+case 18:
+#line 232 "gram.y"
+{
+                           list_append(yyvsp[-2].defaults, yyvsp[0].defaults);
+                           yyval.defaults = yyvsp[-2].defaults;
+                       }
+break;
+case 19:
+#line 238 "gram.y"
+{
+                           yyval.defaults = new_default(yyvsp[0].string, NULL, TRUE);
+                       }
+break;
+case 20:
+#line 241 "gram.y"
+{
+                           yyval.defaults = new_default(yyvsp[0].string, NULL, FALSE);
+                       }
+break;
+case 21:
+#line 244 "gram.y"
+{
+                           yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, TRUE);
+                       }
+break;
+case 22:
+#line 247 "gram.y"
+{
+                           yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+');
+                       }
+break;
+case 23:
+#line 250 "gram.y"
+{
+                           yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-');
+                       }
+break;
+case 25:
+#line 256 "gram.y"
+{
+                           list_append(yyvsp[-2].privilege, yyvsp[0].privilege);
+                           yyval.privilege = yyvsp[-2].privilege;
+                       }
+break;
+case 26:
+#line 262 "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 272 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = FALSE;
+                       }
+break;
+case 28:
+#line 276 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = TRUE;
+                       }
+break;
+case 29:
+#line 282 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, ALIAS);
+                       }
+break;
+case 30:
+#line 285 "gram.y"
+{
+                           yyval.member = new_member(NULL, ALL);
+                       }
+break;
+case 31:
+#line 288 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, NETGROUP);
+                       }
+break;
+case 32:
+#line 291 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, NTWKADDR);
+                       }
+break;
+case 33:
+#line 294 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, WORD);
+                       }
+break;
+case 35:
+#line 300 "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 (yyvsp[0].cmndspec->tags.log_input == UNSPEC)
+                               yyvsp[0].cmndspec->tags.log_input = yyvsp[0].cmndspec->prev->tags.log_input;
+                           if (yyvsp[0].cmndspec->tags.log_output == UNSPEC)
+                               yyvsp[0].cmndspec->tags.log_output = yyvsp[0].cmndspec->prev->tags.log_output;
+                           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 332 "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 358 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = FALSE;
+                       }
+break;
+case 38:
+#line 362 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = TRUE;
+                       }
+break;
+case 39:
+#line 368 "gram.y"
+{
+                           yyval.string = yyvsp[0].string;
+                       }
+break;
+case 40:
+#line 373 "gram.y"
+{
+                           yyval.string = yyvsp[0].string;
+                       }
+break;
+case 41:
+#line 378 "gram.y"
+{
+                           yyval.seinfo.role = NULL;
+                           yyval.seinfo.type = NULL;
+                       }
+break;
+case 42:
+#line 382 "gram.y"
+{
+                           yyval.seinfo.role = yyvsp[0].string;
+                           yyval.seinfo.type = NULL;
+                       }
+break;
+case 43:
+#line 386 "gram.y"
+{
+                           yyval.seinfo.type = yyvsp[0].string;
+                           yyval.seinfo.role = NULL;
+                       }
+break;
+case 44:
+#line 390 "gram.y"
+{
+                           yyval.seinfo.role = yyvsp[-1].string;
+                           yyval.seinfo.type = yyvsp[0].string;
+                       }
+break;
+case 45:
+#line 394 "gram.y"
+{
+                           yyval.seinfo.type = yyvsp[-1].string;
+                           yyval.seinfo.role = yyvsp[0].string;
+                       }
+break;
+case 46:
+#line 400 "gram.y"
+{
+                           yyval.runas = NULL;
+                       }
+break;
+case 47:
+#line 403 "gram.y"
+{
+                           yyval.runas = yyvsp[-1].runas;
+                       }
+break;
+case 48:
+#line 408 "gram.y"
+{
+                           yyval.runas = emalloc(sizeof(struct runascontainer));
+                           yyval.runas->runasusers = yyvsp[0].member;
+                           yyval.runas->runasgroups = NULL;
+                       }
+break;
+case 49:
+#line 413 "gram.y"
+{
+                           yyval.runas = emalloc(sizeof(struct runascontainer));
+                           yyval.runas->runasusers = yyvsp[-2].member;
+                           yyval.runas->runasgroups = yyvsp[0].member;
+                       }
+break;
+case 50:
+#line 418 "gram.y"
+{
+                           yyval.runas = emalloc(sizeof(struct runascontainer));
+                           yyval.runas->runasusers = NULL;
+                           yyval.runas->runasgroups = yyvsp[0].member;
+                       }
+break;
+case 51:
+#line 425 "gram.y"
+{
+                           yyval.tag.nopasswd = yyval.tag.noexec = yyval.tag.setenv =
+                               yyval.tag.log_input = yyval.tag.log_output = UNSPEC;
+                       }
+break;
+case 52:
+#line 429 "gram.y"
+{
+                           yyval.tag.nopasswd = TRUE;
+                       }
+break;
+case 53:
+#line 432 "gram.y"
+{
+                           yyval.tag.nopasswd = FALSE;
+                       }
+break;
+case 54:
+#line 435 "gram.y"
+{
+                           yyval.tag.noexec = TRUE;
+                       }
+break;
+case 55:
+#line 438 "gram.y"
+{
+                           yyval.tag.noexec = FALSE;
+                       }
+break;
+case 56:
+#line 441 "gram.y"
+{
+                           yyval.tag.setenv = TRUE;
+                       }
+break;
+case 57:
+#line 444 "gram.y"
+{
+                           yyval.tag.setenv = FALSE;
+                       }
+break;
+case 58:
+#line 447 "gram.y"
+{
+                           yyval.tag.log_input = TRUE;
+                       }
+break;
+case 59:
+#line 450 "gram.y"
+{
+                           yyval.tag.log_input = FALSE;
+                       }
+break;
+case 60:
+#line 453 "gram.y"
+{
+                           yyval.tag.log_output = TRUE;
+                       }
+break;
+case 61:
+#line 456 "gram.y"
+{
+                           yyval.tag.log_output = FALSE;
+                       }
+break;
+case 62:
+#line 461 "gram.y"
+{
+                           yyval.member = new_member(NULL, ALL);
+                       }
+break;
+case 63:
+#line 464 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, ALIAS);
+                       }
+break;
+case 64:
+#line 467 "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 67:
+#line 479 "gram.y"
+{
+                           char *s;
+                           if ((s = alias_add(yyvsp[-2].string, HOSTALIAS, yyvsp[0].member)) != NULL) {
+                               yyerror(s);
+                               YYERROR;
+                           }
+                       }
+break;
+case 69:
+#line 489 "gram.y"
+{
+                           list_append(yyvsp[-2].member, yyvsp[0].member);
+                           yyval.member = yyvsp[-2].member;
+                       }
+break;
+case 72:
+#line 499 "gram.y"
+{
+                           char *s;
+                           if ((s = alias_add(yyvsp[-2].string, CMNDALIAS, yyvsp[0].member)) != NULL) {
+                               yyerror(s);
+                               YYERROR;
+                           }
+                       }
+break;
+case 74:
+#line 509 "gram.y"
+{
+                           list_append(yyvsp[-2].member, yyvsp[0].member);
+                           yyval.member = yyvsp[-2].member;
+                       }
+break;
+case 77:
+#line 519 "gram.y"
+{
+                           char *s;
+                           if ((s = alias_add(yyvsp[-2].string, RUNASALIAS, yyvsp[0].member)) != NULL) {
+                               yyerror(s);
+                               YYERROR;
+                           }
+                       }
+break;
+case 80:
+#line 532 "gram.y"
+{
+                           char *s;
+                           if ((s = alias_add(yyvsp[-2].string, USERALIAS, yyvsp[0].member)) != NULL) {
+                               yyerror(s);
+                               YYERROR;
+                           }
+                       }
+break;
+case 82:
+#line 542 "gram.y"
+{
+                           list_append(yyvsp[-2].member, yyvsp[0].member);
+                           yyval.member = yyvsp[-2].member;
+                       }
+break;
+case 83:
+#line 548 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = FALSE;
+                       }
+break;
+case 84:
+#line 552 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = TRUE;
+                       }
+break;
+case 85:
+#line 558 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, ALIAS);
+                       }
+break;
+case 86:
+#line 561 "gram.y"
+{
+                           yyval.member = new_member(NULL, ALL);
+                       }
+break;
+case 87:
+#line 564 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, NETGROUP);
+                       }
+break;
+case 88:
+#line 567 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, USERGROUP);
+                       }
+break;
+case 89:
+#line 570 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, WORD);
+                       }
+break;
+case 91:
+#line 576 "gram.y"
+{
+                           list_append(yyvsp[-2].member, yyvsp[0].member);
+                           yyval.member = yyvsp[-2].member;
+                       }
+break;
+case 92:
+#line 582 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = FALSE;
+                       }
+break;
+case 93:
+#line 586 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = TRUE;
+                       }
+break;
+case 94:
+#line 592 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, ALIAS);
+                       }
+break;
+case 95:
+#line 595 "gram.y"
+{
+                           yyval.member = new_member(NULL, ALL);
+                       }
+break;
+case 96:
+#line 598 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, WORD);
+                       }
+break;
+#line 1529 "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/plugins/sudoers/gram.h b/plugins/sudoers/gram.h
new file mode 100644 (file)
index 0000000..2bec420
--- /dev/null
@@ -0,0 +1,47 @@
+#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 LOG_INPUT 275
+#define NOLOG_INPUT 276
+#define LOG_OUTPUT 277
+#define NOLOG_OUTPUT 278
+#define ALL 279
+#define COMMENT 280
+#define HOSTALIAS 281
+#define CMNDALIAS 282
+#define USERALIAS 283
+#define RUNASALIAS 284
+#define ERROR 285
+#define TYPE 286
+#define ROLE 287
+#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/plugins/sudoers/gram.y b/plugins/sudoers/gram.y
new file mode 100644 (file)
index 0000000..b1eed89
--- /dev/null
@@ -0,0 +1,780 @@
+%{
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2011
+ *     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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_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 "sudoers.h" /* XXX */
+#include "parse.h"
+#include "toke.h"
+
+/*
+ * 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(int, struct member *, struct defaults *);
+static void  add_userspec(struct member *, struct privilege *);
+static struct defaults *new_default(char *, char *, int);
+static struct member *new_member(char *, int);
+       void  yyerror(const char *);
+
+void
+yyerror(const char *s)
+{
+    /* Save the line the first error occurred on. */
+    if (errorlineno == -1) {
+       errorlineno = sudolineno ? sudolineno - 1 : 0;
+       errorfile = estrdup(sudoers);
+    }
+    if (trace_print != NULL) {
+       LEXTRACE("<*> ");
+    } else if (verbose && s != NULL) {
+       warningx(">>> %s: %s near line %d <<<", sudoers, s,
+           sudolineno ? sudolineno - 1 : 0);
+    }
+    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>    LOG_INPUT              /* log user's cmnd input */
+%token <tok>    NOLOG_INPUT            /* don't log user's cmnd input */
+%token <tok>    LOG_OUTPUT             /* log cmnd output */
+%token <tok>    NOLOG_OUTPUT           /* don't log cmnd output */
+%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 ($3->tags.log_input == UNSPEC)
+                               $3->tags.log_input = $3->prev->tags.log_input;
+                           if ($3->tags.log_output == UNSPEC)
+                               $3->tags.log_output = $3->prev->tags.log_output;
+                           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 =
+                               $$.log_input = $$.log_output = 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;
+                       }
+               |       cmndtag LOG_INPUT {
+                           $$.log_input = TRUE;
+                       }
+               |       cmndtag NOLOG_INPUT {
+                           $$.log_input = FALSE;
+                       }
+               |       cmndtag LOG_OUTPUT {
+                           $$.log_output = TRUE;
+                       }
+               |       cmndtag NOLOG_OUTPUT {
+                           $$.log_output = 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(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(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(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(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(const 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();
+
+    init_lexer();
+
+    efree(sudoers);
+    sudoers = path ? estrdup(path) : NULL;
+
+    parse_error = FALSE;
+    errorlineno = -1;
+    errorfile = NULL;
+    verbose = !quiet;
+}
diff --git a/plugins/sudoers/group_plugin.c b/plugins/sudoers/group_plugin.c
new file mode 100644 (file)
index 0000000..bd5203a
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2010 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>
+
+#if defined(HAVE_DLOPEN) || defined(HAVE_SHL_LOAD)
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#ifdef HAVE_DLOPEN
+# include <dlfcn.h>
+#else
+# include "compat/dlfcn.h"
+#endif
+#include <ctype.h>
+#include <errno.h>
+#include <pwd.h>
+
+#include "sudoers.h"
+
+#ifndef RTLD_LOCAL
+# define RTLD_LOCAL    0
+#endif
+
+static void *group_handle;
+static struct sudoers_group_plugin *group_plugin;
+
+/*
+ * Load the specified plugin and run its init function.
+ * Returns -1 if unable to open the plugin, else it returns
+ * the value from the plugin's init function.
+ */
+int
+group_plugin_load(char *plugin_info)
+{
+    struct stat sb;
+    char *args, path[PATH_MAX];
+    char **argv = NULL;
+    int len, rc = -1;
+
+    /*
+     * Fill in .so path and split out args (if any).
+     */
+    args = strpbrk(plugin_info, " \t");
+    if ((args = strpbrk(plugin_info, " \t")) != NULL) {
+       len = snprintf(path, sizeof(path), "%s%.*s",
+           (*plugin_info != '/') ? _PATH_SUDO_PLUGIN_DIR : "",
+           (int)(args - plugin_info), plugin_info);
+       args++;
+    } else {
+       len = snprintf(path, sizeof(path), "%s%s",
+           (*plugin_info != '/') ? _PATH_SUDO_PLUGIN_DIR : "", plugin_info);
+    }
+    if (len <= 0 || len >= sizeof(path)) {
+       warningx("%s%s: %s",
+           (*plugin_info != '/') ? _PATH_SUDO_PLUGIN_DIR : "", plugin_info,
+           strerror(ENAMETOOLONG));
+       goto done;
+    }
+
+    /* Sanity check plugin path. */
+    if (stat(path, &sb) != 0) {
+       warning("%s", path);
+       goto done;
+    }
+    if (sb.st_uid != ROOT_UID) {
+       warningx("%s must be owned by uid %d", path, ROOT_UID);
+       goto done;
+    }
+    if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
+       warningx("%s must be only be writable by owner", path);
+       goto done;
+    }
+
+    /* Open plugin and map in symbol. */
+    group_handle = dlopen(path, RTLD_LAZY|RTLD_LOCAL);
+    if (!group_handle) {
+       warningx("unable to dlopen %s: %s", path, dlerror());
+       goto done;
+    }
+    group_plugin = dlsym(group_handle, "group_plugin");
+    if (group_plugin == NULL) {
+       warningx("unable to find symbol \"group_plugin\" in %s", path);
+       goto done;
+    }
+
+    if (GROUP_API_VERSION_GET_MAJOR(group_plugin->version) != GROUP_API_VERSION_MAJOR) {
+       warningx("%s: incompatible group plugin major version %d, expected %d",
+           path, GROUP_API_VERSION_GET_MAJOR(group_plugin->version),
+           GROUP_API_VERSION_MAJOR);
+       goto done;
+    }
+
+    /*
+     * Split args into a vector if specified.
+     */
+    if (args != NULL) {
+       int ac = 0, wasblank = TRUE;
+       char *cp;
+
+        for (cp = args; *cp != '\0'; cp++) {
+            if (isblank((unsigned char)*cp)) {
+                wasblank = TRUE;
+            } else if (wasblank) {
+                wasblank = FALSE;
+                ac++;
+            }
+        }
+       if (ac != 0)    {
+           argv = emalloc2(ac, sizeof(char *));
+           ac = 0;
+           for ((cp = strtok(args, " \t")); cp; (cp = strtok(NULL, " \t")))
+               argv[ac++] = cp;
+       }
+    }
+
+    rc = (group_plugin->init)(GROUP_API_VERSION, sudo_printf, argv);
+
+done:
+    efree(argv);
+
+    if (rc != TRUE) {
+       if (group_handle != NULL) {
+           dlclose(group_handle);
+           group_handle = NULL;
+           group_plugin = NULL;
+       }
+    }
+
+    return rc;
+}
+
+void
+group_plugin_unload(void)
+{
+    if (group_plugin != NULL) {
+       (group_plugin->cleanup)();
+       group_plugin = NULL;
+    }
+    if (group_handle != NULL) {
+       dlclose(group_handle);
+       group_handle = NULL;
+    }
+}
+
+int
+group_plugin_query(const char *user, const char *group,
+    const struct passwd *pwd)
+{
+    if (group_plugin == NULL)
+       return FALSE;
+    return (group_plugin->query)(user, group, pwd);
+}
+
+#else /* !HAVE_DLOPEN && !HAVE_SHL_LOAD */
+
+/*
+ * No loadable shared object support.
+ */
+
+#ifndef FALSE
+#define FALSE  0
+#endif
+
+struct passwd;
+
+int
+group_plugin_load(char *plugin_info)
+{
+    return FALSE;
+}
+
+void
+group_plugin_unload(void)
+{
+    return;
+}
+
+int
+group_plugin_query(const char *user, const char *group,
+    const struct passwd *pwd)
+{
+    return FALSE;
+}
+
+#endif /* HAVE_DLOPEN || HAVE_SHL_LOAD */
diff --git a/plugins/sudoers/ins_2001.h b/plugins/sudoers/ins_2001.h
new file mode 100644 (file)
index 0000000..63a5d64
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 1996, 1998, 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.
+ */
+
+#ifndef _SUDO_INS_2001_H
+#define _SUDO_INS_2001_H
+
+    /*
+     * HAL insults (paraphrased) from 2001.
+     */
+
+    "Just what do you think you're doing Dave?",
+    "It can only be attributed to human error.",
+    "That's something I cannot allow to happen.",
+    "My mind is going. I can feel it.",
+    "Sorry about this, I know it's a bit silly.",
+    "Take a stress pill and think things over.",
+    "This mission is too important for me to allow you to jeopardize it.",
+    "I feel much better now.",
+
+#endif /* _SUDO_INS_2001_H */
diff --git a/plugins/sudoers/ins_classic.h b/plugins/sudoers/ins_classic.h
new file mode 100644 (file)
index 0000000..b1942bd
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1996, 1998, 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.
+ */
+
+#ifndef _SUDO_INS_CLASSIC_H
+#define _SUDO_INS_CLASSIC_H
+
+    /*
+     * Insults from the original sudo(8).
+     */
+
+    "Wrong!  You cheating scum!",
+#ifdef PC_INSULTS
+    "And you call yourself a Rocket Scientist!",
+#else
+    "No soap, honkie-lips.",
+#endif
+    "Where did you learn to type?",
+    "Are you on drugs?",
+    "My pet ferret can type better than you!",
+    "You type like i drive.",
+    "Do you think like you type?",
+    "Your mind just hasn't been the same since the electro-shock, has it?",
+
+#endif /* _SUDO_INS_CLASSIC_H */
diff --git a/plugins/sudoers/ins_csops.h b/plugins/sudoers/ins_csops.h
new file mode 100644 (file)
index 0000000..20e9b02
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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
+ * 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.
+ */
+
+#ifndef _SUDO_INS_CSOPS_H
+#define _SUDO_INS_CSOPS_H
+
+    /*
+     * CSOps insults (may be site dependent).
+     */
+
+    "Maybe if you used more than just two fingers...",
+    "BOB says:  You seem to have forgotten your passwd, enter another!",
+    "stty: unknown mode: doofus",
+    "I can't hear you -- I'm using the scrambler.",
+    "The more you drive -- the dumber you get.",
+#ifdef PC_INSULTS
+    "Listen, broccoli brains, I don't have time to listen to this trash.",
+#else
+    "Listen, burrito brains, I don't have time to listen to this trash.",
+#endif
+    "I've seen penguins that can type better than that.",
+    "Have you considered trying to match wits with a rutabaga?",
+    "You speak an infinite deal of nothing",
+
+#endif /* _SUDO_INS_CSOPS_H */
diff --git a/plugins/sudoers/ins_goons.h b/plugins/sudoers/ins_goons.h
new file mode 100644 (file)
index 0000000..16a262a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1996, 1998, 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.
+ */
+
+#ifndef _SUDO_INS_GOONS_H
+#define _SUDO_INS_GOONS_H
+
+    /*
+     * Insults from the "Goon Show."
+     */
+
+    "You silly, twisted boy you.",
+    "He has fallen in the water!",
+    "We'll all be murdered in our beds!",
+    "You can't come in. Our tiger has got flu",
+    "I don't wish to know that.",
+    "What, what, what, what, what, what, what, what, what, what?",
+    "You can't get the wood, you know.",
+    "You'll starve!",
+    "... and it used to be so popular...",
+    "Pauses for audience applause, not a sausage",
+    "Hold it up to the light --- not a brain in sight!",
+    "Have a gorilla...",
+    "There must be cure for it!",
+    "There's a lot of it about, you know.",
+    "You do that again and see what happens...",
+    "Ying Tong Iddle I Po",
+    "Harm can come to a young lad like that!",
+    "And with that remarks folks, the case of the Crown vs yourself was proven.",
+    "Speak English you fool --- there are no subtitles in this scene.",
+    "You gotta go owwwww!",
+    "I have been called worse.",
+    "It's only your word against mine.",
+    "I think ... err ... I think ... I think I'll go home",
+
+#endif /* _SUDO_INS_GOONS_H */
diff --git a/plugins/sudoers/insults.h b/plugins/sudoers/insults.h
new file mode 100644 (file)
index 0000000..bdb3fc6
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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
+ * 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.
+ */
+
+#ifndef _SUDO_INSULTS_H
+#define _SUDO_INSULTS_H
+
+#if defined(HAL_INSULTS) || defined(GOONS_INSULTS) || defined(CLASSIC_INSULTS) || defined(CSOPS_INSULTS)
+
+/*
+ * Use one or more set of insults as determined by configure
+ */
+
+char *insults[] = {
+
+# ifdef HAL_INSULTS
+#  include "ins_2001.h"
+# endif
+
+# ifdef GOONS_INSULTS
+#  include "ins_goons.h"
+# endif
+
+# ifdef CLASSIC_INSULTS
+#  include "ins_classic.h"
+# endif
+
+# ifdef CSOPS_INSULTS
+#  include "ins_csops.h"
+# endif
+
+    (char *) 0
+
+};
+
+/*
+ * How may I insult you?  Let me count the ways...
+ */
+#define NOFINSULTS (sizeof(insults) / sizeof(insults[0]) - 1)
+
+/*
+ * return a pseudo-random insult.
+ */
+#define INSULT         (insults[time(NULL) % NOFINSULTS])
+
+#endif /* HAL_INSULTS || GOONS_INSULTS || CLASSIC_INSULTS || CSOPS_INSULTS */
+
+#endif /* _SUDO_INSULTS_H */
diff --git a/plugins/sudoers/interfaces.c b/plugins/sudoers/interfaces.c
new file mode 100644 (file)
index 0000000..acf0568
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2010 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/socket.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <netinet/in.h>  
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+
+#include "sudoers.h"
+#include "interfaces.h"
+
+#ifndef INADDR_NONE
+# define INADDR_NONE ((unsigned int)-1)
+#endif
+
+/*
+ * Parse a space-delimited list of IP address/netmask pairs and
+ * store in a list of interface structures.
+ */
+void
+set_interfaces(const char *ai)
+{
+    char *addrinfo, *addr, *mask;
+    struct interface *ifp;
+
+    addrinfo = estrdup(ai);
+    for (addr = strtok(addrinfo, " \t"); addr != NULL; addr = strtok(NULL, " \t")) {
+       /* Separate addr and mask. */
+       if ((mask = strchr(addr, '/')) == NULL)
+           continue;
+       *mask++ = '\0';
+
+       /* Parse addr and store in list. */
+       ifp = emalloc(sizeof(*ifp));
+       if (strchr(addr, ':')) {
+           /* IPv6 */
+#ifdef HAVE_IN6_ADDR
+           ifp->family = AF_INET6;
+           if (inet_pton(AF_INET6, addr, &ifp->addr.ip6) != 1 ||
+               inet_pton(AF_INET6, mask, &ifp->netmask.ip6) != 1)
+#endif
+           {
+               efree(ifp);
+               continue;
+           }
+       } else {
+           /* IPv4 */
+           ifp->family = AF_INET;
+           ifp->addr.ip4.s_addr = inet_addr(addr);
+           ifp->netmask.ip4.s_addr = inet_addr(mask);
+           if (ifp->addr.ip4.s_addr == INADDR_NONE ||
+               ifp->netmask.ip4.s_addr == INADDR_NONE) {
+               efree(ifp);
+               continue;
+           }
+       }
+       ifp->next = interfaces;
+       interfaces = ifp;
+    }
+    efree(addrinfo);
+}
+
+void
+dump_interfaces(const char *ai)
+{
+    char *cp, *addrinfo;
+
+    addrinfo = estrdup(ai);
+
+    sudo_printf(SUDO_CONV_INFO_MSG, "Local IP address and netmask pairs:\n");
+    for (cp = strtok(addrinfo, " \t"); cp != NULL; cp = strtok(NULL, " \t"))
+       sudo_printf(SUDO_CONV_INFO_MSG, "\t%s\n", cp);
+
+    efree(addrinfo);
+}
diff --git a/plugins/sudoers/interfaces.h b/plugins/sudoers/interfaces.h
new file mode 100644 (file)
index 0000000..234d31d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2007, 2010
+ *     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.
+ */
+
+#ifndef _SUDO_INTERFACES_H
+#define _SUDO_INTERFACES_H
+
+/*
+ * Union to hold either strucr in_addr or in6_add
+ */
+union sudo_in_addr_un {
+    struct in_addr ip4;
+#ifdef HAVE_IN6_ADDR
+    struct in6_addr ip6;
+#endif
+};
+
+/*
+ * IP address and netmask pairs for checking against local interfaces.
+ */
+struct interface {
+    int family;        /* AF_INET or AF_INET6 */
+    union sudo_in_addr_un addr;
+    union sudo_in_addr_un netmask;
+    struct interface *next;
+};
+
+/*
+ * Prototypes for external functions.
+ */
+int get_net_ifs(char **addrinfo);
+void dump_interfaces(const char *);
+void set_interfaces(const char *);
+
+/*
+ * Definitions for external variables.
+ */
+#ifndef _SUDO_MAIN
+extern struct interface *interfaces;
+#endif
+
+#endif /* _SUDO_INTERFACES_H */
diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c
new file mode 100644 (file)
index 0000000..903aedf
--- /dev/null
@@ -0,0 +1,670 @@
+/*
+ * Copyright (c) 2009-2011 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 <sys/stat.h>
+#include <sys/time.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <pwd.h>
+#include <grp.h>
+#ifdef HAVE_ZLIB_H
+# include <zlib.h>
+#endif
+
+#include "sudoers.h"
+
+/* plugin_error.c */
+extern sigjmp_buf error_jmp;
+
+union io_fd {
+    FILE *f;
+#ifdef HAVE_ZLIB_H
+    gzFile g;
+#endif
+    void *v;
+};
+
+struct script_buf {
+    int len; /* buffer length (how much read in) */
+    int off; /* write position (how much already consumed) */
+    char buf[16 * 1024];
+};
+
+/* XXX - separate sudoers.h and iolog.h? */
+#undef runas_pw
+#undef runas_gr
+
+struct iolog_details {
+    const char *cwd;
+    const char *tty;
+    const char *user;
+    const char *command;
+    const char *iolog_path;
+    struct passwd *runas_pw;
+    struct group *runas_gr;
+    int iolog_stdin;
+    int iolog_stdout;
+    int iolog_stderr;
+    int iolog_ttyin;
+    int iolog_ttyout;
+};
+
+#define IOFD_STDIN     0
+#define IOFD_STDOUT    1
+#define IOFD_STDERR    2
+#define IOFD_TTYIN     3
+#define IOFD_TTYOUT    4
+#define IOFD_TIMING    5
+#define IOFD_MAX       6
+
+#define SESSID_MAX     2176782336U
+
+static int iolog_compress;
+static struct timeval last_time;
+static union io_fd io_fds[IOFD_MAX];
+extern struct io_plugin sudoers_io;
+
+/*
+ * Create parent directories for path as needed, but not path itself.
+ */
+static void
+mkdir_parents(char *path)
+{
+    struct stat sb;
+    char *slash = path;
+
+    for (;;) {
+       if ((slash = strchr(slash + 1, '/')) == NULL)
+           break;
+       *slash = '\0';
+       if (stat(path, &sb) != 0) {
+           if (mkdir(path, S_IRWXU) != 0)
+               log_error(USE_ERRNO, "Can't mkdir %s", path);
+       } else if (!S_ISDIR(sb.st_mode)) {
+           log_error(0, "%s: %s", path, strerror(ENOTDIR));
+       }
+       *slash = '/';
+    }
+}
+
+/*
+ * Read the on-disk sequence number, set sessid to the next
+ * number, and update the on-disk copy.
+ * Uses file locking to avoid sequence number collisions.
+ */
+void
+io_nextid(char *iolog_dir, char sessid[7])
+{
+    struct stat sb;
+    char buf[32], *ep;
+    int fd, i;
+    unsigned long id = 0;
+    int len;
+    ssize_t nread;
+    char pathbuf[PATH_MAX];
+    static const char b36char[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+    /*
+     * Create I/O log directory if it doesn't already exist.
+     */
+    mkdir_parents(iolog_dir);
+    if (stat(iolog_dir, &sb) != 0) {
+       if (mkdir(iolog_dir, S_IRWXU) != 0)
+           log_error(USE_ERRNO, "Can't mkdir %s", iolog_dir);
+    } else if (!S_ISDIR(sb.st_mode)) {
+       log_error(0, "%s exists but is not a directory (0%o)",
+           iolog_dir, (unsigned int) sb.st_mode);
+    }
+
+    /*
+     * Open sequence file
+     */
+    len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", iolog_dir);
+    if (len <= 0 || len >= sizeof(pathbuf)) {
+       errno = ENAMETOOLONG;
+       log_error(USE_ERRNO, "%s/seq", pathbuf);
+    }
+    fd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
+    if (fd == -1)
+       log_error(USE_ERRNO, "cannot open %s", pathbuf);
+    lock_file(fd, SUDO_LOCK);
+
+    /* Read seq number (base 36). */
+    nread = read(fd, buf, sizeof(buf));
+    if (nread != 0) {
+       if (nread == -1)
+           log_error(USE_ERRNO, "cannot read %s", pathbuf);
+       id = strtoul(buf, &ep, 36);
+       if (buf == ep || id >= SESSID_MAX)
+           log_error(0, "invalid sequence number %s", pathbuf);
+    }
+    id++;
+
+    /*
+     * Convert id to a string and stash in sessid.
+     * Note that that least significant digits go at the end of the string.
+     */
+    for (i = 5; i >= 0; i--) {
+       buf[i] = b36char[id % 36];
+       id /= 36;
+    }
+    buf[6] = '\n';
+
+    /* Stash id logging purposes */
+    memcpy(sessid, buf, 6);
+    sessid[6] = '\0';
+
+    /* Rewind and overwrite old seq file. */
+    if (lseek(fd, 0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7)
+       log_error(USE_ERRNO, "Can't write to %s", pathbuf);
+    close(fd);
+}
+
+/*
+ * Copy iolog_path to pathbuf and create the directory and any intermediate
+ * directories.  If iolog_path ends in 'XXXXXX', use mkdtemp().
+ */
+static size_t
+mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize)
+{
+    size_t len;
+
+    len = strlcpy(pathbuf, iolog_path, pathsize);
+    if (len >= pathsize) {
+       errno = ENAMETOOLONG;
+       log_error(USE_ERRNO, "%s", iolog_path);
+    }
+
+    /*
+     * Create path and intermediate subdirs as needed.
+     * If path ends in at least 6 Xs (ala POSIX mktemp), use mkdtemp().
+     */
+    mkdir_parents(pathbuf);
+    if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0) {
+       if (mkdtemp(pathbuf) == NULL)
+           log_error(USE_ERRNO, "Can't create %s", pathbuf);
+    } else {
+       if (mkdir(pathbuf, S_IRWXU) != 0)
+           log_error(USE_ERRNO, "Can't create %s", pathbuf);
+    }
+
+    return len;
+}
+
+/*
+ * Append suffix to pathbuf after len chars and open the resulting file.
+ * Note that the size of pathbuf is assumed to be PATH_MAX.
+ * Uses zlib if docompress is TRUE.
+ * Returns the open file handle which has the close-on-exec flag set.
+ */
+static void *
+open_io_fd(char *pathbuf, size_t len, const char *suffix, int docompress)
+{
+    void *vfd = NULL;
+    int fd;
+
+    pathbuf[len] = '\0';
+    strlcat(pathbuf, suffix, PATH_MAX);
+    fd = open(pathbuf, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
+    if (fd != -1) {
+       fcntl(fd, F_SETFD, FD_CLOEXEC);
+#ifdef HAVE_ZLIB_H
+       if (docompress)
+           vfd = gzdopen(fd, "w");
+       else
+#endif
+           vfd = fdopen(fd, "w");
+    }
+    return vfd;
+}
+
+/*
+ * Pull out I/O log related data from user_info and command_info arrays.
+ */
+static void
+iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
+    char * const command_info[])
+{
+    const char *runas_uid_str = "0", *runas_euid_str = NULL;
+    const char *runas_gid_str = "0", *runas_egid_str = NULL;
+    char id[MAX_UID_T_LEN + 2], *ep;
+    char * const *cur;
+    unsigned long ulval;
+    uid_t runas_uid = 0;
+    gid_t runas_gid = 0;
+
+    memset(details, 0, sizeof(*details));
+
+    for (cur = user_info; *cur != NULL; cur++) {
+       switch (**cur) {
+       case 'c':
+           if (strncmp(*cur, "cwd=", sizeof("cwd=") - 1) == 0) {
+               details->cwd = *cur + sizeof("cwd=") - 1;
+               continue;
+           }
+           break;
+       case 't':
+           if (strncmp(*cur, "tty=", sizeof("tty=") - 1) == 0) {
+               details->tty = *cur + sizeof("tty=") - 1;
+               continue;
+           }
+           break;
+       case 'u':
+           if (strncmp(*cur, "user=", sizeof("user=") - 1) == 0) {
+               details->user = *cur + sizeof("user=") - 1;
+               continue;
+           }
+           break;
+       }
+    }
+
+    for (cur = command_info; *cur != NULL; cur++) {
+       switch (**cur) {
+       case 'c':
+           if (strncmp(*cur, "command=", sizeof("command=") - 1) == 0) {
+               details->command = *cur + sizeof("command=") - 1;
+               continue;
+           }
+           break;
+       case 'i':
+           if (strncmp(*cur, "iolog_path=", sizeof("iolog_path=") - 1) == 0) {
+               details->iolog_path = *cur + sizeof("iolog_path=") - 1;
+               continue;
+           }
+           if (strncmp(*cur, "iolog_stdin=", sizeof("iolog_stdin=") - 1) == 0) {
+               if (atobool(*cur + sizeof("iolog_stdin=") - 1) == TRUE)
+                   details->iolog_stdin = TRUE;
+               continue;
+           }
+           if (strncmp(*cur, "iolog_stdout=", sizeof("iolog_stdout=") - 1) == 0) {
+               if (atobool(*cur + sizeof("iolog_stdout=") - 1) == TRUE)
+                   details->iolog_stdout = TRUE;
+               continue;
+           }
+           if (strncmp(*cur, "iolog_stderr=", sizeof("iolog_stderr=") - 1) == 0) {
+               if (atobool(*cur + sizeof("iolog_stderr=") - 1) == TRUE)
+                   details->iolog_stderr = TRUE;
+               continue;
+           }
+           if (strncmp(*cur, "iolog_ttyin=", sizeof("iolog_ttyin=") - 1) == 0) {
+               if (atobool(*cur + sizeof("iolog_ttyin=") - 1) == TRUE)
+                   details->iolog_ttyin = TRUE;
+               continue;
+           }
+           if (strncmp(*cur, "iolog_ttyout=", sizeof("iolog_ttyout=") - 1) == 0) {
+               if (atobool(*cur + sizeof("iolog_ttyout=") - 1) == TRUE)
+                   details->iolog_ttyout = TRUE;
+               continue;
+           }
+           if (strncmp(*cur, "iolog_compress=", sizeof("iolog_compress=") - 1) == 0) {
+               if (atobool(*cur + sizeof("iolog_compress=") - 1) == TRUE)
+                   iolog_compress = TRUE; /* must be global */
+               continue;
+           }
+           break;
+       case 'r':
+           if (strncmp(*cur, "runas_gid=", sizeof("runas_gid=") - 1) == 0) {
+               runas_gid_str = *cur + sizeof("runas_gid=") - 1;
+               continue;
+           }
+           if (strncmp(*cur, "runas_egid=", sizeof("runas_egid=") - 1) == 0) {
+               runas_egid_str = *cur + sizeof("runas_egid=") - 1;
+               continue;
+           }
+           if (strncmp(*cur, "runas_uid=", sizeof("runas_uid=") - 1) == 0) {
+               runas_uid_str = *cur + sizeof("runas_uid=") - 1;
+               continue;
+           }
+           if (strncmp(*cur, "runas_euid=", sizeof("runas_euid=") - 1) == 0) {
+               runas_euid_str = *cur + sizeof("runas_euid=") - 1;
+               continue;
+           }
+           break;
+       }
+    }
+
+    /*
+     * Lookup runas user and group, preferring effective over real uid/gid.
+     */
+    if (runas_euid_str != NULL)
+       runas_uid_str = runas_euid_str;
+    if (runas_uid_str != NULL) {
+       errno = 0;
+       ulval = strtoul(runas_uid_str, &ep, 0);
+       if (*runas_uid_str != '\0' && *ep == '\0' &&
+           (errno != ERANGE || ulval != ULONG_MAX)) {
+           runas_uid = (uid_t)ulval;
+       }
+    }
+    if (runas_egid_str != NULL)
+       runas_gid_str = runas_egid_str;
+    if (runas_gid_str != NULL) {
+       errno = 0;
+       ulval = strtoul(runas_gid_str, &ep, 0);
+       if (*runas_gid_str != '\0' && *ep == '\0' &&
+           (errno != ERANGE || ulval != ULONG_MAX)) {
+           runas_gid = (gid_t)ulval;
+       }
+    }
+
+    details->runas_pw = sudo_getpwuid(runas_uid);
+    if (details->runas_pw == NULL) {
+       id[0] = '#';
+       strlcpy(&id[1], runas_uid_str, sizeof(id) - 1);
+       details->runas_pw = sudo_fakepwnam(id, runas_gid);
+    }
+
+    if (runas_gid != details->runas_pw->pw_gid) {
+       details->runas_gr = sudo_getgrgid(runas_gid);
+       if (details->runas_gr == NULL) {
+           id[0] = '#';
+           strlcpy(&id[1], runas_gid_str, sizeof(id) - 1);
+           details->runas_gr = sudo_fakegrnam(id);
+       }
+    }
+}
+
+static int
+sudoers_io_open(unsigned int version, sudo_conv_t conversation,
+    sudo_printf_t plugin_printf, char * const settings[],
+    char * const user_info[], char * const command_info[],
+    int argc, char * const argv[], char * const user_env[])
+{
+    struct iolog_details details;
+    char pathbuf[PATH_MAX], sessid[7];
+    char *tofree = NULL;
+    char * const *cur;
+    FILE *io_logfile;
+    size_t len;
+    int rval = -1;
+
+    if (!sudo_conv)
+       sudo_conv = conversation;
+    if (!sudo_printf)
+       sudo_printf = plugin_printf;
+
+    /* If we have no command (because -V was specified) just return. */
+    if (argc == 0)
+       return TRUE;
+
+    if (sigsetjmp(error_jmp, 1)) {
+       /* called via error(), errorx() or log_error() */
+       rval = -1;
+       goto done;
+    }
+
+    sudo_setpwent();
+    sudo_setgrent();
+
+    /*
+     * Pull iolog settings out of command_info, if any.
+     */
+    iolog_deserialize_info(&details, user_info, command_info);
+    /* Did policy module disable I/O logging? */
+    if (!details.iolog_stdin && !details.iolog_ttyin &&
+       !details.iolog_stdout && !details.iolog_stderr &&
+       !details.iolog_ttyout) {
+       rval = FALSE;
+       goto done;
+    }
+
+    /* If no I/O log path defined we need to figure it out ourselves. */
+    if (details.iolog_path == NULL) {
+       /* Get next session ID and convert it into a path. */
+       tofree = emalloc(sizeof(_PATH_SUDO_IO_LOGDIR) + sizeof(sessid) + 2);
+       memcpy(tofree, _PATH_SUDO_IO_LOGDIR, sizeof(_PATH_SUDO_IO_LOGDIR));
+       io_nextid(tofree, sessid);
+       snprintf(tofree + sizeof(_PATH_SUDO_IO_LOGDIR), sizeof(sessid) + 2,
+           "%c%c/%c%c/%c%c", sessid[0], sessid[1], sessid[2], sessid[3],
+           sessid[4], sessid[5]);
+       details.iolog_path = tofree;
+    }
+
+    /*
+     * Make local copy of I/O log path and create it, along with any
+     * intermediate subdirs.  Calls mkdtemp() if iolog_path ends in XXXXXX.
+     */
+    len = mkdir_iopath(details.iolog_path, pathbuf, sizeof(pathbuf));
+    if (len >= sizeof(pathbuf))
+       goto done;
+
+    /*
+     * We create 7 files: a log file, a timing file and 5 for input/output.
+     */
+    io_logfile = open_io_fd(pathbuf, len, "/log", FALSE);
+    if (io_logfile == NULL)
+       log_error(USE_ERRNO, "Can't create %s", pathbuf);
+
+    io_fds[IOFD_TIMING].v = open_io_fd(pathbuf, len, "/timing",
+       iolog_compress);
+    if (io_fds[IOFD_TIMING].v == NULL)
+       log_error(USE_ERRNO, "Can't create %s", pathbuf);
+
+    if (details.iolog_ttyin) {
+       io_fds[IOFD_TTYIN].v = open_io_fd(pathbuf, len, "/ttyin",
+           iolog_compress);
+       if (io_fds[IOFD_TTYIN].v == NULL)
+           log_error(USE_ERRNO, "Can't create %s", pathbuf);
+    } else {
+       sudoers_io.log_ttyin = NULL;
+    }
+    if (details.iolog_stdin) {
+       io_fds[IOFD_STDIN].v = open_io_fd(pathbuf, len, "/stdin",
+           iolog_compress);
+       if (io_fds[IOFD_STDIN].v == NULL)
+           log_error(USE_ERRNO, "Can't create %s", pathbuf);
+    } else {
+       sudoers_io.log_stdin = NULL;
+    }
+    if (details.iolog_ttyout) {
+       io_fds[IOFD_TTYOUT].v = open_io_fd(pathbuf, len, "/ttyout",
+           iolog_compress);
+       if (io_fds[IOFD_TTYOUT].v == NULL)
+           log_error(USE_ERRNO, "Can't create %s", pathbuf);
+    } else {
+       sudoers_io.log_ttyout = NULL;
+    }
+    if (details.iolog_stdout) {
+       io_fds[IOFD_STDOUT].v = open_io_fd(pathbuf, len, "/stdout",
+           iolog_compress);
+       if (io_fds[IOFD_STDOUT].v == NULL)
+           log_error(USE_ERRNO, "Can't create %s", pathbuf);
+    } else {
+       sudoers_io.log_stdout = NULL;
+    }
+    if (details.iolog_stderr) {
+       io_fds[IOFD_STDERR].v = open_io_fd(pathbuf, len, "/stderr",
+           iolog_compress);
+       if (io_fds[IOFD_STDERR].v == NULL)
+           log_error(USE_ERRNO, "Can't create %s", pathbuf);
+    } else {
+       sudoers_io.log_stderr = NULL;
+    }
+
+    gettimeofday(&last_time, NULL);
+
+    fprintf(io_logfile, "%ld:%s:%s:%s:%s\n", (long)last_time.tv_sec,
+       details.user ? details.user : "unknown", details.runas_pw->pw_name,
+       details.runas_gr ? details.runas_gr->gr_name : "",
+       details.tty ? details.tty : "unknown");
+    fputs(details.cwd ? details.cwd : "unknown", io_logfile);
+    fputc('\n', io_logfile);
+    fputs(details.command ? details.command : "unknown", io_logfile);
+    for (cur = &argv[1]; *cur != NULL; cur++) {
+       if (cur != &argv[1])
+           fputc(' ', io_logfile);
+       fputs(*cur, io_logfile);
+    }
+    fputc('\n', io_logfile);
+    fclose(io_logfile);
+
+    rval = TRUE;
+
+done:
+    efree(tofree);
+    if (details.runas_pw)
+       pw_delref(details.runas_pw);
+    sudo_endpwent();
+    if (details.runas_gr)
+       gr_delref(details.runas_gr);
+    sudo_endgrent();
+
+    return rval;
+}
+
+static void
+sudoers_io_close(int exit_status, int error)
+{
+    int i;
+
+    if (sigsetjmp(error_jmp, 1)) {
+       /* called via error(), errorx() or log_error() */
+       return;
+    }
+
+    for (i = 0; i < IOFD_MAX; i++) {
+       if (io_fds[i].v == NULL)
+           continue;
+#ifdef HAVE_ZLIB_H
+       if (iolog_compress)
+           gzclose(io_fds[i].g);
+       else
+#endif
+           fclose(io_fds[i].f);
+    }
+}
+
+static int
+sudoers_io_version(int verbose)
+{
+    if (sigsetjmp(error_jmp, 1)) {
+       /* called via error(), errorx() or log_error() */
+       return -1;
+    }
+
+    sudo_printf(SUDO_CONV_INFO_MSG, "Sudoers I/O plugin version %s\n",
+       PACKAGE_VERSION);
+
+    return TRUE;
+}
+
+/*
+ * Generic I/O logging function.  Called by the I/O logging entry points.
+ */
+static int
+sudoers_io_log(const char *buf, unsigned int len, int idx)
+{
+    struct timeval now, delay;
+
+    gettimeofday(&now, NULL);
+
+    if (sigsetjmp(error_jmp, 1)) {
+       /* called via error(), errorx() or log_error() */
+       return -1;
+    }
+
+#ifdef HAVE_ZLIB_H
+    if (iolog_compress)
+       gzwrite(io_fds[idx].g, buf, len);
+    else
+#endif
+       fwrite(buf, 1, len, io_fds[idx].f);
+    delay.tv_sec = now.tv_sec;
+    delay.tv_usec = now.tv_usec;
+    timevalsub(&delay, &last_time);
+#ifdef HAVE_ZLIB_H
+    if (iolog_compress)
+       gzprintf(io_fds[IOFD_TIMING].g, "%d %f %d\n", idx,
+           delay.tv_sec + ((double)delay.tv_usec / 1000000), len);
+    else
+#endif
+       fprintf(io_fds[IOFD_TIMING].f, "%d %f %d\n", idx,
+           delay.tv_sec + ((double)delay.tv_usec / 1000000), len);
+    last_time.tv_sec = now.tv_sec;
+    last_time.tv_usec = now.tv_usec;
+
+    return TRUE;
+}
+
+static int
+sudoers_io_log_ttyin(const char *buf, unsigned int len)
+{
+    return sudoers_io_log(buf, len, IOFD_TTYIN);
+}
+
+static int
+sudoers_io_log_ttyout(const char *buf, unsigned int len)
+{
+    return sudoers_io_log(buf, len, IOFD_TTYOUT);
+}
+
+static int
+sudoers_io_log_stdin(const char *buf, unsigned int len)
+{
+    return sudoers_io_log(buf, len, IOFD_STDIN);
+}
+
+static int
+sudoers_io_log_stdout(const char *buf, unsigned int len)
+{
+    return sudoers_io_log(buf, len, IOFD_STDOUT);
+}
+
+static int
+sudoers_io_log_stderr(const char *buf, unsigned int len)
+{
+    return sudoers_io_log(buf, len, IOFD_STDERR);
+}
+
+struct io_plugin sudoers_io = {
+    SUDO_IO_PLUGIN,
+    SUDO_API_VERSION,
+    sudoers_io_open,
+    sudoers_io_close,
+    sudoers_io_version,
+    sudoers_io_log_ttyin,
+    sudoers_io_log_ttyout,
+    sudoers_io_log_stdin,
+    sudoers_io_log_stdout,
+    sudoers_io_log_stderr
+};
diff --git a/plugins/sudoers/iolog_path.c b/plugins/sudoers/iolog_path.c
new file mode 100644 (file)
index 0000000..74f5fdf
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2011 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 <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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_SETLOCALE
+# include <locale.h>
+#endif
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+
+#include "sudoers.h"
+
+struct path_escape {
+    const char *name;
+    size_t (*copy_fn)(char *, size_t);
+};
+
+static size_t fill_seq(char *, size_t);
+static size_t fill_user(char *, size_t);
+static size_t fill_group(char *, size_t);
+static size_t fill_runas_user(char *, size_t);
+static size_t fill_runas_group(char *, size_t);
+static size_t fill_hostname(char *, size_t);
+static size_t fill_command(char *, size_t);
+
+static struct path_escape escapes[] = {
+    { "seq", fill_seq },
+    { "user", fill_user },
+    { "group", fill_group },
+    { "runas_user", fill_runas_user },
+    { "runas_group", fill_runas_group },
+    { "hostname", fill_hostname },
+    { "command", fill_command },
+    { NULL, NULL }
+};
+
+static size_t
+fill_seq(char *str, size_t strsize)
+{
+    static char sessid[7];
+    int len;
+
+    if (sessid[0] == '\0')
+       io_nextid(def_iolog_dir, sessid);
+
+    /* Path is of the form /var/log/sudo-io/00/00/01. */
+    len = snprintf(str, strsize, "%c%c/%c%c/%c%c", sessid[0],
+       sessid[1], sessid[2], sessid[3], sessid[4], sessid[5]);
+    if (len < 0)
+       return strsize; /* handle non-standard snprintf() */
+    return (size_t)len;
+}
+
+static size_t
+fill_user(char *str, size_t strsize)
+{
+    return strlcpy(str, user_name, strsize);
+}
+
+static size_t
+fill_group(char *str, size_t strsize)
+{
+    struct group *grp;
+    size_t len;
+
+    if ((grp = sudo_getgrgid(user_gid)) != NULL) {
+       len = strlcpy(str, grp->gr_name, strsize);
+       gr_delref(grp);
+    } else {
+       len = strlen(str);
+       len = snprintf(str + len, strsize - len, "#%u",
+           (unsigned int) user_gid);
+    }
+    return len;
+}
+
+static size_t
+fill_runas_user(char *str, size_t strsize)
+{
+    return strlcpy(str, runas_pw->pw_name, strsize);
+}
+
+static size_t
+fill_runas_group(char *str, size_t strsize)
+{
+    struct group *grp;
+    size_t len;
+
+    if (runas_gr != NULL) {
+       len = strlcpy(str, runas_gr->gr_name, strsize);
+    } else {
+       if ((grp = sudo_getgrgid(runas_pw->pw_gid)) != NULL) {
+           len = strlcpy(str, grp->gr_name, strsize);
+           gr_delref(grp);
+       } else {
+           len = strlen(str);
+           len = snprintf(str + len, strsize - len, "#%u",
+               (unsigned int) runas_pw->pw_gid);
+       }
+    }
+    return len;
+}
+
+static size_t
+fill_hostname(char *str, size_t strsize)
+{
+    return strlcpy(str, user_shost, strsize);
+}
+
+static size_t
+fill_command(char *str, size_t strsize)
+{
+    return strlcpy(str, user_base, strsize);
+}
+
+char *
+expand_iolog_path(const char *prefix, const char *dir, const char *file,
+    char **slashp)
+{
+    size_t plen = 0, psize = 1024;
+    char *path, *dst;
+    const char *src = dir, *ep;
+    int pass, strfit = FALSE;
+
+    /* Concatenate dir + file -> path, expanding any escape sequences. */
+    dst = path = emalloc(psize);
+    *path = '\0';
+
+    /* Trim leading slashes from file component. */
+    while (*file == '/')
+       file++;
+
+    if (prefix != NULL) {
+       plen = strlcpy(path, prefix, psize);
+       dst += plen;
+    }
+    for (pass = 0; pass < 3; pass++) {
+       switch (pass) {
+       case 0:
+           src = dir;
+           break;
+       case 1:
+           /* Trim trailing slashes from dir component. */
+           while (dst > path && dst[-1] == '/')
+               dst--;
+           if (slashp)
+               *slashp = dst;
+           src = "/";
+           break;
+       case 2:
+           src = file;
+           break;
+       }
+       for (; *src != '\0'; src++) {
+           if (src[0] == '%') {
+               if (src[1] == '{') {
+                   ep = strchr(src + 2, '}');
+                   if (ep != NULL) {
+                       struct path_escape *esc;
+                       size_t len = (size_t)(ep - src - 2);
+                       for (esc = escapes; esc->name != NULL; esc++) {
+                           if (strncmp(src + 2, esc->name, len) == 0 &&
+                               esc->name[len] == '\0')
+                               break;
+                       }
+                       if (esc->name != NULL) {
+                           for (;;) {
+                               len = esc->copy_fn(dst, psize - (dst - path));
+                               if (len < psize - (dst - path))
+                                   break;
+                               path = erealloc3(path, 2, psize);
+                               psize *= 2;
+                               dst = path + plen;
+                           }
+                           dst += len;
+                           plen += len;
+                           src = ep;
+                           continue;
+                       }
+                   }
+               } else if (src[1] == '%') {
+                   /* Collapse %% -> % */
+                   src++;
+               } else {
+                   /* May need strftime() */
+                   strfit = 1;
+               }
+           }
+           /* Need at least 2 chars, including the NUL terminator. */
+           if (plen + 2 >= psize) {
+               path = erealloc3(path, 2, psize);
+               psize *= 2;
+               dst = path + plen;
+           }
+           *dst++ = *src;
+           plen++;
+       }
+    }
+    *dst = '\0';
+
+    if (strfit) {
+       time_t now;
+       struct tm *timeptr;
+       char *buf = NULL;
+
+       time(&now);
+       timeptr = localtime(&now);
+
+#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
+       /* Double the size of the buffer until it is big enough to expand. */
+       do {
+           psize *= 2;
+           buf = erealloc(buf, psize);
+           buf[psize - 1] = '\0';
+       } while (!strftime(buf, psize, path, timeptr) || buf[psize - 1] != '\0');
+#ifdef HAVE_SETLOCALE
+       setlocale(LC_ALL, "");
+#endif
+       if (slashp)
+           *slashp = buf + (*slashp - path);
+       efree(path);
+       path = buf;
+    }
+
+    return path;
+}
diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c
new file mode 100644 (file)
index 0000000..8d64c35
--- /dev/null
@@ -0,0 +1,2474 @@
+/*
+ * Copyright (c) 2003-2011 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * This code is derived from software contributed by Aaron Spangler.
+ *
+ * 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/time.h>
+#include <sys/param.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#ifdef HAVE_LBER_H
+# include <lber.h>
+#endif
+#include <ldap.h>
+#if defined(HAVE_LDAP_SSL_H)
+# include <ldap_ssl.h>
+#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 "sudoers.h"
+#include "parse.h"
+#include "lbuf.h"
+
+#ifndef LDAP_OPT_SUCCESS
+# define LDAP_OPT_SUCCESS LDAP_SUCCESS
+#endif
+
+#ifndef LDAPS_PORT
+# define LDAPS_PORT 636
+#endif
+
+#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
+# ifdef HAVE_LDAP_SEARCH_ST
+#  define ldap_search_ext_s(a, b, c, d, e, f, g, h, i, j, k)           \
+       ldap_search_st(a, b, c, d, e, f, i, k)
+# else
+#  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
+#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
+#define CONF_STR       2
+#define CONF_LIST_STR  4
+
+#define SUDO_LDAP_SSL          1
+#define SUDO_LDAP_STARTTLS     2
+
+/* The TIMEFILTER_LENGTH includes the filter itself plus the global AND
+   wrapped around the user filter and the time filter when timed entries
+   are used. The length is computed as follows:
+       85       for the filter
+       + 2 * 13 for the now timestamp
+       +      3 for the global AND
+*/
+#define TIMEFILTER_LENGTH      114    
+
+/*
+ * The ldap_search structure implements a linked list of ldap and
+ * search result pointers, which allows us to remove them after
+ * all search results have been combined in memory.
+ * XXX - should probably be a tailq since we do appends
+ */
+struct ldap_search_list {
+    LDAP *ldap;
+    LDAPMessage *searchresult;
+    struct ldap_search_list *next;
+};
+
+/*
+ * The ldap_entry_wrapper structure is used to implement sorted result entries.
+ * A double is used for the order to allow for insertion of new entries
+ * without having to renumber everything.
+ * Note: there is no standard floating point type in LDAP.
+ *       As a result, some LDAP servers will only allow an integer.
+ */
+struct ldap_entry_wrapper {
+    LDAPMessage        *entry;
+    double order;
+};
+
+/*
+ * The ldap_result structure contains the list of matching searches as
+ * well as an array of all result entries sorted by the sudoOrder attribute.
+ */
+struct ldap_result {
+    struct ldap_search_list *searches;
+    struct ldap_entry_wrapper *entries;
+    int allocated_entries;
+    int nentries;
+    int user_matches;
+    int host_matches;
+};
+#define        ALLOCATION_INCREMENT    100
+
+struct ldap_config_table {
+    const char *conf_str;      /* config file string */
+    short type;                        /* CONF_BOOL, CONF_INT, CONF_STR */
+    short connected;           /* connection-specific value? */
+    int opt_val;               /* LDAP_OPT_* (or -1 for sudo internal) */
+    void *valp;                        /* pointer into ldap_conf */
+};
+
+struct ldap_config_list_str {
+    struct ldap_config_list_str *next;
+    char val[1];
+};
+
+/* LDAP configuration structure */
+static struct ldap_config {
+    int port;
+    int version;
+    int debug;
+    int ldap_debug;
+    int tls_checkpeer;
+    int timelimit;
+    int timeout;
+    int bind_timelimit;
+    int use_sasl;
+    int rootuse_sasl;
+    int ssl_mode;
+    int timed;
+    char *host;
+    struct ldap_config_list_str *uri;
+    char *binddn;
+    char *bindpw;
+    char *rootbinddn;
+    struct ldap_config_list_str *base;
+    char *search_filter;
+    char *ssl;
+    char *tls_cacertfile;
+    char *tls_cacertdir;
+    char *tls_random_file;
+    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;
+
+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 },
+    { "ssl", CONF_STR, FALSE, -1, &ldap_conf.ssl },
+    { "sslpath", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
+    { "uri", CONF_LIST_STR, FALSE, -1, &ldap_conf.uri },
+#ifdef LDAP_OPT_DEBUG_LEVEL
+    { "debug", CONF_INT, FALSE, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug },
+#endif
+#ifdef LDAP_OPT_PROTOCOL_VERSION
+    { "ldap_version", CONF_INT, TRUE, LDAP_OPT_PROTOCOL_VERSION,
+       &ldap_conf.version },
+#endif
+#ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
+    { "tls_checkpeer", CONF_BOOL, FALSE, LDAP_OPT_X_TLS_REQUIRE_CERT,
+       &ldap_conf.tls_checkpeer },
+#else
+    { "tls_checkpeer", CONF_BOOL, FALSE, -1, &ldap_conf.tls_checkpeer },
+#endif
+#ifdef LDAP_OPT_X_TLS_CACERTFILE
+    { "tls_cacertfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE,
+       &ldap_conf.tls_cacertfile },
+    { "tls_cacert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE,
+       &ldap_conf.tls_cacertfile },
+#endif
+#ifdef LDAP_OPT_X_TLS_CACERTDIR
+    { "tls_cacertdir", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTDIR,
+       &ldap_conf.tls_cacertdir },
+#endif
+#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
+    { "tls_randfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_RANDOM_FILE,
+       &ldap_conf.tls_random_file },
+#endif
+#ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
+    { "tls_ciphers", CONF_STR, FALSE, LDAP_OPT_X_TLS_CIPHER_SUITE,
+       &ldap_conf.tls_cipher_suite },
+#endif
+#ifdef LDAP_OPT_X_TLS_CERTFILE
+    { "tls_cert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CERTFILE,
+       &ldap_conf.tls_certfile },
+#else
+    { "tls_cert", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
+#endif
+#ifdef LDAP_OPT_X_TLS_KEYFILE
+    { "tls_key", CONF_STR, FALSE, LDAP_OPT_X_TLS_KEYFILE,
+       &ldap_conf.tls_keyfile },
+#else
+    { "tls_key", CONF_STR, FALSE, -1, &ldap_conf.tls_keyfile },
+#endif
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+    { "bind_timelimit", CONF_INT, TRUE, -1 /* needs timeval, set manually */,
+       &ldap_conf.bind_timelimit },
+    { "network_timeout", CONF_INT, TRUE, -1 /* needs timeval, set manually */,
+       &ldap_conf.bind_timelimit },
+#elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
+    { "bind_timelimit", CONF_INT, TRUE, LDAP_X_OPT_CONNECT_TIMEOUT,
+       &ldap_conf.bind_timelimit },
+    { "network_timeout", CONF_INT, TRUE, LDAP_X_OPT_CONNECT_TIMEOUT,
+       &ldap_conf.bind_timelimit },
+#endif
+    { "timelimit", CONF_INT, TRUE, LDAP_OPT_TIMELIMIT, &ldap_conf.timelimit },
+#ifdef LDAP_OPT_TIMEOUT
+    { "timeout", CONF_INT, TRUE, -1 /* needs timeval, set manually */,
+       &ldap_conf.timeout },
+#endif
+    { "binddn", CONF_STR, FALSE, -1, &ldap_conf.binddn },
+    { "bindpw", CONF_STR, FALSE, -1, &ldap_conf.bindpw },
+    { "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },
+    { "sudoers_base", CONF_LIST_STR, FALSE, -1, &ldap_conf.base },
+    { "sudoers_timed", CONF_BOOL, FALSE, -1, &ldap_conf.timed },
+    { "sudoers_search_filter", CONF_STR, FALSE, -1, &ldap_conf.search_filter },
+#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 }
+};
+
+/* sudo_nss implementation */
+static int sudo_ldap_open(struct sudo_nss *nss);
+static int sudo_ldap_close(struct sudo_nss *nss);
+static int sudo_ldap_parse(struct sudo_nss *nss);
+static int sudo_ldap_setdefs(struct sudo_nss *nss);
+static int sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag);
+static int sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw);
+static int sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
+    struct lbuf *lbuf);
+static int sudo_ldap_display_bound_defaults(struct sudo_nss *nss,
+    struct passwd *pw, struct lbuf *lbuf);
+static int sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw,
+    struct lbuf *lbuf);
+static struct ldap_result *sudo_ldap_result_get(struct sudo_nss *nss,
+    struct passwd *pw);
+
+/*
+ * LDAP sudo_nss handle.
+ * We store the connection to the LDAP server, the cached ldap_result object
+ * (if any), and the name of the user the query was performed for.
+ * If a new query is launched with sudo_ldap_result_get() that specifies a
+ * different user, the old cached result is freed before the new query is run.
+ */
+struct sudo_ldap_handle {
+    LDAP *ld;
+    struct ldap_result *result;
+    char *username;
+    GETGROUPS_T *groups;
+};
+
+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(void)
+{
+
+    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((unsigned char)port[1])) {
+           if (strlcat(hostbuf, defport, sizeof(hostbuf)) >= sizeof(hostbuf))
+               goto toobig;
+       }
+    }
+
+    efree(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
+/*
+ * For each uri, convert to host:port pairs.  For ldaps:// enable SSL
+ * Accepts: uris of the form ldap:/// or ldap://hostname:portnum/
+ * where the trailing slash is optional.
+ */
+static int
+sudo_ldap_parse_uri(const struct ldap_config_list_str *uri_list)
+{
+    char *buf, *uri, *host, *cp, *port;
+    char hostbuf[LINE_MAX];
+    int nldap = 0, nldaps = 0;
+    int rc = -1;
+
+    do {
+       buf = estrdup(uri_list->val);
+       hostbuf[0] = '\0';
+       for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) {
+           if (strncasecmp(uri, "ldap://", 7) == 0) {
+               nldap++;
+               host = uri + 7;
+           } else if (strncasecmp(uri, "ldaps://", 8) == 0) {
+               nldaps++;
+               host = uri + 8;
+           } else {
+               warningx("unsupported LDAP uri type: %s", uri);
+               goto done;
+           }
+
+           /* trim optional trailing slash */
+           if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') {
+               *cp = '\0';
+           }
+
+           if (hostbuf[0] != '\0') {
+               if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
+                   goto toobig;
+           }
+
+           if (*host == '\0')
+               host = "localhost";             /* no host specified, use localhost */
+
+           if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
+               goto toobig;
+
+           /* If using SSL and no port specified, add port 636 */
+           if (nldaps) {
+               if ((port = strrchr(host, ':')) == NULL ||
+                   !isdigit((unsigned char)port[1]))
+                   if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf))
+                       goto toobig;
+           }
+       }
+       if (hostbuf[0] == '\0') {
+           warningx("invalid uri: %s", uri_list);
+           goto done;
+       }
+
+       if (nldaps != 0) {
+           if (nldap != 0) {
+               warningx("cannot mix ldap and ldaps URIs");
+               goto done;
+           }
+           if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
+               warningx("cannot mix ldaps and starttls");
+               goto done;
+           }
+           ldap_conf.ssl_mode = SUDO_LDAP_SSL;
+       }
+
+       efree(ldap_conf.host);
+       ldap_conf.host = estrdup(hostbuf);
+       efree(buf);
+    } while ((uri_list = uri_list->next));
+
+    buf = NULL;
+    rc = 0;
+
+done:
+    efree(buf);
+    return rc;
+
+toobig:
+    errorx(1, "sudo_ldap_parse_uri: out of space building hostbuf");
+}
+#else
+static char *
+sudo_ldap_join_uri(struct ldap_config_list_str *uri_list)
+{
+    struct ldap_config_list_str *uri;
+    size_t len = 0;
+    char *buf, *cp;
+
+    /* Usually just a single entry. */
+    if (uri_list->next == NULL)
+       return estrdup(uri_list->val);
+
+    for (uri = uri_list; uri != NULL; uri = uri->next) {
+       len += strlen(uri->val) + 1;
+    }
+    buf = cp = emalloc(len);
+    buf[0] = '\0';
+    for (uri = uri_list; uri != NULL; uri = uri->next) {
+       cp += strlcpy(cp, uri->val, len - (cp - buf));
+       *cp++ = ' ';
+    }
+    cp[-1] = '\0';
+    return buf;
+}
+#endif /* HAVE_LDAP_INITIALIZE */
+
+static int
+sudo_ldap_init(LDAP **ldp, const char *host, int port)
+{
+    LDAP *ld = NULL;
+    int rc = LDAP_CONNECT_ERROR;
+
+#ifdef HAVE_LDAPSSL_INIT
+    if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
+       DPRINTF(("ldapssl_clientauth_init(%s, %s)",
+           ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
+           ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
+       rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
+           ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
+       /*
+        * Mozilla-derived SDKs have a bug starting with version 5.0
+        * where the path can no longer be a file name and must be a dir.
+        */
+       if (rc != LDAP_SUCCESS) {
+           char *cp;
+           if (ldap_conf.tls_certfile) {
+               cp = strrchr(ldap_conf.tls_certfile, '/');
+               if (cp != NULL && strncmp(cp + 1, "cert", 4) == 0)
+                   *cp = '\0';
+           }
+           if (ldap_conf.tls_keyfile) {
+               cp = strrchr(ldap_conf.tls_keyfile, '/');
+               if (cp != NULL && strncmp(cp + 1, "key", 3) == 0)
+                   *cp = '\0';
+           }
+           DPRINTF(("ldapssl_clientauth_init(%s, %s)",
+               ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
+               ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
+           rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
+               ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
+           if (rc != LDAP_SUCCESS) {
+               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)
+           rc = LDAP_SUCCESS;
+    } else
+#endif
+    {
+#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
+    }
+
+done:
+    *ldp = ld;
+    return rc;
+}
+
+/*
+ * Walk through search results and return TRUE if we have a matching
+ * netgroup, else FALSE.
+ */
+static int
+sudo_ldap_check_user_netgroup(LDAP *ld, LDAPMessage *entry, char *user)
+{
+    struct berval **bv, **p;
+    char *val;
+    int ret = FALSE;
+
+    if (!entry)
+       return ret;
+
+    /* get the values from the entry */
+    bv = ldap_get_values_len(ld, entry, "sudoUser");
+    if (bv == NULL)
+       return ret;
+
+    /* walk through values */
+    for (p = bv; *p != NULL && !ret; p++) {
+       val = (*p)->bv_val;
+       /* match any */
+       if (netgr_matches(val, NULL, NULL, user))
+           ret = TRUE;
+       DPRINTF(("ldap sudoUser netgroup '%s' ... %s", val,
+           ret ? "MATCH!" : "not"), 2 + ((ret) ? 0 : 1));
+    }
+
+    ldap_value_free_len(bv);   /* cleanup */
+
+    return ret;
+}
+
+/*
+ * Walk through search results and return TRUE if we have a
+ * host match, else FALSE.
+ */
+static int
+sudo_ldap_check_host(LDAP *ld, LDAPMessage *entry)
+{
+    struct berval **bv, **p;
+    char *val;
+    int ret = FALSE;
+
+    if (!entry)
+       return ret;
+
+    /* get the values from the entry */
+    bv = ldap_get_values_len(ld, entry, "sudoHost");
+    if (bv == NULL)
+       return ret;
+
+    /* walk through values */
+    for (p = bv; *p != NULL && !ret; p++) {
+       val = (*p)->bv_val;
+       /* match any or address or netgroup or hostname */
+       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", val,
+           ret ? "MATCH!" : "not"), 2);
+    }
+
+    ldap_value_free_len(bv);   /* cleanup */
+
+    return ret;
+}
+
+static int
+sudo_ldap_check_runas_user(LDAP *ld, LDAPMessage *entry)
+{
+    struct berval **bv, **p;
+    char *val;
+    int ret = FALSE;
+
+    if (!runas_pw)
+       return UNSPEC;
+
+    /* 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:
+     * 
+     * if runas is not specified on the command line, the only information
+     * as to which user to run as is in the runas_default option.  We should
+     * check to see if we have the local option present.  Unfortunately we
+     * don't parse these options until after this routine says yes or no.
+     * The query has already returned, so we could peek at the attribute
+     * values here though.
+     * 
+     * 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 (bv == NULL)
+       return !strcasecmp(runas_pw->pw_name, def_runas_default);
+
+    /* walk through values returned, looking for a match */
+    for (p = bv; *p != NULL && !ret; p++) {
+       val = (*p)->bv_val;
+       switch (val[0]) {
+       case '+':
+           if (netgr_matches(val, NULL, NULL, runas_pw->pw_name))
+               ret = TRUE;
+           break;
+       case '%':
+           if (usergr_matches(val, runas_pw->pw_name, runas_pw))
+               ret = TRUE;
+           break;
+       case 'A':
+           if (strcmp(val, "ALL") == 0) {
+               ret = TRUE;
+               break;
+           }
+           /* FALLTHROUGH */
+       default:
+           if (strcasecmp(val, runas_pw->pw_name) == 0)
+               ret = TRUE;
+           break;
+       }
+       DPRINTF(("ldap sudoRunAsUser '%s' ... %s", val,
+           ret ? "MATCH!" : "not"), 2);
+    }
+
+    ldap_value_free_len(bv);   /* cleanup */
+
+    return ret;
+}
+
+static int
+sudo_ldap_check_runas_group(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 runas match,
+ * else FALSE.  RunAs info is optional.
+ */
+static int
+sudo_ldap_check_runas(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.
+ */
+static int
+sudo_ldap_check_command(LDAP *ld, LDAPMessage *entry, int *setenv_implied)
+{
+    struct berval **bv, **p;
+    char *allowed_cmnd, *allowed_args, *val;
+    int foundbang, ret = UNSPEC;
+
+    if (!entry)
+       return ret;
+
+    bv = ldap_get_values_len(ld, entry, "sudoCommand");
+    if (bv == NULL)
+       return ret;
+
+    for (p = bv; *p != NULL && ret != FALSE; p++) {
+       val = (*p)->bv_val;
+       /* Match against ALL ? */
+       if (!strcmp(val, "ALL")) {
+           ret = TRUE;
+           if (setenv_implied != NULL)
+               *setenv_implied = TRUE;
+           DPRINTF(("ldap sudoCommand '%s' ... MATCH!", val), 2);
+           continue;
+       }
+
+       /* check for !command */
+       if (*val == '!') {
+           foundbang = TRUE;
+           allowed_cmnd = estrdup(1 + val);    /* !command */
+       } else {
+           foundbang = FALSE;
+           allowed_cmnd = estrdup(val);        /* command */
+       }
+
+       /* split optional args away from command */
+       allowed_args = strchr(allowed_cmnd, ' ');
+       if (allowed_args)
+           *allowed_args++ = '\0';
+
+       /* check the command like normal */
+       if (command_matches(allowed_cmnd, allowed_args)) {
+           /*
+            * If allowed (no bang) set ret but keep on checking.
+            * If disallowed (bang), exit loop.
+            */
+           ret = foundbang ? FALSE : TRUE;
+       }
+       DPRINTF(("ldap sudoCommand '%s' ... %s", val,
+           ret == TRUE ? "MATCH!" : "not"), 2);
+
+       efree(allowed_cmnd);    /* cleanup */
+    }
+
+    ldap_value_free_len(bv);   /* more cleanup */
+
+    return ret;
+}
+
+/*
+ * Search for boolean "option" in sudoOption.
+ * Returns TRUE if found and allowed, FALSE if negated, else UNSPEC.
+ */
+static int
+sudo_ldap_check_bool(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;
+}
+
+/*
+ * Read sudoOption and modify the defaults as we go.  This is used once
+ * from the cn=defaults entry and also once when a final sudoRole is matched.
+ */
+static void
+sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry)
+{
+    struct berval **bv, **p;
+    char op, *var, *val;
+
+    if (entry == NULL)
+       return;
+
+    bv = ldap_get_values_len(ld, entry, "sudoOption");
+    if (bv == NULL)
+       return;
+
+    /* walk through options */
+    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, '=');
+       if (val > var) {
+           *val++ = '\0';      /* split on = and truncate var */
+           op = *(val - 2);    /* peek for += or -= cases */
+           if (op == '+' || op == '-') {
+               *(val - 2) = '\0';      /* found, remove extra char */
+               /* case var+=val or var-=val */
+               set_default(var, val, (int) op);
+           } else {
+               /* case var=val */
+               set_default(var, val, TRUE);
+           }
+       } else if (*var == '!') {
+           /* case !var Boolean False */
+           set_default(var + 1, NULL, FALSE);
+       } else {
+           /* case var Boolean True */
+           set_default(var, NULL, TRUE);
+       }
+       efree(var);
+    }
+
+    ldap_value_free_len(bv);
+}
+
+/*
+ * Build an LDAP timefilter.
+ *
+ * Stores a filter in the buffer that makes sure only entries
+ * are selected that have a sudoNotBefore in the past and a
+ * sudoNotAfter in the future, i.e. a filter of the following
+ * structure (spaced out a little more for better readability:
+ *
+ * (&
+ *   (|
+ *     (!(sudoNotAfter=*))
+ *     (sudoNotAfter>__now__)
+ *   )
+ *   (|
+ *     (!(sudoNotBefore=*))
+ *     (sudoNotBefore<__now__)
+ *   )
+ * )
+ *
+ * If either the sudoNotAfter or sudoNotBefore attributes are missing,
+ * no time restriction shall be imposed.
+ */
+static int
+sudo_ldap_timefilter(char *buffer, size_t buffersize)
+{
+    struct tm *tp;
+    time_t now;
+    char timebuffer[16];
+    int bytes = 0;
+
+    /* Make sure we have a formatted timestamp for __now__. */
+    time(&now);
+    if ((tp = gmtime(&now)) == NULL) {
+       warning("unable to get GMT");
+       goto done;
+    }
+
+    /* Format the timestamp according to the RFC. */
+    if (strftime(timebuffer, sizeof(timebuffer), "%Y%m%d%H%MZ", tp) == 0) {
+       warning("unable to format timestamp");
+       goto done;
+    }
+
+    /* Build filter. */
+    bytes = snprintf(buffer, buffersize, "(&(|(!(sudoNotAfter=*))(sudoNotAfter>=%s))(|(!(sudoNotBefore=*))(sudoNotBefore<=%s)))",
+       timebuffer, timebuffer);
+    if (bytes < 0 || bytes >= buffersize) {
+       warning("unable to build time filter");
+       bytes = 0;
+    }
+
+done:
+    return bytes;
+}
+
+/*
+ * Builds up a filter to search for default settings
+ */
+static char *
+sudo_ldap_build_default_filter()
+{
+    char *filt;
+
+    if (ldap_conf.search_filter)
+       easprintf(&filt, "(&%s(cn=defaults))", ldap_conf.search_filter);
+    else
+       filt = estrdup("cn=defaults");
+    return filt;
+}
+
+/*
+ * Builds up a filter to check against LDAP.
+ */
+static char *
+sudo_ldap_build_pass1(struct passwd *pw)
+{
+    struct group *grp;
+    char *buf, timebuffer[TIMEFILTER_LENGTH];
+    size_t sz = 0;
+    int i;
+
+    /* Start with LDAP search filter length + 3 */
+    if (ldap_conf.search_filter)
+       sz += strlen(ldap_conf.search_filter) + 3;
+
+    /* Then add (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
+    sz += 29 + strlen(pw->pw_name);
+
+    /* Add space for groups */
+    if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
+       sz += 12 + strlen(grp->gr_name);        /* primary group */
+       gr_delref(grp);
+    }
+    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 */
+           gr_delref(grp);
+       }
+    }
+
+    /* If timed, add space for time limits. */
+    if (ldap_conf.timed)
+       sz += TIMEFILTER_LENGTH;
+    buf = emalloc(sz);
+    *buf = '\0';
+
+    /*
+     * If timed or using a search filter, start a global AND clause to
+     * contain the search filter, search criteria, and time restriction.
+     */
+    if (ldap_conf.timed || ldap_conf.search_filter)
+       (void) strlcpy(buf, "(&", sz);
+
+    if (ldap_conf.search_filter)
+       (void) strlcat(buf, ldap_conf.search_filter, sz);
+
+    /* Global OR + sudoUser=user_name filter */
+    (void) strlcat(buf, "(|(sudoUser=", sz);
+    (void) strlcat(buf, pw->pw_name, sz);
+    (void) strlcat(buf, ")", sz);
+
+    /* Append primary group */
+    if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
+       (void) strlcat(buf, "(sudoUser=%", sz);
+       (void) strlcat(buf, grp->gr_name, sz);
+       (void) strlcat(buf, ")", sz);
+       gr_delref(grp);
+    }
+
+    /* Append supplementary groups */
+    for (i = 0; i < user_ngroups; i++) {
+       if (user_groups[i] == pw->pw_gid)
+           continue;
+       if ((grp = sudo_getgrgid(user_groups[i])) != NULL) {
+           (void) strlcat(buf, "(sudoUser=%", sz);
+           (void) strlcat(buf, grp->gr_name, sz);
+           (void) strlcat(buf, ")", sz);
+           gr_delref(grp);
+       }
+    }
+
+    /* Add ALL to list and end the global OR */
+    if (strlcat(buf, "(sudoUser=ALL)", sz) >= sz)
+       errorx(1, "sudo_ldap_build_pass1 allocation mismatch");
+
+    /* Add the time restriction, or simply end the global OR. */
+    if (ldap_conf.timed) {
+       strlcat(buf, ")", sz); /* closes the global OR */
+       sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
+       strlcat(buf, timebuffer, sz);
+    } else if (ldap_conf.search_filter) {
+       strlcat(buf, ")", sz); /* closes the global OR */
+    }
+    strlcat(buf, ")", sz); /* closes the global OR or the global AND */
+
+    return buf;
+}
+
+/*
+ * Builds up a filter to check against netgroup entries in LDAP.
+ */
+static char *
+sudo_ldap_build_pass2(void)
+{
+    char *filt, timebuffer[TIMEFILTER_LENGTH];
+
+    if (ldap_conf.timed)
+       sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
+
+    /*
+     * Match all sudoUsers beginning with a '+'.
+     * If a search filter or time restriction is specified, 
+     * those get ANDed in to the expression.
+     */
+    easprintf(&filt, "%s%s(sudoUser=+*)%s%s",
+       (ldap_conf.timed || ldap_conf.search_filter) ? "(&" : "",
+       ldap_conf.search_filter ? ldap_conf.search_filter : "",
+       ldap_conf.timed ? timebuffer : "",
+       (ldap_conf.timed || ldap_conf.search_filter) ? ")" : "");
+
+    return filt;
+}
+
+static void
+sudo_ldap_read_secret(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);
+    }
+}
+
+static int
+sudo_ldap_read_config(void)
+{
+    FILE *fp;
+    char *cp, *keyword, *value;
+    struct ldap_config_table *cur;
+
+    /* defaults */
+    ldap_conf.version = 3;
+    ldap_conf.port = -1;
+    ldap_conf.tls_checkpeer = -1;
+    ldap_conf.timelimit = -1;
+    ldap_conf.timeout = -1;
+    ldap_conf.bind_timelimit = -1;
+    ldap_conf.use_sasl = -1;
+    ldap_conf.rootuse_sasl = -1;
+
+    if ((fp = fopen(_PATH_LDAP_CONF, "r")) == NULL)
+       return FALSE;
+
+    while ((cp = sudo_parseln(fp)) != NULL) {
+       if (*cp == '\0')
+           continue;           /* skip empty line */
+
+       /* 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 (isblank((unsigned char) *cp))
+           cp++;
+       value = cp;
+
+       /* Look up keyword in config table. */
+       for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
+           if (strcasecmp(keyword, cur->conf_str) == 0) {
+               switch (cur->type) {
+               case CONF_BOOL:
+                   *(int *)(cur->valp) = atobool(value) == TRUE;
+                   break;
+               case CONF_INT:
+                   *(int *)(cur->valp) = atoi(value);
+                   break;
+               case CONF_STR:
+                   efree(*(char **)(cur->valp));
+                   *(char **)(cur->valp) = estrdup(value);
+                   break;
+               case CONF_LIST_STR:
+                   {
+                       struct ldap_config_list_str **p;
+                       size_t len = strlen(value);
+
+                       if (len > 0) {
+                           p = (struct ldap_config_list_str **)cur->valp;
+                           while (*p != NULL)
+                               p = &(*p)->next;
+                           *p = emalloc(sizeof(struct ldap_config_list_str) + len);
+                           memcpy((*p)->val, value, len + 1);
+                           (*p)->next = NULL;
+                       }
+                   }
+                   break;
+               }
+               break;
+           }
+       }
+    }
+    fclose(fp);
+
+    if (!ldap_conf.host)
+       ldap_conf.host = estrdup("localhost");
+
+    if (ldap_conf.debug > 1) {
+       sudo_printf(SUDO_CONV_ERROR_MSG, "LDAP Config Summary\n");
+       sudo_printf(SUDO_CONV_ERROR_MSG, "===================\n");
+       if (ldap_conf.uri) {
+           struct ldap_config_list_str *uri = ldap_conf.uri;
+
+           do {
+               sudo_printf(SUDO_CONV_ERROR_MSG, "uri              %s\n",
+                   uri->val);
+           } while ((uri = uri->next) != NULL);
+       } else {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "host             %s\n",
+               ldap_conf.host ?  ldap_conf.host : "(NONE)");
+           sudo_printf(SUDO_CONV_ERROR_MSG, "port             %d\n",
+               ldap_conf.port);
+       }
+       sudo_printf(SUDO_CONV_ERROR_MSG, "ldap_version     %d\n",
+           ldap_conf.version);
+
+       if (ldap_conf.base) {
+           struct ldap_config_list_str *base = ldap_conf.base;
+           do {
+               sudo_printf(SUDO_CONV_ERROR_MSG, "sudoers_base     %s\n",
+                   base->val);
+           } while ((base = base->next) != NULL);
+       } else {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "sudoers_base     %s\n",
+               "(NONE: LDAP disabled)");
+       }
+       if (ldap_conf.search_filter) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "search_filter    %s\n",
+               ldap_conf.search_filter);
+       }
+       sudo_printf(SUDO_CONV_ERROR_MSG, "binddn           %s\n",
+           ldap_conf.binddn ?  ldap_conf.binddn : "(anonymous)");
+       sudo_printf(SUDO_CONV_ERROR_MSG, "bindpw           %s\n",
+           ldap_conf.bindpw ?  ldap_conf.bindpw : "(anonymous)");
+       if (ldap_conf.bind_timelimit > 0) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "bind_timelimit   %d\n",
+               ldap_conf.bind_timelimit);
+       }
+       if (ldap_conf.timelimit > 0) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "timelimit        %d\n",
+               ldap_conf.timelimit);
+       }
+       sudo_printf(SUDO_CONV_ERROR_MSG, "ssl              %s\n",
+           ldap_conf.ssl ?  ldap_conf.ssl : "(no)");
+       if (ldap_conf.tls_checkpeer != -1) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "tls_checkpeer    %s\n",
+               ldap_conf.tls_checkpeer ?  "(yes)" : "(no)");
+       }
+       if (ldap_conf.tls_cacertfile != NULL) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cacertfile   %s\n",
+               ldap_conf.tls_cacertfile);
+       }
+       if (ldap_conf.tls_cacertdir != NULL) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cacertdir    %s\n",
+               ldap_conf.tls_cacertdir);
+       }
+       if (ldap_conf.tls_random_file != NULL) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "tls_random_file  %s\n",
+               ldap_conf.tls_random_file);
+       }
+       if (ldap_conf.tls_cipher_suite != NULL) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cipher_suite %s\n",
+               ldap_conf.tls_cipher_suite);
+       }
+       if (ldap_conf.tls_certfile != NULL) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "tls_certfile     %s\n",
+               ldap_conf.tls_certfile);
+       }
+       if (ldap_conf.tls_keyfile != NULL) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "tls_keyfile      %s\n",
+               ldap_conf.tls_keyfile);
+       }
+#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
+       if (ldap_conf.use_sasl != -1) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "use_sasl         %s\n",
+               ldap_conf.use_sasl ? "yes" : "no");
+           sudo_printf(SUDO_CONV_ERROR_MSG, "sasl_auth_id     %s\n",
+               ldap_conf.sasl_auth_id ?  ldap_conf.sasl_auth_id : "(NONE)");
+           sudo_printf(SUDO_CONV_ERROR_MSG, "rootuse_sasl     %d\n",
+               ldap_conf.rootuse_sasl);
+           sudo_printf(SUDO_CONV_ERROR_MSG, "rootsasl_auth_id %s\n",
+               ldap_conf.rootsasl_auth_id ?  ldap_conf.rootsasl_auth_id : "(NONE)");
+           sudo_printf(SUDO_CONV_ERROR_MSG, "sasl_secprops    %s\n",
+               ldap_conf.sasl_secprops ?  ldap_conf.sasl_secprops : "(NONE)");
+           sudo_printf(SUDO_CONV_ERROR_MSG, "krb5_ccname      %s\n",
+               ldap_conf.krb5_ccname ?  ldap_conf.krb5_ccname : "(NONE)");
+       }
+#endif
+       sudo_printf(SUDO_CONV_ERROR_MSG, "===================\n");
+    }
+    if (!ldap_conf.base)
+       return FALSE;           /* if no base is defined, ignore LDAP */
+
+    if (ldap_conf.bind_timelimit > 0)
+       ldap_conf.bind_timelimit *= 1000;       /* convert to ms */
+
+    /*
+     * Interpret SSL option
+     */
+    if (ldap_conf.ssl != NULL) {
+       if (strcasecmp(ldap_conf.ssl, "start_tls") == 0)
+           ldap_conf.ssl_mode = SUDO_LDAP_STARTTLS;
+       else if (atobool(ldap_conf.ssl) == TRUE)
+           ldap_conf.ssl_mode = SUDO_LDAP_SSL;
+    }
+
+#if defined(HAVE_LDAPSSL_SET_STRENGTH) && !defined(LDAP_OPT_X_TLS_REQUIRE_CERT)
+    if (ldap_conf.tls_checkpeer != -1) {
+       ldapssl_set_strength(NULL,
+           ldap_conf.tls_checkpeer ? LDAPSSL_AUTH_CERT : LDAPSSL_AUTH_WEAK);
+    }
+#endif
+
+#ifndef HAVE_LDAP_INITIALIZE
+    /* Convert uri list to host list if no ldap_initialize(). */
+    if (ldap_conf.uri) {
+       struct ldap_config_list_str *uri = ldap_conf.uri;
+       if (sudo_ldap_parse_uri(uri) != 0)
+           return FALSE;
+       do {
+           ldap_conf.uri = uri->next;
+           efree(uri);
+       } while ((uri = ldap_conf.uri));
+       ldap_conf.port = LDAP_PORT;
+    }
+#endif
+
+    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 search filter is not parenthesized, make it so. */
+    if (ldap_conf.search_filter && ldap_conf.search_filter[0] != '(') {
+       size_t len = strlen(ldap_conf.search_filter);
+       cp = ldap_conf.search_filter;
+       ldap_conf.search_filter = emalloc(len + 3);
+       ldap_conf.search_filter[0] = '(';
+       memcpy(ldap_conf.search_filter + 1, cp, len);
+       ldap_conf.search_filter[len + 1] = ')';
+       ldap_conf.search_filter[len + 2] = '\0';
+       efree(cp);
+    }
+
+    /* If rootbinddn set, read in /etc/ldap.secret if it exists. */
+    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;
+           }
+       }
+    }
+#endif
+    return TRUE;
+}
+
+/*
+ * Extract the dn from an entry and return the first rdn from it.
+ */
+static char *
+sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry)
+{
+#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
+}
+
+/*
+ * Fetch and display the global Options.
+ */
+static int
+sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
+    struct lbuf *lbuf)
+{
+    struct berval **bv, **p;
+    struct timeval tv, *tvp = NULL;
+    struct ldap_config_list_str *base;
+    struct sudo_ldap_handle *handle = nss->handle;
+    LDAP *ld;
+    LDAPMessage *entry, *result;
+    char *prefix, *filt;
+    int rc, count = 0;
+
+    if (handle == NULL || handle->ld == NULL)
+       goto done;
+    ld = handle->ld;
+
+    filt = sudo_ldap_build_default_filter();
+    for (base = ldap_conf.base; base != NULL; base = base->next) {
+       if (ldap_conf.timeout > 0) {
+           tv.tv_sec = ldap_conf.timeout;
+           tv.tv_usec = 0;
+           tvp = &tv;
+       }
+       result = NULL;
+       rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
+           filt, NULL, 0, NULL, NULL, tvp, 0, &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 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
+                   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);
+    }
+    efree(filt);
+done:
+    return count;
+}
+
+/*
+ * STUB
+ */
+static int
+sudo_ldap_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
+    struct lbuf *lbuf)
+{
+    return 0;
+}
+
+/*
+ * Print a record in the short form, ala file sudoers.
+ */
+static int
+sudo_ldap_display_entry_short(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);
+       }
+       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_append(lbuf, "\n", NULL);
+
+    return count;
+}
+
+/*
+ * Print a record in the long form.
+ */
+static int
+sudo_ldap_display_entry_long(LDAP *ld, LDAPMessage *entry, struct lbuf *lbuf)
+{
+    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_append(lbuf, "\nLDAP Role: ", rdn ? rdn : "UNKNOWN", "\n", NULL);
+    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_append(lbuf, "\n", NULL);
+
+    /* 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_append(lbuf, "\n", NULL);
+    }
+
+    /* 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_append(lbuf, "\n", NULL);
+    }
+
+    /*
+     * Display order attribute if present.  This attribute is single valued,
+     * so there is no need for a loop.
+     */
+    bv = ldap_get_values_len(ld, entry, "sudoOrder");
+    if (bv != NULL) {
+       if (*bv != NULL) {
+           lbuf_append(lbuf, "    Order: ", (*bv)->bv_val, "\n", NULL);
+       }
+       ldap_value_free_len(bv);
+    }
+
+    /* Get the command values from the entry. */
+    bv = ldap_get_values_len(ld, entry, "sudoCommand");
+    if (bv != NULL) {
+       lbuf_append(lbuf, "    Commands:\n", NULL);
+       for (p = bv; *p != NULL; p++) {
+           lbuf_append(lbuf, "\t", (*p)->bv_val, "\n", NULL);
+           count++;
+       }
+       ldap_value_free_len(bv);
+    }
+
+    return count;
+}
+
+/*
+ * Like sudo_ldap_lookup(), except we just print entries.
+ */
+static int
+sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw,
+    struct lbuf *lbuf)
+{
+    struct sudo_ldap_handle *handle = nss->handle;
+    LDAP *ld;
+    struct ldap_result *lres;
+    LDAPMessage *entry;
+    int i, count = 0;
+
+    if (handle == NULL || handle->ld == NULL)
+       goto done;
+    ld = handle->ld;
+
+    DPRINTF(("ldap search for command list"), 1);
+    lres = sudo_ldap_result_get(nss, pw);
+
+    /* Display all matching entries. */
+    for (i = 0; i < lres->nentries; i++) {
+       entry = lres->entries[i].entry;
+       if (long_list)
+           count += sudo_ldap_display_entry_long(ld, entry, lbuf);
+       else
+           count += sudo_ldap_display_entry_short(ld, entry, lbuf);
+    }
+
+done:
+    return count;
+}
+
+static int
+sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
+{
+    struct sudo_ldap_handle *handle = nss->handle;
+    LDAP *ld;
+    struct ldap_result *lres;
+    LDAPMessage *entry;
+    int i, found = FALSE;
+
+    if (handle == NULL || handle->ld == NULL)
+       goto done;
+    ld = handle->ld;
+
+    /*
+     * The sudo_ldap_result_get() function returns all nodes that match
+     * the user and the host.
+     */
+    DPRINTF(("ldap search for command list"), 1);
+    lres = sudo_ldap_result_get(nss, pw);
+    for (i = 0; i < lres->nentries; i++) {
+       entry = lres->entries[i].entry;
+       if (sudo_ldap_check_command(ld, entry, NULL) &&
+           sudo_ldap_check_runas(ld, entry)) {
+           found = TRUE;
+           goto done;
+       }
+    }
+
+done:
+    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(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.
+ */
+static int
+sudo_ldap_set_options(LDAP *ld)
+{
+    struct ldap_config_table *cur;
+    int rc;
+
+    /* Set ber options */
+#ifdef LBER_OPT_DEBUG_LEVEL
+    if (ldap_conf.ldap_debug)
+       ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug);
+#endif
+
+    /* Set simple LDAP options */
+    for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
+       LDAP *conn;
+       int ival;
+       char *sval;
+
+       if (cur->opt_val == -1)
+           continue;
+
+       conn = cur->connected ? ld : NULL;
+       switch (cur->type) {
+       case CONF_BOOL:
+       case CONF_INT:
+           ival = *(int *)(cur->valp);
+           if (ival >= 0) {
+               rc = ldap_set_option(conn, cur->opt_val, &ival);
+               if (rc != LDAP_OPT_SUCCESS) {
+                   warningx("ldap_set_option: %s -> %d: %s",
+                       cur->conf_str, ival, ldap_err2string(rc));
+                   return -1;
+               }
+               DPRINTF(("ldap_set_option: %s -> %d", cur->conf_str, ival), 1);
+           }
+           break;
+       case CONF_STR:
+           sval = *(char **)(cur->valp);
+           if (sval != NULL) {
+               rc = ldap_set_option(conn, cur->opt_val, sval);
+               if (rc != LDAP_OPT_SUCCESS) {
+                   warningx("ldap_set_option: %s -> %s: %s",
+                       cur->conf_str, sval, ldap_err2string(rc));
+                   return -1;
+               }
+               DPRINTF(("ldap_set_option: %s -> %s", cur->conf_str, sval), 1);
+           }
+           break;
+       }
+    }
+
+#ifdef LDAP_OPT_TIMEOUT
+    /* Convert timeout to a timeval */
+    if (ldap_conf.timeout > 0) {
+       struct timeval tv;
+       tv.tv_sec = ldap_conf.timeout;
+       tv.tv_usec = 0;
+       rc = ldap_set_option(ld, LDAP_OPT_TIMEOUT, &tv);
+       if (rc != LDAP_OPT_SUCCESS) {
+           warningx("ldap_set_option(TIMEOUT, %ld): %s",
+               (long)tv.tv_sec, ldap_err2string(rc));
+           return -1;
+       }
+       DPRINTF(("ldap_set_option(LDAP_OPT_TIMEOUT, %ld)",
+           (long)tv.tv_sec), 1);
+    }
+#endif
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+    /* Convert bind_timelimit to a timeval */
+    if (ldap_conf.bind_timelimit > 0) {
+       struct timeval tv;
+       tv.tv_sec = ldap_conf.bind_timelimit / 1000;
+       tv.tv_usec = 0;
+       rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
+       if (rc != LDAP_OPT_SUCCESS) {
+           warningx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",
+               (long)tv.tv_sec, ldap_err2string(rc));
+           return -1;
+       }
+       DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)",
+           (long)tv.tv_sec), 1);
+    }
+#endif
+
+#if defined(LDAP_OPT_X_TLS) && !defined(HAVE_LDAPSSL_INIT)
+    if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
+       int val = LDAP_OPT_X_TLS_HARD;
+       rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val);
+       if (rc != LDAP_SUCCESS) {
+           warningx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",
+               ldap_err2string(rc));
+           return -1;
+       }
+       DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)"), 1);
+    }
+#endif
+    return 0;
+}
+
+/*
+ * Create a new sudo_ldap_result structure.
+ */
+static struct ldap_result *
+sudo_ldap_result_alloc(void)
+{
+    struct ldap_result *result;
+
+    result = emalloc(sizeof(*result));
+    result->searches = NULL;
+    result->nentries = 0;
+    result->entries = NULL;
+    result->allocated_entries = 0;
+    result->user_matches = FALSE;
+    result->host_matches = FALSE;
+    return result;
+}
+
+/*
+ * Free the ldap result structure
+ */
+static void
+sudo_ldap_result_free(struct ldap_result *lres)
+{
+    struct ldap_search_list *s;
+
+    if (lres != NULL) {
+       if (lres->nentries) {
+           efree(lres->entries);
+           lres->entries = NULL;
+       }
+       if (lres->searches) {
+           while ((s = lres->searches) != NULL) {
+               ldap_msgfree(s->searchresult);
+               lres->searches = s->next;
+               efree(s);
+           }
+       }
+       efree(lres);
+    }
+}
+
+/*
+ * Add a search result to the ldap_result structure.
+ */
+static struct ldap_search_list *
+sudo_ldap_result_add_search(struct ldap_result *lres, LDAP *ldap,
+    LDAPMessage *searchresult)
+{
+    struct ldap_search_list *s, *news;
+
+    news = emalloc(sizeof(struct ldap_search_list));
+    news->next = NULL;
+    news->ldap = ldap;
+    news->searchresult = searchresult;
+
+    /* Add entry to the end of the chain (XXX - tailq instead?). */
+    if (lres->searches) {
+       for (s = lres->searches; s->next != NULL; s = s->next)
+           continue;
+       s->next = news;
+    } else {
+       lres->searches = news;
+    }
+    return news;
+}
+
+/*
+ * Connect to the LDAP server specified by ld
+ */
+static int
+sudo_ldap_bind_s(LDAP *ld)
+{
+    int rc;
+#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
+    const char *old_ccname = user_ccname;
+# ifdef HAVE_GSS_KRB5_CCACHE_NAME
+    unsigned int status;
+# endif
+#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
+           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)
+               setenv("KRB5CCNAME", old_ccname, TRUE);
+           else
+               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.
+ */
+static int
+sudo_ldap_open(struct sudo_nss *nss)
+{
+    LDAP *ld;
+    int rc, ldapnoinit = FALSE;
+    struct sudo_ldap_handle    *handle;
+
+    if (!sudo_ldap_read_config())
+       return -1;
+
+    /* Prevent reading of user ldaprc and system defaults. */
+    if (getenv("LDAPNOINIT") == NULL) {
+       ldapnoinit = TRUE;
+       setenv("LDAPNOINIT", "1", TRUE);
+    }
+
+    /* Connect to LDAP server */
+#ifdef HAVE_LDAP_INITIALIZE
+    if (ldap_conf.uri != NULL) {
+       char *buf = sudo_ldap_join_uri(ldap_conf.uri);
+       DPRINTF(("ldap_initialize(ld, %s)", buf), 2);
+       rc = ldap_initialize(&ld, buf);
+       efree(buf);
+    } else
+#endif
+       rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port);
+    if (rc != LDAP_SUCCESS) {
+       warningx("unable to initialize LDAP: %s", ldap_err2string(rc));
+       return -1;
+    }
+
+    if (ldapnoinit)
+       unsetenv("LDAPNOINIT");
+
+    /* Set LDAP options */
+    if (sudo_ldap_set_options(ld) < 0)
+       return -1;
+
+    if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
+#if defined(HAVE_LDAP_START_TLS_S)
+       rc = ldap_start_tls_s(ld, NULL, NULL);
+       if (rc != LDAP_SUCCESS) {
+           warningx("ldap_start_tls_s(): %s", ldap_err2string(rc));
+           return -1;
+       }
+       DPRINTF(("ldap_start_tls_s() ok"), 1);
+#elif defined(HAVE_LDAP_SSL_CLIENT_INIT) && defined(HAVE_LDAP_START_TLS_S_NP)
+       if (ldap_ssl_client_init(NULL, NULL, 0, &rc) != LDAP_SUCCESS) {
+           warningx("ldap_ssl_client_init(): %s", ldap_err2string(rc));
+           return -1;
+       }
+       rc = ldap_start_tls_s_np(ld, NULL);
+       if (rc != LDAP_SUCCESS) {
+           warningx("ldap_start_tls_s_np(): %s", ldap_err2string(rc));
+           return -1;
+       }
+       DPRINTF(("ldap_start_tls_s_np() ok"), 1);
+#else
+       warningx("start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()");
+#endif /* !HAVE_LDAP_START_TLS_S && !HAVE_LDAP_START_TLS_S_NP */
+    }
+
+    /* Actually connect */
+    if (sudo_ldap_bind_s(ld) != 0)
+       return -1;
+
+    /* Create a handle container. */
+    handle = emalloc(sizeof(struct sudo_ldap_handle));
+    handle->ld = ld;
+    handle->result = NULL;
+    handle->username = NULL;
+    handle->groups = NULL;
+    nss->handle = handle;
+
+    return 0;
+}
+
+static int
+sudo_ldap_setdefs(struct sudo_nss *nss)
+{
+    struct ldap_config_list_str *base;
+    struct sudo_ldap_handle *handle = nss->handle;
+    struct timeval tv, *tvp = NULL;
+    LDAP *ld;
+    LDAPMessage *entry, *result;
+    char *filt;
+    int rc;
+
+    if (handle == NULL || handle->ld == NULL)
+       return -1;
+    ld = handle->ld;
+
+    filt = sudo_ldap_build_default_filter();
+    DPRINTF(("Looking for cn=defaults: %s", filt), 1);
+
+    for (base = ldap_conf.base; base != NULL; base = base->next) {
+       if (ldap_conf.timeout > 0) {
+           tv.tv_sec = ldap_conf.timeout;
+           tv.tv_usec = 0;
+           tvp = &tv;
+       }
+       result = NULL;
+       rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
+           filt, NULL, 0, NULL, NULL, NULL, 0, &result);
+       if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
+           DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
+           sudo_ldap_parse_options(ld, entry);
+       } else
+           DPRINTF(("no default options found in %s", base->val), 1);
+
+       if (result)
+           ldap_msgfree(result);
+    }
+    efree(filt);
+
+    return 0;
+}
+
+/*
+ * like sudoers_lookup() - only LDAP style
+ */
+static int
+sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
+{
+    struct sudo_ldap_handle *handle = nss->handle;
+    LDAP *ld;
+    LDAPMessage *entry;
+    int i, rc, setenv_implied, matched = UNSPEC;
+    struct ldap_result *lres = NULL;
+
+    if (handle == NULL || handle->ld == NULL)
+       return ret;
+    ld = handle->ld;
+
+    /* Fetch list of sudoRole entries that match user and host. */
+    lres = sudo_ldap_result_get(nss, sudo_user.pw);
+
+    /*
+     * The following queries are only determine whether or not a
+     * password is required, so the order of the entries doesn't matter.
+     */
+    if (pwflag) {
+       DPRINTF(("perform search for pwflag %d", pwflag), 1);
+       int doauth = UNSPEC;
+       enum def_tuple pwcheck = 
+           (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
+
+       for (i = 0; i < lres->nentries; i++) {
+           entry = lres->entries[i].entry;
+           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 = TRUE;
+               break;
+           }
+       }
+       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;
+    }
+
+    DPRINTF(("searching LDAP for sudoers entries"), 1);
+
+    setenv_implied = FALSE;
+    for (i = 0; i < lres->nentries; i++) {
+       entry = lres->entries[i].entry;
+       if (!sudo_ldap_check_runas(ld, entry))
+           continue;
+       rc = sudo_ldap_check_command(ld, entry, &setenv_implied);
+       if (rc != UNSPEC) {
+           /* We have a match. */
+           DPRINTF(("Command %sallowed", rc == TRUE ? "" : "NOT "), 1);
+           matched = TRUE;
+           if (rc == TRUE) {
+               DPRINTF(("LDAP entry: %p", entry), 1);
+               /* Apply entry-specific 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;
+#endif /* HAVE_SELINUX */
+               SET(ret, VALIDATE_OK);
+               CLR(ret, VALIDATE_NOT_OK);
+           } else {
+               SET(ret, VALIDATE_NOT_OK);
+               CLR(ret, VALIDATE_OK);
+           }
+           break;
+       }
+    }
+
+done:
+    DPRINTF(("done with LDAP searches"), 1);
+    DPRINTF(("user_matches=%d", lres->user_matches), 1);
+    DPRINTF(("host_matches=%d", lres->host_matches), 1);
+
+    if (!ISSET(ret, VALIDATE_OK)) {
+       /* No matching entries. */
+       if (pwflag && list_pw == NULL)
+           SET(ret, FLAG_NO_CHECK);
+    }
+    if (lres->user_matches)
+       CLR(ret, FLAG_NO_USER);
+    if (lres->host_matches)
+       CLR(ret, FLAG_NO_HOST);
+    DPRINTF(("sudo_ldap_lookup(%d)=0x%02x", pwflag, ret), 1);
+
+    return ret;
+}
+
+/*
+ * Comparison function for ldap_entry_wrapper structures, descending order.
+ */
+static int
+ldap_entry_compare(const void *a, const void *b)
+{
+    const struct ldap_entry_wrapper *aw = a;
+    const struct ldap_entry_wrapper *bw = b;
+
+    return bw->order < aw->order ? -1 :
+       (bw->order > aw->order ? 1 : 0);
+}
+
+/*
+ * Find the last entry in the list of searches, usually the
+ * one currently being used to add entries.
+ * XXX - use a tailq instead?
+ */
+static struct ldap_search_list *
+sudo_ldap_result_last_search(struct ldap_result *lres)
+{
+    struct ldap_search_list *result = lres->searches;
+
+    if (result) {
+       while (result->next)
+           result = result->next;
+    }
+    return result;
+}
+
+/*
+ * Add an entry to the result structure.
+ */
+static struct ldap_entry_wrapper *
+sudo_ldap_result_add_entry(struct ldap_result *lres, LDAPMessage *entry)
+{
+    struct ldap_search_list *last;
+    struct berval **bv;
+    double order = 0.0;
+    char *ep;
+
+    /* Determine whether the entry has the sudoOrder attribute. */
+    last = sudo_ldap_result_last_search(lres);
+    bv = ldap_get_values_len(last->ldap, entry, "sudoOrder");
+    if (bv != NULL) {
+       if (ldap_count_values_len(bv) > 0) {
+           /* Get the value of this attribute, 0 if not present. */
+           DPRINTF(("order attribute raw: %s", (*bv)->bv_val), 1);
+           order = strtod((*bv)->bv_val, &ep);
+           if (ep == (*bv)->bv_val || *ep != '\0') {
+               warningx("invalid sudoOrder attribute: %s", (*bv)->bv_val);
+               order = 0.0;
+           }
+           DPRINTF(("order attribute: %f", order), 1);
+       }
+       ldap_value_free_len(bv);
+    }
+
+    /*
+     * Enlarge the array of entry wrappers as needed, preallocating blocks
+     * of 100 entries to save on allocation time.
+     */
+    if (++lres->nentries > lres->allocated_entries) {
+       lres->allocated_entries += ALLOCATION_INCREMENT;
+       lres->entries = erealloc3(lres->entries, lres->allocated_entries,
+           sizeof(lres->entries[0]));
+    }
+
+    /* Fill in the new entry and return it. */
+    lres->entries[lres->nentries - 1].entry = entry;
+    lres->entries[lres->nentries - 1].order = order;
+
+    return &lres->entries[lres->nentries - 1];
+}
+
+/*
+ * Free the ldap result structure in the sudo_nss handle.
+ */
+static void
+sudo_ldap_result_free_nss(struct sudo_nss *nss)
+{
+    struct sudo_ldap_handle *handle = nss->handle;
+
+    if (handle->result != NULL) {
+       DPRINTF(("removing reusable search result"), 1);
+       sudo_ldap_result_free(handle->result);
+       if (handle->username) {
+           efree(handle->username);
+           handle->username = NULL;
+       }
+       handle->groups = NULL;
+       handle->result = NULL;
+    }
+}
+
+/*
+ * Perform the LDAP query for the user or return a cached query if
+ * there is one for this user.
+ */
+static struct ldap_result *
+sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
+{
+    struct sudo_ldap_handle *handle = nss->handle;
+    struct ldap_config_list_str *base;
+    struct ldap_result *lres;
+    struct timeval tv, *tvp = NULL;
+    LDAPMessage *entry, *result;
+    LDAP *ld = handle->ld;
+    int do_netgr, rc;
+    char *filt;
+
+    /*
+     * If we already have a cached result, return it so we don't have to
+     * have to contact the LDAP server again.
+     */
+    if (handle->result) {
+       if (handle->groups == user_groups &&
+           strcmp(pw->pw_name, handle->username) == 0) {
+           DPRINTF(("reusing previous result (user %s) with %d entries",
+               handle->username, handle->result->nentries), 1);
+           return handle->result;
+       }
+       /* User mismatch, cached result cannot be used. */
+       DPRINTF(("removing result (user %s), new search (user %s)",
+           handle->username, pw->pw_name), 1);
+       sudo_ldap_result_free_nss(nss);
+    }
+
+    /*
+     * 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.
+     *
+     * Since we have to sort the possible entries before we make a
+     * decision, we perform the queries and store all of the results in
+     * an ldap_result object.  The results are then sorted by sudoOrder.
+     */
+    lres = sudo_ldap_result_alloc();
+    for (do_netgr = 0; do_netgr < 2; do_netgr++) {
+       filt = do_netgr ? sudo_ldap_build_pass2() : sudo_ldap_build_pass1(pw);
+       DPRINTF(("ldap search '%s'", filt), 1);
+       for (base = ldap_conf.base; base != NULL; base = base->next) {
+           DPRINTF(("searching from base '%s'", base->val), 1);
+           if (ldap_conf.timeout > 0) {
+               tv.tv_sec = ldap_conf.timeout;
+               tv.tv_usec = 0;
+               tvp = &tv;
+           }
+           result = NULL;
+           rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, filt,
+               NULL, 0, NULL, NULL, NULL, 0, &result);
+           if (rc != LDAP_SUCCESS) {
+               DPRINTF(("nothing found for '%s'", filt), 1);
+               continue;
+           }
+           lres->user_matches = TRUE;
+
+           /* Add the seach result to list of search results. */
+           DPRINTF(("adding search result"), 1);
+           sudo_ldap_result_add_search(lres, ld, result);
+           LDAP_FOREACH(entry, ld, result) {
+               if ((!do_netgr ||
+                   sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
+                   sudo_ldap_check_host(ld, entry)) {
+                   lres->host_matches = TRUE;
+                   sudo_ldap_result_add_entry(lres, entry);
+               }
+           }
+           DPRINTF(("result now has %d entries", lres->nentries), 1);
+       }
+       efree(filt);
+    }
+
+    /* Sort the entries by the sudoOrder attribute. */
+    DPRINTF(("sorting remaining %d entries", lres->nentries), 1);
+    qsort(lres->entries, lres->nentries, sizeof(lres->entries[0]),
+       ldap_entry_compare);
+
+    /* Store everything in the sudo_nss handle. */
+    handle->result = lres;
+    handle->username = estrdup(pw->pw_name);
+    handle->groups = user_groups;
+
+    return lres;
+}
+
+/*
+ * Shut down the LDAP connection.
+ */
+static int
+sudo_ldap_close(struct sudo_nss *nss)
+{
+    struct sudo_ldap_handle *handle = nss->handle;
+
+    if (handle != NULL) {
+       /* Free the result before unbinding; it may use the LDAP connection. */
+       sudo_ldap_result_free_nss(nss);
+
+       /* Unbind and close the LDAP connection. */
+       if (handle->ld != NULL) {
+           ldap_unbind_ext_s(handle->ld, NULL, NULL);
+           handle->ld = NULL;
+       }
+
+       /* Free the handle container. */
+       efree(nss->handle);
+       nss->handle = NULL;
+    }
+    return 0;
+}
+
+/*
+ * STUB
+ */
+static int
+sudo_ldap_parse(struct sudo_nss *nss)
+{
+    return 0;
+}
+
+#if 0
+/*
+ * Create an ldap_result from an LDAP search result.
+ *
+ * This function is currently not used anywhere, it is left here as
+ * an example of how to use the cached searches.
+ */
+static struct ldap_result *
+sudo_ldap_result_from_search(LDAP *ldap, LDAPMessage *searchresult)
+{
+    /*
+     * An ldap_result is built from several search results, which are
+     * organized in a list. The head of the list is maintained in the
+     * ldap_result structure, together with the wrappers that point
+     * to individual entries, this has to be initialized first.
+     */
+    struct ldap_result *result = sudo_ldap_result_alloc();
+
+    /*
+     * Build a new list node for the search result, this creates the
+     * list node.
+     */
+    struct ldap_search_list *last = sudo_ldap_result_add_search(result,
+       ldap, searchresult);
+
+    /*
+     * Now add each entry in the search result to the array of of entries
+     * in the ldap_result object.
+     */
+    LDAPMessage        *entry;
+    LDAP_FOREACH(entry, last->ldap, last->searchresult) {
+       sudo_ldap_result_add_entry(result, entry);
+    }
+    DPRINTF(("sudo_ldap_result_from_search: %d entries found",
+       result->nentries), 2);
+    return result;
+}
+#endif
diff --git a/plugins/sudoers/linux_audit.c b/plugins/sudoers/linux_audit.c
new file mode 100644 (file)
index 0000000..7505f69
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2010 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 <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <libaudit.h>
+
+#include "missing.h"
+#include "error.h"
+#include "alloc.h"
+#include "linux_audit.h"
+
+/*
+ * Open audit connection if possible.
+ * Returns audit fd on success and -1 on failure.
+ */
+static int
+linux_audit_open(void)
+{
+    static int au_fd = -1;
+
+    if (au_fd != -1)
+       return au_fd;
+    au_fd = audit_open();
+    if (au_fd == -1) {
+       /* Kernel may not have audit support. */
+       if (errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
+           error(1, "unable to open audit system");
+    } else {
+       (void)fcntl(au_fd, F_SETFD, FD_CLOEXEC);
+    }
+    return au_fd;
+}
+
+int
+linux_audit_command(char *argv[], int result)
+{
+    int au_fd, rc;
+    char *command, *cp, **av;
+    size_t size, n;
+
+    if ((au_fd = linux_audit_open()) == -1)
+       return -1;
+
+    /* Convert argv to a flat string. */
+    for (size = 0, av = argv; *av != NULL; av++)
+       size += strlen(*av) + 1;
+    command = cp = emalloc(size);
+    for (av = argv; *av != NULL; av++) {
+       n = strlcpy(cp, *av, size - (cp - command));
+       if (n >= size - (cp - command))
+           errorx(1, "internal error, linux_audit_command() overflow");
+       cp += n;
+       *cp++ = ' ';
+    }
+    *--cp = '\0';
+
+    /* Log command, ignoring ECONNREFUSED on error. */
+    rc = audit_log_user_command(au_fd, AUDIT_USER_CMD, command, NULL, result);
+    if (rc <= 0 && errno != ECONNREFUSED)
+       warning("unable to send audit message");
+
+    efree(command);
+
+    return rc;
+}
diff --git a/plugins/sudoers/linux_audit.h b/plugins/sudoers/linux_audit.h
new file mode 100644 (file)
index 0000000..8f4d46c
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef _SUDO_LINUX_AUDIT_H
+#define        _SUDO_LINUX_AUDIT_H
+
+int    linux_audit_command(char *argv[], int result);
+
+#endif /* _SUDO_LINUX_AUDIT_H */
diff --git a/plugins/sudoers/logging.c b/plugins/sudoers/logging.c
new file mode 100644 (file)
index 0000000..82f3e69
--- /dev/null
@@ -0,0 +1,773 @@
+/*
+ * Copyright (c) 1994-1996, 1998-2011 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.
+ */
+
+#ifdef __TANDEM
+# include <floss.h>
+#endif
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/wait.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_SETLOCALE
+# include <locale.h>
+#endif /* HAVE_SETLOCALE */
+#ifdef HAVE_NL_LANGINFO
+# include <langinfo.h>
+#endif /* HAVE_NL_LANGINFO */
+#include <pwd.h>
+#include <grp.h>
+#include <signal.h>
+#include <time.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <setjmp.h>
+
+#include "sudoers.h"
+
+static void do_syslog(int, char *);
+static void do_logfile(char *);
+static void send_mail(const char *fmt, ...);
+static int should_mail(int);
+static void mysyslog(int, const char *, ...);
+static char *new_logline(const char *, int);
+
+extern sigjmp_buf error_jmp;
+
+#define MAXSYSLOGTRIES 16      /* num of retries for broken syslogs */
+
+/*
+ * We do an openlog(3)/closelog(3) for each message because some
+ * authentication methods (notably PAM) use syslog(3) for their
+ * own nefarious purposes and may call openlog(3) and closelog(3).
+ * Note that because we don't want to assume that all systems have
+ * vsyslog(3) (HP-UX doesn't) "%m" will not be expanded.
+ * Sadly this is a maze of #ifdefs.
+ */
+static void
+mysyslog(int pri, const char *fmt, ...)
+{
+#ifdef BROKEN_SYSLOG
+    int i;
+#endif
+    char buf[MAXSYSLOGLEN+1];
+    va_list ap;
+
+    va_start(ap, fmt);
+#ifdef LOG_NFACILITIES
+    openlog("sudo", 0, def_syslog);
+#else
+    openlog("sudo", 0);
+#endif
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+#ifdef BROKEN_SYSLOG
+    /*
+     * Some versions of syslog(3) don't guarantee success and return
+     * an int (notably HP-UX < 10.0).  So, if at first we don't succeed,
+     * try, try again...
+     */
+    for (i = 0; i < MAXSYSLOGTRIES; i++)
+       if (syslog(pri, "%s", buf) == 0)
+           break;
+#else
+    syslog(pri, "%s", buf);
+#endif /* BROKEN_SYSLOG */
+    va_end(ap);
+    closelog();
+}
+
+#define FMT_FIRST "%8s : %s"
+#define FMT_CONTD "%8s : (command continued) %s"
+
+/*
+ * Log a message to syslog, pre-pending the username and splitting the
+ * message into parts if it is longer than MAXSYSLOGLEN.
+ */
+static void
+do_syslog(int pri, char *msg)
+{
+    size_t len, maxlen;
+    char *p, *tmp, save;
+    const char *fmt;
+
+#ifdef HAVE_SETLOCALE
+    const char *old_locale = estrdup(setlocale(LC_ALL, NULL));
+    if (!setlocale(LC_ALL, def_sudoers_locale))
+       setlocale(LC_ALL, "C");
+#endif /* HAVE_SETLOCALE */
+
+    /*
+     * Log the full line, breaking into multiple syslog(3) calls if necessary
+     */
+    fmt = FMT_FIRST;
+    maxlen = MAXSYSLOGLEN - (sizeof(FMT_FIRST) - 6 + strlen(user_name));
+    for (p = msg; *p != '\0'; ) {
+       len = strlen(p);
+       if (len > maxlen) {
+           /*
+            * Break up the line into what will fit on one syslog(3) line
+            * Try to avoid breaking words into several lines if possible.
+            */
+           tmp = memrchr(p, ' ', maxlen);
+           if (tmp == NULL)
+               tmp = p + maxlen;
+
+           /* NULL terminate line, but save the char to restore later */
+           save = *tmp;
+           *tmp = '\0';
+
+           mysyslog(pri, fmt, user_name, p);
+
+           *tmp = save;                        /* restore saved character */
+
+           /* Advance p and eliminate leading whitespace */
+           for (p = tmp; *p == ' '; p++)
+               ;
+       } else {
+           mysyslog(pri, fmt, user_name, p);
+           p += len;
+       }
+       fmt = FMT_CONTD;
+       maxlen = MAXSYSLOGLEN - (sizeof(FMT_CONTD) - 6 + strlen(user_name));
+    }
+
+#ifdef HAVE_SETLOCALE
+    setlocale(LC_ALL, old_locale);
+    efree((void *)old_locale);
+#endif /* HAVE_SETLOCALE */
+}
+
+static void
+do_logfile(char *msg)
+{
+    char *full_line;
+    char *beg, *oldend, *end;
+    FILE *fp;
+    mode_t oldmask;
+    size_t maxlen;
+
+    oldmask = umask(077);
+    maxlen = def_loglinelen > 0 ? def_loglinelen : 0;
+    fp = fopen(def_logfile, "a");
+    (void) umask(oldmask);
+    if (fp == NULL) {
+       send_mail("Can't open log file: %s: %s", def_logfile, strerror(errno));
+    } else if (!lock_file(fileno(fp), SUDO_LOCK)) {
+       send_mail("Can't lock log file: %s: %s", def_logfile, strerror(errno));
+    } else {
+       time_t now;
+
+#ifdef HAVE_SETLOCALE
+       const char *old_locale = estrdup(setlocale(LC_ALL, NULL));
+       if (!setlocale(LC_ALL, def_sudoers_locale))
+           setlocale(LC_ALL, "C");
+#endif /* HAVE_SETLOCALE */
+
+       now = time(NULL);
+       if (def_loglinelen == 0) {
+           /* Don't pretty-print long log file lines (hard to grep) */
+           if (def_log_host)
+               (void) fprintf(fp, "%s : %s : HOST=%s : %s\n",
+                   get_timestr(now, def_log_year), user_name, user_shost, msg);
+           else
+               (void) fprintf(fp, "%s : %s : %s\n",
+                   get_timestr(now, def_log_year), user_name, msg);
+       } else {
+           if (def_log_host)
+               easprintf(&full_line, "%s : %s : HOST=%s : %s",
+                   get_timestr(now, def_log_year), user_name, user_shost, msg);
+           else
+               easprintf(&full_line, "%s : %s : %s",
+                   get_timestr(now, def_log_year), user_name, msg);
+
+           /*
+            * Print out full_line with word wrap
+            */
+           beg = end = full_line;
+           while (beg) {
+               oldend = end;
+               end = strchr(oldend, ' ');
+
+               if (maxlen > 0 && end) {
+                   *end = '\0';
+                   if (strlen(beg) > maxlen) {
+                       /* too far, need to back up & print the line */
+
+                       if (beg == (char *)full_line)
+                           maxlen -= 4;        /* don't indent first line */
+
+                       *end = ' ';
+                       if (oldend != beg) {
+                           /* rewind & print */
+                           end = oldend-1;
+                           while (*end == ' ')
+                               --end;
+                           *(++end) = '\0';
+                           (void) fprintf(fp, "%s\n    ", beg);
+                           *end = ' ';
+                       } else {
+                           (void) fprintf(fp, "%s\n    ", beg);
+                       }
+
+                       /* reset beg to point to the start of the new substr */
+                       beg = end;
+                       while (*beg == ' ')
+                           ++beg;
+                   } else {
+                       /* we still have room */
+                       *end = ' ';
+                   }
+
+                   /* remove leading whitespace */
+                   while (*end == ' ')
+                       ++end;
+               } else {
+                   /* final line */
+                   (void) fprintf(fp, "%s\n", beg);
+                   beg = NULL;                 /* exit condition */
+               }
+           }
+           efree(full_line);
+       }
+       (void) fflush(fp);
+       (void) lock_file(fileno(fp), SUDO_UNLOCK);
+       (void) fclose(fp);
+
+#ifdef HAVE_SETLOCALE
+       setlocale(LC_ALL, old_locale);
+       efree((void *)old_locale);
+#endif /* HAVE_SETLOCALE */
+    }
+}
+
+/*
+ * Log and mail the denial message, optionally informing the user.
+ */
+void
+log_denial(int status, int inform_user)
+{
+    char *message;
+    char *logline;
+
+    /* 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
+       message = "command not allowed";
+
+    logline = new_logline(message, 0);
+
+    if (should_mail(status))
+       send_mail("%s", logline);       /* send mail based on status */
+
+    /* Inform the user if they failed to authenticate.  */
+    if (inform_user) {
+       if (ISSET(status, FLAG_NO_USER)) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "%s is not in the sudoers file.  "
+               "This incident will be reported.\n", user_name);
+       } else if (ISSET(status, FLAG_NO_HOST)) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "%s is not allowed to run sudo "
+               "on %s.  This incident will be reported.\n",
+               user_name, user_shost);
+       } else if (ISSET(status, FLAG_NO_CHECK)) {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "Sorry, user %s may not run "
+               "sudo on %s.\n", user_name, user_shost);
+       } else {
+           sudo_printf(SUDO_CONV_ERROR_MSG, "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 : "",
+               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(def_syslog_badpri, logline);
+    if (def_logfile)
+       do_logfile(logline);
+
+    efree(logline);
+}
+
+/*
+ * Log and potentially mail the allowed command.
+ */
+void
+log_allowed(int status)
+{
+    char *logline;
+
+    logline = new_logline(NULL, 0);
+
+    if (should_mail(status))
+       send_mail("%s", 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(logline);
+}
+
+void
+log_error(int flags, const char *fmt, ...)
+{
+    int serrno = errno;
+    char *message;
+    char *logline;
+    va_list ap;
+
+    /* Expand printf-style format + args. */
+    va_start(ap, fmt);
+    evasprintf(&message, fmt, ap);
+    va_end(ap);
+
+    /* Become root if we are not already to avoid user interference */
+    set_perms(PERM_ROOT|PERM_NOEXIT);
+
+    if (ISSET(flags, MSG_ONLY))
+       logline = message;
+    else
+       logline = new_logline(message, ISSET(flags, USE_ERRNO) ? serrno : 0);
+
+    /*
+     * Tell the user.
+     */
+    if (!ISSET(flags, NO_STDERR)) {
+       if (ISSET(flags, USE_ERRNO))
+           warning("%s", message);
+       else
+           warningx("%s", message);
+    }
+    if (logline != message)
+        efree(message);
+
+    /*
+     * Send a copy of the error via mail.
+     */
+    if (!ISSET(flags, NO_MAIL))
+       send_mail("%s", logline);
+
+    /*
+     * Log to syslog and/or a file.
+     */
+    if (def_syslog)
+       do_syslog(def_syslog_badpri, logline);
+    if (def_logfile)
+       do_logfile(logline);
+
+    efree(logline);
+
+    restore_perms();
+
+    if (!ISSET(flags, NO_EXIT)) {
+       plugin_cleanup(0);
+       siglongjmp(error_jmp, 1);
+    }
+}
+
+#define MAX_MAILFLAGS  63
+
+/*
+ * Send a message to MAILTO user
+ */
+static void
+send_mail(const char *fmt, ...)
+{
+    FILE *mail;
+    char *p;
+    int fd, pfd[2], status;
+    pid_t pid, rv;
+    sigaction_t sa;
+    va_list ap;
+#ifndef NO_ROOT_MAILER
+    static char *root_envp[] = {
+       "HOME=/",
+       "PATH=/usr/bin:/bin:/usr/sbin:/sbin",
+       "LOGNAME=root",
+       "USERNAME=root",
+       "USER=root",
+       NULL
+    };
+#endif /* NO_ROOT_MAILER */
+
+    /* Just return if mailer is disabled. */
+    if (!def_mailerpath || !def_mailto)
+       return;
+
+    /* Fork and return, child will daemonize. */
+    switch (pid = fork()) {
+       case -1:
+           /* Error. */
+           error(1, "cannot fork");
+           break;
+       case 0:
+           /* Child. */
+           switch (pid = fork()) {
+               case -1:
+                   /* Error. */
+                   mysyslog(LOG_ERR, "cannot fork: %m");
+                   _exit(1);
+               case 0:
+                   /* Grandchild continues below. */
+                   break;
+               default:
+                   /* Parent will wait for us. */
+                   _exit(0);
+           }
+           break;
+       default:
+           /* Parent. */
+           do {
+               rv = waitpid(pid, &status, 0);
+           } while (rv == -1 && errno == EINTR);
+           return;
+    }
+
+    /* Daemonize - disassociate from session/tty. */
+    if (setsid() == -1)
+      warning("setsid");
+    if (chdir("/") == -1)
+      warning("chdir(/)");
+    if ((fd = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) {
+       (void) dup2(fd, STDIN_FILENO);
+       (void) dup2(fd, STDOUT_FILENO);
+       (void) dup2(fd, STDERR_FILENO);
+    }
+
+#ifdef HAVE_SETLOCALE
+    if (!setlocale(LC_ALL, def_sudoers_locale)) {
+       setlocale(LC_ALL, "C");
+       efree(def_sudoers_locale);
+       def_sudoers_locale = estrdup("C");
+    }
+#endif /* HAVE_SETLOCALE */
+
+    /* 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 = SA_INTERRUPT;
+    sa.sa_handler = SIG_IGN;
+    (void) sigaction(SIGPIPE, &sa, NULL);
+
+    if (pipe(pfd) == -1) {
+       mysyslog(LOG_ERR, "cannot open pipe: %m");
+       _exit(1);
+    }
+
+    switch (pid = fork()) {
+       case -1:
+           /* Error. */
+           mysyslog(LOG_ERR, "cannot fork: %m");
+           _exit(1);
+           break;
+       case 0:
+           {
+               char *argv[MAX_MAILFLAGS + 1];
+               char *mpath, *mflags;
+               int i;
+
+               /* Child, set stdin to output side of the pipe */
+               if (pfd[0] != STDIN_FILENO) {
+                   if (dup2(pfd[0], STDIN_FILENO) == -1) {
+                       mysyslog(LOG_ERR, "cannot dup stdin: %m");
+                       _exit(127);
+                   }
+                   (void) close(pfd[0]);
+               }
+               (void) close(pfd[1]);
+
+               /* Build up an argv based on the mailer path and flags */
+               mflags = estrdup(def_mailerflags);
+               mpath = estrdup(def_mailerpath);
+               if ((argv[0] = strrchr(mpath, ' ')))
+                   argv[0]++;
+               else
+                   argv[0] = mpath;
+
+               i = 1;
+               if ((p = strtok(mflags, " \t"))) {
+                   do {
+                       argv[i] = p;
+                   } while (++i < MAX_MAILFLAGS && (p = strtok(NULL, " \t")));
+               }
+               argv[i] = NULL;
+
+               /*
+                * Depending on the config, either run the mailer as root
+                * (so user cannot kill it) or as the user (for the paranoid).
+                */
+#ifndef NO_ROOT_MAILER
+               set_perms(PERM_ROOT|PERM_NOEXIT);
+               execve(mpath, argv, root_envp);
+#else
+               set_perms(PERM_FULL_USER|PERM_NOEXIT);
+               execv(mpath, argv);
+#endif /* NO_ROOT_MAILER */
+               mysyslog(LOG_ERR, "cannot execute %s: %m", mpath);
+               _exit(127);
+           }
+           break;
+    }
+
+    (void) close(pfd[0]);
+    mail = fdopen(pfd[1], "w");
+
+    /* Pipes are all setup, send message. */
+    (void) fprintf(mail, "To: %s\nFrom: %s\nAuto-Submitted: %s\nSubject: ",
+       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) != '%') {
+           switch (*(++p)) {
+               case 'h':
+                   (void) fputs(user_host, mail);
+                   break;
+               case 'u':
+                   (void) fputs(user_name, mail);
+                   break;
+               default:
+                   p--;
+                   break;
+           }
+       } else
+           (void) fputc(*p, mail);
+    }
+
+#ifdef HAVE_NL_LANGINFO
+    if (strcmp(def_sudoers_locale, "C") != 0)
+       (void) fprintf(mail, "\nContent-Type: text/plain; charset=\"%s\"\nContent-Transfer-Encoding: 8bit", nl_langinfo(CODESET));
+#endif /* HAVE_NL_LANGINFO */
+
+    (void) fprintf(mail, "\n\n%s : %s : %s : ", user_host,
+       get_timestr(time(NULL), def_log_year), user_name);
+    va_start(ap, fmt);
+    (void) vfprintf(mail, fmt, ap);
+    va_end(ap);
+    fputs("\n\n", mail);
+
+    fclose(mail);
+    do {
+        rv = waitpid(pid, &status, 0);
+    } while (rv == -1 && errno == EINTR);
+    _exit(0);
+}
+
+/*
+ * Determine whether we should send mail based on "status" and defaults options.
+ */
+static int
+should_mail(int status)
+{
+
+    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));
+}
+
+#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="
+#define        LL_TSID_STR     "TSID="
+
+#define IS_SESSID(s) ( \
+    isalnum((unsigned char)(s)[0]) && isalnum((unsigned char)(s)[1]) && \
+    (s)[2] == '/' && \
+    isalnum((unsigned char)(s)[3]) && isalnum((unsigned char)(s)[4]) && \
+    (s)[5] == '/' && \
+    isalnum((unsigned char)(s)[6]) && isalnum((unsigned char)(s)[7]) && \
+    (s)[8] == '\0')
+
+/*
+ * Allocate and fill in a new logline.
+ */
+static char *
+new_logline(const char *message, int serrno)
+{
+    size_t len = 0;
+    char *errstr = NULL;
+    char *evstr = NULL;
+    char *line, sessid[7], *tsid = NULL;
+
+    /* A TSID may be a sudoers-style session ID or a free-form string. */
+    if (sudo_user.iolog_file != NULL) {
+       if (IS_SESSID(sudo_user.iolog_file)) {
+           sessid[0] = sudo_user.iolog_file[0];
+           sessid[1] = sudo_user.iolog_file[1];
+           sessid[2] = sudo_user.iolog_file[3];
+           sessid[3] = sudo_user.iolog_file[4];
+           sessid[4] = sudo_user.iolog_file[6];
+           sessid[5] = sudo_user.iolog_file[7];
+           sessid[6] = '\0';
+           tsid = sessid;
+       } else {
+           tsid = sudo_user.iolog_file;
+       }
+    }
+
+    /*
+     * 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 (tsid != NULL)
+       len += sizeof(LL_TSID_STR) + 2 + strlen(tsid);
+    if (sudo_user.env_vars != NULL) {
+       size_t evlen = 0;
+       char * const *ep;
+
+       for (ep = sudo_user.env_vars; *ep != NULL; ep++)
+           evlen += strlen(*ep) + 1;
+       evstr = emalloc(evlen);
+       evstr[0] = '\0';
+       for (ep = sudo_user.env_vars; *ep != NULL; ep++) {
+           strlcat(evstr, *ep, evlen);
+           strlcat(evstr, " ", evlen); /* NOTE: last one will fail */
+       }
+       len += sizeof(LL_ENV_STR) + 2 + evlen;
+    }
+    if (user_cmnd != NULL) {
+       /* Note: we log "sudo -l command arg ..." as "list command arg ..." */
+       len += sizeof(LL_CMND_STR) - 1 + strlen(user_cmnd);
+       if (ISSET(sudo_mode, MODE_CHECK))
+           len += sizeof("list ") - 1;
+       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 (tsid != NULL) {
+       if (strlcat(line, LL_TSID_STR, len) >= len ||
+           strlcat(line, tsid, 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 (user_cmnd != NULL) {
+       if (strlcat(line, LL_CMND_STR, len) >= len)
+           goto toobig;
+       if (ISSET(sudo_mode, MODE_CHECK) && strlcat(line, "list ", len) >= len)
+           goto toobig;
+       if (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");
+}
diff --git a/plugins/sudoers/logging.h b/plugins/sudoers/logging.h
new file mode 100644 (file)
index 0000000..43d5ff0
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1999-2005, 2009-2010
+ *     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.
+ */
+
+#ifndef _LOGGING_H
+#define _LOGGING_H
+
+#include <syslog.h>
+#ifdef __STDC__
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+
+/* Logging types */
+#define SLOG_SYSLOG            0x01
+#define SLOG_FILE              0x02
+#define SLOG_BOTH              0x03
+
+/* Flags for log_error() */
+#define MSG_ONLY               0x01
+#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
+ * will log this much, after that, it truncates the log line.
+ * We need this here to make sure that we continue with another
+ * syslog(3) call if the internal buffer is more than 1023 characters.
+ */
+#ifndef MAXSYSLOGLEN
+# define MAXSYSLOGLEN          960
+#endif
+
+void audit_success(char *[]);
+void audit_failure(char *[], char const * const, ...);
+void log_allowed(int);
+void log_denial(int, int);
+void log_error(int flags, const char *fmt, ...) __printflike(2, 3);
+void reapchild(int);
+
+#endif /* _LOGGING_H */
diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c
new file mode 100644 (file)
index 0000000..8e06a4d
--- /dev/null
@@ -0,0 +1,867 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2011
+ *     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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_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 "sudoers.h"
+#include "interfaces.h"
+#include "parse.h"
+#include <gram.h>
+
+#ifndef HAVE_FNMATCH
+# include "compat/fnmatch.h"
+#endif /* HAVE_FNMATCH */
+#ifndef HAVE_EXTENDED_GLOB
+# include "compat/glob.h"
+#endif /* HAVE_EXTENDED_GLOB */
+
+static struct member_list empty;
+
+static int command_matches_dir(char *, size_t);
+static int command_matches_glob(char *, char *);
+static int command_matches_fnmatch(char *, char *);
+static int command_matches_normal(char *, char *);
+
+/*
+ * 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(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 = alias_find(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(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(struct member_list *user_list, struct member_list *group_list)
+{
+    struct member *m;
+    struct alias *a;
+    int rval;
+    int user_matched = UNSPEC;
+    int group_matched = UNSPEC;
+
+    if (runas_pw != NULL) {
+       /* If no runas user or runas group listed in sudoers, use default. */
+       if (tq_empty(user_list) && tq_empty(group_list))
+           return userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw);
+
+       tq_foreach_rev(user_list, m) {
+           switch (m->type) {
+               case ALL:
+                   user_matched = !m->negated;
+                   break;
+               case NETGROUP:
+                   if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name))
+                       user_matched = !m->negated;
+                   break;
+               case USERGROUP:
+                   if (usergr_matches(m->name, runas_pw->pw_name, runas_pw))
+                       user_matched = !m->negated;
+                   break;
+               case ALIAS:
+                   if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
+                       rval = _runaslist_matches(&a->members, &empty);
+                       if (rval != UNSPEC)
+                           user_matched = m->negated ? !rval : rval;
+                       break;
+                   }
+                   /* FALLTHROUGH */
+               case WORD:
+                   if (userpw_matches(m->name, runas_pw->pw_name, runas_pw))
+                       user_matched = !m->negated;
+                   break;
+           }
+           if (user_matched != UNSPEC)
+               break;
+       }
+    }
+
+    if (runas_gr != NULL) {
+       if (user_matched == UNSPEC) {
+           if (runas_pw == NULL || strcmp(runas_pw->pw_name, user_name) == 0)
+               user_matched = ALLOW;   /* only changing group */
+       }
+       tq_foreach_rev(group_list, m) {
+           switch (m->type) {
+               case ALL:
+                   group_matched = !m->negated;
+                   break;
+               case ALIAS:
+                   if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
+                       rval = _runaslist_matches(&a->members, &empty);
+                       if (rval != UNSPEC)
+                           group_matched = m->negated ? !rval : rval;
+                       break;
+                   }
+                   /* FALLTHROUGH */
+               case WORD:
+                   if (group_matches(m->name, runas_gr))
+                       group_matched = !m->negated;
+                   break;
+           }
+           if (group_matched != UNSPEC)
+               break;
+       }
+    }
+
+    if (user_matched == DENY || group_matched == DENY)
+       return DENY;
+    if (user_matched == group_matched || runas_gr == NULL)
+       return user_matched;
+    return UNSPEC;
+}
+
+int
+runaslist_matches(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(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 = alias_find(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(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(struct member_list *list)
+{
+    struct member *m;
+    int matched = UNSPEC;
+
+    tq_foreach_rev(list, m) {
+       matched = cmnd_matches(m);
+       if (matched != UNSPEC)
+           break;
+    }
+    return matched;
+}
+
+int
+cmndlist_matches(struct member_list *list)
+{
+    alias_seqno++;
+    return _cmndlist_matches(list);
+}
+
+/*
+ * Check cmnd and args.
+ * Returns ALLOW, DENY or UNSPEC.
+ */
+int
+cmnd_matches(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 = alias_find(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;
+}
+
+static int
+command_args_match(sudoers_cmnd, sudoers_args)
+    char *sudoers_cmnd;
+    char *sudoers_args;
+{
+    int flags = 0;
+
+    /*
+     * If no args specified in sudoers, any user args are allowed.
+     * If the empty string is specified in sudoers, no user args are allowed.
+     */
+    if (!sudoers_args ||
+       (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)))
+       return TRUE;
+    /*
+     * If args are specified in sudoers, they must match the user args.
+     * If running as sudoedit, all args are assumed to be paths.
+     */
+    if (sudoers_args) {
+       /* For sudoedit, all args are assumed to be pathnames. */
+       if (strcmp(sudoers_cmnd, "sudoedit") == 0)
+           flags = FNM_PATHNAME;
+       if (fnmatch(sudoers_args, user_args ? user_args : "", flags) == 0)
+           return TRUE;
+    }
+    return FALSE;
+}
+
+/*
+ * 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(char *sudoers_cmnd, char *sudoers_args)
+{
+    /* Check for pseudo-commands */
+    if (sudoers_cmnd[0] != '/') {
+       /*
+        * 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 (command_args_match(sudoers_cmnd, sudoers_args)) {
+           efree(safe_cmnd);
+           safe_cmnd = estrdup(sudoers_cmnd);
+           return TRUE;
+       } else
+           return FALSE;
+    }
+
+    if (has_meta(sudoers_cmnd)) {
+       /*
+        * If sudoers_cmnd has meta characters in it, we need to
+        * use glob(3) and/or fnmatch(3) to do the matching.
+        */
+       if (def_fast_glob)
+           return command_matches_fnmatch(sudoers_cmnd, sudoers_args);
+       return command_matches_glob(sudoers_cmnd, sudoers_args);
+    }
+    return command_matches_normal(sudoers_cmnd, sudoers_args);
+}
+
+static int
+command_matches_fnmatch(char *sudoers_cmnd, char *sudoers_args)
+{
+    /*
+     * Return true if fnmatch(3) succeeds 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.
+     */
+    if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0)
+       return FALSE;
+    if (command_args_match(sudoers_cmnd, sudoers_args)) {
+       if (safe_cmnd)
+           free(safe_cmnd);
+       safe_cmnd = estrdup(user_cmnd);
+       return TRUE;
+    } else
+       return FALSE;
+}
+
+static int
+command_matches_glob(char *sudoers_cmnd, char *sudoers_args)
+{
+    struct stat sudoers_stat;
+    size_t dlen;
+    char **ap, *base, *cp;
+    glob_t gl;
+
+    /*
+     * 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.
+     */
+    dlen = strlen(sudoers_cmnd);
+    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 || gl.gl_pathc == 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 (command_args_match(sudoers_cmnd, sudoers_args)) {
+       efree(safe_cmnd);
+       safe_cmnd = estrdup(user_cmnd);
+       return TRUE;
+    }
+    return FALSE;
+}
+
+static int
+command_matches_normal(char *sudoers_cmnd, char *sudoers_args)
+{
+    struct stat sudoers_stat;
+    char *base;
+    size_t dlen;
+
+    /* If it ends in '/' it is a directory spec. */
+    dlen = strlen(sudoers_cmnd);
+    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 (command_args_match(sudoers_cmnd, sudoers_args)) {
+       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(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)) {
+       closedir(dirp);
+       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 == NULL ||
+           (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(char *n)
+{
+    union sudo_in_addr_un addr;
+    struct interface *ifp;
+#ifdef HAVE_IN6_ADDR
+    int j;
+#endif
+    int family;
+
+#ifdef HAVE_IN6_ADDR
+    if (inet_pton(AF_INET6, n, &addr.ip6) > 0) {
+       family = AF_INET6;
+    } else
+#endif
+    {
+       family = AF_INET;
+       addr.ip4.s_addr = inet_addr(n);
+    }
+
+    for (ifp = interfaces; ifp != NULL; ifp = ifp->next) {
+       if (ifp->family != family)
+           continue;
+       switch(family) {
+           case AF_INET:
+               if (ifp->addr.ip4.s_addr == addr.ip4.s_addr ||
+                   (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr)
+                   == addr.ip4.s_addr)
+                   return TRUE;
+               break;
+#ifdef HAVE_IN6_ADDR
+           case AF_INET6:
+               if (memcmp(ifp->addr.ip6.s6_addr, addr.ip6.s6_addr,
+                   sizeof(addr.ip6.s6_addr)) == 0)
+                   return TRUE;
+               for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) {
+                   if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j])
+                       break;
+               }
+               if (j == sizeof(addr.ip6.s6_addr))
+                   return TRUE;
+#endif
+       }
+    }
+
+    return FALSE;
+}
+
+static int
+addr_matches_if_netmask(char *n, char *m)
+{
+    int i;
+    union sudo_in_addr_un addr, mask;
+    struct interface *ifp;
+#ifdef HAVE_IN6_ADDR
+    int j;
+#endif
+    int family;
+
+#ifdef HAVE_IN6_ADDR
+    if (inet_pton(AF_INET6, n, &addr.ip6) > 0)
+       family = AF_INET6;
+    else
+#endif
+    {
+       family = AF_INET;
+       addr.ip4.s_addr = inet_addr(n);
+    }
+
+    if (family == AF_INET) {
+       if (strchr(m, '.'))
+           mask.ip4.s_addr = inet_addr(m);
+       else {
+           i = 32 - atoi(m);
+           mask.ip4.s_addr = 0xffffffff;
+           mask.ip4.s_addr >>= i;
+           mask.ip4.s_addr <<= i;
+           mask.ip4.s_addr = htonl(mask.ip4.s_addr);
+       }
+    }
+#ifdef HAVE_IN6_ADDR
+    else {
+       if (inet_pton(AF_INET6, m, &mask.ip6) <= 0) {
+           j = atoi(m);
+           for (i = 0; i < 16; i++) {
+               if (j < i * 8)
+                   mask.ip6.s6_addr[i] = 0;
+               else if (i * 8 + 8 <= j)
+                   mask.ip6.s6_addr[i] = 0xff;
+               else
+                   mask.ip6.s6_addr[i] = 0xff00 >> (j - i * 8);
+           }
+       }
+    }
+#endif /* HAVE_IN6_ADDR */
+
+    for (ifp = interfaces; ifp != NULL; ifp = ifp->next) {
+       if (ifp->family != family)
+           continue;
+       switch(family) {
+           case AF_INET:
+               if ((ifp->addr.ip4.s_addr & mask.ip4.s_addr) == addr.ip4.s_addr)
+                   return TRUE;
+#ifdef HAVE_IN6_ADDR
+           case AF_INET6:
+               for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) {
+                   if ((ifp->addr.ip6.s6_addr[j] & mask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j])
+                       break;
+               }
+               if (j == sizeof(addr.ip6.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(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(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(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(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.
+ */
+int
+usergr_matches(char *group, char *user, struct passwd *pw)
+{
+    int matched = FALSE;
+    struct passwd *pw0 = NULL;
+
+    /* make sure we have a valid usergroup, sudo style */
+    if (*group++ != '%')
+       goto done;
+
+    if (*group == ':' && def_group_plugin) {
+       matched = group_plugin_query(user, group + 1, pw);
+       goto done;
+    }
+
+    /* look up user's primary gid in the passwd file */
+    if (pw == NULL) {
+       if ((pw0 = sudo_getpwnam(user)) == NULL)
+           goto done;
+       pw = pw0;
+    }
+
+    if (user_in_group(pw, group)) {
+       matched = TRUE;
+       goto done;
+    }
+
+    /* not a Unix group, could be an external group */
+    if (def_group_plugin && group_plugin_query(user, group, pw)) {
+       matched = TRUE;
+       goto done;
+    }
+
+done:
+    if (pw0 != NULL)
+       pw_delref(pw0);
+
+    return matched;
+}
+
+/*
+ * 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(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;
+}
diff --git a/plugins/sudoers/mkdefaults b/plugins/sudoers/mkdefaults
new file mode 100755 (executable)
index 0000000..7befe15
--- /dev/null
@@ -0,0 +1,155 @@
+#!/usr/bin/perl -w
+#
+# Generate sudo_defs_table and associated defines
+#
+# Input should be formatted thusly:
+#
+# var_name
+#      TYPE
+#      description (or NULL)
+#      array of struct def_values if TYPE == T_TUPLE
+
+# Deal with optional -o (output) argument
+if ($#ARGV > 0 && $ARGV[0] eq "-o") {
+    shift;
+    $header = $cfile = shift;
+    $header .= '.h';
+    $cfile .= '.c';
+}
+die "usage: $0 [input_file]\n" unless $#ARGV == -1 || $#ARGV == 0;
+
+$infile = $ARGV[0] || "def_data.in";
+if (!defined($header)) {
+    $header = $infile;
+    $header =~ s/(\.in)?$/.h/;
+}
+if (!defined($cfile)) {
+    $cfile = $infile;
+    $cfile =~ s/(\.in)?$/.c/;
+}
+
+open(IN, "<$infile") || die "$0: can't open $infile: $!\n";
+open(HEADER, ">$header") || die "$0: can't open $header: $!\n";
+open(CFILE, ">$cfile") || die "$0: can't open $cfile: $!\n";
+
+$count = 0;
+@tuple_values = ( "never" );
+@records = ();
+while(<IN>) {
+    chomp;
+    s/\s*#.*$//;
+    next if /^\s*$/;
+
+    if (/^\S/) {
+       # Store previous record and begin new one
+       $records[$count++] = [$var, $type, $desc, $values, $callback] if defined($var);
+
+       $var = $_;
+       $type = '';
+       $desc = undef;
+       $values = undef;
+       $callback = undef;
+       $field = 0;
+    } else {
+       $field++;
+       s/^\s+//;
+       s/\s+$//;
+       if ($field == 1) {
+           # type
+           $type = $_;
+       } elsif ($field == 2) {
+           # description
+           if ($_ eq "NULL") {
+               $desc = "NULL";
+           } else {
+               # Strip leading and trailing double quote and escape the rest
+               s/^"//;
+               s/"$//;
+               s/"/\\"/g;
+               $desc = "\"$_\"";
+           }
+       } elsif ($field == 3 || $field == 4) {
+           if (s/^\*//) {
+               $callback = $_;
+           } else {
+               die "$0: syntax error near line $.\n" if $type !~ /^T_TUPLE/;
+               $values = [ split ];
+               foreach $v (@$values) {
+                   push(@tuple_values, $v) unless grep(/^$v$/, @tuple_values);
+               }
+           }
+       } else {
+           die "$0: syntax error near line $.\n";
+       }
+    }
+}
+$records[$count++] = [$var, $type, $desc, $values, $callback] if defined($var);
+
+# Print out value arrays
+for ($i = 0; $i < $count; $i++) {
+    if (defined($records[$i]->[3])) {
+       die "Values list specified for non-tuple\n" unless
+           $records[$i]->[1] =~ /^T_TUPLE/;
+       printf CFILE "static struct def_values def_data_%s[] = {\n", $records[$i]->[0];
+       foreach (@{$records[$i]->[3]}) {
+           print CFILE "    { \"$_\", $_ },\n";
+       }
+       print CFILE "    { NULL, 0 },\n";
+       print CFILE "};\n\n";
+    }
+}
+
+# Print each record
+print CFILE "struct sudo_defs_types sudo_defs_table[] = {\n    {\n";
+for ($i = 0; $i < $count; $i++) {
+    &print_record($records[$i], $i);
+}
+print CFILE "\tNULL, 0, NULL\n    }\n};\n";
+
+# Print out def_tuple
+if (@tuple_values) {
+    print HEADER "\nenum def_tuple {\n";
+    for ($i = 0; $i <= $#tuple_values; $i++) {
+       printf HEADER "\t%s%s\n", $tuple_values[$i],
+           $i != $#tuple_values ? "," : "";
+    }
+    print HEADER "};\n";
+}
+
+close(IN);
+close(HEADER);
+close(CFILE);
+
+sub print_record {
+    my ($rec, $recnum) = @_;
+    my ($i, $v, $defname);
+    # each variable gets a macro to access its value
+    for ($rec->[1]) {
+       if    (/^T_U?INT/)  { $v = "ival"; }
+       elsif (/^T_STR/)    { $v = "str"; }
+       elsif (/^T_FLAG/)   { $v = "flag"; }
+       elsif (/^T_MODE/)   { $v = "mode"; }
+       elsif (/^T_LIST/)   { $v = "list"; }
+       elsif (/^T_LOGFAC/) { $v = "ival"; }
+       elsif (/^T_LOGPRI/) { $v = "ival"; }
+       elsif (/^T_TUPLE/)  { $v = "tuple"; }
+       elsif (/^T_FLOAT/)  { $v = "fval"; }
+       else { die "$0: unknown defaults type: $_\n"; }
+    }
+    printf HEADER "#define %-23s (sudo_defs_table[$recnum].sd_un.${v})\n",
+       "def_$rec->[0]";
+
+    $defname = "I_" . uc($rec->[0]);
+    printf HEADER "#define %-24s%d", $defname, $recnum;
+    #print HEADER "\t/* $rec->[2] */" if defined($rec->[2]);
+    print HEADER "\n";
+
+    print CFILE "\t\"$rec->[0]\", $rec->[1],\n\t$rec->[2],\n";
+    if (defined($rec->[3])) {
+       printf CFILE "\tdef_data_$rec->[0],\n";
+    } else {
+       printf CFILE "\tNULL,\n";
+    }
+    printf CFILE "\t$rec->[4],\n" if defined($rec->[4]);
+    print CFILE "    }, {\n";
+}
diff --git a/plugins/sudoers/parse.c b/plugins/sudoers/parse.c
new file mode 100644 (file)
index 0000000..985c435
--- /dev/null
@@ -0,0 +1,657 @@
+/*
+ * Copyright (c) 2004-2005, 2007-2011 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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "sudoers.h"
+#include "parse.h"
+#include "lbuf.h"
+#include <gram.h>
+
+/* 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
+};
+
+/*
+ * Parser externs.
+ */
+extern FILE *yyin;
+extern char *errorfile;
+extern int errorlineno, parse_error;
+
+/*
+ * Local prototypes.
+ */
+static void print_member(struct lbuf *, char *, int, int, int);
+static int display_bound_defaults(int, struct lbuf *);
+
+int
+sudo_file_open(struct sudo_nss *nss)
+{
+    if (def_ignore_local_sudoers)
+       return -1;
+    nss->handle = open_sudoers(sudoers_file, FALSE, NULL);
+    return nss->handle ? 0 : -1;
+}
+
+int
+sudo_file_close(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;
+}
+
+/*
+ * Parse the specified sudoers file.
+ */
+int
+sudo_file_parse(struct sudo_nss *nss)
+{
+    if (nss->handle == NULL)
+       return -1;
+
+    init_parser(sudoers_file, 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;
+}
+
+/*
+ * Wrapper around update_defaults() for nsswitch code.
+ */
+int
+sudo_file_setdefs(struct sudo_nss *nss)
+{
+    if (nss->handle == NULL)
+       return -1;
+
+    if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER))
+       return -1;
+    return 0;
+}
+
+/*
+ * 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(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;
+
+    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.
+     */
+    if (pwflag) {
+       int nopass;
+       enum def_tuple pwcheck;
+
+       pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
+       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;
+               }
+           }
+       }
+       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;
+    }
+
+    /* Need to be runas user while stat'ing things. */
+    set_perms(PERM_RUNAS);
+
+    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
+               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 = 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;
+                   }
+               }
+           }
+       }
+    }
+    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;
+           if (tags->log_input != UNSPEC)
+               def_log_input = tags->log_input;
+           if (tags->log_output != UNSPEC)
+               def_log_output = tags->log_output;
+       }
+    } else if (match == DENY) {
+       SET(validated, VALIDATE_NOT_OK);
+       CLR(validated, VALIDATE_OK);
+    }
+    restore_perms();
+    return validated;
+}
+
+#define        TAG_CHANGED(t) \
+       (cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags->t)
+
+static void
+sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags,
+    struct lbuf *lbuf)
+{
+    struct member *m;
+
+#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;
+    }
+    if (TAG_CHANGED(log_input)) {
+       lbuf_append(lbuf, cs->tags.log_input ? "LOG_INPUT: " :
+           "NOLOG_INPUT: ", NULL);
+       tags->log_input = cs->tags.log_input;
+    }
+    if (TAG_CHANGED(log_output)) {
+       lbuf_append(lbuf, cs->tags.log_output ? "LOG_OUTPUT: " :
+           "NOLOG_OUTPUT: ", NULL);
+       tags->log_output = cs->tags.log_output;
+    }
+    m = cs->cmnd;
+    print_member(lbuf, m->name, m->type, m->negated,
+       CMNDALIAS);
+}
+
+static int
+sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
+    struct lbuf *lbuf)
+{
+    struct cmndspec *cs;
+    struct member *m;
+    struct privilege *priv;
+    struct cmndtag tags;
+    int nfound = 0;
+
+    tq_foreach_fwd(&us->privileges, priv) {
+       if (hostlist_matches(&priv->hostlist) != ALLOW)
+           continue;
+       tags.noexec = UNSPEC;
+       tags.setenv = UNSPEC;
+       tags.nopasswd = UNSPEC;
+       tags.log_input = UNSPEC;
+       tags.log_output = 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);
+               }
+           } else if (tq_empty(&cs->runasgrouplist)) {
+               lbuf_append(lbuf, def_runas_default, NULL);
+           } else {
+               lbuf_append(lbuf, pw->pw_name, 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_append(lbuf, "\n", NULL);
+    }
+    return nfound;
+}
+
+static int
+sudo_file_display_priv_long(struct passwd *pw, struct userspec *us,
+    struct lbuf *lbuf)
+{
+    struct cmndspec *cs;
+    struct member *m;
+    struct privilege *priv;
+    struct cmndtag tags;
+    int nfound = 0;
+
+    tq_foreach_fwd(&us->privileges, priv) {
+       if (hostlist_matches(&priv->hostlist) != ALLOW)
+           continue;
+       tags.noexec = UNSPEC;
+       tags.setenv = UNSPEC;
+       tags.nopasswd = UNSPEC;
+       tags.log_input = UNSPEC;
+       tags.log_output = UNSPEC;
+       lbuf_append(lbuf, "\nSudoers entry:\n", NULL);
+       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 if (tq_empty(&cs->runasgrouplist)) {
+               lbuf_append(lbuf, def_runas_default, NULL);
+           } else {
+               lbuf_append(lbuf, pw->pw_name, NULL);
+           }
+           lbuf_append(lbuf, "\n", NULL);
+           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);
+               }
+               lbuf_append(lbuf, "\n", NULL);
+           }
+           lbuf_append(lbuf, "    Commands:\n\t", NULL);
+           sudo_file_append_cmnd(cs, &tags, lbuf);
+           lbuf_append(lbuf, "\n", NULL);
+           nfound++;
+       }
+    }
+    return nfound;
+}
+
+int
+sudo_file_display_privs(struct sudo_nss *nss, struct passwd *pw,
+    struct lbuf *lbuf)
+{
+    struct userspec *us;
+    int nfound = 0;
+
+    if (nss->handle == NULL)
+       goto done;
+
+    tq_foreach_fwd(&userspecs, us) {
+       if (userlist_matches(pw, &us->users) != ALLOW)
+           continue;
+
+       if (long_list)
+           nfound += sudo_file_display_priv_long(pw, us, lbuf);
+       else
+           nfound += sudo_file_display_priv_short(pw, us, lbuf);
+    }
+done:
+    return nfound;
+}
+
+/*
+ * Display matching Defaults entries for the given user on this host.
+ */
+int
+sudo_file_display_defaults(struct sudo_nss *nss, struct passwd *pw,
+    struct lbuf *lbuf)
+{
+    struct defaults *d;
+    char *prefix;
+    int nfound = 0;
+
+    if (nss->handle == NULL)
+       goto done;
+
+    if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
+       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++;
+    }
+done:
+    return nfound;
+}
+
+/*
+ * Display Defaults entries that are per-runas or per-command
+ */
+int
+sudo_file_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
+    struct lbuf *lbuf)
+{
+    int nfound = 0;
+
+    /* 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);
+
+    return nfound;
+}
+
+/*
+ * Display Defaults entries of the given type.
+ */
+static int
+display_bound_defaults(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;
+    }
+    /* sudo_printf(SUDO_CONV_INFO_MSG, "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);
+           if (nfound != 1)
+               lbuf_append(lbuf, "\n", NULL);
+           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 nfound;
+}
+
+int
+sudo_file_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
+{
+    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)
+       goto done;
+
+    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;
+                   }
+               }
+           }
+       }
+    }
+    matched:
+    if (match != NULL && !match->negated) {
+       sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n",
+           safe_cmnd, user_args ? " " : "", user_args ? user_args : "");
+       rval = 0;
+    }
+done:
+    return rval;
+}
+
+/*
+ * Print the contents of a struct member to stdout
+ */
+static void
+_print_member(struct lbuf *lbuf, char *name, int type, int negated,
+    int alias_type)
+{
+    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 = alias_find(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;
+    }
+}
+
+static void
+print_member(struct lbuf *lbuf, char *name, int type, int negated,
+    int alias_type)
+{
+    alias_seqno++;
+    _print_member(lbuf, name, type, negated, alias_type);
+}
diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h
new file mode 100644 (file)
index 0000000..6976b16
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 1996, 1998-2000, 2004, 2007-2011
+ *     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.
+ */
+
+#ifndef _SUDO_PARSE_H
+#define _SUDO_PARSE_H
+
+#undef UNSPEC
+#define UNSPEC -1
+#undef DENY
+#define DENY    0
+#undef ALLOW
+#define ALLOW   1
+#undef IMPLIED
+#define IMPLIED         2
+
+/*
+ * 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 int nopasswd: 3;
+    __signed int noexec: 3;
+    __signed int setenv: 3;
+    __signed int log_input: 3;
+    __signed int log_output: 3;
+};
+
+/*
+ * SELinux-specific container struct.
+ * Currently just contains a role and type.
+ */
+struct selinux_info {
+    char *role;
+    char *type;
+};
+
+/*
+ * 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 describing a user specification and list thereof.
+ */
+struct userspec {
+    struct userspec *prev, *next;
+    struct member_list users;          /* list of users */
+    struct privilege_list privileges;  /* list of privileges */
+};
+
+/*
+ * Structure describing a privilege specification.
+ */
+struct privilege {
+    struct privilege *prev, *next;
+    struct member_list hostlist;       /* list of hosts */
+    struct cmndspec_list cmndlist;     /* list of Cmnd_Specs */
+};
+
+/*
+ * Structure describing a linked list of Cmnd_Specs.
+ */
+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
+};
+
+/*
+ * 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(char *, int, struct member *);
+int addr_matches(char *);
+int cmnd_matches(struct member *);
+int cmndlist_matches(struct member_list *);
+int command_matches(char *, char *);
+int hostlist_matches(struct member_list *);
+int hostname_matches(char *, char *, char *);
+int netgr_matches(char *, char *, char *, char *);
+int no_aliases(void);
+int runaslist_matches(struct member_list *, struct member_list *);
+int userlist_matches(struct passwd *, struct member_list *);
+int usergr_matches(char *, char *, struct passwd *);
+int userpw_matches(char *, char *, struct passwd *);
+int group_matches(char *, struct group *);
+struct alias *alias_find(char *, int);
+struct alias *alias_remove(char *, int);
+void alias_free(void *);
+void alias_apply(int (*)(void *, void *), void *);
+void init_aliases(void);
+void init_lexer(void);
+void init_parser(const char *, int);
+int alias_compare(const void *, const void *);
+
+#endif /* _SUDO_PARSE_H */
diff --git a/plugins/sudoers/plugin_error.c b/plugins/sudoers/plugin_error.c
new file mode 100644 (file)
index 0000000..2d42871
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2004-2005, 2010 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h>
+
+#include "missing.h"
+#include "alloc.h"
+#include "error.h"
+#include "sudo_plugin.h"
+
+static void _warning(int, const char *, va_list);
+       void plugin_cleanup(int);
+
+sigjmp_buf error_jmp;
+
+extern sudo_conv_t sudo_conv;
+
+void
+error(int eval, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    _warning(1, fmt, ap);
+    va_end(ap);
+    plugin_cleanup(0);
+    siglongjmp(error_jmp, eval);
+}
+
+void
+errorx(int eval, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    _warning(0, fmt, ap);
+    va_end(ap);
+    plugin_cleanup(0);
+    siglongjmp(error_jmp, eval);
+}
+
+void
+warning(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    _warning(1, fmt, ap);
+    va_end(ap);
+}
+
+void
+warningx(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    _warning(0, fmt, ap);
+    va_end(ap);
+}
+
+static void
+_warning(int use_errno, const char *fmt, va_list ap)
+{
+    struct sudo_conv_message msg[6];
+    struct sudo_conv_reply repl[6];
+    char *str;
+    int nmsgs = 4;
+
+    evasprintf(&str, fmt, ap);
+
+    /* Call conversation function */
+    memset(&msg, 0, sizeof(msg));
+    msg[0].msg_type = SUDO_CONV_ERROR_MSG;
+    msg[0].msg = getprogname();
+    msg[1].msg_type = SUDO_CONV_ERROR_MSG;
+    msg[1].msg = ": ";
+    msg[2].msg_type = SUDO_CONV_ERROR_MSG;
+    msg[2].msg = str;
+    if (use_errno) {
+       msg[3].msg_type = SUDO_CONV_ERROR_MSG;
+       msg[3].msg = ": ";
+       msg[4].msg_type = SUDO_CONV_ERROR_MSG;
+       msg[4].msg = strerror(errno);
+       nmsgs = 6;
+    }
+    msg[nmsgs - 1].msg_type = SUDO_CONV_ERROR_MSG;
+    msg[nmsgs - 1].msg = "\n";
+    memset(&repl, 0, sizeof(repl));
+    sudo_conv(nmsgs, msg, repl);
+    efree(str);
+}
diff --git a/plugins/sudoers/pwutil.c b/plugins/sudoers/pwutil.c
new file mode 100644 (file)
index 0000000..ac0d34a
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2011
+ *     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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_SETAUTHDB
+# include <usersec.h>
+#endif /* HAVE_SETAUTHDB */
+#include <pwd.h>
+#include <grp.h>
+
+#include "sudoers.h"
+#include "redblack.h"
+
+/*
+ * The passwd and group caches.
+ */
+static struct rbtree *pwcache_byuid, *pwcache_byname;
+static struct rbtree *grcache_bygid, *grcache_byname;
+
+static int  cmp_pwuid(const void *, const void *);
+static int  cmp_pwnam(const void *, const void *);
+static int  cmp_grgid(const void *, const void *);
+
+#define cmp_grnam      cmp_pwnam
+
+#define ptr_to_item(p) ((struct cache_item *)((char *)(p) - sizeof(struct cache_item)))
+
+struct cache_item {
+    unsigned int refcnt;
+    /* key */
+    union {
+       uid_t uid;
+       gid_t gid;
+       char *name;
+    } k;
+    /* datum */
+    union {
+       struct passwd *pw;
+       struct group *gr;
+    } d;
+};
+
+/*
+ * Compare by uid.
+ */
+static int
+cmp_pwuid(const void *v1, const void *v2)
+{
+    const struct cache_item *ci1 = (const struct cache_item *) v1;
+    const struct cache_item *ci2 = (const struct cache_item *) v2;
+    return ci1->k.uid - ci2->k.uid;
+}
+
+/*
+ * Compare by user name.
+ */
+static int
+cmp_pwnam(const void *v1, const void *v2)
+{
+    const struct cache_item *ci1 = (const struct cache_item *) v1;
+    const struct cache_item *ci2 = (const struct cache_item *) v2;
+    return strcmp(ci1->k.name, ci2->k.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 item plus the key and data
+ * elements.  If name is non-NULL it is used as the key, else the
+ * uid is the key.  Fills in datum from struct password.
+ *
+ * We would like to fill in the encrypted password too but the
+ * call to the shadow function could overwrite the pw buffer (NIS).
+ */
+static struct cache_item *
+make_pwitem(const struct passwd *pw, const char *name)
+{
+    char *cp;
+    const char *pw_shell;
+    size_t nsize, psize, csize, gsize, dsize, ssize, total;
+    struct cache_item *item;
+    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 cache_item) + 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);
+    /* Treat shell specially since we expand "" -> _PATH_BSHELL */
+    ssize = strlen(pw_shell) + 1;
+    total += ssize;
+    if (name != NULL)
+       total += strlen(name) + 1;
+
+    /* Allocate space for struct item, struct passwd and the strings. */
+    if ((item = malloc(total)) == NULL)
+           return NULL;
+    cp = (char *) item + sizeof(struct cache_item);
+
+    /*
+     * Copy in passwd contents and make strings relative to space
+     * at the end of the buffer.
+     */
+    newpw = (struct passwd *) cp;
+    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);
+    /* Treat shell specially since we expand "" -> _PATH_BSHELL */
+    memcpy(cp, pw_shell, ssize);
+    newpw->pw_shell = cp;
+    cp += ssize;
+
+    /* Set key and datum. */
+    if (name != NULL) {
+       memcpy(cp, name, strlen(name) + 1);
+       item->k.name = cp;
+    } else {
+       item->k.uid = pw->pw_uid;
+    }
+    item->d.pw = newpw;
+    item->refcnt = 1;
+
+    return item;
+}
+
+void
+pw_addref(struct passwd *pw)
+{
+    ptr_to_item(pw)->refcnt++;
+}
+
+static void
+pw_delref_item(void *v)
+{
+    struct cache_item *item = v;
+
+    if (--item->refcnt == 0)
+       efree(item);
+}
+
+void
+pw_delref(struct passwd *pw)
+{
+    pw_delref_item(ptr_to_item(pw));
+}
+
+/*
+ * 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_t uid)
+{
+    struct cache_item key, *item;
+    struct rbnode *node;
+
+    key.k.uid = uid;
+    if ((node = rbfind(pwcache_byuid, &key)) != NULL) {
+       item = (struct cache_item *) node->data;
+       goto done;
+    }
+    /*
+     * Cache passwd db entry if it exists or a negative response if not.
+     */
+#ifdef HAVE_SETAUTHDB
+    aix_setauthdb(IDtouser(uid));
+#endif
+    if ((key.d.pw = getpwuid(uid)) != NULL) {
+       item = make_pwitem(key.d.pw, NULL);
+       if (rbinsert(pwcache_byuid, item) != NULL)
+           errorx(1, "unable to cache uid %u (%s), already exists",
+               (unsigned int) uid, item->d.pw->pw_name);
+    } else {
+       item = emalloc(sizeof(*item));
+       item->refcnt = 1;
+       item->k.uid = uid;
+       item->d.pw = NULL;
+       if (rbinsert(pwcache_byuid, item) != NULL)
+           errorx(1, "unable to cache uid %u, already exists",
+               (unsigned int) uid);
+    }
+#ifdef HAVE_SETAUTHDB
+    aix_restoreauthdb();
+#endif
+done:
+    item->refcnt++;
+    return item->d.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(const char *name)
+{
+    struct cache_item key, *item;
+    struct rbnode *node;
+    size_t len;
+
+    key.k.name = (char *) name;
+    if ((node = rbfind(pwcache_byname, &key)) != NULL) {
+       item = (struct cache_item *) node->data;
+       goto done;
+    }
+    /*
+     * Cache passwd db entry if it exists or a negative response if not.
+     */
+#ifdef HAVE_SETAUTHDB
+    aix_setauthdb((char *) name);
+#endif
+    if ((key.d.pw = getpwnam(name)) != NULL) {
+       item = make_pwitem(key.d.pw, name);
+       if (rbinsert(pwcache_byname, item) != NULL)
+           errorx(1, "unable to cache user %s, already exists", name);
+    } else {
+       len = strlen(name) + 1;
+       item = emalloc(sizeof(*item) + len);
+       item->refcnt = 1;
+       item->k.name = (char *) item + sizeof(*item);
+       memcpy(item->k.name, name, len);
+       item->d.pw = NULL;
+       if (rbinsert(pwcache_byname, item) != NULL)
+           errorx(1, "unable to cache user %s, already exists", name);
+    }
+#ifdef HAVE_SETAUTHDB
+    aix_restoreauthdb();
+#endif
+done:
+    item->refcnt++;
+    return item->d.pw;
+}
+
+/*
+ * Take a uid in string form "#123" and return a faked up passwd struct.
+ */
+struct passwd *
+sudo_fakepwnam(const char *user, gid_t gid)
+{
+    struct cache_item *item;
+    struct passwd *pw;
+    struct rbnode *node;
+    size_t len, namelen;
+    int i;
+
+    namelen = strlen(user);
+    len = sizeof(*item) + sizeof(*pw) + namelen + 1 /* pw_name */ +
+       sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +
+       sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL);
+
+    for (i = 0; i < 2; i++) {
+       item = emalloc(len);
+       zero_bytes(item, sizeof(*item) + sizeof(*pw));
+       pw = (struct passwd *) ((char *)item + sizeof(*item));
+       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, namelen + 1);
+       pw->pw_passwd = pw->pw_name + namelen + 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));
+
+       item->refcnt = 1;
+       item->d.pw = pw;
+       if (i == 0) {
+           /* Store by uid, overwriting cached version. */
+           item->k.uid = pw->pw_uid;
+           if ((node = rbinsert(pwcache_byuid, item)) != NULL) {
+               pw_delref_item(node->data);
+               node->data = item;
+           }
+       } else {
+           /* Store by name, overwriting cached version. */
+           item->k.name = pw->pw_name;
+           if ((node = rbinsert(pwcache_byname, item)) != NULL) {
+               pw_delref_item(node->data);
+               node->data = item;
+           }
+       }
+    }
+    item->refcnt++;
+    return pw;
+}
+
+void
+sudo_setpwent(void)
+{
+    setpwent();
+    if (pwcache_byuid == NULL)
+       pwcache_byuid = rbcreate(cmp_pwuid);
+    if (pwcache_byname == NULL)
+       pwcache_byname = rbcreate(cmp_pwnam);
+}
+
+void
+sudo_freepwcache(void)
+{
+    if (pwcache_byuid != NULL) {
+       rbdestroy(pwcache_byuid, pw_delref_item);
+       pwcache_byuid = NULL;
+    }
+    if (pwcache_byname != NULL) {
+       rbdestroy(pwcache_byname, pw_delref_item);
+       pwcache_byname = NULL;
+    }
+}
+
+void
+sudo_endpwent(void)
+{
+    endpwent();
+    sudo_freepwcache();
+}
+
+/*
+ * Compare by gid.
+ */
+static int
+cmp_grgid(const void *v1, const void *v2)
+{
+    const struct cache_item *ci1 = (const struct cache_item *) v1;
+    const struct cache_item *ci2 = (const struct cache_item *) v2;
+    return ci1->k.gid - ci2->k.gid;
+}
+
+/*
+ * Dynamically allocate space for a struct item plus the key and data
+ * elements.  If name is non-NULL it is used as the key, else the
+ * gid is the key.  Fills in datum from struct group.
+ */
+struct cache_item *
+make_gritem(const struct group *gr, const char *name)
+{
+    char *cp;
+    size_t nsize, psize, nmem, total, len;
+    struct cache_item *item;
+    struct group *newgr;
+
+    /* Allocate in one big chunk for easy freeing. */
+    nsize = psize = nmem = 0;
+    total = sizeof(struct cache_item) + 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 (name != NULL)
+       total += strlen(name) + 1;
+
+    if ((item = malloc(total)) == NULL)
+           return NULL;
+    cp = (char *) item + sizeof(struct cache_item);
+
+    /*
+     * 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.
+     */
+    newgr = (struct group *)cp;
+    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);
+
+    /* Set key and datum. */
+    if (name != NULL) {
+       memcpy(cp, name, strlen(name) + 1);
+       item->k.name = cp;
+    } else {
+       item->k.gid = gr->gr_gid;
+    }
+    item->d.gr = newgr;
+    item->refcnt = 1;
+
+    return item;
+}
+
+void
+gr_addref(struct group *gr)
+{
+    ptr_to_item(gr)->refcnt++;
+}
+
+static void
+gr_delref_item(void *v)
+{
+    struct cache_item *item = v;
+
+    if (--item->refcnt == 0)
+       efree(item);
+}
+
+void
+gr_delref(struct group *gr)
+{
+    gr_delref_item(ptr_to_item(gr));
+}
+
+/*
+ * Get a group entry by gid and allocate space for it.
+ */
+struct group *
+sudo_getgrgid(gid_t gid)
+{
+    struct cache_item key, *item;
+    struct rbnode *node;
+
+    key.k.gid = gid;
+    if ((node = rbfind(grcache_bygid, &key)) != NULL) {
+       item = (struct cache_item *) node->data;
+       goto done;
+    }
+    /*
+     * Cache group db entry if it exists or a negative response if not.
+     */
+    if ((key.d.gr = getgrgid(gid)) != NULL) {
+       item = make_gritem(key.d.gr, NULL);
+       if (rbinsert(grcache_bygid, item) != NULL)
+           errorx(1, "unable to cache gid %u (%s), already exists",
+               (unsigned int) gid, key.d.gr->gr_name);
+    } else {
+       item = emalloc(sizeof(*item));
+       item->refcnt = 1;
+       item->k.gid = gid;
+       item->d.gr = NULL;
+       if (rbinsert(grcache_bygid, item) != NULL)
+           errorx(1, "unable to cache gid %u, already exists",
+               (unsigned int) gid);
+    }
+done:
+    item->refcnt++;
+    return item->d.gr;
+}
+
+/*
+ * Get a group entry by name and allocate space for it.
+ */
+struct group *
+sudo_getgrnam(const char *name)
+{
+    struct cache_item key, *item;
+    struct rbnode *node;
+    size_t len;
+
+    key.k.name = (char *) name;
+    if ((node = rbfind(grcache_byname, &key)) != NULL) {
+       item = (struct cache_item *) node->data;
+       goto done;
+    }
+    /*
+     * Cache group db entry if it exists or a negative response if not.
+     */
+    if ((key.d.gr = getgrnam(name)) != NULL) {
+       item = make_gritem(key.d.gr, name);
+       if (rbinsert(grcache_byname, item) != NULL)
+           errorx(1, "unable to cache group %s, already exists", name);
+    } else {
+       len = strlen(name) + 1;
+       item = emalloc(sizeof(*item) + len);
+       item->refcnt = 1;
+       item->k.name = (char *) item + sizeof(*item);
+       memcpy(item->k.name, name, len);
+       item->d.gr = NULL;
+       if (rbinsert(grcache_byname, item) != NULL)
+           errorx(1, "unable to cache group %s, already exists", name);
+    }
+done:
+    item->refcnt++;
+    return item->d.gr;
+}
+
+/*
+ * Take a gid in string form "#123" and return a faked up group struct.
+ */
+struct group *
+sudo_fakegrnam(const char *group)
+{
+    struct cache_item *item;
+    struct group *gr;
+    struct rbnode *node;
+    size_t len, namelen;
+    int i;
+
+    namelen = strlen(group);
+    len = sizeof(*item) + sizeof(*gr) + namelen + 1;
+
+    for (i = 0; i < 2; i++) {
+       item = emalloc(len);
+       zero_bytes(item, sizeof(*item) + sizeof(*gr));
+       gr = (struct group *) ((char *)item + sizeof(*item));
+       gr->gr_gid = (gid_t) atoi(group + 1);
+       gr->gr_name = (char *)gr + sizeof(struct group);
+       memcpy(gr->gr_name, group, namelen + 1);
+
+       item->refcnt = 1;
+       item->d.gr = gr;
+       if (i == 0) {
+           /* Store by gid, overwriting cached version. */
+           item->k.gid = gr->gr_gid;
+           if ((node = rbinsert(grcache_bygid, item)) != NULL) {
+               gr_delref_item(node->data);
+               node->data = item;
+           }
+       } else {
+           /* Store by name, overwriting cached version. */
+           item->k.name = gr->gr_name;
+           if ((node = rbinsert(grcache_byname, item)) != NULL) {
+               gr_delref_item(node->data);
+               node->data = item;
+           }
+       }
+    }
+    item->refcnt++;
+    return gr;
+}
+
+void
+sudo_setgrent(void)
+{
+    setgrent();
+    if (grcache_bygid == NULL)
+       grcache_bygid = rbcreate(cmp_grgid);
+    if (grcache_byname == NULL)
+       grcache_byname = rbcreate(cmp_grnam);
+}
+
+void
+sudo_freegrcache(void)
+{
+    if (grcache_bygid != NULL) {
+       rbdestroy(grcache_bygid, gr_delref_item);
+       grcache_bygid = NULL;
+    }
+    if (grcache_byname != NULL) {
+       rbdestroy(grcache_byname, gr_delref_item);
+       grcache_byname = NULL;
+    }
+}
+
+void
+sudo_endgrent(void)
+{
+    endgrent();
+    sudo_freegrcache();
+}
+
+int
+user_in_group(struct passwd *pw, const char *group)
+{
+#ifdef HAVE_MBR_CHECK_MEMBERSHIP
+    uuid_t gu, uu;
+    int ismember;
+#else
+    char **gr_mem;
+    int i;
+#endif
+    struct group *grp;
+    int retval = FALSE;
+
+#ifdef HAVE_SETAUTHDB
+    aix_setauthdb(pw->pw_name);
+#endif
+    /* A group name that begins with a '#' may be a gid. */
+    if ((grp = sudo_getgrnam(group)) == NULL && *group == '#')
+       grp = sudo_getgrgid(atoi(group + 1));
+#ifdef HAVE_SETAUTHDB
+    aix_restoreauthdb();
+#endif
+    if (grp == NULL)
+       goto done;
+
+    /* check against user's primary (passwd file) gid */
+    if (grp->gr_gid == pw->pw_gid) {
+       retval = TRUE;
+       goto done;
+    }
+
+#ifdef HAVE_MBR_CHECK_MEMBERSHIP
+    /* If we are matching the invoking user use the stashed uuid. */
+    if (strcmp(pw->pw_name, user_name) == 0) {
+       if (mbr_gid_to_uuid(grp->gr_gid, gu) == 0 &&
+           mbr_check_membership(user_uuid, gu, &ismember) == 0 && ismember) {
+           retval = TRUE;
+           goto done;
+       }
+    } else {
+       if (mbr_uid_to_uuid(pw->pw_uid, uu) == 0 &&
+           mbr_gid_to_uuid(grp->gr_gid, gu) == 0 &&
+           mbr_check_membership(uu, gu, &ismember) == 0 && ismember) {
+           retval = TRUE;
+           goto done;
+       }
+    }
+#else /* HAVE_MBR_CHECK_MEMBERSHIP */
+# ifdef HAVE_GETGROUPS
+    /*
+     * If we are matching the invoking or list user and that user has a
+     * supplementary group vector, check it.
+     */
+    if (user_ngroups > 0 &&
+       strcmp(pw->pw_name, list_pw ? list_pw->pw_name : user_name) == 0) {
+       for (i = 0; i < user_ngroups; i++) {
+           if (grp->gr_gid == user_groups[i]) {
+               retval = TRUE;
+               goto done;
+           }
+       }
+    } else
+# endif /* HAVE_GETGROUPS */
+    {
+       if (grp != NULL && grp->gr_mem != NULL) {
+           for (gr_mem = grp->gr_mem; *gr_mem; gr_mem++) {
+               if (strcmp(*gr_mem, pw->pw_name) == 0) {
+                   retval = TRUE;
+                   goto done;
+               }
+           }
+       }
+    }
+#endif /* HAVE_MBR_CHECK_MEMBERSHIP */
+
+done:
+    if (grp != NULL)
+       gr_delref(grp);
+    return retval;
+}
diff --git a/plugins/sudoers/redblack.c b/plugins/sudoers/redblack.c
new file mode 100644 (file)
index 0000000..23c74d3
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2004-2005, 2007, 2009-2011
+ *     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 "missing.h"
+#include "alloc.h"
+#include "redblack.h"
+
+static void rbrepair(struct rbtree *, struct rbnode *);
+static void rotate_left(struct rbtree *, struct rbnode *);
+static void rotate_right(struct rbtree *, struct rbnode *);
+static void _rbdestroy(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) Every node is either red or black.
+ *  2) The root is black.
+ *  3) All leaves are black.
+ *  4) Both children of each red node are black.
+ *  5) 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(int (*compar)(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(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(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(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(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(struct rbtree *tree, struct rbnode *node,
+    int (*func)(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(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(struct rbtree *tree, struct rbnode *node, void (*destroy)(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(struct rbtree *tree, void (*destroy)(void *))
+{
+    _rbdestroy(tree, rbfirst(tree), destroy);
+    efree(tree);
+}
+
+/*
+ * Delete node 'z' from the tree and return its data pointer.
+ */
+void *rbdelete(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(struct rbtree *tree, struct rbnode *node)
+{
+    struct rbnode *sibling;
+
+    while (node->color == black && node != rbroot(tree)) {
+       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);
+               node = rbroot(tree); /* exit loop */
+           }
+       } 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);
+               node = rbroot(tree); /* exit loop */
+           }
+       }
+    }
+    node->color = black;
+}
diff --git a/plugins/sudoers/redblack.h b/plugins/sudoers/redblack.h
new file mode 100644 (file)
index 0000000..eab5e8f
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2004, 2007, 2010 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.
+ */
+
+#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)(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(struct rbtree *, struct rbnode *);
+int rbapply_node(struct rbtree *, struct rbnode *,
+       int (*)(void *, void *), void *, enum rbtraversal);
+struct rbnode *rbfind(struct rbtree *, void *);
+struct rbnode *rbinsert(struct rbtree *, void *);
+struct rbtree *rbcreate(int (*)(const void *, const void *));
+void rbdestroy(struct rbtree *, void (*)(void *));
+
+#endif /* _SUDO_REDBLACK_H */
diff --git a/plugins/sudoers/regress/iolog_path/check_iolog_path.c b/plugins/sudoers/regress/iolog_path/check_iolog_path.c
new file mode 100644 (file)
index 0000000..cef22ff
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2011 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 <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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_SETLOCALE
+# include <locale.h>
+#endif
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+
+#define _SUDO_MAIN
+#include "sudoers.h"
+#include "def_data.c"
+
+struct sudo_user sudo_user;
+struct passwd *list_pw;
+
+static char sessid[7];
+
+static void
+usage(void)
+{
+    fprintf(stderr, "usage: check_iolog_path datafile\n");
+    exit(1);
+}
+
+static int
+do_check(char *dir_in, char *file_in, char *tdir_out, char *tfile_out)
+{
+    char *path, *slash;
+    char dir_out[4096], file_out[4096];
+    struct tm *timeptr;
+    time_t now;
+    int error = 0;
+
+    /*
+     * Expand any strftime(3) escapes
+     * XXX - want to pass timeptr to expand_iolog_path
+     */
+    time(&now);
+    timeptr = localtime(&now);
+    strftime(dir_out, sizeof(dir_out), tdir_out, timeptr);
+    strftime(file_out, sizeof(file_out), tfile_out, timeptr);
+
+    path = expand_iolog_path(NULL, dir_in, file_in, &slash);
+    *slash = '\0';
+    if (strcmp(path, dir_out) != 0) {
+       warningx("%s: expected %s, got %s", dir_in, dir_out, path);
+       error = 1;
+    }
+    if (strcmp(slash + 1, file_out) != 0) {
+       warningx("%s: expected %s, got %s", file_in, file_out, slash + 1);
+       error = 1;
+    }
+
+    return error;
+}
+
+#define MAX_STATE      12
+
+int
+main(int argc, char *argv[])
+{
+    struct passwd pw, rpw;
+    size_t len;
+    FILE *fp;
+    char line[2048];
+    char *file_in = NULL, *file_out = NULL;
+    char *dir_in = NULL, *dir_out = NULL;
+    int state = 0;
+    int errors = 0;
+    int tests = 0;
+
+    if (argc != 2)
+       usage();
+
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+       errorx(1, "unable to open %s", argv[1]);
+
+    memset(&pw, 0, sizeof(pw));
+    memset(&rpw, 0, sizeof(rpw));
+    sudo_user.pw = &pw;
+    sudo_user._runas_pw = &rpw;
+
+    /*
+     * Input consists of 12 lines:
+     * sequence number
+     * user name
+     * user gid
+     * runas user name
+     * runas gid
+     * hostname [short form]
+     * command
+     * dir [with escapes]
+     * file [with escapes]
+     * expanded dir
+     * expanded file
+     * empty line
+     */
+    while (fgets(line, sizeof(line), fp) != NULL) {
+       len = strcspn(line, "\n");
+       line[len] = '\0';
+
+       switch (state) {
+       case 0:
+           strlcpy(sessid, line, sizeof(sessid));
+           break;
+       case 1:
+           if (user_name != NULL)
+               free(user_name);
+           user_name = strdup(line);
+           break;
+       case 2:
+           user_gid = atoi(line);
+           break;
+       case 3:
+           if (runas_pw->pw_name != NULL)
+               free(runas_pw->pw_name);
+           runas_pw->pw_name = strdup(line);
+           break;
+       case 4:
+           runas_pw->pw_gid = atoi(line);
+           break;
+       case 5:
+           user_shost = strdup(line);
+           break;
+       case 6:
+           user_base = strdup(line);
+           break;
+       case 7:
+           dir_in = strdup(line);
+           break;
+       case 8:
+           file_in = strdup(line);
+           break;
+       case 9:
+           dir_out = strdup(line);
+           break;
+       case 10:
+           file_out = strdup(line);
+           break;
+       case 11:
+           errors += do_check(dir_in, file_in, dir_out, file_out);
+           tests++;
+           break;
+       default:
+           errorx(1, "internal error, invalid state %d", state);
+       }
+       state = (state + 1) % MAX_STATE;
+    }
+
+    if (tests != 0) {
+       printf("iolog_path: %d test%s run, %d errors, %d%% success rate\n",
+           tests, tests == 1 ? "" : "s", errors,
+           (tests - errors) * 100 / tests);
+    }
+
+    exit(errors);
+}
+
+void io_nextid(char *iolog_dir, char id[7])
+{
+    memcpy(id, sessid, sizeof(sessid));
+}
+
+void
+cleanup(int gotsig)
+{
+    return;
+}
diff --git a/plugins/sudoers/regress/iolog_path/data b/plugins/sudoers/regress/iolog_path/data
new file mode 100644 (file)
index 0000000..e2877b2
--- /dev/null
@@ -0,0 +1,72 @@
+000001
+nobody
+1
+root
+0
+somehost
+id
+/var/log/sudo-io
+%%{bogus}
+/var/log/sudo-io
+%%{bogus}
+
+000001
+nobody
+1
+root
+0
+somehost
+id
+/var/log/sudo-io
+%%{seq}
+/var/log/sudo-io
+%%{seq}
+
+000001
+nobody
+1
+root
+0
+somehost
+id
+/var/log/sudo-io
+%{seq}
+/var/log/sudo-io
+00/00/01
+
+000001
+nobody
+1
+root
+0
+somehost
+id
+/var/log/sudo-io/%{user}
+%{seq}
+/var/log/sudo-io/nobody
+00/00/01
+
+000001
+nobody
+1
+root
+0
+somehost
+su
+/var/log/sudo-io/%{user}/%{runas_user}
+%{command}_%Y%m%s_%H%M
+/var/log/sudo-io/nobody/root
+su_%Y%m%s_%H%M
+
+000001
+nobody
+1
+root
+0
+somehost
+su
+/var/log/sudo-io/
+/%{user}/%{runas_user}/%{command}_%Y%m%s_%H%M
+/var/log/sudo-io
+nobody/root/su_%Y%m%s_%H%M
+
diff --git a/plugins/sudoers/regress/parser/check_fill.c b/plugins/sudoers/regress/parser/check_fill.c
new file mode 100644 (file)
index 0000000..599a202
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2011 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 <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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <grp.h>
+#include <pwd.h>
+
+#include "list.h"
+#include "parse.h"
+#include "toke.h"
+#include "gram.h"
+
+/*
+ * TODO: test realloc
+ */
+
+YYSTYPE yylval;
+
+struct fill_test {
+    const char *input;
+    const char *output;
+    int len;
+    int addspace;
+};
+
+/*
+ * In "normal" fill, anything can be escaped and hex chars are expanded.
+ */
+static struct fill_test txt_data[] = {
+    { "Embedded\\x20Space", "Embedded Space", 0 },
+    { "\\x20Leading", " Leading", 0 },
+    { "Trailing\\x20", "Trailing ", 0 },
+    { "Multiple\\x20\\x20Spaces", "Multiple  Spaces", 0 },
+    { "Hexparse\\x200Check", "Hexparse 0Check", 0 },
+    { "Escaped\\\\Escape", "Escaped\\Escape", 0 },
+    { "LongGroupName", "LongGrou", 8 }
+};
+
+/*
+ * The only escaped chars in a command should be [,:= \t#]
+ * The rest are done by glob() or fnmatch().
+ */
+static struct fill_test cmd_data[] = {
+    { "foo\\,bar", "foo,bar", 0 },
+    { "this\\:that", "this:that", 0 },
+    { "foo\\=bar", "foo=bar", 0 },
+    { "tab\\\tstop", "tab\tstop", 0 },
+    { "not a \\#comment", "not a #comment", 0 }
+};
+
+/*
+ * No escaped characters in command line args.
+ * Arguments get appended.
+ */
+static struct fill_test args_data[] = {
+    { "/", "/", 0, 0 },
+    { "-type", "/ -type", 0, 1 },
+    { "f", "/ -type f", 0, 1 },
+    { "-exec", "/ -type f -exec", 0, 1 },
+    { "ls", "/ -type f -exec ls", 0, 1 },
+    { "{}", "/ -type f -exec ls {}", 0, 1 }
+};
+
+static int
+check_fill(const char *input, int len, int addspace, const char *expect, char **resultp)
+{
+    if (!fill(input, len))
+       return -1;
+    *resultp = yylval.string;
+    return !strcmp(yylval.string, expect);
+}
+
+static int
+check_fill_cmnd(const char *input, int len, int addspace, const char *expect, char **resultp)
+{
+    if (!fill_cmnd(input, len))
+       return -1;
+    *resultp = yylval.command.cmnd;
+    return !strcmp(yylval.command.cmnd, expect);
+}
+
+static int
+check_fill_args(const char *input, int len, int addspace, const char *expect, char **resultp)
+{
+    if (!fill_args(input, len, addspace))
+       return -1;
+    *resultp = yylval.command.args;
+    return !strcmp(yylval.command.args, expect);
+}
+
+static int
+do_tests(int (*checker)(const char *, int, int, const char *, char **),
+    struct fill_test *data, size_t ntests)
+{
+    int i, len;
+    int errors = 0;
+    char *result;
+
+    for (i = 0; i < ntests; i++) {
+       if (data[i].len == 0)
+           len = strlen(data[i].input);
+       else
+           len = data[i].len;
+
+       switch ((*checker)(data[i].input, len, data[i].addspace, data[i].output, &result)) {
+       case 0:
+           /* no match */
+           fprintf(stderr, "Failed parsing %.*s: expected [%s], got [%s]\n",
+               (int)data[i].len, data[i].input, data[i].output, result);
+           errors++;
+           break;
+       case 1:
+           /* match */
+           break;
+       default:
+           /* error */
+           fprintf(stderr, "Failed parsing %.*s: fill function failure\n",
+               (int)data[i].len, data[i].input);
+           errors++;
+           break;
+       }
+    }
+
+    return errors;
+}
+
+int
+main(int argc, char *argv[])
+{
+    int ntests, errors = 0;
+
+    errors += do_tests(check_fill, txt_data, sizeof(txt_data) / sizeof(txt_data[0]));
+    errors += do_tests(check_fill_cmnd, cmd_data, sizeof(cmd_data) / sizeof(cmd_data[0]));
+    errors += do_tests(check_fill_args, args_data, sizeof(args_data) / sizeof(args_data[0]));
+
+    ntests = sizeof(txt_data) / sizeof(txt_data[0]) +
+       sizeof(cmd_data) / sizeof(cmd_data[0]) +
+       sizeof(args_data) / sizeof(args_data[0]);
+    printf("check_fill: %d tests run, %d errors, %d%% success rate\n",
+       ntests, errors, (ntests - errors) * 100 / ntests);
+
+    exit(errors);
+}
+
+/* STUB */
+void
+cleanup(int gotsig)
+{
+    return;
+}
+
+/* STUB */
+void
+yyerror(const char *s)
+{
+    return;
+}
diff --git a/plugins/sudoers/regress/sudoers/test1.in b/plugins/sudoers/regress/sudoers/test1.in
new file mode 100644 (file)
index 0000000..872925c
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Verify that all command tags are parsed OK.
+# See http://www.sudo.ws/bugs/show_bug.cgi?id=437
+#
+user1 ALL = LOG_INPUT: LOG_OUTPUT: /usr/bin/su -:\
+      ALL = NOLOG_INPUT: NOLOG_OUTPUT: /usr/bin/id
+user2 ALL = NOPASSWD: NOEXEC: SETENV: /usr/bin/vi:\
+      ALL = PASSWD: EXEC: NOSETENV: /usr/bin/echo
diff --git a/plugins/sudoers/regress/sudoers/test1.out.ok b/plugins/sudoers/regress/sudoers/test1.out.ok
new file mode 100644 (file)
index 0000000..44cb652
--- /dev/null
@@ -0,0 +1,6 @@
+Parses OK.
+
+
+
+user1  ALL = /usr/bin/su - : ALL = /usr/bin/id
+user2  ALL = NOPASSWD: NOEXEC: /usr/bin/vi : ALL = PASSWD: EXEC: /usr/bin/echo
diff --git a/plugins/sudoers/regress/sudoers/test1.toke.ok b/plugins/sudoers/regress/sudoers/test1.toke.ok
new file mode 100644 (file)
index 0000000..3f3a7ad
--- /dev/null
@@ -0,0 +1,6 @@
+#
+#
+#
+#
+WORD(5) ALL = LOG_INPUT LOG_OUTPUT COMMAND ARG : ALL = NOLOG_INPUT NOLOG_OUTPUT COMMAND 
+WORD(5) ALL = NOPASSWD NOEXEC SETENV COMMAND : ALL = PASSWD EXEC NOSETENV COMMAND 
diff --git a/plugins/sudoers/regress/sudoers/test2.in b/plugins/sudoers/regress/sudoers/test2.in
new file mode 100644 (file)
index 0000000..cfdfaa3
--- /dev/null
@@ -0,0 +1,60 @@
+# Check quoted user name in User_Alias
+User_Alias UA1 = "foo"
+User_Alias UA2 = "foo.bar"
+User_Alias UA3 = "foo\""
+User_Alias UA4 = "foo:bar"
+User_Alias UA5 = "foo:bar\""
+
+# Check quoted group name in User_Alias
+User_Alias UA6 = "%baz"
+User_Alias UA7 = "%baz.biz"
+
+# Check quoted non-Unix group name in User_Alias
+User_Alias UA8 = "%:C/non UNIX 0 c"
+User_Alias UA9 = "%:C/non\'UNIX\'1 c"
+User_Alias UA10 = "%:C/non\"UNIX\"0 c"
+User_Alias UA11 = "%:C/non_UNIX_0 c"
+User_Alias UA12 = "%:C/non\'UNIX_3 c"
+
+# Check quoted user name in Runas_Alias
+Runas_Alias RA1 = "foo"
+Runas_Alias RA2 = "foo\""
+Runas_Alias RA3 = "foo:bar"
+Runas_Alias RA4 = "foo:bar\""
+
+# Check quoted host name in Defaults
+Defaults@"somehost" set_home
+Defaults@"quoted\"" set_home
+
+# Check quoted user name in Defaults
+Defaults:"you" set_home
+Defaults:"us\"" set_home
+Defaults:"%them" set_home
+Defaults:"%: non UNIX 0 c" set_home
+Defaults:"+net" set_home
+
+# Check quoted runas name in Defaults
+Defaults>"someone" set_home
+Defaults>"some one" set_home
+
+# Check quoted command in Defaults
+# XXX - not currently supported
+#Defaults!"/bin/ls -l" set_home
+#Defaults!"/bin/ls -l \"foo\"" set_home
+
+# Check quoted user, runas and host name in Cmnd_Spec
+"foo"          "hosta" = ("root") ALL
+"foo.bar"      "hostb" = ("root") ALL
+"foo\""                "hostc" = ("root") ALL
+"foo:bar"      "hostd" = ("root") ALL
+"foo:bar\""    "hoste" = ("root") ALL
+
+# Check quoted group/netgroup name in Cmnd_Spec
+"%baz"                 "hosta" = ("root") ALL
+"%baz.biz"             "hostb" = ("root") ALL
+"%:C/non UNIX 0 c"     "hostc" = ("root") ALL
+"%:C/non\'UNIX\'1 c"   "hostd" = ("root") ALL
+"%:C/non\"UNIX\"0 c"   "hoste" = ("root") ALL
+"%:C/non_UNIX_0 c"     "hostf" = ("root") ALL
+"%:C/non\'UNIX_3 c"    "hostg" = ("root") ALL
+"+netgr"               "hosth" = ("root") ALL
diff --git a/plugins/sudoers/regress/sudoers/test2.out.ok b/plugins/sudoers/regress/sudoers/test2.out.ok
new file mode 100644 (file)
index 0000000..8f55faf
--- /dev/null
@@ -0,0 +1,42 @@
+Parses OK.
+
+Defaults@somehost      set_home
+Defaults@quoted"       set_home
+Defaults:you   set_home
+Defaults:us"   set_home
+Defaults:%them set_home
+Defaults:%: non UNIX 0 c       set_home
+Defaults:+net  set_home
+Defaults>someone       set_home
+Defaults>some one      set_home
+
+Runas_Alias    RA1 = foo
+Runas_Alias    RA2 = foo"
+Runas_Alias    RA3 = foo:bar
+Runas_Alias    RA4 = foo:bar"
+User_Alias     UA1 = foo
+User_Alias     UA10 = %:C/non"UNIX"0 c
+User_Alias     UA11 = %:C/non_UNIX_0 c
+User_Alias     UA12 = %:C/non\'UNIX_3 c
+User_Alias     UA2 = foo.bar
+User_Alias     UA3 = foo"
+User_Alias     UA4 = foo:bar
+User_Alias     UA5 = foo:bar"
+User_Alias     UA6 = %baz
+User_Alias     UA7 = %baz.biz
+User_Alias     UA8 = %:C/non UNIX 0 c
+User_Alias     UA9 = %:C/non\'UNIX\'1 c
+
+foo    hosta = (root) ALL
+foo.bar        hostb = (root) ALL
+foo"   hostc = (root) ALL
+foo:bar        hostd = (root) ALL
+foo:bar"       hoste = (root) ALL
+%baz   hosta = (root) ALL
+%baz.biz       hostb = (root) ALL
+%:C/non UNIX 0 c       hostc = (root) ALL
+%:C/non\'UNIX\'1 c     hostd = (root) ALL
+%:C/non"UNIX"0 c       hoste = (root) ALL
+%:C/non_UNIX_0 c       hostf = (root) ALL
+%:C/non\'UNIX_3 c      hostg = (root) ALL
++netgr hosth = (root) ALL
diff --git a/plugins/sudoers/regress/sudoers/test2.toke.ok b/plugins/sudoers/regress/sudoers/test2.toke.ok
new file mode 100644 (file)
index 0000000..fcd7b73
--- /dev/null
@@ -0,0 +1,60 @@
+#
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) 
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) 
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) 
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) 
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) 
+
+#
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR USERGROUP 
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR USERGROUP 
+
+#
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR USERGROUP 
+USERALIAS ALIAS = BEGINSTR STRBODY BACKSLASH STRBODY BACKSLASH STRBODY ENDSTR USERGROUP 
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR USERGROUP 
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR USERGROUP 
+USERALIAS ALIAS = BEGINSTR STRBODY BACKSLASH STRBODY ENDSTR USERGROUP 
+
+#
+RUNASALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) 
+RUNASALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) 
+RUNASALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) 
+RUNASALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) 
+
+#
+DEFAULTS_HOST BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
+DEFAULTS_HOST BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
+
+#
+DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
+DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
+DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
+DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
+DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
+
+#
+DEFAULTS_RUNAS BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
+DEFAULTS_RUNAS BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
+
+#
+#
+#
+#
+
+#
+BEGINSTR STRBODY ENDSTR WORD(4) BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
+BEGINSTR STRBODY ENDSTR WORD(4) BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
+BEGINSTR STRBODY ENDSTR WORD(4) BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
+BEGINSTR STRBODY ENDSTR WORD(4) BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
+BEGINSTR STRBODY ENDSTR WORD(4) BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
+
+#
+BEGINSTR STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
+BEGINSTR STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
+BEGINSTR STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
+BEGINSTR STRBODY BACKSLASH STRBODY BACKSLASH STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
+BEGINSTR STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
+BEGINSTR STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
+BEGINSTR STRBODY BACKSLASH STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
+BEGINSTR STRBODY ENDSTR NETGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
diff --git a/plugins/sudoers/regress/sudoers/test3.in b/plugins/sudoers/regress/sudoers/test3.in
new file mode 100644 (file)
index 0000000..82fcd83
--- /dev/null
@@ -0,0 +1,6 @@
+# Test whitespace in User_List as part of a per-user Defaults entry
+User_Alias FOO = foo, bar
+Defaults:FOO env_reset
+Defaults:foo,bar env_reset
+Defaults:foo,\ bar env_reset
+Defaults:foo, bar env_reset
diff --git a/plugins/sudoers/regress/sudoers/test3.out.ok b/plugins/sudoers/regress/sudoers/test3.out.ok
new file mode 100644 (file)
index 0000000..af2f402
--- /dev/null
@@ -0,0 +1,9 @@
+Parses OK.
+
+Defaults:FOO   env_reset
+Defaults:foo,bar       env_reset
+Defaults:foo, bar      env_reset
+Defaults:foo,bar       env_reset
+
+User_Alias     FOO = foo, bar
+
diff --git a/plugins/sudoers/regress/sudoers/test3.toke.ok b/plugins/sudoers/regress/sudoers/test3.toke.ok
new file mode 100644 (file)
index 0000000..49f2e51
--- /dev/null
@@ -0,0 +1,6 @@
+#
+USERALIAS ALIAS = WORD(5) , WORD(5) 
+DEFAULTS_USER ALIAS DEFVAR 
+DEFAULTS_USER WORD(5) , WORD(5) DEFVAR 
+DEFAULTS_USER WORD(5) , WORD(5) DEFVAR 
+DEFAULTS_USER WORD(5) , WORD(5) DEFVAR 
diff --git a/plugins/sudoers/regress/sudoers/test4.in b/plugins/sudoers/regress/sudoers/test4.in
new file mode 100644 (file)
index 0000000..b8df454
--- /dev/null
@@ -0,0 +1,7 @@
+# Test line continuation with anchored matches
+User_Alias FOO = foo \
+: BAR = bar
+
+# This used to pass for sudo < 1.8.1 (though it should not have)
+User_Alias FOO = foo \
+User_Alias BAR = bar
diff --git a/plugins/sudoers/regress/sudoers/test4.out.ok b/plugins/sudoers/regress/sudoers/test4.out.ok
new file mode 100644 (file)
index 0000000..851e644
--- /dev/null
@@ -0,0 +1,6 @@
+Does not parse.
+
+
+User_Alias     BAR = bar
+User_Alias     FOO = foo
+
diff --git a/plugins/sudoers/regress/sudoers/test4.toke.ok b/plugins/sudoers/regress/sudoers/test4.toke.ok
new file mode 100644 (file)
index 0000000..a225792
--- /dev/null
@@ -0,0 +1,5 @@
+#
+USERALIAS ALIAS = WORD(5) : ALIAS = WORD(5) 
+
+#
+USERALIAS ALIAS = WORD(5) ERROR <*> ALIAS = WORD(5) 
diff --git a/plugins/sudoers/regress/sudoers/test5.in b/plugins/sudoers/regress/sudoers/test5.in
new file mode 100644 (file)
index 0000000..354f589
--- /dev/null
@@ -0,0 +1,3 @@
+# Test empty string in User_Alias and Command_Spec
+User_Alias FOO = ""
+"" ALL = ALL
diff --git a/plugins/sudoers/regress/sudoers/test5.out.ok b/plugins/sudoers/regress/sudoers/test5.out.ok
new file mode 100644 (file)
index 0000000..6b6f261
--- /dev/null
@@ -0,0 +1,4 @@
+Does not parse.
+
+
+
diff --git a/plugins/sudoers/regress/sudoers/test5.toke.ok b/plugins/sudoers/regress/sudoers/test5.toke.ok
new file mode 100644 (file)
index 0000000..9376455
--- /dev/null
@@ -0,0 +1,3 @@
+#
+USERALIAS ALIAS = BEGINSTR ENDSTR ERROR <*> 
+BEGINSTR ENDSTR ERROR <*> ALL = ALL 
diff --git a/plugins/sudoers/regress/sudoers/test6.in b/plugins/sudoers/regress/sudoers/test6.in
new file mode 100644 (file)
index 0000000..e804571
--- /dev/null
@@ -0,0 +1,15 @@
+# Check that uids work in per-user and per-runas Defaults
+Defaults:#123 set_home
+Defaults>#123 set_home
+Defaults:"#123" set_home
+Defaults>"#123" set_home
+
+# Check that uids work in a Command_Spec
+#0 ALL = ALL
+#0 ALL = (#0 : #0) ALL
+"#0" ALL = ALL
+"#0" ALL = ("#0" : "#0") ALL
+
+# Check that gids work in a Command_Spec
+%#0 ALL = ALL
+"%#0" ALL = ALL
diff --git a/plugins/sudoers/regress/sudoers/test6.out.ok b/plugins/sudoers/regress/sudoers/test6.out.ok
new file mode 100644 (file)
index 0000000..275add6
--- /dev/null
@@ -0,0 +1,14 @@
+Parses OK.
+
+Defaults:#123  set_home
+Defaults>#123  set_home
+Defaults:#123  set_home
+Defaults>#123  set_home
+
+
+#0     ALL = ALL
+#0     ALL = (#0 : #0) ALL
+#0     ALL = ALL
+#0     ALL = (#0 : #0) ALL
+%#0    ALL = ALL
+%#0    ALL = ALL
diff --git a/plugins/sudoers/regress/sudoers/test6.toke.ok b/plugins/sudoers/regress/sudoers/test6.toke.ok
new file mode 100644 (file)
index 0000000..a9c0522
--- /dev/null
@@ -0,0 +1,15 @@
+#
+DEFAULTS_USER WORD(5) DEFVAR 
+DEFAULTS_RUNAS WORD(5) DEFVAR 
+DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
+DEFAULTS_RUNAS BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
+
+#
+WORD(5) ALL = ALL 
+WORD(5) ALL = ( WORD(5) : WORD(5) ) ALL 
+BEGINSTR STRBODY ENDSTR WORD(4) ALL = ALL 
+BEGINSTR STRBODY ENDSTR WORD(4) ALL = ( BEGINSTR STRBODY ENDSTR WORD(4) : BEGINSTR STRBODY ENDSTR WORD(4) ) ALL 
+
+#
+USERGROUP ALL = ALL 
+BEGINSTR STRBODY ENDSTR USERGROUP ALL = ALL 
diff --git a/plugins/sudoers/regress/sudoers/test7.in b/plugins/sudoers/regress/sudoers/test7.in
new file mode 100644 (file)
index 0000000..7b241d0
--- /dev/null
@@ -0,0 +1,7 @@
+# These should all be syntax errors
+User_Alias FOO1 = "%"
+User_Alias FOO2 = "%:"
+User_Alias FOO3 = "+"
+User_Alias FOO4 = %
+User_Alias FOO5 = %:
+User_Alias FOO6 = +
diff --git a/plugins/sudoers/regress/sudoers/test7.out.ok b/plugins/sudoers/regress/sudoers/test7.out.ok
new file mode 100644 (file)
index 0000000..6b6f261
--- /dev/null
@@ -0,0 +1,4 @@
+Does not parse.
+
+
+
diff --git a/plugins/sudoers/regress/sudoers/test7.toke.ok b/plugins/sudoers/regress/sudoers/test7.toke.ok
new file mode 100644 (file)
index 0000000..a5bf018
--- /dev/null
@@ -0,0 +1,7 @@
+#
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR ERROR <*> 
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR ERROR <*> 
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR ERROR <*> 
+USERALIAS ALIAS = ERROR <*> 
+USERALIAS ALIAS = ERROR <*> 
+USERALIAS ALIAS = ERROR <*> 
diff --git a/plugins/sudoers/regress/sudoers/test8.in b/plugins/sudoers/regress/sudoers/test8.in
new file mode 100644 (file)
index 0000000..d25e834
--- /dev/null
@@ -0,0 +1,8 @@
+# Test quoted strings
+User_Alias UA1 = "xy"
+User_Alias UA2 = "x\
+y"
+User_Alias UA3 = x\"y
+
+# A newline in the middle of a string is an error
+User_Alias UA4 = "x
diff --git a/plugins/sudoers/regress/sudoers/test8.out.ok b/plugins/sudoers/regress/sudoers/test8.out.ok
new file mode 100644 (file)
index 0000000..ccea904
--- /dev/null
@@ -0,0 +1,7 @@
+Does not parse.
+
+
+User_Alias     UA1 = xy
+User_Alias     UA2 = xy
+User_Alias     UA3 = x"y
+
diff --git a/plugins/sudoers/regress/sudoers/test8.toke.ok b/plugins/sudoers/regress/sudoers/test8.toke.ok
new file mode 100644 (file)
index 0000000..0f7e2a9
--- /dev/null
@@ -0,0 +1,7 @@
+#
+USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) 
+USERALIAS ALIAS = BEGINSTR STRBODY STRBODY ENDSTR WORD(4) 
+USERALIAS ALIAS = WORD(5) 
+
+#
+USERALIAS ALIAS = BEGINSTR STRBODY ERROR <*> ERROR 
\ No newline at end of file
diff --git a/plugins/sudoers/regress/testsudoers/test1.out.ok b/plugins/sudoers/regress/testsudoers/test1.out.ok
new file mode 100644 (file)
index 0000000..f980873
--- /dev/null
@@ -0,0 +1,8 @@
+Parses OK.
+
+Entries for user root:
+
+ALL = ALL
+       host  matched
+
+Command unmatched
diff --git a/plugins/sudoers/regress/testsudoers/test1.sh b/plugins/sudoers/regress/testsudoers/test1.sh
new file mode 100755 (executable)
index 0000000..a6358b3
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+#
+# Test for NULL dereference with "sudo -g group" when the sudoers rule
+# has no runas user or group listed.
+# This is RedHat bug Bug 667103.
+#
+
+./testsudoers -g bin root id <<EOF
+root ALL = ALL
+EOF
diff --git a/plugins/sudoers/set_perms.c b/plugins/sudoers/set_perms.c
new file mode 100644 (file)
index 0000000..17c87b4
--- /dev/null
@@ -0,0 +1,972 @@
+/*
+ * Copyright (c) 1994-1996,1998-2011 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/param.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#include <errno.h>
+#include <grp.h>
+
+#include "sudoers.h"
+
+/*
+ * Prototypes
+ */
+static void runas_setgroups(void);
+
+/*
+ * We keep track of the current permisstions and use a stack to restore
+ * the old permissions.  A depth of 16 is overkill.
+ */
+struct perm_state {
+    uid_t ruid;
+    uid_t euid;
+#ifdef HAVE_SETRESUID
+    uid_t suid;
+#endif
+    gid_t rgid;
+    gid_t egid;
+#ifdef HAVE_SETRESUID
+    gid_t sgid;
+#endif
+    GETGROUPS_T *groups;
+    int ngroups;
+};
+
+#define PERM_STACK_MAX 16
+static struct perm_state perm_stack[PERM_STACK_MAX];
+static int perm_stack_depth = 0;
+
+/* XXX - make a runas_user struct? */
+int runas_ngroups = -1;
+#ifdef HAVE_GETGROUPS
+GETGROUPS_T *runas_groups;
+#endif
+
+#undef ID
+#define ID(x) (state->x == ostate->x ? -1 : state->x)
+#undef OID
+#define OID(x) (ostate->x == state->x ? -1 : ostate->x)
+
+void
+rewind_perms(void)
+{
+    while (perm_stack_depth > 1)
+       restore_perms();
+}
+
+#ifdef HAVE_SETRESUID
+
+/*
+ * Set real and effective and saved uids and gids based on perm.
+ * We always retain a saved uid of 0 unless we are headed for an exec().
+ * We only flip the effective gid since it only changes for PERM_SUDOERS.
+ * This version of set_perms() works fine with the "stay_setuid" option.
+ */
+int
+set_perms(int perm)
+{
+    struct perm_state *state, *ostate = NULL;
+    const char *errstr;
+    int noexit;
+
+    noexit = ISSET(perm, PERM_NOEXIT);
+    CLR(perm, PERM_MASK);
+
+    if (perm_stack_depth == PERM_STACK_MAX) {
+       errstr = "perm stack overflow";
+       errno = EINVAL;
+       goto bad;
+    }
+
+    state = &perm_stack[perm_stack_depth];
+    if (perm_stack_depth)
+       ostate = &perm_stack[perm_stack_depth - 1];
+
+    if (perm != PERM_INITIAL && memcmp(state, ostate, sizeof(*state)) == 0)
+       goto done;
+
+    switch (perm) {
+    case PERM_INITIAL:
+       /* Stash initial state */
+#ifdef HAVE_GETRESUID
+       if (getresuid(&state->ruid, &state->euid, &state->suid)) {
+           errstr = "getresuid";
+           goto bad;
+
+       }
+       if (getresgid(&state->rgid, &state->egid, &state->sgid)) {
+           errstr = "getresgid";
+           goto bad;
+       }
+#else
+       state->ruid = getuid();
+       state->euid = geteuid();
+       state->suid = state->euid; /* in case we are setuid */
+
+       state->rgid = getgid();
+       state->egid = getegid();
+       state->sgid = state->egid; /* in case we are setgid */
+#endif
+       state->groups = user_groups;
+       state->ngroups = user_ngroups;
+       break;
+
+    case PERM_ROOT:
+       state->ruid = ROOT_UID;
+       state->euid = ROOT_UID;
+       state->suid = ROOT_UID;
+       if (setresuid(ID(ruid), ID(euid), ID(suid))) {
+           errstr = "setresuid(ROOT_UID, ROOT_UID, ROOT_UID)";
+           goto bad;
+       }
+       state->rgid = -1;
+       state->egid = -1;
+       state->sgid = -1;
+       state->groups = NULL;
+       state->ngroups = -1;
+       break;
+
+    case PERM_USER:
+       state->groups = user_groups;
+       state->ngroups = user_ngroups;
+       if (state->ngroups != -1 && state->groups != ostate->groups) {
+           if (setgroups(state->ngroups, state->groups)) {
+               errstr = "setgroups()";
+               goto bad;
+           }
+       }
+       state->rgid = -1;
+       state->egid = user_gid;
+       state->sgid = -1;
+       if (setresgid(-1, ID(egid), -1)) {
+           errstr = "setresgid(-1, user_gid, -1)";
+           goto bad;
+       }
+       state->ruid = user_uid;
+       state->euid = user_uid;
+       state->suid = ROOT_UID;
+       if (setresuid(ID(ruid), ID(euid), ID(suid))) {
+           errstr = "setresuid(user_uid, user_uid, ROOT_UID)";
+           goto bad;
+       }
+       break;
+
+    case PERM_FULL_USER:
+       /* headed for exec() */
+       state->groups = user_groups;
+       state->ngroups = user_ngroups;
+       if (state->ngroups != -1 && state->groups != ostate->groups) {
+           if (setgroups(state->ngroups, state->groups)) {
+               errstr = "setgroups()";
+               goto bad;
+           }
+       }
+       state->rgid = user_gid;
+       state->egid = user_gid;
+       state->sgid = user_gid;
+       if (setresgid(ID(rgid), ID(egid), ID(sgid))) {
+           errstr = "setresgid(user_gid, user_gid, user_gid)";
+           goto bad;
+       }
+       state->ruid = user_uid;
+       state->euid = user_uid;
+       state->suid = user_uid;
+       if (setresuid(ID(ruid), ID(euid), ID(suid))) {
+           errstr = "setresuid(user_uid, user_uid, user_uid)";
+           goto bad;
+       }
+       break;
+
+    case PERM_RUNAS:
+       runas_setgroups();
+       state->groups = runas_groups;
+       state->ngroups = runas_ngroups;
+
+       state->rgid = -1;
+       state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
+       state->sgid = -1;
+       if (setresgid(-1, ID(egid), -1)) {
+           errstr = "unable to change to runas gid";
+           goto bad;
+       }
+       state->ruid = -1;
+       state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
+       state->suid = -1;
+       if (setresuid(-1, ID(euid), -1)) {
+           errstr = "unable to change to runas uid";
+           goto bad;
+       }
+       break;
+
+    case PERM_SUDOERS:
+       state->groups = NULL;
+       state->ngroups = -1;
+
+       /* assumes euid == ROOT_UID, ruid == user */
+       state->rgid = -1;
+       state->egid = sudoers_gid;
+       state->sgid = -1;
+       if (setresgid(-1, ID(egid), -1))
+           error(1, "unable to change to sudoers gid");
+
+       state->ruid = ROOT_UID;
+       /*
+        * If sudoers_uid == ROOT_UID and sudoers_mode is group readable
+        * we use a non-zero uid in order to avoid NFS lossage.
+        * Using uid 1 is a bit bogus but should work on all OS's.
+        */
+       if (sudoers_uid == ROOT_UID && (sudoers_mode & 040))
+           state->euid = 1;
+       else
+           state->euid = sudoers_uid;
+       state->suid = ROOT_UID;
+       if (setresuid(ID(ruid), ID(euid), ID(suid))) {
+           errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)";
+           goto bad;
+       }
+       break;
+
+    case PERM_TIMESTAMP:
+       state->groups = NULL;
+       state->ngroups = -1;
+       state->rgid = -1;
+       state->egid = -1;
+       state->sgid = -1;
+       state->ruid = ROOT_UID;
+       state->euid = timestamp_uid;
+       state->suid = ROOT_UID;
+       if (setresuid(ID(ruid), ID(euid), ID(suid))) {
+           errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)";
+           goto bad;
+       }
+       break;
+    }
+
+done:
+    perm_stack_depth++;
+    return 1;
+bad:
+    /* XXX - better warnings inline */
+    warningx("%s: %s", errstr,
+       errno == EAGAIN ? "too many processes" : strerror(errno));
+    if (noexit)
+       return 0;
+    exit(1);
+}
+
+void
+restore_perms(void)
+{
+    struct perm_state *state, *ostate;
+
+    if (perm_stack_depth < 2)
+       return;
+
+    state = &perm_stack[perm_stack_depth - 1];
+    ostate = &perm_stack[perm_stack_depth - 2];
+    perm_stack_depth--;
+
+    /* XXX - more cases here where euid != ruid */
+    if (OID(euid) == ROOT_UID && state->euid != ROOT_UID) {
+       if (setresuid(-1, ROOT_UID, -1)) {
+           warning("setresuid() [%d, %d, %d] -> [%d, %d, %d]", state->ruid,
+               state->euid, state->suid, -1, ROOT_UID, -1);
+           goto bad;
+       }
+    }
+    if (setresuid(OID(ruid), OID(euid), OID(suid))) {
+       warning("setresuid() [%d, %d, %d] -> [%d, %d, %d]", state->ruid,
+           state->euid, state->suid, OID(ruid), OID(euid), OID(suid));
+       goto bad;
+    }
+    if (setresgid(OID(rgid), OID(egid), OID(sgid))) {
+       warning("setresgid() [%d, %d, %d] -> [%d, %d, %d]", state->rgid,
+           state->egid, state->sgid, OID(rgid), OID(egid), OID(sgid));
+       goto bad;
+    }
+    if (state->ngroups != -1 && state->groups != ostate->groups) {
+       if (setgroups(ostate->ngroups, ostate->groups)) {
+           warning("setgroups()");
+           goto bad;
+       }
+    }
+    return;
+
+bad:
+    exit(1);
+}
+
+#else
+# ifdef HAVE_SETREUID
+
+/*
+ * Set real and effective uids and gids based on perm.
+ * We always retain a real or effective uid of ROOT_UID unless
+ * we are headed for an exec().
+ * This version of set_perms() works fine with the "stay_setuid" option.
+ */
+int
+set_perms(int perm)
+{
+    struct perm_state *state, *ostate = NULL;
+    const char *errstr;
+    int noexit;
+
+    noexit = ISSET(perm, PERM_NOEXIT);
+    CLR(perm, PERM_MASK);
+
+    if (perm_stack_depth == PERM_STACK_MAX) {
+       errstr = "perm stack overflow";
+       errno = EINVAL;
+       goto bad;
+    }
+
+    state = &perm_stack[perm_stack_depth];
+    if (perm_stack_depth)
+       ostate = &perm_stack[perm_stack_depth - 1];
+
+    if (perm != PERM_INITIAL && memcmp(state, ostate, sizeof(*state)) == 0)
+       goto done;
+
+    switch (perm) {
+    case PERM_INITIAL:
+       /* Stash initial state */
+       state->ruid = getuid();
+       state->euid = geteuid();
+       state->rgid = getgid();
+       state->egid = getegid();
+       state->groups = user_groups;
+       state->ngroups = user_ngroups;
+       break;
+
+    case PERM_ROOT:
+       /*
+        * setreuid(0, 0) may fail on some systems
+        * when the euid is not already 0.
+        */
+       if (setreuid(-1, ROOT_UID)) {
+           errstr = "setreuid(-1, ROOT_UID)";
+           goto bad;
+       }
+       if (setuid(ROOT_UID)) {
+           errstr = "setuid(ROOT_UID)";
+           goto bad;
+       }
+       state->ruid = ROOT_UID;
+       state->euid = ROOT_UID;
+       state->rgid = -1;
+       state->egid = -1;
+       state->groups = NULL;
+       state->ngroups = -1;
+       break;
+
+    case PERM_USER:
+       state->groups = user_groups;
+       state->ngroups = user_ngroups;
+       if (state->ngroups != -1 && state->groups != ostate->groups) {
+           if (setgroups(state->ngroups, state->groups)) {
+               errstr = "setgroups()";
+               goto bad;
+           }
+       }
+       state->rgid = -1;
+       state->egid = user_gid;
+       if (setregid(-1, ID(egid))) {
+           errstr = "setregid(-1, user_gid)";
+           goto bad;
+       }
+       state->ruid = ROOT_UID;
+       state->euid = user_uid;
+       if (setreuid(ID(ruid), ID(euid))) {
+           errstr = "setreuid(ROOT_UID, user_uid)";
+           goto bad;
+       }
+       break;
+
+    case PERM_FULL_USER:
+       /* headed for exec() */
+       state->groups = user_groups;
+       state->ngroups = user_ngroups;
+       if (state->ngroups != -1 && state->groups != ostate->groups) {
+           if (setgroups(state->ngroups, state->groups)) {
+               errstr = "setgroups()";
+               goto bad;
+           }
+       }
+       state->rgid = user_gid;
+       state->egid = user_gid;
+       if (setregid(ID(rgid), ID(egid))) {
+           errstr = "setregid(user_gid, user_gid)";
+           goto bad;
+       }
+       state->ruid = user_uid;
+       state->euid = user_uid;
+       if (setreuid(ID(ruid), ID(euid))) {
+           errstr = "setreuid(user_uid, user_uid)";
+           goto bad;
+       }
+       break;
+
+    case PERM_RUNAS:
+       runas_setgroups();
+       state->groups = runas_groups;
+       state->ngroups = runas_ngroups;
+
+       state->rgid = -1;
+       state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
+       if (setregid(ID(rgid), ID(egid))) {
+           errstr = "unable to change to runas gid";
+           goto bad;
+       }
+       state->ruid = ROOT_UID;
+       state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
+       if (setreuid(ID(ruid), ID(euid))) {
+           errstr = "unable to change to runas uid";
+           goto bad;
+       }
+       break;
+
+    case PERM_SUDOERS:
+       state->groups = NULL;
+       state->ngroups = -1;
+
+       /* assume euid == ROOT_UID, ruid == user */
+       state->rgid = -1;
+       state->egid = sudoers_gid;
+       if (setregid(-1, ID(egid)))
+           error(1, "unable to change to sudoers gid");
+
+       state->ruid = ROOT_UID;
+       /*
+        * If sudoers_uid == ROOT_UID and sudoers_mode is group readable
+        * we use a non-zero uid in order to avoid NFS lossage.
+        * Using uid 1 is a bit bogus but should work on all OS's.
+        */
+       if (sudoers_uid == ROOT_UID && (sudoers_mode & 040))
+           state->euid = 1;
+       else
+           state->euid = sudoers_uid;
+       if (setreuid(ID(ruid), ID(euid))) {
+           errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
+           goto bad;
+       }
+       break;
+
+    case PERM_TIMESTAMP:
+       state->groups = NULL;
+       state->ngroups = -1;
+       state->rgid = -1;
+       state->egid = -1;
+       state->ruid = ROOT_UID;
+       state->euid = timestamp_uid;
+       if (setreuid(ID(ruid), ID(euid))) {
+           errstr = "setreuid(ROOT_UID, timestamp_uid)";
+           goto bad;
+       }
+       break;
+    }
+
+done:
+    perm_stack_depth++;
+    return 1;
+bad:
+    /* XXX - better warnings inline */
+    warningx("%s: %s", errstr,
+       errno == EAGAIN ? "too many processes" : strerror(errno));
+    if (noexit)
+       return 0;
+    exit(1);
+}
+
+void
+restore_perms(void)
+{
+    struct perm_state *state, *ostate;
+
+    if (perm_stack_depth < 2)
+       return;
+
+    state = &perm_stack[perm_stack_depth - 1];
+    ostate = &perm_stack[perm_stack_depth - 2];
+    perm_stack_depth--;
+
+    /*
+     * When changing euid to ROOT_UID, setreuid() may fail even if
+     * the ruid is ROOT_UID so call setuid() first.
+     */
+    if (OID(euid) == ROOT_UID) {
+       /* setuid() may not set the saved ID unless the euid is ROOT_UID */
+       if (ID(euid) != ROOT_UID)
+           (void)setreuid(-1, ROOT_UID);
+       if (setuid(ROOT_UID)) {
+           warning("setuid(%d)", ROOT_UID);
+           goto bad;
+       }
+    }
+    if (setreuid(OID(ruid), OID(euid))) {
+       warning("setreuid() [%d, %d] -> [%d, %d]", state->ruid,
+           state->euid, OID(ruid), OID(euid));
+       goto bad;
+    }
+    if (setregid(OID(rgid), OID(egid))) {
+       warning("setregid() [%d, %d] -> [%d, %d]", state->rgid,
+           state->egid, OID(rgid), OID(egid));
+       goto bad;
+    }
+    if (state->ngroups != -1 && state->groups != ostate->groups) {
+       if (setgroups(ostate->ngroups, ostate->groups)) {
+           warning("setgroups()");
+           goto bad;
+       }
+    }
+    return;
+
+bad:
+    exit(1);
+}
+
+# else /* !HAVE_SETRESUID && !HAVE_SETREUID */
+# ifdef HAVE_SETEUID
+
+/*
+ * Set real and effective uids and gids based on perm.
+ * We always retain a real or effective uid of ROOT_UID unless
+ * we are headed for an exec().
+ * This version of set_perms() works fine with the "stay_setuid" option.
+ */
+int
+set_perms(int perm)
+{
+    struct perm_state *state, *ostate = NULL;
+    const char *errstr;
+    int noexit;
+
+    noexit = ISSET(perm, PERM_NOEXIT);
+    CLR(perm, PERM_MASK);
+
+    if (perm_stack_depth == PERM_STACK_MAX) {
+       errstr = "perm stack overflow";
+       errno = EINVAL;
+       goto bad;
+    }
+
+    state = &perm_stack[perm_stack_depth];
+    if (perm_stack_depth)
+       ostate = &perm_stack[perm_stack_depth - 1];
+
+    if (perm != PERM_INITIAL && memcmp(state, ostate, sizeof(*state)) == 0)
+       goto done;
+
+    /*
+     * Since we only have setuid() and seteuid() and semantics
+     * for these calls differ on various systems, we set
+     * real and effective uids to ROOT_UID initially to be safe.
+     */
+    if (perm != PERM_INITIAL) {
+       if (seteuid(ROOT_UID)) {
+           errstr = "seteuid(ROOT_UID)";
+           goto bad;
+       }
+       if (setuid(ROOT_UID)) {
+           errstr = "setuid(ROOT_UID)";
+           goto bad;
+       }
+    }
+
+    switch (perm) {
+    case PERM_INITIAL:
+       /* Stash initial state */
+       state->ruid = getuid();
+       state->euid = geteuid();
+       state->rgid = getgid();
+       state->egid = getegid();
+       state->groups = user_groups;
+       state->ngroups = user_ngroups;
+       break;
+
+    case PERM_ROOT:
+       /* We already set ruid/euid above. */
+       state->ruid = ROOT_UID;
+       state->euid = ROOT_UID;
+       state->rgid = -1;
+       state->egid = -1;
+       state->groups = NULL;
+       state->ngroups = -1;
+       break;
+
+    case PERM_USER:
+       state->groups = user_groups;
+       state->ngroups = user_ngroups;
+       if (state->ngroups != -1 && state->groups != ostate->groups) {
+           if (setgroups(state->ngroups, state->groups)) {
+               errstr = "setgroups()";
+               goto bad;
+           }
+       }
+       state->rgid = -1;
+       state->egid = user_gid;
+       if (setegid(ID(egid))) {
+           errstr = "setegid(user_gid)";
+           goto bad;
+       }
+       state->ruid = ROOT_UID;
+       state->euid = user_uid;
+       if (seteuid(ID(euid))) {
+           errstr = "seteuid(user_uid)";
+           goto bad;
+       }
+       break;
+
+    case PERM_FULL_USER:
+       /* headed for exec() */
+       state->groups = user_groups;
+       state->ngroups = user_ngroups;
+       if (state->ngroups != -1 && state->groups != ostate->groups) {
+           if (setgroups(state->ngroups, state->groups)) {
+               errstr = "setgroups()";
+               goto bad;
+           }
+       }
+       state->rgid = user_gid;
+       state->egid = user_gid;
+       if (setgid(user_gid)) {
+           errstr = "setgid(user_gid)";
+           goto bad;
+       }
+       state->ruid = user_uid;
+       state->euid = user_uid;
+       if (setuid(user_uid)) {
+           errstr = "setuid(user_uid)";
+           goto bad;
+       }
+       break;
+
+    case PERM_RUNAS:
+       runas_setgroups();
+       state->groups = runas_groups;
+       state->ngroups = runas_ngroups;
+
+       state->rgid = -1;
+       state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
+       if (setegid(ID(egid))) {
+           errstr = "unable to change to runas gid";
+           goto bad;
+       }
+       state->ruid = -1;
+       state->euid = runas_pw ? runas_pw->pw_uid : user_uid;
+       if (seteuid(ID(euid))) {
+           errstr = "unable to change to runas uid";
+           goto bad;
+       }
+       break;
+
+    case PERM_SUDOERS:
+       state->groups = NULL;
+       state->ngroups = -1;
+
+       /* assume euid == ROOT_UID, ruid == user */
+       state->rgid = -1;
+       state->egid = sudoers_gid;
+       if (setegid(ID(egid)))
+           error(1, "unable to change to sudoers gid");
+
+       state->ruid = ROOT_UID;
+       /*
+        * If sudoers_uid == ROOT_UID and sudoers_mode is group readable
+        * we use a non-zero uid in order to avoid NFS lossage.
+        * Using uid 1 is a bit bogus but should work on all OS's.
+        */
+       if (sudoers_uid == ROOT_UID && (sudoers_mode & 040))
+           state->euid = 1;
+       else
+           state->euid = sudoers_uid;
+       if (seteuid(ID(euid))) {
+           errstr = "seteuid(SUDOERS_UID)";
+           goto bad;
+       }
+       break;
+
+    case PERM_TIMESTAMP:
+       state->groups = NULL;
+       state->ngroups = -1;
+       state->rgid = -1;
+       state->egid = -1;
+       state->ruid = ROOT_UID;
+       state->euid = timestamp_uid;
+       if (seteuid(ID(euid))) {
+           errstr = "seteuid(timestamp_uid)";
+           goto bad;
+       }
+       break;
+    }
+
+done:
+    perm_stack_depth++;
+    return 1;
+bad:
+    /* XXX - better warnings inline */
+    warningx("%s: %s", errstr,
+       errno == EAGAIN ? "too many processes" : strerror(errno));
+    if (noexit)
+       return 0;
+    exit(1);
+}
+
+void
+restore_perms(void)
+{
+    struct perm_state *state, *ostate;
+
+    if (perm_stack_depth < 2)
+       return;
+
+    state = &perm_stack[perm_stack_depth - 1];
+    ostate = &perm_stack[perm_stack_depth - 2];
+    perm_stack_depth--;
+
+    /*
+     * Since we only have setuid() and seteuid() and semantics
+     * for these calls differ on various systems, we set
+     * real and effective uids to ROOT_UID initially to be safe.
+     */
+    if (seteuid(ROOT_UID)) {
+       errstr = "seteuid(ROOT_UID)";
+       goto bad;
+    }
+    if (setuid(ROOT_UID)) {
+       errstr = "setuid(ROOT_UID)";
+       goto bad;
+    }
+
+    if (setegid(OID(egid))) {
+       warning("setegid(%d)", OID(egid));
+       goto bad;
+    }
+    if (state->ngroups != -1 && state->groups != ostate->groups) {
+       if (setgroups(ostate->ngroups, ostate->groups)) {
+           warning("setgroups()");
+           goto bad;
+       }
+    }
+    if (seteuid(OID(euid))) {
+       warning("seteuid(%d)", OID(euid));
+       goto bad;
+    }
+    return;
+
+bad:
+    exit(1);
+}
+
+# else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
+
+/*
+ * Set uids and gids based on perm via setuid() and setgid().
+ * NOTE: does not support the "stay_setuid" or timestampowner options.
+ *       Also, sudoers_uid and sudoers_gid are not used.
+ */
+int
+set_perms(int perm)
+{
+    struct perm_state *state, *ostate = NULL;
+    const char *errstr;
+    int noexit;
+
+    noexit = ISSET(perm, PERM_NOEXIT);
+    CLR(perm, PERM_MASK);
+
+    if (perm_stack_depth == PERM_STACK_MAX) {
+       errstr = "perm stack overflow";
+       errno = EINVAL;
+       goto bad;
+    }
+
+    state = &perm_stack[perm_stack_depth];
+    if (perm_stack_depth)
+       ostate = &perm_stack[perm_stack_depth - 1];
+
+    if (perm != PERM_INITIAL && memcmp(state, ostate, sizeof(*state)) == 0)
+       goto done;
+
+    switch (perm) {
+    case PERM_INITIAL:
+       /* Stash initial state */
+       state->ruid = getuid();
+       state->rgid = getgid();
+       state->groups = user_groups;
+       state->ngroups = user_ngroups;
+       break;
+
+    case PERM_ROOT:
+       state->ruid = ROOT_UID;
+       state->rgid = -1;
+       state->groups = NULL;
+       state->ngroups = -1;
+       if (setuid(ROOT_UID)) {
+           errstr = "setuid(ROOT_UID)";
+           goto bad;
+       }
+       break;
+
+    case PERM_FULL_USER:
+       state->groups = user_groups;
+       state->ngroups = user_ngroups;
+       if (state->ngroups != -1 && state->groups != ostate->groups) {
+           if (setgroups(state->ngroups, state->groups)) {
+               errstr = "setgroups()";
+               goto bad;
+           }
+       }
+       state->rgid = user_gid;
+       (void) setgid(user_gid);
+       state->ruid = user_uid;
+       if (setuid(user_uid)) {
+           errstr = "setuid(user_uid)";
+           goto bad;
+       }
+       break;
+
+    case PERM_USER:
+    case PERM_SUDOERS:
+    case PERM_RUNAS:
+    case PERM_TIMESTAMP:
+       /* Unsupported since we can't set euid. */
+       break;
+    }
+
+done:
+    perm_stack_depth++;
+    return 1;
+bad:
+    /* XXX - better warnings inline */
+    warningx("%s: %s", errstr,
+       errno == EAGAIN ? "too many processes" : strerror(errno));
+    if (noexit)
+       return 0;
+    exit(1);
+}
+
+void
+restore_perms(void)
+{
+    struct perm_state *state, *ostate;
+
+    if (perm_stack_depth < 2)
+       return;
+
+    state = &perm_stack[perm_stack_depth - 1];
+    ostate = &perm_stack[perm_stack_depth - 2];
+    perm_stack_depth--;
+
+    if (state->ngroups != -1 && state->groups != ostate->groups) {
+       if (setgroups(ostate->ngroups, ostate->groups)) {
+           warning("setgroups()");
+           goto bad;
+       }
+    }
+    if (OID(rgid) != -1 && setgid(ostate->rgid)) {
+       warning("setgid(%d)", ostate->rgid);
+       goto bad;
+    }
+    if (OID(ruid) != -1 && setuid(ostate->ruid)) {
+       warning("setuid(%d)", ostate->ruid);
+       goto bad;
+    }
+    return;
+
+bad:
+    exit(1);
+}
+#  endif /* HAVE_SETEUID */
+# endif /* HAVE_SETREUID */
+#endif /* HAVE_SETRESUID */
+
+#ifdef HAVE_INITGROUPS
+static void
+runas_setgroups()
+{
+    static struct passwd *pw;
+    struct passwd *opw = pw;
+
+    if (def_preserve_groups)
+       return;
+
+    /*
+     * Use stashed copy of runas groups if available, else initgroups and stash.
+     */
+    pw = runas_pw ? runas_pw : sudo_user.pw;
+    if (pw != opw) {
+       pw = runas_pw ? runas_pw : sudo_user.pw;
+# ifdef HAVE_SETAUTHDB
+       aix_setauthdb(pw->pw_name);
+# endif
+       if (initgroups(pw->pw_name, pw->pw_gid) < 0)
+           log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
+# ifdef HAVE_GETGROUPS
+       if (runas_groups) {
+           efree(runas_groups);
+           runas_groups = NULL;
+       }
+       if ((runas_ngroups = getgroups(0, NULL)) > 0) {
+           runas_groups = emalloc2(runas_ngroups, sizeof(GETGROUPS_T));
+           if (getgroups(runas_ngroups, runas_groups) < 0)
+               log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
+       }
+#  ifdef HAVE_SETAUTHDB
+       aix_restoreauthdb();
+#  endif
+    } else {
+       if (setgroups(runas_ngroups, runas_groups) < 0)
+           log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
+# endif /* HAVE_GETGROUPS */
+    }
+}
+
+#else
+
+static void
+runas_setgroups()
+{
+    /* STUB */
+}
+
+#endif /* HAVE_INITGROUPS */
diff --git a/plugins/sudoers/sudo_nss.c b/plugins/sudoers/sudo_nss.c
new file mode 100644 (file)
index 0000000..2f77d89
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2007-2011 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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+
+#include "sudoers.h"
+#include "lbuf.h"
+
+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(void)
+{
+    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_if_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 */
+
+# if defined(HAVE_LDAP) && defined(_PATH_NETSVC_CONF)
+
+/*
+ * Read in /etc/netsvc.conf (like nsswitch.conf on AIX)
+ * Returns a tail queue of matches.
+ */
+struct sudo_nss_list *
+sudo_read_nss(void)
+{
+    FILE *fp;
+    char *cp, *ep;
+    int saw_files = FALSE;
+    int saw_ldap = FALSE;
+    int got_match = FALSE;
+    static struct sudo_nss_list snl;
+
+    if ((fp = fopen(_PATH_NETSVC_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", 7) != 0)
+           continue;
+       cp += 7;
+       while (isspace((unsigned char)*cp))
+           cp++;
+       if (*cp++ != '=')
+           continue;
+
+       /* Parse line */
+       for ((cp = strtok(cp, ",")); cp != NULL; (cp = strtok(NULL, ","))) {
+           /* Trim leading whitespace. */
+           while (isspace((unsigned char)*cp))
+               cp++;
+
+           if (!saw_files && strncasecmp(cp, "files", 5) == 0 &&
+               (isspace((unsigned char)cp[5]) || cp[5] == '\0')) {
+               tq_append(&snl, &sudo_nss_file);
+               got_match = TRUE;
+               ep = &cp[5];
+           } else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 &&
+               (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
+               tq_append(&snl, &sudo_nss_ldap);
+               got_match = TRUE;
+               ep = &cp[4];
+           } else {
+               got_match = FALSE;
+           }
+
+           /* check for = auth qualifier */
+           if (got_match && *ep) {
+               cp = ep;
+               while (isspace((unsigned char)*cp) || *cp == '=')
+                   cp++;
+               if (strncasecmp(cp, "auth", 4) == 0 &&
+                   (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
+                   tq_last(&snl)->ret_if_found = TRUE;
+               }
+           }
+       }
+       /* 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 /* !_PATH_NETSVC_CONF && !_PATH_NSSWITCH_CONF */
+
+/*
+ * Non-nsswitch.conf version with hard-coded order.
+ */
+struct sudo_nss_list *
+sudo_read_nss(void)
+{
+    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_NETSVC_CONF */
+
+#endif /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
+
+/* Reset user_groups based on passwd entry. */
+static void
+reset_groups(struct passwd *pw)
+{
+#if defined(HAVE_INITGROUPS) && defined(HAVE_GETGROUPS)
+    if (pw != sudo_user.pw) {
+# ifdef HAVE_SETAUTHDB
+       aix_setauthdb(pw->pw_name);
+# endif
+       if (initgroups(pw->pw_name, pw->pw_gid) == -1)
+           log_error(USE_ERRNO|MSG_ONLY, "can't reset group vector");
+       efree(user_groups);
+       user_groups = NULL;
+       if ((user_ngroups = getgroups(0, NULL)) > 0) {
+           user_groups = emalloc2(user_ngroups, sizeof(GETGROUPS_T));
+           if (getgroups(user_ngroups, user_groups) < 0)
+               log_error(USE_ERRNO|MSG_ONLY, "can't get group vector");
+       }
+# ifdef HAVE_SETAUTHDB
+       aix_restoreauthdb();
+# endif
+    }
+#endif
+}
+
+static int
+output(const char *buf)
+{
+    struct sudo_conv_message msg;
+    struct sudo_conv_reply repl;
+
+    /* Call conversation function */
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_type = SUDO_CONV_INFO_MSG;
+    msg.msg = buf;
+    memset(&repl, 0, sizeof(repl));
+    if (sudo_conv(1, &msg, &repl) == -1)
+       return 0;
+    return (int)strlen(buf);
+}
+
+/*
+ * 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(struct sudo_nss_list *snl, struct passwd *pw)
+{
+    struct sudo_nss *nss;
+    struct lbuf defs, privs;
+    int count, olen;
+
+    /* Reset group vector so group matching works correctly. */
+    reset_groups(pw);
+
+    lbuf_init(&defs, output, 4, NULL, sudo_user.cols);
+    lbuf_init(&privs, output, 4, NULL, sudo_user.cols);
+
+    /* Display defaults from all sources. */
+    lbuf_append(&defs, "Matching Defaults entries for ", pw->pw_name,
+       " on this host:\n", NULL);
+    count = 0;
+    tq_foreach_fwd(snl, nss) {
+       count += nss->display_defaults(nss, pw, &defs);
+    }
+    if (count)
+       lbuf_append(&defs, "\n\n", NULL);
+    else
+       defs.len = 0;
+
+    /* Display Runas and Cmnd-specific defaults from all sources. */
+    olen = defs.len;
+    lbuf_append(&defs, "Runas and Command-specific defaults for ", pw->pw_name,
+       ":\n", NULL);
+    count = 0;
+    tq_foreach_fwd(snl, nss) {
+       count += nss->display_bound_defaults(nss, pw, &defs);
+    }
+    if (count)
+       lbuf_append(&defs, "\n\n", NULL);
+    else
+       defs.len = olen;
+
+    /* Display privileges from all sources. */
+    lbuf_append(&privs, "User ", pw->pw_name,
+       " may run the following commands on this host:\n", NULL);
+    count = 0;
+    tq_foreach_fwd(snl, nss) {
+       count += nss->display_privs(nss, pw, &privs);
+    }
+    if (count) {
+       lbuf_print(&defs);
+       lbuf_print(&privs);
+    } else {
+       printf("User %s is not allowed to run sudo on %s.\n", pw->pw_name,
+           user_shost);
+    }
+
+    lbuf_destroy(&defs);
+    lbuf_destroy(&privs);
+}
+
+/*
+ * Check user_cmnd against sudoers and print the matching entry if the
+ * command is allowed.
+ * Returns TRUE if the command is allowed, else FALSE.
+ */
+int
+display_cmnd(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 TRUE;
+    }
+    return FALSE;
+}
diff --git a/plugins/sudoers/sudo_nss.h b/plugins/sudoers/sudo_nss.h
new file mode 100644 (file)
index 0000000..8d08944
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2007-2011
+ *
+ * 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.
+ */
+
+#ifndef _SUDO_NSS_H
+#define _SUDO_NSS_H
+
+struct lbuf;
+struct passwd;
+
+struct sudo_nss {
+    struct sudo_nss *prev;
+    struct sudo_nss *next;
+    int (*open)(struct sudo_nss *nss);
+    int (*close)(struct sudo_nss *nss);
+    int (*parse)(struct sudo_nss *nss);
+    int (*setdefs)(struct sudo_nss *nss);
+    int (*lookup)(struct sudo_nss *nss, int, int);
+    int (*display_cmnd)(struct sudo_nss *nss, struct passwd *);
+    int (*display_defaults)(struct sudo_nss *nss, struct passwd *, struct lbuf *);
+    int (*display_bound_defaults)(struct sudo_nss *nss, struct passwd *, struct lbuf *);
+    int (*display_privs)(struct sudo_nss *nss, struct passwd *, struct lbuf *);
+    void *handle;
+    short ret_if_found;
+    short ret_if_notfound;
+};
+
+TQ_DECLARE(sudo_nss)
+
+struct sudo_nss_list *sudo_read_nss(void);
+
+#endif /* _SUDO_NSS_H */
diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c
new file mode 100644 (file)
index 0000000..f533e59
--- /dev/null
@@ -0,0 +1,1462 @@
+/*
+ * Copyright (c) 1993-1996, 1998-2011 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.
+ *
+ * For a brief history of sudo, please see the HISTORY file included
+ * with this distribution.
+ */
+
+#define _SUDO_MAIN
+
+#ifdef __TANDEM
+# include <floss.h>
+#endif
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/socket.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <grp.h>
+#include <time.h>
+#ifdef HAVE_SETLOCALE
+# include <locale.h>
+#endif
+#include <netinet/in.h>
+#include <netdb.h>
+#ifdef HAVE_LOGIN_CAP_H
+# include <login_cap.h>
+# ifndef LOGIN_DEFROOTCLASS
+#  define LOGIN_DEFROOTCLASS   "daemon"
+# endif
+#endif
+#ifdef HAVE_SELINUX
+# include <selinux/selinux.h>
+#endif
+#ifdef HAVE_MBR_CHECK_MEMBERSHIP
+# include <membership.h>
+#endif
+#include <ctype.h>
+#include <setjmp.h>
+
+#include "sudoers.h"
+#include "lbuf.h"
+#include "interfaces.h"
+#include "sudoers_version.h"
+#include "auth/sudo_auth.h"
+
+/*
+ * Prototypes
+ */
+static void init_vars(char * const *);
+static int set_cmnd(int);
+static void set_loginclass(struct passwd *);
+static void set_runasgr(char *);
+static void set_runaspw(char *);
+static int sudoers_policy_version(int verbose);
+static int deserialize_info(char * const settings[], char * const user_info[]);
+static char *find_editor(int nfiles, char **files, char ***argv_out);
+static void create_admin_success_flag(void);
+
+/* XXX */
+extern int runas_ngroups;
+extern GETGROUPS_T *runas_groups;
+
+/*
+ * Globals
+ */
+const char *sudoers_file = _PATH_SUDOERS;
+mode_t sudoers_mode = SUDOERS_MODE;
+uid_t sudoers_uid = SUDOERS_UID;
+gid_t sudoers_gid = SUDOERS_GID;
+struct sudo_user sudo_user;
+struct passwd *list_pw;
+struct interface *interfaces;
+int long_list;
+int debug_level;
+uid_t timestamp_uid;
+extern int errorlineno;
+extern int parse_error;
+extern char *errorfile;
+#ifdef HAVE_LOGIN_CAP_H
+login_cap_t *lc;
+#endif /* HAVE_LOGIN_CAP_H */
+#ifdef HAVE_BSD_AUTH_H
+char *login_style;
+#endif /* HAVE_BSD_AUTH_H */
+sudo_conv_t sudo_conv;
+sudo_printf_t sudo_printf;
+int sudo_mode;
+
+static char *prev_user;
+static char *runas_user;
+static char *runas_group;
+static struct sudo_nss_list *snl;
+static const char *interfaces_string;
+static sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
+
+/* XXX - must be extern for audit bits of sudo_auth.c */
+int NewArgc;
+char **NewArgv;
+
+/* plugin_error.c */
+extern sigjmp_buf error_jmp;
+
+static int
+sudoers_policy_open(unsigned int version, sudo_conv_t conversation,
+    sudo_printf_t plugin_printf, char * const settings[],
+    char * const user_info[], char * const envp[])
+{
+    volatile int sources = 0;
+    sigaction_t sa;
+    struct sudo_nss *nss;
+
+    if (!sudo_conv)
+       sudo_conv = conversation;
+    if (!sudo_printf)
+       sudo_printf = plugin_printf;
+
+    if (sigsetjmp(error_jmp, 1)) {
+       /* called via error(), errorx() or log_error() */
+       rewind_perms();
+       return -1;
+    }
+
+    /*
+     * Signal setup:
+     * Ignore keyboard-generated signals so the user cannot interrupt
+     *  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;
+    (void) sigaction(SIGINT, &sa, &saved_sa_int);
+    (void) sigaction(SIGQUIT, &sa, &saved_sa_quit);
+    (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
+
+    sudo_setpwent();
+    sudo_setgrent();
+
+    /* Initialize environment functions (including replacements). */
+    env_init(envp);
+
+    /* Setup defaults data structures. */
+    init_defaults();
+
+    /* Parse settings and user_info */
+    sudo_mode = deserialize_info(settings, user_info);
+
+    init_vars(envp);           /* XXX - move this later? */
+
+    /* Parse nsswitch.conf for sudoers order. */
+    snl = sudo_read_nss();
+
+    set_perms(PERM_INITIAL);
+
+    /* Open and parse sudoers, set global defaults */
+    tq_foreach_fwd(snl, nss) {
+       if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
+           sources++;
+           if (nss->setdefs(nss) != 0)
+               log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
+       }
+    }
+    if (sources == 0) {
+       warningx("no valid sudoers sources found, quitting");
+       return -1;
+    }
+
+    /* XXX - collect post-sudoers parse settings into a function */
+
+    /*
+     * Initialize external group plugin.
+     */
+    if (def_group_plugin) {
+       switch (group_plugin_load(def_group_plugin)) {
+       case -1:
+           return -1;
+       case FALSE:
+           def_group_plugin = NULL;
+       }
+    }
+
+    /*
+     * 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");
+
+    if (def_fqdn)
+       set_fqdn();     /* deferred until after sudoers is parsed */
+
+    /* Set login class if applicable. */
+    set_loginclass(sudo_user.pw);
+
+    restore_perms();
+
+    return TRUE;
+}
+
+static void
+sudoers_policy_close(int exit_status, int error_code)
+{
+    if (sigsetjmp(error_jmp, 1)) {
+       /* called via error(), errorx() or log_error() */
+       return;
+    }
+
+    /* We do not currently log the exit status. */
+    if (error_code)
+       warningx("unable to execute %s: %s", safe_cmnd, strerror(error_code));
+
+    /* Close the session we opened in sudoers_policy_init_session(). */
+    if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT))
+       (void)auth_end_session();
+
+    /* Free remaining references to password and group entries. */
+    pw_delref(sudo_user.pw);
+    pw_delref(runas_pw);
+    if (runas_gr != NULL)
+       gr_delref(runas_gr);
+}
+
+/*
+ * The init_session function is called before executing the command
+ * and before uid/gid changes occur.
+ */
+static int
+sudoers_policy_init_session(struct passwd *pwd)
+{
+    if (sigsetjmp(error_jmp, 1)) {
+       /* called via error(), errorx() or log_error() */
+       return -1;
+    }
+
+    return auth_begin_session(pwd);
+}
+
+static int
+sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
+    char **command_infop[], char **argv_out[], char **user_env_out[])
+{
+    static char *command_info[32]; /* XXX */
+    char **edit_argv = NULL;
+    struct sudo_nss *nss;
+    int cmnd_status = -1, validated;
+    volatile int info_len = 0;
+    volatile int rval = TRUE;
+
+    if (sigsetjmp(error_jmp, 1)) {
+       /* error recovery via error(), errorx() or log_error() */
+       rval = -1;
+       goto done;
+    }
+
+    /* Is root even allowed to run sudo? */
+    if (user_uid == 0 && !def_root_sudo) {
+        warningx("sudoers specifies that root is not allowed to sudo");
+        goto bad;
+    }    
+
+    /* Check for -C overriding def_closefrom. */
+    if (user_closefrom >= 0 && user_closefrom != def_closefrom) {
+       if (!def_closefrom_override) {
+           warningx("you are not permitted to use the -C option");
+           goto bad;
+       }
+       def_closefrom = user_closefrom;
+    }
+
+    set_perms(PERM_INITIAL);
+
+    /* Environment variables specified on the command line. */
+    if (env_add != NULL && env_add[0] != NULL)
+       sudo_user.env_vars = env_add;
+
+    /*
+     * Make a local copy of argc/argv, with special handling
+     * for pseudo-commands and the '-i' option.
+     */
+    if (argc == 0) {
+       NewArgc = 1;
+       NewArgv = emalloc2(NewArgc + 1, sizeof(char *));
+       NewArgv[0] = user_cmnd;
+       NewArgv[1] = NULL;
+    } else {
+       NewArgc = argc;
+       NewArgv = emalloc2(NewArgc + 1, sizeof(char *));
+       memcpy(NewArgv, argv, argc * sizeof(char *));
+       NewArgv[NewArgc] = NULL;
+       if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
+           NewArgv[0] = estrdup(runas_pw->pw_shell);
+    }
+
+    /* Find command in path */
+    cmnd_status = set_cmnd(sudo_mode);
+    if (cmnd_status == -1) {
+       rval = -1;
+       goto done;
+    }
+
+#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
+
+    /*
+     * Check sudoers sources.
+     */
+    validated = FLAG_NO_USER | FLAG_NO_HOST;
+    tq_foreach_fwd(snl, nss) {
+       validated = nss->lookup(nss, validated, pwflag);
+
+       if (ISSET(validated, VALIDATE_OK)) {
+           /* Handle "= auth" in netsvc.conf */
+           if (nss->ret_if_found)
+               break;
+       } else {
+           /* Handle [NOTFOUND=return] */
+           if (nss->ret_if_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.
+     */
+    if (def_timestampowner) {
+       struct passwd *pw;
+
+       if (*def_timestampowner == '#')
+           pw = sudo_getpwuid(atoi(def_timestampowner + 1));
+       else
+           pw = sudo_getpwnam(def_timestampowner);
+       if (!pw)
+           log_error(0, "timestamp owner (%s): No such user",
+               def_timestampowner);
+       timestamp_uid = pw->pw_uid;
+       pw_delref(pw);
+    }
+
+    /* If given the -P option, set the "preserve_groups" flag. */
+    if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
+       def_preserve_groups = TRUE;
+
+    /* If no command line args and "shell_noargs" is not set, error out. */
+    if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) {
+       rval = -2; /* usage error */
+       goto done;
+    }
+
+    /* Bail if a tty is required and we don't have one.  */
+    if (def_requiretty) {
+       int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);
+       if (fd == -1) {
+           audit_failure(NewArgv, "no tty");
+           warningx("sorry, you must have a tty to run sudo");
+           goto bad;
+       } else
+           (void) close(fd);
+    }
+
+    /*
+     * We don't reset the environment for sudoedit or if the user
+     * specified the -E command line flag and they have setenv privs.
+     */
+    if (ISSET(sudo_mode, MODE_EDIT) ||
+       (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv))
+       def_env_reset = FALSE;
+
+    /* Build a new environment that avoids any nasty bits. */
+    rebuild_env();
+
+    /* Require a password if sudoers says so.  */
+    if (def_authenticate) {
+       int rc = check_user(validated, sudo_mode);
+       if (rc != TRUE) {
+           rval = rc;
+           goto done;
+       }
+    }
+
+    /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
+    /* 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) {
+                   if (sudo_user.pw != NULL)
+                       pw_delref(sudo_user.pw);
+                   sudo_user.pw = pw;
+#ifdef HAVE_MBR_CHECK_MEMBERSHIP
+                   mbr_uid_to_uuid(user_uid, user_uuid);
+#endif
+           }
+       }
+    }
+
+    /* If the user was not allowed to run the command we are done. */
+    if (!ISSET(validated, VALIDATE_OK)) {
+       if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) {
+           audit_failure(NewArgv, "No user or host");
+           log_denial(validated, 1);
+       } else {
+           if (def_path_info) {
+               /*
+                * We'd like to not leak path info at all here, but that can
+                * *really* confuse the users.  To really close the leak we'd
+                * have to say "not allowed to run foo" even when the problem
+                * is just "no foo in path" since the user can trivially set
+                * their path to just contain a single dir.
+                */
+               log_denial(validated,
+                   !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND));
+               if (cmnd_status == NOT_FOUND)
+                   warningx("%s: command not found", user_cmnd);
+               else if (cmnd_status == NOT_FOUND_DOT)
+                   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_denial(validated, 1);
+           }
+           audit_failure(NewArgv, "validation failure");
+       }
+       goto bad;
+    }
+
+    /* Create Ubuntu-style dot file to indicate sudo was successful. */
+    create_admin_success_flag();
+
+    /* Finally tell the user if the command did not exist. */
+    if (cmnd_status == NOT_FOUND_DOT) {
+       audit_failure(NewArgv, "command in current directory");
+       warningx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
+       goto bad;
+    } else if (cmnd_status == NOT_FOUND) {
+       audit_failure(NewArgv, "%s: command not found", user_cmnd);
+       warningx("%s: command not found", user_cmnd);
+       goto bad;
+    }
+
+    /* If user specified env vars make sure sudoers allows it. */
+    if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) {
+       if (ISSET(sudo_mode, MODE_PRESERVE_ENV)) {
+           warningx("sorry, you are not allowed to preserve the environment");
+           goto bad;
+       } else
+           validate_env_vars(sudo_user.env_vars);
+    }
+
+    if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT)) && (def_log_input || def_log_output)) {
+       if (def_iolog_file && def_iolog_dir) {
+           command_info[info_len++] = expand_iolog_path("iolog_path=",
+               def_iolog_dir, def_iolog_file, &sudo_user.iolog_file);
+           sudo_user.iolog_file++;
+       }
+       if (def_log_input) {
+           command_info[info_len++] = estrdup("iolog_stdin=true");
+           command_info[info_len++] = estrdup("iolog_ttyin=true");
+       }
+       if (def_log_output) {
+           command_info[info_len++] = estrdup("iolog_stdout=true");
+           command_info[info_len++] = estrdup("iolog_stderr=true");
+           command_info[info_len++] = estrdup("iolog_ttyout=true");
+       }
+       if (def_compress_io)
+           command_info[info_len++] = estrdup("iolog_compress=true");
+    }
+
+    log_allowed(validated);
+    if (ISSET(sudo_mode, MODE_CHECK))
+       rval = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw);
+    else if (ISSET(sudo_mode, MODE_LIST))
+       display_privs(snl, list_pw ? list_pw : sudo_user.pw); /* XXX - return val */
+
+    /* Cleanup sudoers sources */
+    tq_foreach_fwd(snl, nss) {
+       nss->close(nss);
+    }
+    if (def_group_plugin)
+       group_plugin_unload();
+
+    if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) {
+       /* rval already set appropriately */
+       goto done;
+    }
+
+    /*
+     * Set umask based on sudoers.
+     * If user's umask is more restrictive, OR in those bits too
+     * unless umask_override is set.
+     */
+    if (def_umask != 0777) {
+       mode_t mask = def_umask;
+       if (!def_umask_override) {
+           mode_t omask = umask(mask);
+           mask |= omask;
+           umask(omask);
+       }
+       easprintf(&command_info[info_len++], "umask=0%o", (unsigned int)mask);
+    }
+
+    if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
+       char *p;
+
+       /* Convert /bin/sh -> -sh so shell knows it is a login shell */
+       if ((p = strrchr(NewArgv[0], '/')) == NULL)
+           p = NewArgv[0];
+       *p = '-';
+       NewArgv[0] = p;
+
+       /* Set cwd to run user's homedir. */
+       command_info[info_len++] = fmt_string("cwd", runas_pw->pw_dir);
+
+#if defined(__linux__) || defined(_AIX)
+       /* Insert system-wide environment variables. */
+       read_env_file(_PATH_ENVIRONMENT, TRUE);
+#endif
+    }
+
+    /* Insert system-wide environment variables. */
+    if (def_env_file)
+       read_env_file(def_env_file, FALSE);
+
+    /* Insert user-specified environment variables. */
+    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);
+
+    if (ISSET(sudo_mode, MODE_EDIT)) {
+       char *editor = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv);
+       if (editor == NULL)
+           goto bad;
+       command_info[info_len++] = fmt_string("command", editor);
+       command_info[info_len++] = estrdup("sudoedit=true");
+    } else {
+       command_info[info_len++] = fmt_string("command", safe_cmnd);
+    }
+    if (def_stay_setuid) {
+       easprintf(&command_info[info_len++], "runas_uid=%u",
+           (unsigned int)user_uid);
+       easprintf(&command_info[info_len++], "runas_gid=%u",
+           (unsigned int)user_gid);
+       easprintf(&command_info[info_len++], "runas_euid=%u",
+           (unsigned int)runas_pw->pw_uid);
+       easprintf(&command_info[info_len++], "runas_egid=%u",
+           runas_gr ? (unsigned int)runas_gr->gr_gid :
+           (unsigned int)runas_pw->pw_gid);
+    } else {
+       easprintf(&command_info[info_len++], "runas_uid=%u",
+           (unsigned int)runas_pw->pw_uid);
+       easprintf(&command_info[info_len++], "runas_gid=%u",
+           runas_gr ? (unsigned int)runas_gr->gr_gid :
+           (unsigned int)runas_pw->pw_gid);
+    }
+    if (def_preserve_groups) {
+       command_info[info_len++] = "preserve_groups=true";
+    } else if (runas_ngroups != -1) {
+       int i, len;
+       size_t glsize;
+       char *cp, *gid_list;
+
+       glsize = sizeof("runas_groups=") - 1 + (runas_ngroups * (MAX_UID_T_LEN + 1));
+       gid_list = emalloc(glsize);
+       memcpy(gid_list, "runas_groups=", sizeof("runas_groups=") - 1);
+       cp = gid_list + sizeof("runas_groups=") - 1;
+       for (i = 0; i < runas_ngroups; i++) {
+           /* XXX - check rval */
+           len = snprintf(cp, glsize - (cp - gid_list), "%s%u",
+                i ? "," : "", (unsigned int) runas_groups[i]);
+           cp += len;
+       }
+       command_info[info_len++] = gid_list;
+    }
+    if (def_closefrom >= 0)
+       easprintf(&command_info[info_len++], "closefrom=%d", def_closefrom);
+    if (def_noexec)
+       command_info[info_len++] = estrdup("noexec=true");
+    if (def_noexec_file)
+       command_info[info_len++] = fmt_string("noexec_file", def_noexec_file);
+    if (def_set_utmp)
+       command_info[info_len++] = estrdup("set_utmp=true");
+    if (def_utmp_runas)
+       command_info[info_len++] = fmt_string("utmp_user", runas_pw->pw_name);
+#ifdef HAVE_LOGIN_CAP_H
+    if (lc != NULL)
+       command_info[info_len++] = fmt_string("login_class", lc->lc_class);
+#endif /* HAVE_LOGIN_CAP_H */
+#ifdef HAVE_SELINUX
+    if (user_role != NULL)
+       command_info[info_len++] = fmt_string("selinux_role", user_role);
+    if (user_type != NULL)
+       command_info[info_len++] = fmt_string("selinux_type", user_type);
+#endif /* HAVE_SELINUX */
+
+    /* Must audit before uid change. */
+    audit_success(NewArgv);
+
+    *command_infop = command_info;
+
+    *argv_out = edit_argv ? edit_argv : NewArgv;
+    *user_env_out = env_get(); /* our private copy */
+
+    goto done;
+
+bad:
+    rval = FALSE;
+
+done:
+    rewind_perms();
+
+    /* Close the password and group files and free up memory. */
+    sudo_endpwent();
+    sudo_endgrent();
+
+    return rval;
+}
+
+static int
+sudoers_policy_check(int argc, char * const argv[], char *env_add[],
+    char **command_infop[], char **argv_out[], char **user_env_out[])
+{
+    if (!ISSET(sudo_mode, MODE_EDIT))
+       SET(sudo_mode, MODE_RUN);
+
+    return sudoers_policy_main(argc, argv, 0, env_add, command_infop,
+       argv_out, user_env_out);
+}
+
+static int
+sudoers_policy_validate(void)
+{
+    user_cmnd = "validate";
+    SET(sudo_mode, MODE_VALIDATE);
+
+    return sudoers_policy_main(0, NULL, I_VERIFYPW, NULL, NULL, NULL, NULL);
+}
+
+static void
+sudoers_policy_invalidate(int remove)
+{
+    user_cmnd = "kill";
+    if (sigsetjmp(error_jmp, 1) == 0) {
+       remove_timestamp(remove);
+       plugin_cleanup(0);
+    }
+}
+
+static int
+sudoers_policy_list(int argc, char * const argv[], int verbose,
+    const char *list_user)
+{
+    int rval;
+
+    user_cmnd = "list";
+    if (argc)
+       SET(sudo_mode, MODE_CHECK);
+    else
+       SET(sudo_mode, MODE_LIST);
+    if (verbose)
+       long_list = 1;
+    if (list_user) {
+       list_pw = sudo_getpwnam(list_user);
+       if (list_pw == NULL) {
+           warningx("unknown user: %s", list_user);
+           return -1;
+       }
+    }
+    rval = sudoers_policy_main(argc, argv, I_LISTPW, NULL, NULL, NULL, NULL);
+    if (list_user) {
+       pw_delref(list_pw);
+       list_pw = NULL;
+    }
+
+    return rval;
+}
+
+/*
+ * Initialize timezone, set umask, fill in ``sudo_user'' struct and
+ * load the ``interfaces'' array.
+ */
+static void
+init_vars(char * const envp[])
+{
+    char * const * ep;
+
+#ifdef HAVE_TZSET
+    (void) tzset();            /* set the timezone if applicable */
+#endif /* HAVE_TZSET */
+
+    for (ep = envp; *ep; ep++) {
+       /* XXX - don't fill in if empty string */
+       switch (**ep) {
+           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;
+               break;
+           case 'S':
+               if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0)
+                   user_prompt = *ep + 12;
+               else if (strncmp("SUDO_USER=", *ep, 10) == 0)
+                   prev_user = *ep + 10;
+               break;
+           }
+    }
+
+    /*
+     * Get a local copy of the user's struct passwd with the shadow password
+     * if necessary.  It is assumed that euid is 0 at this point so we
+     * can read the shadow passwd file if necessary.
+     */
+    if ((sudo_user.pw = sudo_getpwnam(user_name)) == NULL) {
+       struct passwd pw;
+
+       /* Create a fake struct passwd for log_error(). */
+       memset(&pw, 0, sizeof(pw));
+       pw.pw_uid = getuid();
+       pw.pw_name = user_name;
+       sudo_user.pw = &pw;
+
+       /*
+        * 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.
+        */
+       if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE)
+           errorx(1, "unknown user: %s", user_name);
+       log_error(0, "unknown user: %s", user_name);
+       /* NOTREACHED */
+    }
+#ifdef HAVE_MBR_CHECK_MEMBERSHIP
+    mbr_uid_to_uuid(user_uid, user_uuid);
+#endif
+
+    /* It is now safe to use log_error() and set_perms() */
+}
+
+/*
+ * Fill in user_cmnd, user_args, user_base and user_stat variables
+ * and apply any command-specific defaults entries.
+ */
+static int
+set_cmnd(int sudo_mode)
+{
+    int rval;
+    char *path = user_path;
+
+    /* Resolve the path and return. */
+    rval = FOUND;
+    user_stat = emalloc(sizeof(struct stat));
+
+    /* Default value for cmnd, overridden below. */
+    if (user_cmnd == NULL)
+       user_cmnd = NewArgv[0];
+
+    if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
+       if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
+           if (def_secure_path && !user_is_exempt())
+               path = def_secure_path;
+           set_perms(PERM_RUNAS);
+           rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
+               def_ignore_dot);
+           restore_perms();
+           if (rval != FOUND) {
+               /* Failed as root, try as invoking user. */
+               set_perms(PERM_USER);
+               rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
+                   def_ignore_dot);
+               restore_perms();
+           }
+       }
+
+       /* set user_args */
+       if (NewArgc > 1) {
+           char *to, **from;
+           size_t size, n;
+
+           /* Alloc and build up user_args. */
+           for (size = 0, from = NewArgv + 1; *from; from++)
+               size += strlen(*from) + 1;
+           user_args = 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, set_cmnd() overflow");
+               to += n;
+               *to++ = ' ';
+           }
+           *--to = '\0';
+       }
+    }
+    if (strlen(user_cmnd) >= PATH_MAX)
+       errorx(1, "%s: file name too long", user_cmnd);
+
+    if ((user_base = strrchr(user_cmnd, '/')) != NULL)
+       user_base++;
+    else
+       user_base = user_cmnd;
+
+    if (!update_defaults(SETDEF_CMND))
+       log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
+
+    if (!runas_user && !runas_group)
+       set_runaspw(def_runas_default); /* may have been updated above */
+
+    return rval;
+}
+
+/*
+ * Open sudoers and sanity check mode/owner/type.
+ * Returns a handle to the sudoers file or NULL on error.
+ */
+FILE *
+open_sudoers(const char *sudoers, int doedit, int *keepopen)
+{
+    struct stat statbuf;
+    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(sudoers, &statbuf)) == 0 &&
+       sudoers_uid == statbuf.st_uid && sudoers_mode != 0400 &&
+       (statbuf.st_mode & 0007777) == 0400) {
+
+       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(sudoers, (uid_t) -1, sudoers_gid) == 0) {
+                   warningx("set group on %s", sudoers);
+                   statbuf.st_gid = sudoers_gid;
+               } else
+                   warning("unable to set group on %s", sudoers);
+           }
+       } else
+           warning("unable to fix mode on %s", sudoers);
+    }
+
+    /*
+     * Sanity checks on sudoers file.  Must be done as sudoers
+     * file owner.  We already did a stat as root, so use that
+     * data if we can't stat as sudoers file owner.
+     */
+    set_perms(PERM_SUDOERS);
+
+    if (rootstat != 0 && stat_sudoers(sudoers, &statbuf) != 0)
+       log_error(USE_ERRNO|NO_EXIT, "can't stat %s", sudoers);
+    else if (!S_ISREG(statbuf.st_mode))
+       log_error(NO_EXIT, "%s is not a regular file", sudoers);
+    else if ((statbuf.st_mode & 07577) != sudoers_mode)
+       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(NO_EXIT, "%s is owned by uid %u, should be %u", sudoers,
+           (unsigned int) statbuf.st_uid, (unsigned int) sudoers_uid);
+    else if (statbuf.st_gid != sudoers_gid)
+       log_error(NO_EXIT, "%s is owned by gid %u, should be %u", sudoers,
+           (unsigned int) statbuf.st_gid, (unsigned int) sudoers_gid);
+    else if ((fp = fopen(sudoers, "r")) == NULL)
+       log_error(USE_ERRNO|NO_EXIT, "can't open %s", sudoers);
+    else {
+       /*
+        * Make sure we can actually read sudoers so we can present the
+        * user with a reasonable error message (unlike the lexer).
+        */
+       if (statbuf.st_size != 0 && fgetc(fp) == EOF) {
+           log_error(USE_ERRNO|NO_EXIT, "can't read %s", sudoers);
+           fclose(fp);
+           fp = NULL;
+       }
+    }
+
+    if (fp != NULL) {
+       rewind(fp);
+       (void) fcntl(fileno(fp), F_SETFD, 1);
+    }
+
+    restore_perms();           /* change back to root */
+    return fp;
+}
+
+#ifdef HAVE_LOGIN_CAP_H
+static void
+set_loginclass(struct passwd *pw)
+{
+    int errflags;
+
+    /*
+     * Don't make it a fatal error if the user didn't specify the login
+     * class themselves.  We do this because if login.conf gets
+     * corrupted we want the admin to be able to use sudo to fix it.
+     */
+    if (login_class)
+       errflags = NO_MAIL|MSG_ONLY;
+    else
+       errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
+
+    if (login_class && strcmp(login_class, "-") != 0) {
+       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)
+           login_class =
+               (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
+    }
+
+    lc = login_getclass(login_class);
+    if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
+       log_error(errflags, "unknown login class: %s", login_class);
+       if (!lc)
+           lc = login_getclass(NULL);  /* needed for login_getstyle() later */
+    }
+}
+#else
+static void
+set_loginclass(struct passwd *pw)
+{
+}
+#endif /* HAVE_LOGIN_CAP_H */
+
+/*
+ * Look up the fully qualified domain name and set user_host and user_shost.
+ */
+void
+set_fqdn(void)
+{
+#ifdef HAVE_GETADDRINFO
+    struct addrinfo *res0, hint;
+#else
+    struct hostent *hp;
+#endif
+    char *p;
+
+#ifdef HAVE_GETADDRINFO
+    zero_bytes(&hint, sizeof(hint));
+    hint.ai_family = PF_UNSPEC;
+    hint.ai_flags = AI_CANONNAME;
+    if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
+#else
+    if (!(hp = gethostbyname(user_host))) {
+#endif
+       log_error(MSG_ONLY|NO_EXIT,
+           "unable to resolve host %s", user_host);
+    } else {
+       if (user_shost != user_host)
+           efree(user_shost);
+       efree(user_host);
+#ifdef HAVE_GETADDRINFO
+       user_host = estrdup(res0->ai_canonname);
+       freeaddrinfo(res0);
+#else
+       user_host = estrdup(hp->h_name);
+#endif
+    }
+    if ((p = strchr(user_host, '.')) != NULL)
+       user_shost = estrndup(user_host, (size_t)(p - user_host));
+    else
+       user_shost = user_host;
+}
+
+/*
+ * Get passwd entry for the user we are going to run commands as
+ * and store it in runas_pw.  By default, commands run as "root".
+ */
+static void
+set_runaspw(char *user)
+{
+    if (runas_pw != NULL)
+       pw_delref(runas_pw);
+    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) {
+           audit_failure(NewArgv, "unknown user: %s", user);
+           log_error(NO_MAIL|MSG_ONLY, "unknown user: %s", user);
+       }
+    }
+}
+
+/*
+ * Get group entry for the group we are going to run commands as
+ * and store it in runas_gr.
+ */
+static void
+set_runasgr(char *group)
+{
+    if (runas_gr != NULL)
+       gr_delref(runas_gr);
+    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);
+    }
+}
+
+/*
+ * Cleanup hook for error()/errorx()
+ */
+void
+plugin_cleanup(int gotsignal)
+{
+    struct sudo_nss *nss;
+
+    if (!gotsignal) {
+       if (snl != NULL) {
+           tq_foreach_fwd(snl, nss)
+               nss->close(nss);
+       }
+       if (def_group_plugin)
+           group_plugin_unload();
+       sudo_endpwent();
+       sudo_endgrent();
+    }
+}
+
+static int
+sudoers_policy_version(int verbose)
+{
+    if (sigsetjmp(error_jmp, 1)) {
+       /* error recovery via error(), errorx() or log_error() */
+       return -1;
+    }
+
+    sudo_printf(SUDO_CONV_INFO_MSG, "Sudoers policy plugin version %s\n",
+       PACKAGE_VERSION);
+    sudo_printf(SUDO_CONV_INFO_MSG, "Sudoers file grammar version %d\n",
+       SUDOERS_GRAMMAR_VERSION);
+
+    if (verbose) {
+       sudo_printf(SUDO_CONV_INFO_MSG, "\nSudoers path: %s\n", sudoers_file);
+#ifdef HAVE_LDAP
+# ifdef _PATH_NSSWITCH_CONF
+       sudo_printf(SUDO_CONV_INFO_MSG, "nsswitch path: %s\n", _PATH_NSSWITCH_CONF);
+# endif
+       sudo_printf(SUDO_CONV_INFO_MSG, "ldap.conf path: %s\n", _PATH_LDAP_CONF);
+       sudo_printf(SUDO_CONV_INFO_MSG, "ldap.secret path: %s\n", _PATH_LDAP_SECRET);
+#endif
+       dump_auth_methods();
+       dump_defaults();
+       sudo_printf(SUDO_CONV_INFO_MSG, "\n");
+       dump_interfaces(interfaces_string);
+       sudo_printf(SUDO_CONV_INFO_MSG, "\n");
+    }
+    return TRUE;
+}
+
+static int
+deserialize_info(char * const settings[], char * const user_info[])
+{
+    char * const *cur;
+    const char *p;
+    int flags = 0;
+
+#define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0)
+
+    /* Parse command line settings. */
+    user_closefrom = -1;
+    for (cur = settings; *cur != NULL; cur++) {
+       if (MATCHES(*cur, "closefrom=")) {
+           user_closefrom = atoi(*cur + sizeof("closefrom=") - 1);
+           continue;
+       }
+       if (MATCHES(*cur, "debug_level=")) {
+           debug_level = atoi(*cur + sizeof("debug_level=") - 1);
+           continue;
+       }
+       if (MATCHES(*cur, "runas_user=")) {
+           runas_user = *cur + sizeof("runas_user=") - 1;
+           continue;
+       }
+       if (MATCHES(*cur, "runas_group=")) {
+           runas_group = *cur + sizeof("runas_group=") - 1;
+           continue;
+       }
+       if (MATCHES(*cur, "prompt=")) {
+           user_prompt = *cur + sizeof("prompt=") - 1;
+           def_passprompt_override = TRUE;
+           continue;
+       }
+       if (MATCHES(*cur, "set_home=")) {
+           if (atobool(*cur + sizeof("set_home=") - 1) == TRUE)
+               SET(flags, MODE_RESET_HOME);
+           continue;
+       }
+       if (MATCHES(*cur, "preserve_environment=")) {
+           if (atobool(*cur + sizeof("preserve_environment=") - 1) == TRUE)
+               SET(flags, MODE_PRESERVE_ENV);
+           continue;
+       }
+       if (MATCHES(*cur, "run_shell=")) {
+           if (atobool(*cur + sizeof("run_shell=") - 1) == TRUE)
+               SET(flags, MODE_SHELL);
+           continue;
+       }
+       if (MATCHES(*cur, "login_shell=")) {
+           if (atobool(*cur + sizeof("login_shell=") - 1) == TRUE) {
+               SET(flags, MODE_LOGIN_SHELL);
+               def_env_reset = TRUE;
+           }
+           continue;
+       }
+       if (MATCHES(*cur, "implied_shell=")) {
+           if (atobool(*cur + sizeof("implied_shell=") - 1) == TRUE)
+               SET(flags, MODE_IMPLIED_SHELL);
+           continue;
+       }
+       if (MATCHES(*cur, "preserve_groups=")) {
+           if (atobool(*cur + sizeof("preserve_groups=") - 1) == TRUE)
+               SET(flags, MODE_PRESERVE_GROUPS);
+           continue;
+       }
+       if (MATCHES(*cur, "ignore_ticket=")) {
+           if (atobool(*cur + sizeof("ignore_ticket=") - 1) == TRUE)
+               SET(flags, MODE_IGNORE_TICKET);
+           continue;
+       }
+       if (MATCHES(*cur, "noninteractive=")) {
+           if (atobool(*cur + sizeof("noninteractive=") - 1) == TRUE)
+               SET(flags, MODE_NONINTERACTIVE);
+           continue;
+       }
+       if (MATCHES(*cur, "sudoedit=")) {
+           if (atobool(*cur + sizeof("sudoedit=") - 1) == TRUE)
+               SET(flags, MODE_EDIT);
+           continue;
+       }
+       if (MATCHES(*cur, "login_class=")) {
+           login_class = *cur + sizeof("login_class=") - 1;
+           def_use_loginclass = TRUE;
+           continue;
+       }
+#ifdef HAVE_SELINUX
+       if (MATCHES(*cur, "selinux_role=")) {
+           user_role = *cur + sizeof("selinux_role=") - 1;
+           continue;
+       }
+       if (MATCHES(*cur, "selinux_type=")) {
+           user_type = *cur + sizeof("selinux_type=") - 1;
+           continue;
+       }
+#endif /* HAVE_SELINUX */
+#ifdef HAVE_BSD_AUTH_H
+       if (MATCHES(*cur, "bsdauth_type=")) {
+           login_style = *cur + sizeof("bsdauth_type=") - 1;
+           continue;
+       }
+#endif /* HAVE_BSD_AUTH_H */
+#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
+       if (MATCHES(*cur, "progname=")) {
+           setprogname(*cur + sizeof("progname=") - 1);
+           continue;
+       }
+#endif
+       if (MATCHES(*cur, "network_addrs=")) {
+           interfaces_string = *cur + sizeof("network_addrs=") - 1;
+           set_interfaces(interfaces_string);
+           continue;
+       }
+       if (MATCHES(*cur, "sudoers_file=")) {
+           sudoers_file = *cur + sizeof("sudoers_file=") - 1;
+           continue;
+       }
+       if (MATCHES(*cur, "sudoers_uid=")) {
+           sudoers_uid = (uid_t) atoi(*cur + sizeof("sudoers_uid=") - 1);
+           continue;
+       }
+       if (MATCHES(*cur, "sudoers_gid=")) {
+           sudoers_gid = (gid_t) atoi(*cur + sizeof("sudoers_gid=") - 1);
+           continue;
+       }
+       if (MATCHES(*cur, "sudoers_mode=")) {
+           sudoers_mode = (mode_t) strtol(*cur + sizeof("sudoers_mode=") - 1,
+               NULL, 8);
+           continue;
+       }
+    }
+
+    for (cur = user_info; *cur != NULL; cur++) {
+       if (MATCHES(*cur, "user=")) {
+           user_name = estrdup(*cur + sizeof("user=") - 1);
+           continue;
+       }
+       if (MATCHES(*cur, "uid=")) {
+           user_uid = (uid_t) atoi(*cur + sizeof("uid=") - 1);
+           continue;
+       }
+       if (MATCHES(*cur, "gid=")) {
+           user_gid = (gid_t) atoi(*cur + sizeof("gid=") - 1);
+           continue;
+       }
+       if (MATCHES(*cur, "groups=")) {
+           /* Count number of groups */
+           const char *val = *cur + sizeof("groups=") - 1;
+           const char *cp;
+           if (val[0] != '\0') {
+               user_ngroups = 1;
+               for (cp = val; *cp != '\0'; cp++) {
+                   if (*cp == ',')
+                       user_ngroups++;
+               }
+
+               user_groups = emalloc2(user_ngroups, sizeof(GETGROUPS_T));
+               user_ngroups = 0;
+               cp = val;
+               for (;;) {
+                   /* XXX - strtol would be better here */
+                   user_groups[user_ngroups++] = atoi(cp);
+                   cp = strchr(cp, ',');
+                   if (cp == NULL)
+                       break;
+                   cp++; /* skip over comma */
+               }
+           }
+           continue;
+       }
+       if (MATCHES(*cur, "cwd=")) {
+           user_cwd = estrdup(*cur + sizeof("cwd=") - 1);
+           continue;
+       }
+       if (MATCHES(*cur, "tty=")) {
+           user_tty = user_ttypath = estrdup(*cur + sizeof("tty=") - 1);
+           if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+               user_tty += sizeof(_PATH_DEV) - 1;
+           continue;
+       }
+       if (MATCHES(*cur, "host=")) {
+           user_host = user_shost = estrdup(*cur + sizeof("host=") - 1);
+           if ((p = strchr(user_host, '.')))
+               user_shost = estrndup(user_host, (size_t)(p - user_host));
+           continue;
+       }
+       if (MATCHES(*cur, "lines=")) {
+           sudo_user.lines = atoi(*cur + sizeof("lines=") - 1);
+           continue;
+       }
+       if (MATCHES(*cur, "cols=")) {
+           sudo_user.cols = atoi(*cur + sizeof("cols=") - 1);
+           continue;
+       }
+    }
+    if (user_cwd == NULL)
+       user_cwd = "unknown";
+    if (user_tty == NULL)
+       user_tty = "unknown"; /* user_ttypath remains NULL */
+
+#undef MATCHES
+    return flags;
+}
+
+static char *
+resolve_editor(char *editor, int nfiles, char **files, char ***argv_out)
+{
+    char *cp, **nargv, *editor_path = NULL;
+    int ac, i, nargc, wasblank;
+
+    editor = estrdup(editor); /* becomes part of argv_out */
+
+    /*
+     * Split editor into an argument vector; editor is reused (do not free).
+     * The EDITOR and VISUAL environment variables may contain command
+     * line args so look for those and alloc space for them too.
+     */
+    nargc = 1;
+    for (wasblank = FALSE, cp = editor; *cp != '\0'; cp++) {
+       if (isblank((unsigned char) *cp))
+           wasblank = TRUE;
+       else if (wasblank) {
+           wasblank = FALSE;
+           nargc++;
+       }
+    }
+    /* If we can't find the editor in the user's PATH, give up. */
+    cp = strtok(editor, " \t");
+    if (cp == NULL ||
+       find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) {
+       efree(editor);
+       return NULL;
+    }
+    nargv = (char **) emalloc2(nargc + 1 + nfiles + 1, sizeof(char *));
+    for (ac = 0; cp != NULL && ac < nargc; ac++) {
+       nargv[ac] = cp;
+       cp = strtok(NULL, " \t");
+    }
+    nargv[ac++] = "--";
+    for (i = 0; i < nfiles; )
+       nargv[ac++] = files[i++];
+    nargv[ac] = NULL;
+
+    *argv_out = nargv;
+    return editor_path;
+}
+
+/*
+ * Determine which editor to use.  We don't need to worry about restricting
+ * this to a "safe" editor since it runs with the uid of the invoking user,
+ * not the runas (privileged) user.
+ */
+static char *
+find_editor(int nfiles, char **files, char ***argv_out)
+{
+    char *cp, *editor, *editor_path = NULL, **ev, *ev0[4];
+
+    /*
+     * If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one.
+     */
+    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') {
+           editor_path = resolve_editor(editor, nfiles, files, argv_out);
+           if (editor_path != NULL)
+               break;
+       }
+    }
+    if (editor_path == NULL) {
+       /* def_editor could be a path, split it up */
+       editor = estrdup(def_editor);
+       cp = strtok(editor, ":");
+       while (cp != NULL && editor_path == NULL) {
+           editor_path = resolve_editor(cp, nfiles, files, argv_out);
+           cp = strtok(NULL, ":");
+       }
+       if (editor_path)
+           efree(editor);
+    }
+    if (!editor_path) {
+       audit_failure(NewArgv, "%s: command not found", editor);
+       warningx("%s: command not found", editor);
+    }
+    return editor_path;
+}
+
+#ifdef USE_ADMIN_FLAG
+static void
+create_admin_success_flag(void)
+{
+    struct stat statbuf;
+    char flagfile[PATH_MAX];
+    int fd, n;
+
+    /* Check whether the user is in the admin group. */
+    if (!user_in_group(sudo_user.pw, "admin"))
+       return;
+
+    /* Build path to flag file. */
+    n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful",
+       user_dir);
+    if (n <= 0 || n >= sizeof(flagfile))
+       return;
+
+    /* Create admin flag file if it doesn't already exist. */
+    set_perms(PERM_USER);
+    if (stat(flagfile, &statbuf) != 0) {
+       fd = open(flagfile, O_CREAT|O_WRONLY|O_EXCL, 0644);
+       close(fd);
+    }
+    restore_perms();
+}
+#else /* !USE_ADMIN_FLAG */
+static void
+create_admin_success_flag(void)
+{
+    /* STUB */
+}
+#endif /* USE_ADMIN_FLAG */
+
+struct policy_plugin sudoers_policy = {
+    SUDO_POLICY_PLUGIN,
+    SUDO_API_VERSION,
+    sudoers_policy_open,
+    sudoers_policy_close,
+    sudoers_policy_version,
+    sudoers_policy_check,
+    sudoers_policy_list,
+    sudoers_policy_validate,
+    sudoers_policy_invalidate,
+    sudoers_policy_init_session
+};
diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h
new file mode 100644 (file)
index 0000000..7e5d56b
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 1993-1996, 1998-2005, 2007-2011
+ *     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.
+ */
+
+#ifndef _SUDO_SUDOERS_H
+#define _SUDO_SUDOERS_H
+
+#include <limits.h>
+
+#include <pathnames.h>
+#include "missing.h"
+#include "error.h"
+#include "alloc.h"
+#include "list.h"
+#include "fileops.h"
+#include "defaults.h"
+#include "logging.h"
+#include "sudo_nss.h"
+#include "sudo_plugin.h"
+
+#ifdef HAVE_MBR_CHECK_MEMBERSHIP
+# include <membership.h>
+#endif
+
+/*
+ * 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 *name;
+    char *path;
+    char *tty;
+    char *ttypath;
+    char *host;
+    char *shost;
+    char *prompt;
+    char *cmnd;
+    char *cmnd_args;
+    char *cmnd_base;
+    char *cmnd_safe;
+    char *class_name;
+    char *krb5_ccname;
+    int   closefrom;
+    int   ngroups;
+    uid_t uid;
+    uid_t gid;
+    int   lines;
+    int   cols;
+    GETGROUPS_T *groups;
+    char * const * env_vars;
+#ifdef HAVE_SELINUX
+    char *role;
+    char *type;
+#endif
+    char *cwd;
+    char *iolog_file;
+#ifdef HAVE_MBR_CHECK_MEMBERSHIP
+    uuid_t uuid;
+#endif
+};
+
+/*
+ * Return values for sudoers_lookup(), also used as arguments for log_auth()
+ * Note: cannot use '0' as a value here.
+ */
+/* XXX - VALIDATE_SUCCESS and VALIDATE_FAILURE instead? */
+#define VALIDATE_ERROR          0x001
+#define VALIDATE_OK            0x002
+#define VALIDATE_NOT_OK                0x004
+#define FLAG_CHECK_USER                0x010
+#define FLAG_NO_USER           0x020
+#define FLAG_NO_HOST           0x040
+#define FLAG_NO_CHECK          0x080
+
+/*
+ * Pseudo-boolean values
+ */
+#undef TRUE
+#define TRUE                     1
+#undef FALSE
+#define FALSE                    0
+
+/*
+ * find_path()/load_cmnd() return values
+ */
+#define FOUND                   0
+#define NOT_FOUND               1
+#define NOT_FOUND_DOT          2
+
+/*
+ * Various modes sudo can be in (based on arguments) in hex
+ */
+#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 /* XXX - unused */
+#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
+#define MODE_IGNORE_TICKET     0x01000000
+
+/*
+ * Used with set_perms()
+ */
+#define PERM_INITIAL             0x00
+#define PERM_ROOT                0x01
+#define PERM_USER                0x02
+#define PERM_FULL_USER           0x03
+#define PERM_SUDOERS             0x04
+#define PERM_RUNAS               0x05
+#define PERM_TIMESTAMP           0x06
+#define PERM_NOEXIT              0x10 /* flag */
+#define PERM_MASK                0xf0
+
+/*
+ * Shortcuts for sudo_user contents.
+ */
+#define user_name              (sudo_user.name)
+#define user_uid               (sudo_user.uid)
+#define user_gid               (sudo_user.gid)
+#define user_passwd            (sudo_user.pw->pw_passwd)
+#define user_uuid              (sudo_user.uuid)
+#define user_dir               (sudo_user.pw->pw_dir)
+#define user_ngroups           (sudo_user.ngroups)
+#define user_groups            (sudo_user.groups)
+#define user_tty               (sudo_user.tty)
+#define user_ttypath           (sudo_user.ttypath)
+#define user_cwd               (sudo_user.cwd)
+#define user_cmnd              (sudo_user.cmnd)
+#define user_args              (sudo_user.cmnd_args)
+#define user_base              (sudo_user.cmnd_base)
+#define user_stat              (sudo_user.cmnd_stat)
+#define user_path              (sudo_user.path)
+#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 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)
+#define user_closefrom         (sudo_user.closefrom)
+
+#ifdef __TANDEM
+# define ROOT_UID       65535
+#else
+# define ROOT_UID       0
+#endif
+
+/*
+ * We used to use the system definition of PASS_MAX or _PASSWD_LEN,
+ * but that caused problems with various alternate authentication
+ * methods.  So, we just define our own and assume that it is >= the
+ * system max.
+ */
+#define SUDO_PASS_MAX  256
+
+struct lbuf;
+struct passwd;
+struct stat;
+struct timeval;
+
+/*
+ * Function prototypes
+ */
+#define YY_DECL int yylex(void)
+
+/* goodpath.c */
+char *sudo_goodpath(const char *, struct stat *);
+
+/* findpath.c */
+int find_path(char *, char **, struct stat *, char *, int);
+
+/* check.c */
+int check_user(int, int);
+void remove_timestamp(int);
+int user_is_exempt(void);
+
+/* sudo_auth.c */
+int verify_user(struct passwd *, char *);
+int auth_begin_session(struct passwd *);
+int auth_end_session();
+
+/* parse.c */
+int sudo_file_open(struct sudo_nss *);
+int sudo_file_close(struct sudo_nss *);
+int sudo_file_setdefs(struct sudo_nss *);
+int sudo_file_lookup(struct sudo_nss *, int, int);
+int sudo_file_parse(struct sudo_nss *);
+int sudo_file_display_cmnd(struct sudo_nss *, struct passwd *);
+int sudo_file_display_defaults(struct sudo_nss *, struct passwd *, struct lbuf *);
+int sudo_file_display_bound_defaults(struct sudo_nss *, struct passwd *, struct lbuf *);
+int sudo_file_display_privs(struct sudo_nss *, struct passwd *, struct lbuf *);
+
+/* set_perms.c */
+void rewind_perms(void);
+int set_perms(int);
+void restore_perms(void);
+int pam_prep_user(struct passwd *);
+
+/* gram.y */
+int yyparse(void);
+
+/* toke.l */
+YY_DECL;
+
+/* defaults.c */
+void dump_defaults(void);
+void dump_auth_methods(void);
+
+/* getspwuid.c */
+char *sudo_getepw(const struct passwd *);
+
+/* zero_bytes.c */
+void zero_bytes(volatile void *, size_t);
+
+/* sudo_nss.c */
+void display_privs(struct sudo_nss_list *, struct passwd *);
+int display_cmnd(struct sudo_nss_list *, struct passwd *);
+
+/* pwutil.c */
+void sudo_setgrent(void);
+void sudo_endgrent(void);
+void sudo_setpwent(void);
+void sudo_endpwent(void);
+void sudo_setspent(void);
+void sudo_endspent(void);
+struct passwd *sudo_getpwnam(const char *);
+struct passwd *sudo_fakepwnam(const char *, gid_t);
+struct passwd *sudo_getpwuid(uid_t);
+struct group *sudo_getgrnam(const char *);
+struct group *sudo_fakegrnam(const char *);
+struct group *sudo_getgrgid(gid_t);
+void gr_addref(struct group *);
+void gr_delref(struct group *);
+void pw_addref(struct passwd *);
+void pw_delref(struct passwd *);
+int user_in_group(struct passwd *, const char *);
+
+/* timestr.c */
+char *get_timestr(time_t, int);
+
+/* atobool.c */
+int atobool(const char *str);
+
+/* boottime.c */
+int get_boottime(struct timeval *);
+
+/* iolog.c */
+void io_nextid(char *iolog_dir, char sessid[7]);
+
+/* iolog_path.c */
+char *expand_iolog_path(const char *prefix, const char *dir, const char *file,
+    char **slashp);
+
+/* env.c */
+char **env_get(void);
+void env_init(char * const envp[]);
+void init_envtables(void);
+void insert_env_vars(char * const envp[]);
+void read_env_file(const char *, int);
+void rebuild_env(void);
+void validate_env_vars(char * const envp[]);
+
+/* fmt_string.c */
+char *fmt_string(const char *, const char *);
+
+/* sudoers.c */
+void plugin_cleanup(int);
+void set_fqdn(void);
+FILE *open_sudoers(const char *, int, int *);
+
+/* aix.c */
+void aix_restoreauthdb(void);
+void aix_setauthdb(char *user);
+
+/* group_plugin.c */
+int group_plugin_load(char *plugin_info);
+void group_plugin_unload(void);
+int group_plugin_query(const char *user, const char *group,
+    const struct passwd *pwd);
+
+#ifndef _SUDO_MAIN
+extern struct sudo_user sudo_user;
+extern struct passwd *list_pw;
+extern const char *sudoers_file;
+extern mode_t sudoers_mode;
+extern uid_t sudoers_uid;
+extern gid_t sudoers_gid;
+extern int long_list;
+extern int sudo_mode;
+extern uid_t timestamp_uid;
+extern sudo_conv_t sudo_conv;
+extern sudo_printf_t sudo_printf;
+#endif
+
+/* Some systems don't declare errno in errno.h */
+#ifndef errno
+extern int errno;
+#endif
+
+#endif /* _SUDO_SUDOERS_H */
diff --git a/plugins/sudoers/sudoers.in b/plugins/sudoers/sudoers.in
new file mode 100644 (file)
index 0000000..42e639e
--- /dev/null
@@ -0,0 +1,90 @@
+## sudoers file.
+##
+## This file MUST be edited with the 'visudo' command as root.
+## Failure to use 'visudo' may result in syntax or file permission errors
+## that prevent sudo from running.
+##
+## See the sudoers man page for the details on how to write a sudoers file.
+##
+
+##
+## Host alias specification
+##
+## Groups of machines. These may include host names (optionally with wildcards),
+## IP addresses, network numbers or netgroups.
+# Host_Alias   WEBSERVERS = www1, www2, www3
+
+##
+## User alias specification
+##
+## Groups of users.  These may consist of user names, uids, Unix groups,
+## or netgroups.
+# User_Alias   ADMINS = millert, dowdy, mikef
+
+##
+## Cmnd alias specification
+##
+## Groups of commands.  Often used to group related commands together.
+# Cmnd_Alias   PROCESSES = /usr/bin/nice, /bin/kill, /usr/bin/renice, \
+#                          /usr/bin/pkill, /usr/bin/top
+
+##
+## Defaults specification
+##
+## You may wish to keep some of the following environment variables
+## when running commands via sudo.
+##
+## Locale settings
+# Defaults env_keep += "LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET"
+##
+## Run X applications through sudo; HOME is used to find the
+## .Xauthority file.  Note that other programs use HOME to find   
+## configuration files and this may lead to privilege escalation!
+# Defaults env_keep += "HOME"
+##
+## X11 resource path settings
+# Defaults env_keep += "XAPPLRESDIR XFILESEARCHPATH XUSERFILESEARCHPATH"
+##
+## Desktop path settings
+# Defaults env_keep += "QTDIR KDEDIR"
+##
+## Allow sudo-run commands to inherit the callers' ConsoleKit session
+# Defaults env_keep += "XDG_SESSION_COOKIE"
+##
+## Uncomment to enable special input methods.  Care should be taken as
+## this may allow users to subvert the command being run via sudo.
+# Defaults env_keep += "XMODIFIERS GTK_IM_MODULE QT_IM_MODULE QT_IM_SWITCHER"
+##
+## Uncomment to enable logging of a command's output, except for
+## sudoreplay and reboot.  Use sudoreplay to play back logged sessions.
+# Defaults log_output
+# Defaults!/usr/bin/sudoreplay !log_output
+# Defaults!/usr/local/bin/sudoreplay !log_output
+# Defaults!/sbin/reboot !log_output
+
+##
+## Runas alias specification
+##
+
+##
+## User privilege specification
+##
+root ALL=(ALL) ALL
+
+## Uncomment to allow members of group wheel to execute any command
+# %wheel ALL=(ALL) ALL
+
+## Same thing without a password
+# %wheel ALL=(ALL) NOPASSWD: ALL
+
+## Uncomment to allow members of group sudo to execute any command
+# %sudo        ALL=(ALL) ALL
+
+## Uncomment to allow any user to run sudo if they know the password
+## of the user they are running the command as (root by default).
+# Defaults targetpw  # Ask for the password of the target user
+# ALL ALL=(ALL) ALL  # WARNING: only use this together with 'Defaults targetpw'
+
+## Read drop-in files from @sysconfdir@/sudoers.d
+## (the '#' here does not indicate a comment)
+#includedir @sysconfdir@/sudoers.d
diff --git a/plugins/sudoers/sudoers.sym b/plugins/sudoers/sudoers.sym
new file mode 100644 (file)
index 0000000..7f74694
--- /dev/null
@@ -0,0 +1,2 @@
+sudoers_policy
+sudoers_io
diff --git a/plugins/sudoers/sudoers2ldif b/plugins/sudoers/sudoers2ldif
new file mode 100755 (executable)
index 0000000..442155e
--- /dev/null
@@ -0,0 +1,139 @@
+#!/usr/bin/env perl
+use strict;
+
+#
+# Converts a sudoers file to LDIF format in prepration for loading into
+# the LDAP server.
+#
+
+# BUGS:
+#   Does not yet handle multiple lines with : in them
+#   Does not yet remove quotation marks from options
+#   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)
+#
+# 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;
+my $base=$ENV{SUDOERS_BASE} or die "$0: Container SUDOERS_BASE undefined\n";
+my @options=();
+
+my $did_defaults=0;
+my $order = 0;
+
+# parse sudoers one line at a time
+while (<>){
+
+  # remove comment
+  s/#.*//;
+
+  # line continuation
+  $_.=<> while s/\\\s*$//s;
+
+  # cleanup newline
+  chomp;
+
+  # ignore blank lines
+  next if /^\s*$/;
+
+  if (/^Defaults\s+/i) {
+    my $opt=$';
+    $opt=~s/\s+$//; # remove trailing whitespace
+    push @options,$opt;
+  } elsif (/^(\S+)\s+(.+)=\s*(.*)/) {
+
+    # Aliases or Definitions
+    my ($p1,$p2,$p3)=($1,$2,$3);
+    $p2=~s/\s+$//; # remove trailing whitespace
+    $p3=~s/\s+$//; # remove trailing whitespace
+
+    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") {
+      $CA{$p2}=$p3;
+    } else {
+      if (!$did_defaults++){
+        # do this once
+        print "dn: cn=defaults,$base\n";
+        print "objectClass: top\n";
+        print "objectClass: sudoRole\n";
+        print "cn: defaults\n";
+        print "description: Default sudoOption's go here\n";
+        print "sudoOption: $_\n" foreach @options;
+        printf "sudoOrder: %d\n", ++$order;
+        print "\n";
+      }
+      # Definition
+      my @users=split /\s*,\s*/,$p1;
+      my @hosts=split /\s*,\s*/,$p2;
+      my @cmds= split /\s*,\s*/,$p3;
+      @options=();
+      print "dn: cn=$users[0],$base\n";
+      print "objectClass: top\n";
+      print "objectClass: sudoRole\n";
+      print "cn: $users[0]\n";
+      # will clobber options
+      print "sudoUser: $_\n"   foreach expand(\%UA,@users);
+      print "sudoHost: $_\n"   foreach expand(\%HA,@hosts);
+      foreach (@cmds) {
+       if (s/^\(([^\)]+)\)\s*//) {
+         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);
+      print "sudoOption: $_\n" foreach @options;
+      printf "sudoOrder: %d\n", ++$order;
+      print "\n";
+    }
+
+  } else {
+    print "parse error: $_\n";
+  }
+
+}
+
+#
+# recursively expand hash elements
+sub expand{
+  my $ref=shift;
+  my @a=();
+
+  # preen the line a little
+  foreach (@_){
+    # if NOPASSWD: directive found, mark entire entry as not requiring
+    s/NOPASSWD:\s*// && push @options,"!authenticate";
+    s/PASSWD:\s*// && push @options,"authenticate";
+    s/NOEXEC:\s*// && push @options,"noexec";
+    s/EXEC:\s*// && push @options,"!noexec";
+    s/SETENV:\s*// && push @options,"setenv";
+    s/NOSETENV:\s*// && push @options,"!setenv";
+    s/LOG_INPUT:\s*// && push @options,"log_input";
+    s/NOLOG_INPUT:\s*// && push @options,"!log_input";
+    s/LOG_OUTPUT:\s*// && push @options,"log_output";
+    s/NOLOG_OUTPUT:\s*// && push @options,"!log_output";
+    s/\w+://; # silently remove other directives
+    s/\s+$//; # right trim
+  }
+
+  # do the expanding
+  push @a,$ref->{$_} ? expand($ref,split /\s*,\s*/,$ref->{$_}):$_ foreach @_;
+  @a;
+}
+
+
diff --git a/plugins/sudoers/sudoers_version.h b/plugins/sudoers/sudoers_version.h
new file mode 100644 (file)
index 0000000..3593d29
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Major sudoers grammar changes are documented here.
+ * Note that minor changes such as added Defaults options are not listed here.
+ * This file placed in the public domain by Todd C. Miller on Apr 5, 2011.
+ *
+ * 1   sudo 1.1
+ * 2   sudo 1.3, adds support specifying a directory instead of a command.
+ * 3   sudo 1.3.2, new parser, Aliases have to be upper case
+ * 4   sudo 1.3.2, adds User_Alias
+ * 5   sudo 1.3.4, netgroup support
+ * 6   sudo 1.3.5, support for escaping special chars
+ * 7   sudo 1.3.7, unix group support
+ * 8   sudo 1.4.1, wildcard support
+ * 9   sudo 1.4.2, double quote support in sudoers command line args
+ * 10  sudo 1.4.3, added NOPASSWD tag
+ * 11  sudo 1.4.3, added Runas_Spec
+ * 12  sudo 1.4.3, wildcards may be used in the pathname
+ * 13  sudo 1.4.3, command args of "" means no args allowed
+ * 14  sudo 1.4.4, '(' in command args no longer are a syntax error.
+ * 15  sudo 1.4.4, '!command' works in the presence of runas user or NOPASSWD.
+ * 16  sudo 1.4.4, all-caps user and host names are now handled properly.
+ * 17  sudo 1.5.0, usernames may now begin with a digit
+ * 18  sudo 1.5.3, adds Runas_Alias
+ * 19  sudo 1.5.7, %group may be used in a Runas_List
+ * 20  sudo 1.6.0, The runas user and NOPASSWD tags are now persistent across entries in a command list.  A PASSWD tag has been added to reverse NOPASSWD
+ * 21  sudo 1.6.0, The '!' operator can be used in a Runas_Spec or an *_Alias
+ * 22  sudo 1.6.0, a list of hosts may be used in a Host_Spec
+ * 23  sudo 1.6.0, a list of users may be used in a User_Spec
+ * 24  sudo 1.6.0, It is now possible to escape "special" characters in usernames, hostnames, etc with a backslash.
+ * 25  sudo 1.6.0, Added Defaults run-time settings in sudoers.
+ * 26  sudo 1.6.0, relaxed the regexp for matching user, host, group names.
+ * 27  sudo 1.6.1, #uid is now allowed in a Runas_Alias.
+ * 28  sudo 1.6.2, Wildcards are now allowed in hostnames.
+ * 29  sudo 1.6.3p7, escaped special characters may be included in pathnames.
+ * 30  sudo 1.6.8, added NOEXEC and EXEC tags.
+ * 31  sudo 1.6.9, added SETENV and NOSETENV tags.
+ * 32  sudo 1.6.9p4, support for IPv6 address matching.
+ * 33  sudo 1.7.0, #include support.
+ * 34  sudo 1.7.0, Runas_Group support.
+ * 35  sudo 1.7.0, uid may now be used anywhere a username is valid.
+ * 36  sudo 1.7.2, #includedir support.
+ * 37  sudo 1.7.4, per-command Defaults support.
+ * 38  sudo 1.7.4, added LOG_INPUT/LOG_OUTPUT and NOLOG_INPUT/NOLOG_OUTPUT tags
+ * 39  sudo 1.7.6/1.8.1, White space is now permitted within a User_List in a per-user Defaults definition.
+ * 40  sudo 1.7.6/1.8.1, A group ID is now allowed in a User_List or Runas_List.
+*/
+
+#ifndef _SUDOERS_VERSION_H
+#define        _SUDOERS_VERSION_H
+
+#define SUDOERS_GRAMMAR_VERSION        40
+
+#endif /* _SUDOERS_VERSION_H */
diff --git a/plugins/sudoers/sudoreplay.c b/plugins/sudoers/sudoreplay.c
new file mode 100644 (file)
index 0000000..e40fcef
--- /dev/null
@@ -0,0 +1,969 @@
+/*
+ * Copyright (c) 2009-2011 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>
+#ifdef HAVE_SYS_SYSMACROS_H
+# include <sys/sysmacros.h>
+#endif
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#ifndef HAVE_TIMESPEC
+# include "compat/timespec.h"
+#endif
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <fcntl.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
+#ifdef HAVE_REGCOMP
+# include <regex.h>
+#endif
+#ifdef HAVE_ZLIB_H
+# include <zlib.h>
+#endif
+#ifdef HAVE_SETLOCALE
+# include <locale.h>
+#endif
+#include <signal.h>
+
+#include <pathnames.h>
+
+#include "missing.h"
+#include "alloc.h"
+#include "error.h"
+
+#ifndef LINE_MAX
+# define LINE_MAX 2048
+#endif
+
+/* Must match the defines in iolog.c */
+#define IOFD_STDIN      0
+#define IOFD_STDOUT     1
+#define IOFD_STDERR     2
+#define IOFD_TTYIN      3
+#define IOFD_TTYOUT     4
+#define IOFD_TIMING     5
+#define IOFD_MAX        6
+
+/* Bitmap of iofds to be replayed */
+unsigned int replay_filter = (1 << IOFD_STDOUT) | (1 << IOFD_STDERR) |
+                            (1 << IOFD_TTYOUT);
+
+/* For getopt(3) */
+extern char *optarg;
+extern int optind;
+
+union io_fd {
+    FILE *f;
+#ifdef HAVE_ZLIB_H
+    gzFile g;
+#endif
+    void *v;
+};
+
+/*
+ * Info present in the I/O log file
+ */
+struct log_info {
+    char *cwd;
+    char *user;
+    char *runas_user;
+    char *runas_group;
+    char *tty;
+    char *cmd;
+    time_t tstamp;
+};
+
+/*
+ * Handle expressions like:
+ * ( user millert or user root ) and tty console and command /bin/sh
+ */
+struct search_node {
+    struct search_node *next;
+#define ST_EXPR                1
+#define ST_TTY         2
+#define ST_USER                3
+#define ST_PATTERN     4
+#define ST_RUNASUSER   5
+#define ST_RUNASGROUP  6
+#define ST_FROMDATE    7
+#define ST_TODATE      8
+#define ST_CWD         9
+    char type;
+    char negated;
+    char or;
+    char pad;
+    union {
+#ifdef HAVE_REGCOMP
+       regex_t cmdre;
+#endif
+       time_t tstamp;
+       char *cwd;
+       char *tty;
+       char *user;
+       char *pattern;
+       char *runas_group;
+       char *runas_user;
+       struct search_node *expr;
+       void *ptr;
+    } u;
+} *search_expr;
+
+#define STACK_NODE_SIZE        32
+static struct search_node *node_stack[32];
+static int stack_top;
+
+static const char *session_dir = _PATH_SUDO_IO_LOGDIR;
+
+static union io_fd io_fds[IOFD_MAX];
+static const char *io_fnames[IOFD_MAX] = {
+    "/stdin",
+    "/stdout",
+    "/stderr",
+    "/ttyin",
+    "/ttyout",
+    "/timing"
+};
+
+extern time_t get_date(char *);
+extern char *get_timestr(time_t, int);
+extern int term_raw(int, int);
+extern int term_restore(int, int);
+extern void zero_bytes(volatile void *, size_t);
+void cleanup(int);
+
+static int list_sessions(int, char **, const char *, const char *, const char *);
+static int parse_expr(struct search_node **, char **);
+static void check_input(int, double *);
+static void delay(double);
+static void help(void) __attribute__((__noreturn__));
+static void usage(int);
+static void *open_io_fd(char *pathbuf, int len, const char *suffix);
+static int parse_timing(const char *buf, const char *decimal, int *idx, double *seconds, size_t *nbytes);
+
+#ifdef HAVE_REGCOMP
+# define REGEX_T       regex_t
+#else
+# define REGEX_T       char
+#endif
+
+#define VALID_ID(s) (isalnum((unsigned char)(s)[0]) && \
+    isalnum((unsigned char)(s)[1]) && isalnum((unsigned char)(s)[2]) && \
+    isalnum((unsigned char)(s)[3]) && isalnum((unsigned char)(s)[4]) && \
+    isalnum((unsigned char)(s)[5]) && (s)[6] == '\0')
+
+#define IS_IDLOG(s) ( \
+    isalnum((unsigned char)(s)[0]) && isalnum((unsigned char)(s)[1]) && \
+    (s)[2] == '/' && \
+    isalnum((unsigned char)(s)[3]) && isalnum((unsigned char)(s)[4]) && \
+    (s)[5] == '/' && \
+    isalnum((unsigned char)(s)[6]) && isalnum((unsigned char)(s)[7]) && \
+    (s)[8] == '/' && (s)[9] == 'l' && (s)[10] == 'o' && (s)[11] == 'g' && \
+    (s)[9] == '\0')
+
+int
+main(int argc, char *argv[])
+{
+    int ch, idx, plen, nready, interactive = 0, listonly = 0;
+    const char *id, *user = NULL, *pattern = NULL, *tty = NULL, *decimal = ".";
+    char path[PATH_MAX], buf[LINE_MAX], *cp, *ep;
+    double seconds, to_wait, speed = 1.0, max_wait = 0;
+    FILE *lfile;
+    fd_set *fdsw;
+    sigaction_t sa;
+    size_t len, nbytes, nread, off;
+    ssize_t nwritten;
+
+#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
+    setprogname(argc > 0 ? argv[0] : "sudoreplay");
+#endif
+
+#ifdef HAVE_SETLOCALE
+    setlocale(LC_ALL, "");
+    decimal = localeconv()->decimal_point;
+#endif
+
+    while ((ch = getopt(argc, argv, "d:f:hlm:s:V")) != -1) {
+       switch(ch) {
+       case 'd':
+           session_dir = optarg;
+           break;
+       case 'f':
+           /* Set the replay filter. */
+           replay_filter = 0;
+           for (cp = strtok(optarg, ","); cp; cp = strtok(NULL, ",")) {
+               if (strcmp(cp, "stdout") == 0)
+                   SET(replay_filter, 1 << IOFD_STDOUT);
+               else if (strcmp(cp, "stderr") == 0)
+                   SET(replay_filter, 1 << IOFD_STDERR);
+               else if (strcmp(cp, "ttyout") == 0)
+                   SET(replay_filter, 1 << IOFD_TTYOUT);
+               else
+                   errorx(1, "invalid filter option: %s", optarg);
+           }
+           break;
+       case 'h':
+           help();
+           /* NOTREACHED */
+       case 'l':
+           listonly = 1;
+           break;
+       case 'm':
+           errno = 0;
+           max_wait = strtod(optarg, &ep);
+           if (*ep != '\0' || errno != 0)
+               errorx(1, "invalid max wait: %s", optarg);
+           break;
+       case 's':
+           errno = 0;
+           speed = strtod(optarg, &ep);
+           if (*ep != '\0' || errno != 0)
+               errorx(1, "invalid speed factor: %s", optarg);
+           break;
+       case 'V':
+           (void) printf("%s version %s\n", getprogname(), PACKAGE_VERSION);
+           exit(0);
+       default:
+           usage(1);
+           /* NOTREACHED */
+       }
+
+    }
+    argc -= optind;
+    argv += optind;
+
+    if (listonly)
+       exit(list_sessions(argc, argv, pattern, user, tty));
+
+    if (argc != 1)
+       usage(1);
+
+    /* 6 digit ID in base 36, e.g. 01G712AB or free-form name */
+    id = argv[0];
+    if (VALID_ID(id)) {
+       plen = snprintf(path, sizeof(path), "%s/%.2s/%.2s/%.2s/timing",
+           session_dir, id, &id[2], &id[4]);
+       if (plen <= 0 || plen >= sizeof(path))
+           errorx(1, "%s/%.2s/%.2s/%.2s/%.2s/timing: %s", session_dir,
+               id, &id[2], &id[4], strerror(ENAMETOOLONG));
+    } else {
+       plen = snprintf(path, sizeof(path), "%s/%s/timing",
+           session_dir, id);
+       if (plen <= 0 || plen >= sizeof(path))
+           errorx(1, "%s/%s/timing: %s", session_dir,
+               id, strerror(ENAMETOOLONG));
+    }
+    plen -= 7;
+
+    /* Open files for replay, applying replay filter for the -f flag. */
+    for (idx = 0; idx < IOFD_MAX; idx++) {
+       if (ISSET(replay_filter, 1 << idx) || idx == IOFD_TIMING) {
+           io_fds[idx].v = open_io_fd(path, plen, io_fnames[idx]);
+           if (io_fds[idx].v == NULL)
+               error(1, "unable to open %s", path);
+       }
+    }
+
+    /* Read log file. */
+    path[plen] = '\0';
+    strlcat(path, "/log", sizeof(path));
+    lfile = fopen(path, "r");
+    if (lfile == NULL)
+       error(1, "unable to open %s", path);
+    cp = NULL;
+    len = 0;
+    /* Pull out command (third line). */
+    if (getline(&cp, &len, lfile) == -1 ||
+       getline(&cp, &len, lfile) == -1 ||
+       getline(&cp, &len, lfile) == -1) {
+       errorx(1, "invalid log file %s", path);
+    }
+    printf("Replaying sudo session: %s", cp);
+    free(cp);
+    fclose(lfile);
+
+    fflush(stdout);
+    zero_bytes(&sa, sizeof(sa));
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = SA_RESETHAND;
+    sa.sa_handler = cleanup;
+    (void) sigaction(SIGINT, &sa, NULL);
+    (void) sigaction(SIGKILL, &sa, NULL);
+    (void) sigaction(SIGTERM, &sa, NULL);
+    (void) sigaction(SIGHUP, &sa, NULL);
+    sa.sa_flags = SA_RESTART;
+    sa.sa_handler = SIG_IGN;
+    (void) sigaction(SIGTSTP, &sa, NULL);
+    (void) sigaction(SIGQUIT, &sa, NULL);
+
+    /* XXX - read user input from /dev/tty and set STDOUT to raw if not a pipe */
+    /* Set stdin to raw mode if it is a tty */
+    interactive = isatty(STDIN_FILENO);
+    if (interactive) {
+       ch = fcntl(STDIN_FILENO, F_GETFL, 0);
+       if (ch != -1)
+           (void) fcntl(STDIN_FILENO, F_SETFL, ch | O_NONBLOCK);
+       if (!term_raw(STDIN_FILENO, 1))
+           error(1, "cannot set tty to raw mode");
+    }
+    fdsw = (fd_set *)emalloc2(howmany(STDOUT_FILENO + 1, NFDBITS),
+       sizeof(fd_mask));
+
+    /*
+     * Timing file consists of line of the format: "%f %d\n"
+     */
+#ifdef HAVE_ZLIB_H
+    while (gzgets(io_fds[IOFD_TIMING].g, buf, sizeof(buf)) != NULL) {
+#else
+    while (fgets(buf, sizeof(buf), io_fds[IOFD_TIMING].f) != NULL) {
+#endif
+       if (!parse_timing(buf, decimal, &idx, &seconds, &nbytes))
+           errorx(1, "invalid timing file line: %s", buf);
+
+       if (interactive)
+           check_input(STDIN_FILENO, &speed);
+
+       /* Adjust delay using speed factor and clamp to max_wait */
+       to_wait = seconds / speed;
+       if (max_wait && to_wait > max_wait)
+           to_wait = max_wait;
+       delay(to_wait);
+
+       /* Even if we are not relaying, we still have to delay. */
+       if (io_fds[idx].v == NULL)
+           continue;
+
+       /* All output is sent to stdout. */
+       while (nbytes != 0) {
+           if (nbytes > sizeof(buf))
+               len = sizeof(buf);
+           else
+               len = nbytes;
+#ifdef HAVE_ZLIB_H
+           nread = gzread(io_fds[idx].g, buf, len);
+#else
+           nread = fread(buf, 1, len, io_fds[idx].f);
+#endif
+           nbytes -= nread;
+           off = 0;
+           do {
+               /* no stdio, must be unbuffered */
+               nwritten = write(STDOUT_FILENO, buf + off, nread - off);
+               if (nwritten == -1) {
+                   if (errno == EINTR)
+                       continue;
+                   if (errno == EAGAIN) {
+                       FD_SET(STDOUT_FILENO, fdsw);
+                       do {
+                           nready = select(STDOUT_FILENO + 1, NULL, fdsw, NULL, NULL);
+                       } while (nready == -1 && errno == EINTR);
+                       if (nready == 1)
+                           continue;
+                   }
+                   error(1, "writing to standard output");
+               }
+               off += nwritten;
+           } while (nread > off);
+       }
+    }
+    term_restore(STDIN_FILENO, 1);
+    exit(0);
+}
+
+static void
+delay(double secs)
+{
+    struct timespec ts, rts;
+    int rval;
+
+    /*
+     * Typical max resolution is 1/HZ but we can't portably check that.
+     * If the interval is small enough, just ignore it.
+     */
+    if (secs < 0.0001)
+       return;
+
+    rts.tv_sec = secs;
+    rts.tv_nsec = (secs - (double) rts.tv_sec) * 1000000000.0;
+    do {
+      memcpy(&ts, &rts, sizeof(ts));
+      rval = nanosleep(&ts, &rts);
+    } while (rval == -1 && errno == EINTR);
+    if (rval == -1)
+       error(1, "nanosleep: tv_sec %ld, tv_nsec %ld", ts.tv_sec, ts.tv_nsec);
+}
+
+static void *
+open_io_fd(char *path, int len, const char *suffix)
+{
+    path[len] = '\0';
+    strlcat(path, suffix, PATH_MAX);
+
+#ifdef HAVE_ZLIB_H
+    return gzopen(path, "r");
+#else
+    return fopen(path, "r");
+#endif
+}
+
+/*
+ * Build expression list from search args
+ */
+static int
+parse_expr(struct search_node **headp, char *argv[])
+{
+    struct search_node *sn, *newsn;
+    char or = 0, not = 0, type, **av;
+
+    sn = *headp;
+    for (av = argv; *av; av++) {
+       switch (av[0][0]) {
+       case 'a': /* and (ignore) */
+           if (strncmp(*av, "and", strlen(*av)) != 0)
+               goto bad;
+           continue;
+       case 'o': /* or */
+           if (strncmp(*av, "or", strlen(*av)) != 0)
+               goto bad;
+           or = 1;
+           continue;
+       case '!': /* negate */
+           if (av[0][1] != '\0')
+               goto bad;
+           not = 1;
+           continue;
+       case 'c': /* command */
+           if (av[0][1] == '\0')
+               errorx(1, "ambiguous expression \"%s\"", *av);
+           if (strncmp(*av, "cwd", strlen(*av)) == 0)
+               type = ST_CWD;
+           else if (strncmp(*av, "command", strlen(*av)) == 0)
+               type = ST_PATTERN;
+           else
+               goto bad;
+           break;
+       case 'f': /* from date */
+           if (strncmp(*av, "fromdate", strlen(*av)) != 0)
+               goto bad;
+           type = ST_FROMDATE;
+           break;
+       case 'g': /* runas group */
+           if (strncmp(*av, "group", strlen(*av)) != 0)
+               goto bad;
+           type = ST_RUNASGROUP;
+           break;
+       case 'r': /* runas user */
+           if (strncmp(*av, "runas", strlen(*av)) != 0)
+               goto bad;
+           type = ST_RUNASUSER;
+           break;
+       case 't': /* tty or to date */
+           if (av[0][1] == '\0')
+               errorx(1, "ambiguous expression \"%s\"", *av);
+           if (strncmp(*av, "todate", strlen(*av)) == 0)
+               type = ST_TODATE;
+           else if (strncmp(*av, "tty", strlen(*av)) == 0)
+               type = ST_TTY;
+           else
+               goto bad;
+           break;
+       case 'u': /* user */
+           if (strncmp(*av, "user", strlen(*av)) != 0)
+               goto bad;
+           type = ST_USER;
+           break;
+       case '(': /* start sub-expression */
+           if (av[0][1] != '\0')
+               goto bad;
+           if (stack_top + 1 == STACK_NODE_SIZE) {
+               errorx(1, "too many parenthesized expressions, max %d",
+                   STACK_NODE_SIZE);
+           }
+           node_stack[stack_top++] = sn;
+           type = ST_EXPR;
+           break;
+       case ')': /* end sub-expression */
+           if (av[0][1] != '\0')
+               goto bad;
+           /* pop */
+           if (--stack_top < 0)
+               errorx(1, "unmatched ')' in expression");
+           if (node_stack[stack_top])
+               sn->next = node_stack[stack_top]->next;
+           return av - argv + 1;
+       bad:
+       default:
+           errorx(1, "unknown search term \"%s\"", *av);
+           /* NOTREACHED */
+       }
+
+       /* Allocate new search node */
+       newsn = emalloc(sizeof(*newsn));
+       newsn->next = NULL;
+       newsn->type = type;
+       newsn->or = or;
+       newsn->negated = not;
+       if (type == ST_EXPR) {
+           av += parse_expr(&newsn->u.expr, av + 1);
+       } else {
+           if (*(++av) == NULL)
+               errorx(1, "%s requires an argument", av[-1]);
+#ifdef HAVE_REGCOMP
+           if (type == ST_PATTERN) {
+               if (regcomp(&newsn->u.cmdre, *av, REG_EXTENDED|REG_NOSUB) != 0)
+                   errorx(1, "invalid regex: %s", *av);
+           } else
+#endif
+           if (type == ST_TODATE || type == ST_FROMDATE) {
+               newsn->u.tstamp = get_date(*av);
+               if (newsn->u.tstamp == -1)
+                   errorx(1, "could not parse date \"%s\"", *av);
+           } else {
+               newsn->u.ptr = *av;
+           }
+       }
+       not = or = 0; /* reset state */
+       if (sn)
+           sn->next = newsn;
+       else
+           *headp = newsn;
+       sn = newsn;
+    }
+    if (stack_top)
+       errorx(1, "unmatched '(' in expression");
+    if (or)
+       errorx(1, "illegal trailing \"or\"");
+    if (not)
+       errorx(1, "illegal trailing \"!\"");
+
+    return av - argv;
+}
+
+static int
+match_expr(struct search_node *head, struct log_info *log)
+{
+    struct search_node *sn;
+    int matched = 1, rc;
+
+    for (sn = head; sn; sn = sn->next) {
+       /* If we have no match, skip ahead to the next OR entry. */
+       if (!matched && !sn->or)
+           continue;
+
+       switch (sn->type) {
+       case ST_EXPR:
+           matched = match_expr(sn->u.expr, log);
+           break;
+       case ST_CWD:
+           matched = strcmp(sn->u.cwd, log->cwd) == 0;
+           break;
+       case ST_TTY:
+           matched = strcmp(sn->u.tty, log->tty) == 0;
+           break;
+       case ST_RUNASGROUP:
+           matched = strcmp(sn->u.runas_group, log->runas_group) == 0;
+           break;
+       case ST_RUNASUSER:
+           matched = strcmp(sn->u.runas_user, log->runas_user) == 0;
+           break;
+       case ST_USER:
+           matched = strcmp(sn->u.user, log->user) == 0;
+           break;
+       case ST_PATTERN:
+#ifdef HAVE_REGCOMP
+           rc = regexec(&sn->u.cmdre, log->cmd, 0, NULL, 0);
+           if (rc && rc != REG_NOMATCH) {
+               char buf[BUFSIZ];
+               regerror(rc, &sn->u.cmdre, buf, sizeof(buf));
+               errorx(1, "%s", buf);
+           }
+           matched = rc == REG_NOMATCH ? 0 : 1;
+#else
+           matched = strstr(log.cmd, sn->u.pattern) != NULL;
+#endif
+           break;
+       case ST_FROMDATE:
+           matched = log->tstamp >= sn->u.tstamp;
+           break;
+       case ST_TODATE:
+           matched = log->tstamp <= sn->u.tstamp;
+           break;
+       }
+       if (sn->negated)
+           matched = !matched;
+    }
+    return matched;
+}
+
+static int
+list_session(char *logfile, REGEX_T *re, const char *user, const char *tty)
+{
+    FILE *fp;
+    char *buf = NULL, *cmd = NULL, *cwd = NULL, idbuf[7], *idstr, *cp;
+    struct log_info li;
+    size_t bufsize = 0, cwdsize = 0, cmdsize = 0;
+    int rval = -1;
+
+    fp = fopen(logfile, "r");
+    if (fp == NULL) {
+       warning("unable to open %s", logfile);
+       goto done;
+    }
+
+    /*
+     * ID file has three lines:
+     *  1) a log info line
+     *  2) cwd
+     *  3) command with args
+     */
+    if (getline(&buf, &bufsize, fp) == -1 ||
+       getline(&cwd, &cwdsize, fp) == -1 ||
+       getline(&cmd, &cmdsize, fp) == -1) {
+       goto done;
+    }
+
+    /* crack the log line: timestamp:user:runas_user:runas_group:tty */
+    buf[strcspn(buf, "\n")] = '\0';
+    if ((li.tstamp = atoi(buf)) == 0)
+       goto done;
+
+    if ((cp = strchr(buf, ':')) == NULL)
+       goto done;
+    *cp++ = '\0';
+    li.user = cp;
+
+    if ((cp = strchr(cp, ':')) == NULL)
+       goto done;
+    *cp++ = '\0';
+    li.runas_user = cp;
+
+    if ((cp = strchr(cp, ':')) == NULL)
+       goto done;
+    *cp++ = '\0';
+    li.runas_group = cp;
+
+    if ((cp = strchr(cp, ':')) == NULL)
+       goto done;
+    *cp++ = '\0';
+    li.tty = cp;
+
+    cwd[strcspn(cwd, "\n")] = '\0';
+    li.cwd = cwd;
+
+    cmd[strcspn(cmd, "\n")] = '\0';
+    li.cmd = cmd;
+
+    /* Match on search expression if there is one. */
+    if (search_expr && !match_expr(search_expr, &li))
+       goto done;
+
+    /* Convert from /var/log/sudo-sessions/00/00/01/log to 000001 */
+    cp = logfile + strlen(session_dir) + 1;
+    if (IS_IDLOG(cp)) {
+       idbuf[0] = cp[7];
+       idbuf[1] = cp[6];
+       idbuf[2] = cp[4];
+       idbuf[3] = cp[3];
+       idbuf[4] = cp[1];
+       idbuf[5] = cp[0];
+       idbuf[6] = '\0';
+       idstr = idbuf;
+    } else {
+       /* Not an id, just use the iolog_file portion. */
+       cp[strlen(cp) - 4] = '\0';
+       idstr = cp;
+    }
+    printf("%s : %s : TTY=%s ; CWD=%s ; USER=%s ; ",
+       get_timestr(li.tstamp, 1), li.user, li.tty, li.cwd, li.runas_user);
+    if (*li.runas_group)
+       printf("GROUP=%s ; ", li.runas_group);
+    printf("TSID=%s ; COMMAND=%s\n", idstr, li.cmd);
+
+    rval = 0;
+
+done:
+    fclose(fp);
+    return rval;
+}
+
+static int
+find_sessions(const char *dir, REGEX_T *re, const char *user, const char *tty)
+{
+    DIR *d;
+    struct dirent *dp;
+    struct stat sb;
+    size_t sdlen;
+    int len;
+    char pathbuf[PATH_MAX];
+
+    d = opendir(dir);
+    if (d == NULL)
+       error(1, "unable to open %s", dir);
+
+    /* XXX - would be faster to chdir and use relative names */
+    sdlen = strlcpy(pathbuf, dir, sizeof(pathbuf));
+    if (sdlen + 1 >= sizeof(pathbuf)) {
+       errno = ENAMETOOLONG;
+       error(1, "%s/", dir);
+    }
+    pathbuf[sdlen++] = '/';
+    pathbuf[sdlen] = '\0';
+    while ((dp = readdir(d)) != NULL) {
+       /* Skip "." and ".." */
+       if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
+           (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
+           continue;
+
+       len = snprintf(&pathbuf[sdlen], sizeof(pathbuf) - sdlen,
+           "%s/log", dp->d_name);
+       if (len <= 0 || len >= sizeof(pathbuf) - sdlen) {
+           errno = ENAMETOOLONG;
+           error(1, "%s/%s/log", dir, dp->d_name);
+       }
+
+       /* Check for dir with a log file. */
+       if (lstat(pathbuf, &sb) == 0 && S_ISREG(sb.st_mode)) {
+           list_session(pathbuf, re, user, tty);
+       } else {
+           /* Strip off "/log" and recurse if a dir. */
+           pathbuf[sdlen + len - 4] = '\0';
+           if (lstat(pathbuf, &sb) == 0 && S_ISDIR(sb.st_mode))
+               find_sessions(pathbuf, re, user, tty);
+       }
+    }
+    closedir(d);
+
+    return 0;
+}
+
+static int
+list_sessions(int argc, char **argv, const char *pattern, const char *user,
+    const char *tty)
+{
+    REGEX_T rebuf, *re = NULL;
+
+    /* Parse search expression if present */
+    parse_expr(&search_expr, argv);
+
+#ifdef HAVE_REGCOMP
+    /* optional regex */
+    if (pattern) {
+       re = &rebuf;
+       if (regcomp(re, pattern, REG_EXTENDED|REG_NOSUB) != 0)
+           errorx(1, "invalid regex: %s", pattern);
+    }
+#else
+    re = (char *) pattern;
+#endif /* HAVE_REGCOMP */
+
+    return find_sessions(session_dir, re, user, tty);
+}
+
+/*
+ * Check input for ' ', '<', '>'
+ * pause, slow, fast
+ */
+static void
+check_input(int ttyfd, double *speed)
+{
+    fd_set *fdsr;
+    int nready, paused = 0;
+    struct timeval tv;
+    char ch;
+    ssize_t n;
+
+    fdsr = (fd_set *)emalloc2(howmany(ttyfd + 1, NFDBITS), sizeof(fd_mask));
+
+    for (;;) {
+       FD_SET(ttyfd, fdsr);
+       tv.tv_sec = 0;
+       tv.tv_usec = 0;
+
+       nready = select(ttyfd + 1, fdsr, NULL, NULL, paused ? NULL : &tv);
+       if (nready != 1)
+           break;
+       n = read(ttyfd, &ch, 1);
+       if (n == 1) {
+           if (paused) {
+               paused = 0;
+               continue;
+           }
+           switch (ch) {
+           case ' ':
+               paused = 1;
+               break;
+           case '<':
+               *speed /= 2;
+               break;
+           case '>':
+               *speed *= 2;
+               break;
+           }
+       }
+    }
+    free(fdsr);
+}
+
+/*
+ * Parse a timing line, which is formatted as:
+ *     index sleep_time num_bytes
+ * Where index is IOFD_*, sleep_time is the number of seconds to sleep
+ * before writing the data and num_bytes is the number of bytes to output.
+ * Returns 1 on success and 0 on failure.
+ */
+static int
+parse_timing(buf, decimal, idx, seconds, nbytes)
+    const char *buf;
+    const char *decimal;
+    int *idx;
+    double *seconds;
+    size_t *nbytes;
+{
+    unsigned long ul;
+    long l;
+    double d, fract = 0;
+    char *cp, *ep;
+
+    /* Parse index */
+    ul = strtoul(buf, &ep, 10);
+    if (ul > IOFD_MAX)
+       goto bad;
+    *idx = (int)ul;
+    for (cp = ep + 1; isspace((unsigned char) *cp); cp++)
+       continue;
+
+    /*
+     * Parse number of seconds.  Sudo logs timing data in the C locale
+     * but this may not match the current locale so we cannot use strtod().
+     * Furthermore, sudo < 1.7.4 logged with the user's locale so we need
+     * to be able to parse those logs too.
+     */
+    errno = 0;
+    l = strtol(cp, &ep, 10);
+    if ((errno == ERANGE && (l == LONG_MAX || l == LONG_MIN)) ||
+       l < 0 || l > INT_MAX ||
+       (*ep != '.' && strncmp(ep, decimal, strlen(decimal)) != 0)) {
+       goto bad;
+    }
+    *seconds = (double)l;
+    cp = ep + (*ep == '.' ? 1 : strlen(decimal));
+    d = 10.0;
+    while (isdigit((unsigned char) *cp)) {
+       fract += (*cp - '0') / d;
+       d *= 10;
+       cp++;
+    }
+    *seconds += fract;
+    while (isspace((unsigned char) *cp))
+       cp++;
+
+    errno = 0;
+    ul = strtoul(cp, &ep, 10);
+    if (errno == ERANGE && ul == ULONG_MAX)
+       goto bad;
+    *nbytes = (size_t)ul;
+
+    return 1;
+bad:
+    return 0;
+}
+
+static void
+usage(int fatal)
+{
+    fprintf(fatal ? stderr : stdout,
+       "usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n",
+       getprogname());
+    fprintf(fatal ? stderr : stdout,
+       "usage: %s [-h] [-d directory] -l [search expression]\n",
+       getprogname());
+    if (fatal)
+       exit(1);
+}
+
+static void
+help(void)
+{
+    (void) printf("%s - replay sudo session logs\n\n", getprogname());
+    usage(0);
+    (void) puts("\nOptions:");
+    (void) puts("  -d directory     specify directory for session logs");
+    (void) puts("  -f filter        specify which I/O type to display");
+    (void) puts("  -h               display help message and exit");
+    (void) puts("  -l [expression]  list available session IDs that match expression");
+    (void) puts("  -m max_wait      max number of seconds to wait between events");
+    (void) puts("  -s speed_factor  speed up or slow down output");
+    (void) puts("  -V               display version information and exit");
+    exit(0);
+}
+
+/*
+ * Cleanup hook for error()/errorx()
+  */
+void
+cleanup(int signo)
+{
+    term_restore(STDIN_FILENO, 0);
+    if (signo)
+       kill(getpid(), signo);
+}
diff --git a/plugins/sudoers/testsudoers.c b/plugins/sudoers/testsudoers.c
new file mode 100644 (file)
index 0000000..60e338b
--- /dev/null
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2011
+ *     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.
+ */
+
+#define _SUDO_MAIN
+
+#include <config.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FNMATCH
+# include <fnmatch.h>
+#endif /* HAVE_FNMATCH */
+#ifdef HAVE_NETGROUP_H
+# include <netgroup.h>
+#endif /* HAVE_NETGROUP_H */
+#include <ctype.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "tsgetgrpw.h"
+#include "sudoers.h"
+#include "interfaces.h"
+#include "parse.h"
+#include <gram.h>
+
+#ifndef HAVE_FNMATCH
+# include "compat/fnmatch.h"
+#endif /* HAVE_FNMATCH */
+
+/*
+ * Function Prototypes
+ */
+int  print_alias(void *, void *);
+void dump_sudoers(void);
+void print_defaults(void);
+void print_privilege(struct privilege *);
+void print_userspecs(void);
+void usage(void) __attribute__((__noreturn__));
+void set_runasgr(char *);
+void set_runaspw(char *);
+void cleanup(int);
+static int testsudoers_printf(int msg_type, const char *fmt, ...);
+static int testsudoers_print(const char *msg);
+
+extern void setgrfile(const char *);
+extern void setgrent(void);
+extern void endgrent(void);
+extern struct group *getgrent(void);
+extern struct group *getgrnam(const char *);
+extern struct group *getgrgid(gid_t);
+extern void setpwfile(const char *);
+extern void setpwent(void);
+extern void endpwent(void);
+extern struct passwd *getpwent(void);
+extern struct passwd *getpwnam(const char *);
+extern struct passwd *getpwuid(uid_t);
+
+extern int (*trace_print)(const char *msg);
+
+/*
+ * Globals
+ */
+struct interface *interfaces;
+struct sudo_user sudo_user;
+struct passwd *list_pw;
+extern int parse_error;
+sudo_printf_t sudo_printf = testsudoers_printf;
+
+/* 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
+
+int
+main(int argc, char *argv[])
+{
+    struct cmndspec *cs;
+    struct privilege *priv;
+    struct userspec *us;
+    char *p, *grfile, *pwfile, *runas_group, *runas_user;
+    char hbuf[MAXHOSTNAMELEN + 1];
+    int match, host_match, runas_match, cmnd_match;
+    int ch, dflag;
+
+#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
+    malloc_options = "AFGJPR";
+#endif
+#ifdef YYDEBUG
+    yydebug = 1;
+#endif
+
+#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
+    setprogname(argc > 0 ? argv[0] : "testsudoers");
+#endif
+
+    dflag = 0;
+    grfile = pwfile = runas_group = runas_user = NULL;
+    while ((ch = getopt(argc, argv, "dg:G:h:p:tu:")) != -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 't':
+               trace_print = testsudoers_print;
+               break;
+           case 'u':
+               runas_user = optarg;
+               break;
+           default:
+               usage();
+               break;
+       }
+    }
+    argc -= optind;
+    argv += optind;
+
+    /* Set group/passwd file and init the cache. */
+    if (grfile)
+       setgrfile(grfile);
+    if (pwfile)
+       setpwfile(pwfile);
+    sudo_setpwent();
+    sudo_setgrent();
+
+    if (argc < 2) {
+       if (!dflag)
+           usage();
+       user_name = "root";
+       user_cmnd = user_base = "true";
+    } else {
+       user_name = *argv;
+       user_cmnd = *++argv;
+       if ((p = strrchr(user_cmnd, '/')) != NULL)
+           user_base = p + 1;
+       else
+           user_base = user_cmnd;
+       argc -= 2;
+    }
+    if ((sudo_user.pw = sudo_getpwnam(user_name)) == NULL)
+       errorx(1, "no passwd entry for %s!", user_name);
+
+    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;
+    }
+
+    /* Fill in user_args from argv. */
+    if (argc > 0) {
+       char *to, **from;
+       size_t size, n;
+
+       for (size = 0, from = argv + 1; *from; from++)
+           size += strlen(*from) + 1;
+
+       user_args = (char *) emalloc(size);
+       for (to = user_args, from = argv + 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';
+    }
+
+    /* Initialize default values. */
+    init_defaults();
+
+    /* Load ip addr/mask for each interface. */
+    if (get_net_ifs(&p) > 0)
+       set_interfaces(p);
+
+    /* Allocate space for data structures in the parser. */
+    init_parser("sudoers", 0);
+
+    if (yyparse() != 0 || parse_error) {
+       parse_error = TRUE;
+       (void) fputs("Does not parse", stdout);
+    } else {
+       (void) fputs("Parses OK", stdout);
+    }
+
+    if (!update_defaults(SETDEF_ALL))
+       (void) fputs(" (problem with defaults entries)", stdout);
+    puts(".");
+
+    if (def_group_plugin && group_plugin_load(def_group_plugin) != TRUE)
+       def_group_plugin = NULL;
+
+    /*
+     * 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(parse_error ? 1 : 0);
+    }
+
+    /* This loop must match the one in sudo_file_lookup() */
+    printf("\nEntries for user %s:\n", user_name);
+    match = UNSPEC;
+    tq_foreach_rev(&userspecs, us) {
+       if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
+           continue;
+       tq_foreach_rev(&us->privileges, priv) {
+           putchar('\n');
+           print_privilege(priv); /* XXX */
+           putchar('\n');
+           host_match = hostlist_matches(&priv->hostlist);
+           if (host_match == ALLOW) {
+               puts("\thost  matched");
+               tq_foreach_rev(&priv->cmndlist, cs) {
+                   runas_match = runaslist_matches(&cs->runasuserlist,
+                       &cs->runasgrouplist);
+                   if (runas_match == ALLOW) {
+                       puts("\trunas matched");
+                       cmnd_match = cmnd_matches(cs->cmnd);
+                       if (cmnd_match != UNSPEC)
+                           match = cmnd_match;
+                       printf("\tcmnd  %s\n", match == ALLOW ? "allowed" :
+                           match == DENY ? "denied" : "unmatched");
+                   }
+               }
+           } else
+               puts("\thost  unmatched");
+       }
+    }
+    printf("\nCommand %s\n", match == ALLOW ? "allowed" :
+       match == DENY ? "denied" : "unmatched");
+
+    /*
+     * Exit codes:
+     * 0 - parsed OK and command matched.
+     * 1 - parse error
+     * 2 - command not matched
+     * 3 - command denied
+     */
+    if (parse_error)
+       exit(1);
+    exit(match == ALLOW ? 0 : match + 3);
+}
+
+void
+set_runaspw(char *user)
+{
+    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);
+    }
+}
+
+void
+set_runasgr(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)
+           errorx(1, "unknown group: %s", group);
+    }
+}
+
+void
+sudo_setspent(void)
+{
+    return;
+}
+
+void
+sudo_endspent(void)
+{
+    return;
+}
+
+void
+set_fqdn(void)
+{
+    return;
+}
+
+FILE *
+open_sudoers(const char *path, int isdir, int *keepopen)
+{
+    return fopen(path, "r");
+}
+
+void
+init_envtables(void)
+{
+    return;
+}
+
+int
+set_perms(int perm)
+{
+    return 1;
+}
+
+void
+restore_perms(void)
+{
+}
+
+void
+cleanup(int gotsignal)
+{
+    if (!gotsignal) {
+       sudo_endpwent();
+       sudo_endgrent();
+    }
+}
+
+void
+print_member(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 : "");
+    }
+}
+
+void
+print_defaults(void)
+{
+    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;
+       }
+       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');
+    }
+}
+
+int
+print_alias(void *v1, void *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 if (m->type == ALL) {
+           fputs("ALL", stdout);
+       } else {
+           fputs(m->name, stdout);
+       }
+    }
+    putchar('\n');
+    return 0;
+}
+
+void
+print_privilege(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);
+           if (!tq_empty(&cs->runasuserlist) || !tq_empty(&cs->runasgrouplist)) {
+               fputs("(", stdout);
+               if (!tq_empty(&cs->runasuserlist)) {
+                   tq_foreach_fwd(&cs->runasuserlist, m) {
+                       if (m != tq_first(&cs->runasuserlist))
+                           fputs(", ", stdout);
+                       print_member(m);
+                   }  
+               } else if (tq_empty(&cs->runasgrouplist)) {
+                   fputs(def_runas_default, stdout);
+               } else {
+                   fputs(sudo_user.pw->pw_name, stdout);
+               }
+               if (!tq_empty(&cs->runasgrouplist)) {
+                   fputs(" : ", stdout);
+                   tq_foreach_fwd(&cs->runasgrouplist, m) {
+                       if (m != tq_first(&cs->runasgrouplist))
+                           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));
+       }
+    }
+}
+
+void
+print_userspecs(void)
+{
+    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');
+    }
+}
+
+static int
+testsudoers_printf(int msg_type, const char *fmt, ...)
+{
+    va_list ap;
+    FILE *fp;
+            
+    switch (msg_type) {
+    case SUDO_CONV_INFO_MSG:
+       fp = stdout;
+       break;
+    case SUDO_CONV_ERROR_MSG:
+       fp = stderr;
+       break;
+    default:
+       errno = EINVAL;
+       return -1;
+    }
+   
+    va_start(ap, fmt);
+    vfprintf(fp, fmt, ap);
+    va_end(ap);
+   
+    return 0;
+}
+
+void
+dump_sudoers(void)
+{
+    print_defaults();
+
+    putchar('\n');
+    alias_apply(print_alias, NULL);
+
+    putchar('\n');
+    print_userspecs();
+}
+
+static int testsudoers_print(const char *msg)
+{
+    return fputs(msg, stderr);
+}
+
+void
+usage(void)
+{
+    (void) fprintf(stderr, "usage: %s [-dt] [-G grfile] [-g group] [-h host] [-p pwfile] [-u user] <user> <command> [args]\n", getprogname());
+    exit(1);
+}
diff --git a/plugins/sudoers/timestr.c b/plugins/sudoers/timestr.c
new file mode 100644 (file)
index 0000000..b2df41b
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1999, 2009-2011 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 <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#include <time.h>
+
+#include "missing.h"
+
+char *get_timestr(time_t, int);
+
+/*
+ * Return an ascii string with the current date + time
+ * Uses strftime() if available, else falls back to ctime().
+ */
+char *
+get_timestr(time_t tstamp, int log_year)
+{
+    char *s;
+#ifdef HAVE_STRFTIME
+    static char buf[128];
+    struct tm *timeptr;
+
+    timeptr = localtime(&tstamp);
+    if (log_year)
+       s = "%h %e %T %Y";
+    else
+       s = "%h %e %T";
+
+    /* strftime() does not guarantee to NUL-terminate so we must check. */
+    buf[sizeof(buf) - 1] = '\0';
+    if (strftime(buf, sizeof(buf), s, timeptr) && buf[sizeof(buf) - 1] == '\0')
+       return buf;
+
+#endif /* HAVE_STRFTIME */
+
+    s = ctime(&tstamp) + 4;            /* skip day of the week */
+    if (log_year)
+       s[20] = '\0';                   /* avoid the newline */
+    else
+       s[15] = '\0';                   /* don't care about year */
+
+    return s;
+}
diff --git a/plugins/sudoers/toke.c b/plugins/sudoers/toke.c
new file mode 100644 (file)
index 0000000..7e84b56
--- /dev/null
@@ -0,0 +1,3643 @@
+#include <config.h>
+/*     $OpenBSD: flex.skl,v 1.11 2010/08/04 18:24:50 millert Exp $     */
+
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /home/cvs/openbsd/src/usr.bin/lex/flex.skl,v 1.11 2010/08/04 18:24:50 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 59
+#define YY_END_OF_BUFFER 60
+static yyconst short int yy_accept[607] =
+    {   0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,   60,   47,   55,   54,   53,   46,   58,   32,
+       48,   49,   32,   50,   47,   47,   47,   47,   52,   51,
+       58,   42,   42,   42,   42,   42,   42,   42,   42,   42,
+       42,   58,   47,   47,   55,   58,   42,   42,   42,   42,
+       42,    2,   58,    1,   47,   47,   17,   16,   17,   16,
+       16,   58,   58,   58,    3,    9,    8,    9,    4,    9,
+        5,   58,   13,   13,   13,   11,   12,   47,    0,   55,
+       53,    0,   57,    0,   47,   34,    0,   32,    0,   33,
+        0,   45,   45,    0,   47,   47,    0,   47,   47,   47,
+
+       47,    0,   37,   42,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   47,   56,   47,   55,    0,    0,    0,
+        0,    0,    0,   47,   47,   47,   47,   47,    2,    1,
+        0,    1,   43,   43,    0,   47,   17,   17,   15,   14,
+       15,    0,    0,    3,    9,    0,    6,    7,    9,    9,
+       13,    0,   13,   13,    0,   10,    0,    0,    0,   34,
+       34,    0,    0,   47,   47,   47,   47,   47,    0,    0,
+       37,   37,   42,   39,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   47,    0,    0,    0,    0,    0,
+        0,   47,   47,   47,   47,   47,    0,   47,   10,    0,
+
+       47,   47,   47,   47,   47,   47,    0,   38,   38,   38,
+        0,    0,   37,   37,   37,   37,   37,   37,   37,   42,
+       42,   42,   42,   42,   42,   42,   42,   40,   42,   41,
+       47,    0,    0,    0,    0,    0,    0,   47,   47,   47,
+       47,   47,   47,   47,    0,    0,   38,   38,   38,    0,
+       37,   37,    0,   37,   37,   37,   37,   37,   37,   37,
+       37,   37,   37,   37,    0,   25,   42,   42,   42,   42,
+       42,   42,   42,   42,   47,    0,    0,    0,    0,   47,
+       47,   47,   47,   47,   47,   47,   47,    0,   38,    0,
+       37,   37,   37,    0,    0,    0,   37,   37,   37,   37,
+
+       37,   37,   37,   37,   37,   37,   37,   37,   37,   42,
+       42,   42,   42,   42,   42,   42,   42,   47,    0,    0,
+        0,   47,   47,   47,   35,   35,   35,    0,    0,   37,
+       37,   37,   37,   37,   37,   37,    0,    0,    0,    0,
+        0,   37,   37,   37,   37,   37,   37,   37,   37,   37,
+       37,   37,   37,   37,   37,   42,   42,    0,   24,   42,
+       42,   42,   42,    0,   23,    0,   26,   47,    0,    0,
+        0,   47,   47,   47,   47,   35,   35,   35,   35,    0,
+       37,    0,   37,   37,   37,   37,   37,   37,   37,   37,
+       37,   37,   37,    0,    0,    0,   37,   37,   37,   37,
+
+       37,   37,   37,   37,   37,   37,   37,   37,   37,   42,
+       42,   42,   42,   42,   42,   44,    0,    0,    0,   47,
+       20,   43,   36,   36,   36,   36,   37,    0,    0,    0,
+       37,   37,   37,   37,   37,   37,   37,   37,   37,   37,
+       37,   37,   37,    0,    0,    0,    0,    0,   37,   37,
+       37,   37,   37,   37,   37,   37,   42,   42,   42,   42,
+        0,   22,    0,   27,    0,   20,    0,    0,   47,    0,
+       47,   47,   47,   36,   36,   36,   36,    0,    0,    0,
+        0,    0,   37,   37,   37,   37,   37,   37,   37,   37,
+       37,   37,   37,   37,   37,   37,   37,   37,   37,   37,
+
+       37,   37,    0,   30,   42,   42,   42,    0,    0,    0,
+       21,   20,    0,    0,    0,    0,    0,   20,    0,   47,
+       47,   47,    0,    0,    0,   37,   37,   37,   37,   37,
+       37,   37,   37,   37,   37,   37,   37,   37,   37,   37,
+       37,   37,   37,    0,   28,   42,   42,   21,    0,   18,
+        0,    0,   20,   47,   47,   47,   47,   47,    0,    0,
+        0,    0,    0,   37,   37,   37,   37,   37,   37,   37,
+       37,    0,   31,   42,    0,   47,   47,   47,   37,   37,
+       37,   37,   37,   37,    0,   29,    0,   47,   47,   47,
+       47,   47,   37,   37,   37,   37,   37,    0,   19,   35,
+
+       35,   35,   35,   35,   35,    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,   35,   36,   36,   37,   36,   38,   39,   40,
+       36,   41,   42,   43,   44,   45,   46,   47,   48,   36,
+       10,   49,   10,    1,   50,    1,   51,   52,   53,   54,
+
+       55,   56,   57,   57,   58,   57,   57,   59,   60,   61,
+       62,   57,   57,   63,   64,   65,   66,   57,   57,   57,
+       57,   57,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    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[67] =
+    {   0,
+        1,    2,    3,    4,    5,    6,    1,    7,    7,    1,
+        1,    8,    1,    9,   10,   11,   11,   11,   11,   11,
+       11,   11,   11,   12,   13,    7,    1,   11,   11,   11,
+       11,   11,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,   14,   15,
+       16,   16,   16,   16,   16,   16,   15,   15,   15,   15,
+       15,   15,   15,   15,   15,   15
+    } ;
+
+static yyconst short int yy_base[671] =
+    {   0,
+        0,   65,   67,   72,   99,  114,  162,  227,  292,  340,
+       86,  125, 2840, 2790, 2836, 3665, 2833, 3665,  387,   70,
+     3665, 3665, 2771, 3665,  136,  397,  133,  159, 2795, 3665,
+     3665,  453, 2781,   33,  504, 2770, 2767, 2777, 2765, 2771,
+     2754,  559,  170,   19,  165,  583,   38,   49, 2739,   68,
+     2727,   81,  219, 2771,  305,   48,    0, 3665, 2761, 3665,
+        0,  250,  639,  119,    0, 2709, 3665,  108, 3665,  112,
+     3665,  140, 2699,   98,  121, 3665,  195, 2693,  661, 2739,
+     2736, 2736, 3665,  227,  247,  300,  316,  152,  354, 2681,
+      686,  373, 2670,  711,  352,  722, 2692, 2669,  375,  414,
+
+      302, 2656,   57,  763,    0, 2628, 2625, 2614,  505, 2602,
+     2606, 2599, 2601,  202, 3665,  153,  546, 2572, 2565, 2549,
+     2537, 2524,  200,  110,  244,   28,  111,  252,  171, 2578,
+      422, 2577,  565, 2529,  818,  262,    0, 2573,  179, 3665,
+     3665,  599,  269,    0, 2513,  453, 3665, 3665, 2512,  548,
+     2490, 2533,  206,  253,  323, 2535, 2524, 2513,  607,  615,
+      306,  722,  586,  831,  867,  903,  939, 2499, 2456,  980,
+      333, 1022, 1063,    0, 2430, 2394, 2363, 2364, 2374, 2369,
+     2327, 2330, 2329, 2328,  266, 2289, 2283, 2272, 2274, 2279,
+      409,  334, 2279,  145,  335,   83,  672,  278, 2327, 2325,
+
+      627,  259, 1106, 1142,  741,  210, 2293, 2279,  683,  513,
+     2275, 2271,  352,  747, 1178,  780,  788, 1220,  815, 2270,
+      400,  325, 2261, 2258, 2248, 2246, 2242,    0, 2240,    0,
+      489, 2223, 2213, 2198, 2211, 2198,  420,  407,  529,  490,
+      491, 1263, 1299, 1335, 2235, 2234,  839, 2234, 2232, 2228,
+     2226,  528,  848,  657,  856,  665, 1371,    0,  877, 1382,
+      886,  894, 1424,  913,  570, 3665, 2208, 2197, 2198, 2177,
+     2184, 2193, 2190, 2169,  558, 2145, 2098, 2099,  648,  626,
+      530,  559,  923,  336, 1467, 1503,  964, 2138, 2137, 2108,
+     2086, 1537,  551, 1000, 1041, 1082,  653,  694,  797, 1049,
+
+      923, 1580,    0, 1116, 1591, 1090, 1008, 1633, 1125, 2069,
+     2065,  747,  686, 2046, 2005,  786,  926,  905, 2014, 1982,
+      679,  634,  544,  915, 1675, 1710, 1745, 2015, 1978, 1962,
+     1150, 1781, 1158, 1133, 1822, 1197, 1166, 1954, 1239, 1273,
+     1207,  950,  951,  962,  991, 1247, 1073, 1865,    0, 1283,
+     1876, 1307, 1315, 1918, 1323, 1923, 1923, 1188, 3665, 1924,
+     1898, 1893, 1873, 1286, 3665, 1336, 3665,  707, 1790, 1783,
+      786,  930,  764, 1298, 1358, 1041, 1960, 1995, 1400, 1823,
+     1799, 1348,  708, 1406, 1348, 2031,    0,  559, 2042, 1441,
+     1449, 2083, 1477, 1487, 1513, 1523, 1230, 1290, 1458, 1548,
+
+     1557, 1602, 2126,    0, 1613, 2137, 1650, 1565, 1660, 1765,
+     1763, 1680, 1675, 1359, 1406, 1626, 1601, 1577,  897,  938,
+     1695, 1589, 2180, 2216, 2252, 2288, 1611, 1686, 1720, 1731,
+     1563, 1478, 1504, 1694, 1524, 2324,    0,  617, 2335, 1753,
+     1761, 2376, 1769, 1798, 1550, 1808, 1841, 1851, 1335, 1358,
+     1887,  714,  825, 2419,    0,  926, 1407, 1508, 1506, 1471,
+     1547, 3665, 1616, 3665, 1423, 1731, 1907, 1512, 1575, 1910,
+     1915, 1935, 1498, 2429, 2465, 1971, 1611, 1977, 1457, 2005,
+     2015, 1987, 1408, 1254, 1732, 1782, 2059, 1842, 2501,    0,
+     1025, 2512, 2067, 2100, 2553, 2108, 2155, 2164, 2189, 1769,
+
+     1207, 1189, 1634, 3665, 1699, 1162, 1113, 1074, 1118,  384,
+     1040, 2211, 2218, 2238, 2243, 2263, 2288, 2249, 2307, 2596,
+     2632, 2668, 2304, 2354, 2395, 1025, 1006, 1889, 2016, 2362,
+     2043, 2704,    0, 1224, 2715, 2403, 2437, 2445,  992, 2454,
+     2474, 2483,  903, 1921, 3665, 1941,  839, 3665,  843, 3665,
+     1306, 2489, 2529, 2537, 1911, 2758, 2794, 2573, 2579,  811,
+     2607, 2617, 2642,  640,  629, 2109,  535,  447, 2650,    0,
+     1428, 1942, 3665, 2044, 2216, 2830, 2866, 2902, 2676, 2684,
+     2692,  337,    0,  333, 2067, 3665,  327, 2733, 1912, 2938,
+     2974, 2743, 3665, 2767, 2777, 2658, 3665,  166, 3665, 2805,
+
+     2813, 2847,   63, 2855, 2881, 3665, 3023, 3039, 3055, 3071,
+     3087, 3103, 3119, 3135, 3151, 3157, 3173, 3189, 1498, 3205,
+     3221, 3237, 3253, 3269, 3285, 3301, 3307, 3314, 3330, 3346,
+     3352, 3359, 3365, 3371, 3377, 3384, 3390, 3396, 3402, 3409,
+     3417, 3423, 3429, 3435, 3442, 3450, 3456, 3462, 3469, 3477,
+     3483, 3491, 3498, 3506, 3512, 3520, 3527, 3535, 3551, 3567,
+     3573, 3581, 3588, 3604, 3610, 3618, 3624, 3632, 1295, 3648
+    } ;
+
+static yyconst short int yy_def[671] =
+    {   0,
+      606,    1,    1,    1,  607,  607,  608,  608,  609,  609,
+      610,  610,  606,  611,  606,  606,  606,  606,  612,  613,
+      606,  606,  614,  606,  615,  611,   26,   26,  616,  606,
+      606,  606,   32,   32,   32,   35,   35,   35,   35,   35,
+       35,  611,   26,  611,  606,  612,   32,   32,   35,   35,
+       35,  606,  606,  606,  617,  611,  618,  606,  618,  606,
+      618,  606,  612,  606,  619,  620,  606,  620,  606,  620,
+      606,  621,  622,  622,  622,  606,  606,  611,  611,  606,
+      606,  623,  606,  624,  606,  613,  606,  625,  613,  614,
+      614,  615,  626,  611,  611,   26,  616,   96,   96,   96,
+
+       96,  627,  628,   35,   35,   35,   35,   35,   35,   35,
+       35,   35,   35,  611,  606,  611,  606,  606,  606,  606,
+      606,  606,  623,  611,   96,  611,  611,  611,  606,  606,
+      606,  606,  617,  629,  611,  611,  618,  618,  606,  606,
+      606,  624,  606,  619,  620,  620,  606,  606,  620,  620,
+      622,  606,  622,  622,  606,  606,  623,  630,  606,  606,
+      625,  625,  606,  611,  611,  611,   96,  167,  631,  606,
+      632,  606,  104,   35,   35,   35,   35,   35,   35,   35,
+       35,   35,   35,   35,  611,  606,  606,  606,  606,  606,
+      623,  611,  167,  611,  611,  611,  606,  611,  606,  630,
+
+      611,  611,  611,  611,  611,  611,  633,  634,  634,  209,
+      635,  634,  636,  172,  606,  215,  215,  606,  215,   35,
+       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
+      611,  606,  606,  606,  606,  606,  623,  611,  611,  611,
+      611,  611,  611,  611,  606,  637,  637,  247,  637,  638,
+      639,  640,  606,  641,  218,  641,  641,  257,  641,  606,
+      260,  260,  606,  260,  606,  606,   35,   35,   35,   35,
+       35,   35,   35,   35,  611,  606,  606,  606,  623,  611,
+      611,  611,  611,  611,  611,  611,  611,  642,  642,  643,
+      644,  606,  606,  606,  606,  606,  645,  645,  646,  263,
+
+      646,  646,  302,  646,  606,  305,  305,  606,  305,   35,
+       35,   35,   35,   35,   35,   35,   35,  611,  606,  606,
+      623,  611,  611,  611,  611,  611,  611,  606,  647,  648,
+      292,  606,  332,  332,  606,  332,  606,  606,  606,  606,
+      606,  606,  649,  649,  650,  308,  650,  650,  348,  650,
+      606,  351,  351,  606,  351,   35,   35,  606,  606,   35,
+       35,   35,   35,  606,  606,  606,  606,  611,  606,  606,
+      623,  611,  611,  611,  611,  611,  611,  611,  611,  606,
+      651,  606,  652,  335,  652,  652,  386,  386,  606,  389,
+      389,  606,  389,  606,  606,  606,  606,  653,  653,  654,
+
+      354,  654,  654,  403,  654,  606,  406,  406,  406,   35,
+       35,   35,   35,   35,   35,  611,  606,  606,  623,  611,
+      611,  611,  611,  611,  611,  611,  606,  606,  606,  606,
+      655,  655,  656,  392,  656,  656,  436,  436,  606,  439,
+      439,  606,  439,  606,  606,  606,  606,  606,  606,  657,
+      657,  658,  658,  658,  454,  454,   35,   35,   35,   35,
+      606,  606,  606,  606,  606,  606,  623,  623,  611,  659,
+      660,  611,  611,  611,  611,  611,  611,  606,  606,  606,
+      606,  606,  606,  661,  661,  662,  442,  662,  662,  489,
+      489,  606,  492,  492,  606,  492,  606,  606,  606,  606,
+
+      663,  663,  606,  606,   35,   35,   35,  606,  664,  623,
+      611,  659,  659,  659,  659,  606,  659,  660,  660,  611,
+      611,  611,  606,  606,  606,  606,  665,  665,  666,  495,
+      666,  666,  532,  532,  606,  535,  535,  535,  606,  606,
+      606,  606,  606,  606,  606,   35,   35,  606,  664,  606,
+      623,  606,  606,  611,  611,  611,  611,  611,  606,  606,
+      606,  606,  606,  606,  667,  667,  668,  668,  668,  569,
+      569,  606,  606,   35,  623,  611,  611,  611,  606,  606,
+      606,  606,  669,  669,  606,  606,  670,  611,  611,  611,
+      611,  611,  606,  606,  606,  606,  606,  670,  606,  611,
+
+      611,  611,  611,  611,  611,    0,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606
+    } ;
+
+static yyconst short int yy_nxt[3732] =
+    {   0,
+       14,   15,   16,   17,   18,   19,   20,   21,   22,   14,
+       23,   24,   14,   14,   25,   26,   27,   28,   26,   26,
+       26,   26,   26,   29,   30,   31,   14,   32,   33,   33,
+       33,   34,   35,   35,   35,   35,   36,   37,   35,   38,
+       39,   40,   41,   35,   35,   35,   35,   35,   42,   14,
+       43,   43,   43,   43,   43,   43,   14,   14,   14,   14,
+       14,   14,   14,   44,   14,   14,   45,   79,   52,  105,
+       46,  170,   53,   52,  105,   87,   79,   53,   54,  107,
+      172,   55,  129,   54,  116,  105,   55,   74,   16,   75,
+       76,  194,  130,   88,   47,   48,   79,  124,   49,  153,
+
+       15,   58,   59,  125,   60,   50,  111,   35,   51,   35,
+       60,   79,   35,  136,   35,   15,   58,   59,   89,   60,
+      143,  115,   60,   61,  154,   60,   74,   16,   75,   76,
+       56,   79,  147,  127,   77,   56,  148,   60,   61,   93,
+       93,  150,  115,   93,   93,  238,  152,   62,   99,   99,
+       99,   99,   99,   99,   99,   99,  146,   87,   79,   79,
+      146,   93,   62,   15,   16,   17,  117,   63,  599,  152,
+      192,  195,  129,   77,  100,  100,  100,  100,  100,  101,
+      143,  115,  130,   78,   94,   98,   98,   98,   98,   98,
+       98,   98,   98,   79,  118,  119,  155,  156,  120,  151,
+
+      162,   79,   83,  143,  115,  121,  185,  153,  122,  238,
+       64,   65,   65,   65,   65,   65,   65,   65,   65,   65,
+       65,   65,   65,   65,   65,   65,   65,   65,   15,   16,
+       17,  131,   63,   97,   85,   85,   85,   85,   85,   85,
+       85,   85,   85,   85,   85,   85,   85,   85,   85,   85,
+       79,  139,  115,  140,  152,  141,  154,   78,   79,  140,
+      191,  141,   85,   85,   85,   85,   85,   85,   85,   85,
+      143,  115,  201,  141,  141,   64,   65,   65,   65,   65,
+       65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
+       65,   65,   65,   15,   16,   17,   67,   63,  141,  193,
+
+       79,  152,   68,   69,   70,  606,  196,   79,  134,  134,
+       79,  606,  134,  134,   79,  198,   71,  168,  168,  168,
+      168,  168,  168,  606,  155,  156,   79,  231,  159,  599,
+      134,  160,  160,  160,  160,  160,  160,  160,  160,  241,
+       72,   15,   16,   17,   67,   63,  382,  170,   89,  283,
+       68,   69,   70,  135,  162,   86,  214,   86,   86,  267,
+      530,   86,   86,  268,   71,   86,  170,  164,  165,  166,
+      164,  164,  164,  164,  164,  214,   93,   93,   86,   86,
+       93,   93,   79,   79,   79,  240,   83,  238,   72,   83,
+      168,  168,  168,  168,  168,  168,  168,  168,   93,   84,
+
+       79,  265,   85,   85,   85,   85,   85,   85,   85,   85,
+       95,   83,   96,   96,   96,   96,   96,   96,   96,   96,
+       97,   94,   83,  266,   98,   98,   98,   98,   98,  168,
+      168,  168,  168,  168,  168,  168,  168,   85,   85,   85,
+       85,   85,   85,   85,   85,   79,  551,   98,   98,   98,
+       98,   98,   98,   78,  145,   79,  280,  145,  145,   78,
+      606,  237,   78,   78,  145,   78,   78,   78,  104,  104,
+      104,  104,  104,  104,  104,  104,   97,  145,  279,   78,
+      104,  104,  104,  104,  104,  105,  105,  105,  105,  106,
+      105,  105,  105,  105,  105,  105,  105,  105,  105,  105,
+
+      105,   79,  105,   98,   98,   98,   98,   98,   98,   78,
+       78,   78,   78,   78,   78,   78,   78,   78,   78,  105,
+      105,  105,  105,  105,  105,  105,  105,  606,  249,  249,
+      249,  105,  105,  105,  105,  105,  177,   79,   79,   79,
+      105,  178,  170,  275,  179,  282,  180,  117,  382,  143,
+      115,  214,   97,  238,   78,   78,   78,   78,   78,   78,
+      114,  115,   78,   78,   78,  170,   78,   78,  134,  134,
+       78,  265,  134,  134,  214,  118,  119,   79,   79,  120,
+      431,  431,   78,   78,   78,   83,  121,   93,  323,  122,
+      134,   93,   79,  266,  281,   84,  146,   93,   85,   85,
+
+       85,   85,   85,   85,   85,   85,   79,   79,  373,   93,
+       93,  318,  324,  135,  606,  606,  606,  606,  606,  606,
+      606,  606,  160,  160,  160,  160,  160,  160,  160,  160,
+      160,  160,  160,  160,  160,  160,  160,  160,  484,  484,
+      123,   83,  242,  243,  244,  242,  242,  242,  242,  242,
+       83,  142,  530,  322,  606,  606,  606,  606,  606,  606,
+      606,  606,   78,  487,   78,   78,   78,  170,   78,   78,
+      253,  170,   78,  134,   79,   79,  255,  134,  606,  170,
+      255,   83,   79,  134,   78,   78,   78,   90,  255,   90,
+       90,   90,  372,   90,   90,  134,  134,   90,  247,  247,
+
+      248,  249,  249,  249,  249,  249,  211,  253,  170,   90,
+       90,   90,   92,  321,   78,   78,   92,  255,   78,   78,
+      360,  382,   92,  161,  361,  161,  161,  253,  170,  161,
+      161,  384,  371,  161,   92,   92,   78,  167,  167,  167,
+      167,  167,  167,  167,  167,  161,  161,  161,  358,  167,
+      167,  167,  167,  167,  201,   79,  202,  202,  202,  202,
+      202,  202,  219,  219,  219,  219,  219,  219,  219,  219,
+      359,  416,  167,  167,  167,  167,  167,  167,  173,  173,
+      173,  173,  173,  173,  173,  173,   97,  364,   83,   79,
+      173,  173,  173,  173,  173,  257,  257,  257,  257,  257,
+
+      257,  257,  257,  258,  258,  258,  258,  258,  259,  365,
+      253,  170,   79,  167,  167,  167,  167,  167,  167,  133,
+      300,   78,   78,  133,  559,   78,   78,  421,  606,  133,
+      256,  256,  256,  256,  256,  256,  256,  256,  606,  170,
+      419,  133,  133,   78,  201,  550,  202,  202,  202,  202,
+      202,  202,  202,  202,  289,  289,  289,  289,  289,  289,
+      289,  289,  211,  294,  295,  296,  294,  294,  294,  294,
+      294,  264,  264,  264,  264,  264,  264,  264,  264,   79,
+      201,  574,  203,  203,  203,  203,  203,  203,  203,  203,
+      253,  170,  298,  298,  298,  298,  298,  298,  467,   83,
+
+      255,  302,  302,  302,  302,  302,  302,  302,  302,  303,
+      303,  303,  303,  303,  304,   79,  201,  170,  204,  204,
+      204,  204,  204,  205,  202,  202,  606,  366,  301,  301,
+      301,  301,  301,  301,  301,  301,  606,  170,  325,  326,
+      327,  325,  325,  325,  325,  325,  300,  501,  501,  367,
+      468,   79,   78,   79,  206,  206,  206,  206,  206,  206,
+      206,  206,  368,   79,  170,  170,  206,  206,  206,  206,
+      206,   79,  374,  255,  300,  253,  170,  283,   79,  284,
+      284,  284,  284,  284,  284,  300,   79,  420,  469,  206,
+      206,  206,  206,  206,  206,  208,  209,  210,  210,  210,
+
+      210,  210,  210,  211,  253,  170,  170,  212,  212,  212,
+      212,  212,   79,  337,  346,  338,  338,  338,  338,  338,
+      338,  338,  338,  349,  349,  349,  349,  349,  350,  487,
+      212,  212,  212,  212,  212,  212,  170,  215,  216,  217,
+      215,  215,  215,  215,  215,  218,  527,  527,  434,  219,
+      219,  219,  219,  219,  337,  375,  339,  339,  339,  339,
+      339,  339,  339,  339,  309,  309,  309,  309,  309,  309,
+      309,  309,  219,  219,  219,  219,  219,  219,  220,  220,
+      220,  220,  220,  220,  220,  220,  606,  170,   79,   79,
+      220,  220,  220,  220,  220,  337,  346,  340,  340,  340,
+
+      340,  340,  341,  338,  338,  348,  348,  348,  348,  348,
+      348,  348,  348,  206,  206,  206,  206,  206,  206,  201,
+      550,  202,  202,  202,  202,  202,  202,  202,  202,  253,
+      170,  344,  344,  344,  344,  344,  344,  548,  606,  300,
+      347,  347,  347,  347,  347,  347,  347,  347,  387,  387,
+      387,  387,  387,  388,   79,  201,  547,  202,  202,  202,
+      202,  202,  202,  202,  202,  336,  336,  336,  336,  336,
+      336,  336,  336,  386,  386,  386,  386,  386,  386,  386,
+      386,  394,  395,  396,  394,  394,  394,  394,  394,  358,
+       79,  253,  170,  254,  254,  254,  254,  254,  254,  254,
+
+      254,  255,  253,  170,  546,  256,  256,  256,  256,  256,
+      606,  359,  385,  385,  385,  385,  385,  385,  385,  385,
+      337,  170,  338,  338,  338,  338,  338,  338,  256,  256,
+      256,  256,  256,  256,  170,  260,  261,  262,  260,  260,
+      260,  260,  260,  263,  170,  565,  565,  264,  264,  264,
+      264,  264,  337,  300,  338,  338,  338,  338,  338,  338,
+      338,  338,  355,  355,  355,  355,  355,  355,  355,  355,
+      264,  264,  264,  264,  264,  264,  283,  434,  284,  284,
+      284,  284,  284,  284,  284,  284,  337,  364,  338,  338,
+      338,  338,  338,  338,  338,  338,  253,  170,  399,  399,
+
+      399,  399,  399,  399,  170,  597,  346,  575,   83,  365,
+      597,   79,  283,  346,  285,  285,  285,  285,  285,  285,
+      285,  285,  403,  403,  403,  403,  403,  403,  403,  403,
+      404,  404,  404,  404,  404,  405,  606,  366,  402,  402,
+      402,  402,  402,  402,  402,  402,   79,   79,  283,  170,
+      286,  286,  286,  286,  286,  287,  284,  284,  346,  367,
+      461,  606,  422,  428,  429,  430,  428,  428,  428,  428,
+      428,  384,  170,  423,  424,  425,  426,  423,  423,  423,
+      423,  401,  462,   79,  253,  170,  298,  298,  298,  298,
+      298,  298,  298,  298,  255,  253,  170,  299,  299,  299,
+
+      299,  299,  299,  299,  299,  300,   79,  463,  503,  301,
+      301,  301,  301,  301,  375,  376,  376,  376,  376,  376,
+      376,  393,  393,  393,  393,  393,  393,  393,  393,  464,
+      504,  384,  301,  301,  301,  301,  301,  301,  170,  305,
+      306,  307,  305,  305,  305,  305,  305,  308,   79,  583,
+      583,  309,  309,  309,  309,  309,  436,  436,  436,  436,
+      436,  436,  436,  436,  437,  437,  437,  437,  437,  438,
+      478,  253,  170,  508,  309,  309,  309,  309,  309,  309,
+      283,  346,  284,  284,  284,  284,  284,  284,  284,  284,
+      606,  382,  435,  435,  435,  435,  435,  435,  435,  435,
+
+      444,  384,  445,  445,  445,  445,  445,  445,  445,  445,
+      507,  472,  144,  144,   83,   79,  283,  382,  284,  284,
+      284,  284,  284,  284,  284,  284,  444,  434,  446,  446,
+      446,  446,  446,  446,  446,  446,  444,  606,  447,  447,
+      447,  447,  447,  448,  445,  445,   79,  434,  461,  506,
+      505,   79,  332,  333,  334,  332,  332,  332,  332,  332,
+      335,  253,  170,  444,  336,  336,  336,  336,  336,  510,
+      462,  401,  409,  409,  409,  409,  409,  409,  409,  409,
+      455,  455,  455,  455,  455,  456,  384,  336,  336,  336,
+      336,  336,  336,  253,  170,  344,  344,  344,  344,  344,
+
+      344,  344,  344,  300,  253,  170,  345,  345,  345,  345,
+      345,  345,  345,  345,  346,  606,  170,  463,  347,  347,
+      347,  347,  347,   79,  472,  401,  253,  170,  451,  451,
+      451,  451,  451,  451,  331,  503,  401,   79,  511,  464,
+      466,  347,  347,  347,  347,  347,  347,  170,  351,  352,
+      353,  351,  351,  351,  351,  351,  354,  504,  465,   79,
+      355,  355,  355,  355,  355,  454,  454,  454,  454,  454,
+      454,  454,  454,  606,   79,  453,  453,  453,  453,  453,
+      453,  453,  453,  355,  355,  355,  355,  355,  355,  375,
+      376,  376,  376,  376,  376,  376,  376,  376,  470,  478,
+
+      544,  479,  479,  479,  479,  479,  479,  479,  479,  443,
+      443,  443,  443,  443,  443,  443,  443,  460,  470,  459,
+      470,  471,  545,   79,  375,  377,  377,  377,  377,  377,
+      377,  377,  377,  478,  470,  480,  480,  480,  480,  480,
+      480,  480,  480,   79,  478,  382,  481,  481,  481,  481,
+      481,  482,  479,  479,  470,  434,  470,  470,   79,  375,
+      378,  378,  378,  378,  378,  379,  376,  376,  489,  489,
+      489,  489,  489,  489,  489,  489,  490,  490,  490,  490,
+      490,  491,  606,  170,  488,  488,  488,  488,  488,  488,
+      488,  488,  401,   79,  382,  382,  383,  383,  383,  383,
+
+      383,  383,  383,  383,  384,  487,  458,  457,  385,  385,
+      385,  385,  385,  497,  498,  499,  497,  497,  497,  497,
+      497,  444,  331,  445,  445,  445,  445,  445,  445,  445,
+      445,  385,  385,  385,  385,  385,  385,  389,  390,  391,
+      389,  389,  389,  389,  389,  392,  251,  418,  417,  393,
+      393,  393,  393,  393,  444,  606,  445,  445,  445,  445,
+      445,  445,  445,  445,  444,  487,  445,  445,  445,  445,
+      445,  445,  393,  393,  393,  393,  393,  393,  253,  170,
+      399,  399,  399,  399,  399,  399,  399,  399,  346,  253,
+      170,  400,  400,  400,  400,  400,  400,  400,  400,  401,
+
+      253,  170,  382,  402,  402,  402,  402,  402,  467,   83,
+      401,  513,  487,  514,  515,  516,  513,  415,  514,  515,
+      516,  509,  544,  414,  554,  588,  402,  402,  402,  402,
+      402,  402,  170,  406,  407,  408,  406,  406,  406,  406,
+      406,  413,  572,  572,  545,  409,  409,  409,  409,  409,
+      520,  521,  522,  520,  520,  520,  520,  520,  517,   79,
+       79,  412,  411,  519,  573,  573,  410,  337,  409,  409,
+      409,  409,  409,  409,  375,  376,  376,  376,  376,  376,
+      376,  376,  376,   79,  472,  331,  473,  473,  473,  473,
+      473,  473,  523,  524,  525,  523,  523,  523,  523,  523,
+
+      478,  251,  479,  479,  479,  479,  479,  479,   79,  375,
+      376,  376,  376,  376,  376,  376,  376,  376,  478,   79,
+      479,  479,  479,  479,  479,  479,  479,  479,  478,  382,
+      479,  479,  479,  479,  479,  479,  479,  479,  211,  530,
+      370,  369,  363,   79,  382,  585,  432,  432,  432,  432,
+      432,  432,  432,  432,  384,  382,  606,  433,  433,  433,
+      433,  433,  433,  433,  433,  434,  530,  586,  585,  435,
+      435,  435,  435,  435,  496,  496,  496,  496,  496,  496,
+      496,  496,  532,  532,  532,  532,  532,  532,  532,  532,
+      586,  362,  435,  435,  435,  435,  435,  435,  439,  440,
+
+      441,  439,  439,  439,  439,  439,  442,  357,  356,  331,
+      443,  443,  443,  443,  443,  533,  533,  533,  533,  533,
+      534,  606,  382,  531,  531,  531,  531,  531,  531,  531,
+      531,  251,  530,  443,  443,  443,  443,  443,  443,  253,
+      170,  451,  451,  451,  451,  451,  451,  451,  451,  401,
+      253,  170,  452,  452,  452,  452,  452,  452,  452,  452,
+      211,  211,  276,  320,  453,  453,  453,  453,  453,  170,
+      539,  539,  539,  539,  539,  539,  539,  539,  170,  540,
+      540,  540,  540,  540,  540,  540,  540,  453,  453,  453,
+      453,  453,  453,  472,  319,  473,  473,  473,  473,  473,
+
+      473,  473,  473,  170,  541,  541,  541,  541,  541,  542,
+      539,  539,  606,  317,  606,  606,  606,  575,   83,  513,
+      316,  514,  515,  516,  315,  314,  313,  312,   79,  472,
+      587,  474,  474,  474,  474,  474,  474,  474,  474,  606,
+      311,  514,  515,  516,  606,  310,  606,  606,  516,  292,
+      606,  251,  606,  606,  606,  211,  288,  211,  103,  517,
+      276,  278,  276,  277,   79,  472,  517,  475,  475,  475,
+      475,  475,  476,  477,  477,  552,  276,  274,  553,  553,
+      553,  553,  553,  553,  553,  553,  517,  273,  272,  271,
+      270,  517,  269,   97,  211,  512,  512,  519,  251,  512,
+
+       79,  472,  211,  477,  477,  477,  473,  473,  473,  473,
+      473,  512,  512,  512,  518,  518,  103,  559,  518,  560,
+      560,  560,  560,  560,  560,  560,  560,   83,  199,  239,
+      518,  518,  518,  236,  235,  234,   79,  382,  233,  485,
+      485,  485,  485,  485,  485,  485,  485,  434,  382,  232,
+      486,  486,  486,  486,  486,  486,  486,  486,  487,  230,
+      229,  228,  488,  488,  488,  488,  488,  559,  227,  561,
+      561,  561,  561,  561,  561,  561,  561,  538,  538,  538,
+      538,  538,  538,  538,  538,  488,  488,  488,  488,  488,
+      488,  492,  493,  494,  492,  492,  492,  492,  492,  495,
+
+      226,  225,  224,  496,  496,  496,  496,  496,  559,  223,
+      562,  562,  562,  562,  562,  563,  560,  560,  569,  569,
+      569,  569,  569,  569,  569,  569,  496,  496,  496,  496,
+      496,  496,  253,  170,  502,  502,  502,  502,  502,  502,
+      502,  502,  472,  222,  473,  473,  473,  473,  473,  473,
+      473,  473,  570,  570,  570,  570,  570,  571,  606,  221,
+      568,  568,  568,  568,  568,  568,  568,  568,  170,  539,
+      539,  539,  539,  539,  539,  539,  539,   79,  472,  103,
+      473,  473,  473,  473,  473,  473,  473,  473,  170,  539,
+      539,  539,  539,  539,  539,  539,  539,  170,  539,  539,
+
+      539,  539,  539,  539,  553,  553,  553,  553,  553,  553,
+      553,  553,   95,   79,  382,   83,  528,  528,  528,  528,
+      528,  528,  528,  528,  487,  382,   83,  529,  529,  529,
+      529,  529,  529,  529,  529,  530,  199,  151,  152,  531,
+      531,  531,  531,  531,  553,  553,  553,  553,  553,  553,
+      553,  553,  576,  577,  578,  576,  576,  576,  576,  576,
+      146,  146,  531,  531,  531,  531,  531,  531,  535,  536,
+      537,  535,  535,  535,  535,  535,  138,  197,  132,  132,
+      538,  538,  538,  538,  538,   79,  554,  190,  555,  555,
+      555,  555,  555,  555,  579,  580,  581,  579,  579,  579,
+
+      579,  579,  189,  538,  538,  538,  538,  538,  538,  554,
+      188,  555,  555,  555,  555,  555,  555,  555,  555,  187,
+      559,   79,  560,  560,  560,  560,  560,  560,  560,  560,
+      559,  186,  560,  560,  560,  560,  560,  560,  560,  560,
+      184,  183,  182,  181,   79,  554,  176,  556,  556,  556,
+      556,  556,  556,  556,  556,  559,  175,  560,  560,  560,
+      560,  560,  560,  382,  174,  584,  584,  584,  584,  584,
+      584,  584,  584,  593,  593,  593,  593,  593,  593,  103,
+       79,  554,   78,  557,  557,  557,  557,  557,  558,  555,
+      555,  593,  593,  593,  593,  593,  593,  593,  593,  594,
+
+      594,  594,  594,  594,  594,  594,  594,  595,  595,  595,
+      595,  595,  596,  593,  593,  103,   79,  382,  163,  566,
+      566,  566,  566,  566,  566,  566,  566,  530,  382,   91,
+      567,  567,  567,  567,  567,  567,  567,  567,   83,   81,
+       80,   79,  568,  568,  568,  568,  568,  152,  600,  601,
+      602,  600,  600,  600,  600,  600,  588,  146,  589,  589,
+      589,  589,  589,  589,  138,  568,  568,  568,  568,  568,
+      568,  554,  132,  555,  555,  555,  555,  555,  555,  555,
+      555,   79,  593,  593,  593,  593,  593,  593,  593,  593,
+      128,   79,  593,  593,  593,  593,  593,  593,  593,  593,
+
+      126,  113,  112,  111,  110,  109,   79,  554,  108,  555,
+      555,  555,  555,  555,  555,  555,  555,  105,  103,   91,
+      603,  603,  603,  603,  603,  603,  603,  603,  600,  600,
+      600,  600,  600,  600,  600,  600,   81,   80,   79,  606,
+      606,  606,   79,  588,  606,  589,  589,  589,  589,  589,
+      589,  589,  589,   79,  606,  606,  606,  606,  606,  606,
+      606,   79,  604,  604,  604,  604,  604,  605,  603,  603,
+      603,  603,  603,  603,  603,  603,  603,  603,   79,  588,
+      606,  590,  590,  590,  590,  590,  590,  590,  590,  606,
+      606,  606,  606,  606,  606,   79,  603,  603,  603,  603,
+
+      603,  603,  606,   79,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,   79,  588,  606,  591,  591,  591,
+      591,  591,  592,  589,  589,  606,  606,  606,  606,   79,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+       79,  588,  606,  589,  589,  589,  589,  589,  589,  589,
+      589,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,   79,  588,  606,  589,
+      589,  589,  589,  589,  589,  589,  589,  606,  606,  606,
+
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,   79,   57,   57,   57,   57,   57,   57,   57,
+       57,   57,   57,   57,   57,   57,   57,   57,   57,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   31,   66,   66,   66,   66,   66,
+       66,   66,   66,   66,   66,   66,   66,   66,   66,   66,
+       66,   73,   73,   73,   73,   73,   73,   73,   73,   73,
+       73,   73,   73,   73,   73,   73,   73,   78,  606,  606,
+      606,  606,  606,  606,  606,   78,   78,   78,  606,  606,
+
+       78,   78,   78,   82,   82,   82,   82,   82,   82,   82,
+       82,   82,   82,   82,   82,   82,   82,   82,   82,   86,
+      606,  606,  606,  606,   86,  606,  606,   86,   86,   86,
+       86,  606,   86,   86,   86,   90,  606,  606,  606,  606,
+      606,  606,  606,   90,   90,   90,  606,  606,   90,   90,
+       90,   92,  606,  606,   92,   92,  606,   92,  606,   92,
+       92,   92,  606,  606,   92,   92,   92,  102,  102,  606,
+      606,  606,  102,  133,  606,  606,  133,  133,  606,  133,
+      606,  133,  133,  133,  606,  606,  133,  133,  133,  137,
+      606,  606,  137,  137,  606,  137,  606,  137,  137,  137,
+
+      606,  137,  606,  137,  137,  145,  606,  606,  145,  606,
+      606,  145,  606,  145,  145,  145,  145,  606,  145,  145,
+      145,  149,  149,  149,  149,  149,  149,  149,  149,  149,
+      149,  149,  149,  149,  149,  149,  149,  151,  151,  606,
+      151,  606,  151,  151,  151,  151,  151,  151,  151,  151,
+      151,  151,  151,  157,  157,  157,  157,  157,  157,  157,
+      157,  157,  157,  157,  157,  157,  157,  157,  157,  158,
+      158,  606,  158,  158,  158,  158,  158,  158,  158,  158,
+      158,  158,  158,  158,  158,  161,  606,  606,  606,  606,
+      161,  606,  606,  161,  161,  161,  606,  606,  161,  161,
+
+      161,   93,  606,  606,   93,   93,  606,   93,  606,   93,
+       93,   93,  606,  606,   93,   93,   93,  169,  169,  606,
+      606,  606,  169,  171,  171,  171,  606,  606,  606,  171,
+      134,  606,  606,  134,  134,  606,  134,  606,  134,  134,
+      134,  606,  606,  134,  134,  134,  200,  200,  200,  200,
+      200,  200,  200,  200,  200,  200,  200,  200,  200,  200,
+      200,  200,  207,  207,  606,  606,  606,  207,  213,  213,
+      213,  606,  606,  606,  213,  245,  245,  606,  606,  606,
+      245,  246,  246,  606,  606,  606,  246,  250,  250,  606,
+      606,  606,  250,  252,  252,  252,  606,  606,  606,  252,
+
+      288,  288,  606,  606,  606,  288,  290,  290,  606,  606,
+      606,  290,  291,  291,  606,  606,  606,  291,  293,  293,
+      293,  606,  606,  606,  293,  297,  297,  297,  297,  606,
+      606,  606,  297,  328,  328,  606,  606,  606,  328,  329,
+      329,  606,  606,  606,  329,  330,  330,  606,  606,  606,
+      330,  342,  342,  342,  606,  606,  606,  342,  343,  343,
+      343,  343,  606,  606,  606,  343,  380,  380,  606,  606,
+      606,  380,  381,  381,  606,  606,  606,  381,  397,  397,
+      397,  606,  606,  606,  397,  398,  398,  398,  398,  606,
+      606,  606,  398,  427,  427,  606,  606,  606,  427,  431,
+
+      606,  431,  431,  606,  606,  606,  431,  449,  449,  449,
+      606,  606,  606,  449,  450,  450,  450,  450,  606,  606,
+      606,  450,  483,  483,  606,  606,  606,  483,  484,  606,
+      484,  484,  606,  606,  606,  484,  500,  500,  500,  606,
+      606,  606,  500,  501,  501,  501,  606,  606,  606,  606,
+      501,  512,  512,  606,  512,  512,  512,  606,  606,  512,
+      512,  512,  606,  606,  512,  512,  512,  518,  518,  606,
+      518,  518,  518,  606,  606,  518,  518,  518,  606,  606,
+      518,  518,  518,  526,  526,  606,  606,  606,  526,  527,
+      606,  527,  527,  606,  606,  606,  527,  543,  543,  606,
+
+      606,  606,  606,  543,  549,  549,  549,  549,  549,  549,
+      549,  549,  549,  549,  549,  549,  549,  549,  549,  549,
+      564,  564,  606,  606,  606,  564,  565,  606,  565,  565,
+      606,  606,  606,  565,  582,  582,  606,  606,  606,  582,
+      583,  606,  583,  606,  606,  606,  606,  583,  598,  598,
+      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
+      598,  598,  598,  598,   13,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606
+    } ;
+
+static yyconst short int yy_chk[3732] =
+    {   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,    1,    1,    1,    1,    2,   44,    3,   34,
+        2,  103,    3,    4,   47,   20,  126,    4,    3,   34,
+      103,    3,   52,    4,   44,   48,    4,   11,   11,   11,
+       11,  126,   52,   20,    2,    2,   56,   47,    2,   74,
+
+        5,    5,    5,   48,    5,    2,   50,    3,    2,    3,
+        5,  603,    4,   56,    4,    6,    6,    6,   20,    6,
+       64,   64,    5,    5,   75,    6,   12,   12,   12,   12,
+        3,  196,   68,   50,   11,    4,   70,    6,    6,   25,
+       25,   72,   72,   25,   25,  196,   74,    5,   27,   27,
+       27,   27,   27,   27,   27,   27,   68,   88,  124,  127,
+       70,   25,    6,    7,    7,    7,   45,    7,  598,   75,
+      124,  127,  129,   12,   28,   28,   28,   28,   28,   28,
+      139,  139,  129,   43,   25,   43,   43,   43,   43,   43,
+       43,   43,   43,  194,   45,   45,   77,   77,   45,   77,
+
+       88,  116,  123,  114,  114,   45,  116,  153,   45,  194,
+        7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
+        7,    7,    7,    7,    7,    7,    7,    7,    8,    8,
+        8,   53,    8,  206,   53,   53,   53,   53,   53,   53,
+       53,   53,   84,   84,   84,   84,   84,   84,   84,   84,
+      114,   62,   62,   62,  153,   62,  154,  125,  206,   62,
+      123,   62,   85,   85,   85,   85,   85,   85,   85,   85,
+      143,  143,  202,   62,   62,    8,    8,    8,    8,    8,
+        8,    8,    8,    8,    8,    8,    8,    8,    8,    8,
+        8,    8,    8,    9,    9,    9,    9,    9,   62,  125,
+
+      128,  154,    9,    9,    9,   86,  128,  202,   55,   55,
+      136,  161,   55,   55,  185,  136,    9,  101,  101,  101,
+      101,  101,  101,   86,  155,  155,  198,  185,   87,  587,
+       55,   87,   87,   87,   87,   87,   87,   87,   87,  198,
+        9,   10,   10,   10,   10,   10,  584,  171,   86,  284,
+       10,   10,   10,   55,  161,   89,  171,   89,   89,  222,
+      582,   89,   89,  222,   10,   89,  213,   95,   95,   95,
+       95,   95,   95,   95,   95,  213,   92,   92,   89,   89,
+       92,   92,  192,  195,  284,  195,  510,  192,   10,   19,
+       99,   99,   99,   99,   99,   99,   99,   99,   92,   19,
+
+       95,  221,   19,   19,   19,   19,   19,   19,   19,   19,
+       26,  191,   26,   26,   26,   26,   26,   26,   26,   26,
+       26,   92,  237,  221,   26,   26,   26,   26,   26,  100,
+      100,  100,  100,  100,  100,  100,  100,  131,  131,  131,
+      131,  131,  131,  131,  131,   26,  510,   26,   26,   26,
+       26,   26,   26,   32,  146,  238,  238,  146,  146,   32,
+      568,  191,   32,   32,  146,   32,   32,   32,   32,   32,
+       32,   32,   32,   32,   32,   32,   32,  146,  237,   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,   32,   32,   32,   32,   32,   32,   35,
+       35,   35,   35,   35,   35,   35,   35,   35,  210,  210,
+      210,   35,   35,   35,   35,   35,  109,  231,  240,  241,
+       35,  109,  252,  231,  109,  241,  109,  117,  567,  150,
+      150,  252,  239,  240,   35,   35,   35,   35,   35,   35,
+       42,   42,   42,   42,   42,  293,   42,   42,  133,  133,
+       42,  265,  133,  133,  293,  117,  117,  239,  281,  117,
+      388,  388,   42,   42,   42,   46,  117,  163,  281,  117,
+      133,  163,  323,  265,  239,   46,  150,  163,   46,   46,
+
+       46,   46,   46,   46,   46,   46,  275,  282,  323,  163,
+      163,  275,  282,  133,  142,  142,  142,  142,  142,  142,
+      142,  142,  159,  159,  159,  159,  159,  159,  159,  159,
+      160,  160,  160,  160,  160,  160,  160,  160,  438,  438,
+       46,   63,  201,  201,  201,  201,  201,  201,  201,  201,
+      279,   63,  565,  280,   63,   63,   63,   63,   63,   63,
+       63,   63,   79,  564,   79,   79,   79,  297,   79,   79,
+      254,  254,   79,  197,  280,  201,  297,  197,  256,  256,
+      254,  321,  322,  197,   79,   79,   79,   91,  256,   91,
+       91,   91,  322,   91,   91,  197,  197,   91,  209,  209,
+
+      209,  209,  209,  209,  209,  209,  209,  298,  298,   91,
+       91,   91,   94,  279,   94,   94,   94,  298,   94,   94,
+      313,  383,   94,  162,  313,  162,  162,  452,  452,  162,
+      162,  383,  321,  162,   94,   94,   94,   96,   96,   96,
+       96,   96,   96,   96,   96,  162,  162,  162,  312,   96,
+       96,   96,   96,   96,  205,  368,  205,  205,  205,  205,
+      205,  205,  214,  214,  214,  214,  214,  214,  214,  214,
+      312,  368,   96,   96,   96,   96,   96,   96,  104,  104,
+      104,  104,  104,  104,  104,  104,  104,  316,  371,  205,
+      104,  104,  104,  104,  104,  216,  216,  216,  216,  216,
+
+      216,  216,  216,  217,  217,  217,  217,  217,  217,  316,
+      299,  299,  373,  104,  104,  104,  104,  104,  104,  135,
+      299,  135,  135,  135,  560,  135,  135,  373,  219,  135,
+      219,  219,  219,  219,  219,  219,  219,  219,  453,  453,
+      371,  135,  135,  135,  164,  549,  164,  164,  164,  164,
+      164,  164,  164,  164,  247,  247,  247,  247,  247,  247,
+      247,  247,  247,  253,  253,  253,  253,  253,  253,  253,
+      253,  255,  255,  255,  255,  255,  255,  255,  255,  164,
+      165,  547,  165,  165,  165,  165,  165,  165,  165,  165,
+      259,  259,  259,  259,  259,  259,  259,  259,  419,  419,
+
+      259,  261,  261,  261,  261,  261,  261,  261,  261,  262,
+      262,  262,  262,  262,  262,  165,  166,  543,  166,  166,
+      166,  166,  166,  166,  166,  166,  264,  317,  264,  264,
+      264,  264,  264,  264,  264,  264,  301,  301,  283,  283,
+      283,  283,  283,  283,  283,  283,  301,  456,  456,  317,
+      419,  166,  167,  318,  167,  167,  167,  167,  167,  167,
+      167,  167,  318,  324,  342,  343,  167,  167,  167,  167,
+      167,  283,  324,  342,  343,  344,  344,  287,  372,  287,
+      287,  287,  287,  287,  287,  344,  420,  372,  420,  167,
+      167,  167,  167,  167,  167,  170,  170,  170,  170,  170,
+
+      170,  170,  170,  170,  345,  345,  539,  170,  170,  170,
+      170,  170,  287,  294,  345,  294,  294,  294,  294,  294,
+      294,  294,  294,  307,  307,  307,  307,  307,  307,  527,
+      170,  170,  170,  170,  170,  170,  172,  172,  172,  172,
+      172,  172,  172,  172,  172,  172,  491,  491,  526,  172,
+      172,  172,  172,  172,  295,  376,  295,  295,  295,  295,
+      295,  295,  295,  295,  300,  300,  300,  300,  300,  300,
+      300,  300,  172,  172,  172,  172,  172,  172,  173,  173,
+      173,  173,  173,  173,  173,  173,  347,  347,  511,  376,
+      173,  173,  173,  173,  173,  296,  347,  296,  296,  296,
+
+      296,  296,  296,  296,  296,  306,  306,  306,  306,  306,
+      306,  306,  306,  173,  173,  173,  173,  173,  173,  203,
+      509,  203,  203,  203,  203,  203,  203,  203,  203,  304,
+      304,  304,  304,  304,  304,  304,  304,  508,  309,  304,
+      309,  309,  309,  309,  309,  309,  309,  309,  334,  334,
+      334,  334,  334,  334,  203,  204,  507,  204,  204,  204,
+      204,  204,  204,  204,  204,  331,  331,  331,  331,  331,
+      331,  331,  331,  333,  333,  333,  333,  333,  333,  333,
+      333,  337,  337,  337,  337,  337,  337,  337,  337,  358,
+      204,  215,  215,  215,  215,  215,  215,  215,  215,  215,
+
+      215,  215,  502,  502,  506,  215,  215,  215,  215,  215,
+      336,  358,  336,  336,  336,  336,  336,  336,  336,  336,
+      341,  501,  341,  341,  341,  341,  341,  341,  215,  215,
+      215,  215,  215,  215,  218,  218,  218,  218,  218,  218,
+      218,  218,  218,  218,  397,  534,  534,  218,  218,  218,
+      218,  218,  339,  397,  339,  339,  339,  339,  339,  339,
+      339,  339,  346,  346,  346,  346,  346,  346,  346,  346,
+      218,  218,  218,  218,  218,  218,  242,  484,  242,  242,
+      242,  242,  242,  242,  242,  242,  340,  364,  340,  340,
+      340,  340,  340,  340,  340,  340,  350,  350,  350,  350,
+
+      350,  350,  350,  350,  398,  669,  350,  551,  551,  364,
+      669,  242,  243,  398,  243,  243,  243,  243,  243,  243,
+      243,  243,  352,  352,  352,  352,  352,  352,  352,  352,
+      353,  353,  353,  353,  353,  353,  355,  366,  355,  355,
+      355,  355,  355,  355,  355,  355,  374,  243,  244,  449,
+      244,  244,  244,  244,  244,  244,  244,  244,  449,  366,
+      414,  385,  374,  382,  382,  382,  382,  382,  382,  382,
+      382,  385,  450,  375,  375,  375,  375,  375,  375,  375,
+      375,  450,  414,  244,  257,  257,  257,  257,  257,  257,
+      257,  257,  257,  257,  257,  260,  260,  260,  260,  260,
+
+      260,  260,  260,  260,  260,  260,  375,  415,  457,  260,
+      260,  260,  260,  260,  379,  379,  379,  379,  379,  379,
+      379,  384,  384,  384,  384,  384,  384,  384,  384,  415,
+      457,  483,  260,  260,  260,  260,  260,  260,  263,  263,
+      263,  263,  263,  263,  263,  263,  263,  263,  379,  571,
+      571,  263,  263,  263,  263,  263,  390,  390,  390,  390,
+      390,  390,  390,  390,  391,  391,  391,  391,  391,  391,
+      479,  399,  399,  465,  263,  263,  263,  263,  263,  263,
+      285,  399,  285,  285,  285,  285,  285,  285,  285,  285,
+      393,  432,  393,  393,  393,  393,  393,  393,  393,  393,
+
+      394,  432,  394,  394,  394,  394,  394,  394,  394,  394,
+      460,  473,  619,  619,  468,  285,  286,  433,  286,  286,
+      286,  286,  286,  286,  286,  286,  395,  433,  395,  395,
+      395,  395,  395,  395,  395,  395,  396,  435,  396,  396,
+      396,  396,  396,  396,  396,  396,  473,  435,  461,  459,
+      458,  286,  292,  292,  292,  292,  292,  292,  292,  292,
+      292,  400,  400,  445,  292,  292,  292,  292,  292,  468,
+      461,  400,  401,  401,  401,  401,  401,  401,  401,  401,
+      408,  408,  408,  408,  408,  408,  431,  292,  292,  292,
+      292,  292,  292,  302,  302,  302,  302,  302,  302,  302,
+
+      302,  302,  302,  302,  305,  305,  305,  305,  305,  305,
+      305,  305,  305,  305,  305,  402,  402,  463,  305,  305,
+      305,  305,  305,  469,  477,  402,  405,  405,  405,  405,
+      405,  405,  405,  405,  427,  503,  405,  422,  469,  463,
+      418,  305,  305,  305,  305,  305,  305,  308,  308,  308,
+      308,  308,  308,  308,  308,  308,  308,  503,  417,  477,
+      308,  308,  308,  308,  308,  407,  407,  407,  407,  407,
+      407,  407,  407,  409,  416,  409,  409,  409,  409,  409,
+      409,  409,  409,  308,  308,  308,  308,  308,  308,  325,
+      325,  325,  325,  325,  325,  325,  325,  325,  421,  428,
+
+      505,  428,  428,  428,  428,  428,  428,  428,  428,  434,
+      434,  434,  434,  434,  434,  434,  434,  413,  421,  412,
+      421,  421,  505,  325,  326,  326,  326,  326,  326,  326,
+      326,  326,  326,  429,  466,  429,  429,  429,  429,  429,
+      429,  429,  429,  421,  430,  485,  430,  430,  430,  430,
+      430,  430,  430,  430,  466,  485,  466,  466,  326,  327,
+      327,  327,  327,  327,  327,  327,  327,  327,  440,  440,
+      440,  440,  440,  440,  440,  440,  441,  441,  441,  441,
+      441,  441,  443,  500,  443,  443,  443,  443,  443,  443,
+      443,  443,  500,  327,  332,  486,  332,  332,  332,  332,
+
+      332,  332,  332,  332,  332,  486,  411,  410,  332,  332,
+      332,  332,  332,  444,  444,  444,  444,  444,  444,  444,
+      444,  446,  381,  446,  446,  446,  446,  446,  446,  446,
+      446,  332,  332,  332,  332,  332,  332,  335,  335,  335,
+      335,  335,  335,  335,  335,  335,  380,  370,  369,  335,
+      335,  335,  335,  335,  447,  488,  447,  447,  447,  447,
+      447,  447,  447,  447,  448,  488,  448,  448,  448,  448,
+      448,  448,  335,  335,  335,  335,  335,  335,  348,  348,
+      348,  348,  348,  348,  348,  348,  348,  348,  348,  351,
+      351,  351,  351,  351,  351,  351,  351,  351,  351,  351,
+
+      451,  451,  528,  351,  351,  351,  351,  351,  467,  467,
+      451,  470,  528,  470,  470,  470,  471,  363,  471,  471,
+      471,  467,  544,  362,  555,  589,  351,  351,  351,  351,
+      351,  351,  354,  354,  354,  354,  354,  354,  354,  354,
+      354,  361,  546,  572,  544,  354,  354,  354,  354,  354,
+      472,  472,  472,  472,  472,  472,  472,  472,  470,  555,
+      589,  360,  357,  471,  546,  572,  356,  338,  354,  354,
+      354,  354,  354,  354,  377,  377,  377,  377,  377,  377,
+      377,  377,  377,  472,  476,  330,  476,  476,  476,  476,
+      476,  476,  478,  478,  478,  478,  478,  478,  478,  478,
+
+      482,  329,  482,  482,  482,  482,  482,  482,  377,  378,
+      378,  378,  378,  378,  378,  378,  378,  378,  480,  476,
+      480,  480,  480,  480,  480,  480,  480,  480,  481,  529,
+      481,  481,  481,  481,  481,  481,  481,  481,  328,  529,
+      320,  319,  315,  378,  386,  574,  386,  386,  386,  386,
+      386,  386,  386,  386,  386,  389,  531,  389,  389,  389,
+      389,  389,  389,  389,  389,  389,  531,  574,  585,  389,
+      389,  389,  389,  389,  487,  487,  487,  487,  487,  487,
+      487,  487,  493,  493,  493,  493,  493,  493,  493,  493,
+      585,  314,  389,  389,  389,  389,  389,  389,  392,  392,
+
+      392,  392,  392,  392,  392,  392,  392,  311,  310,  291,
+      392,  392,  392,  392,  392,  494,  494,  494,  494,  494,
+      494,  496,  566,  496,  496,  496,  496,  496,  496,  496,
+      496,  290,  566,  392,  392,  392,  392,  392,  392,  403,
+      403,  403,  403,  403,  403,  403,  403,  403,  403,  403,
+      406,  406,  406,  406,  406,  406,  406,  406,  406,  406,
+      289,  288,  278,  277,  406,  406,  406,  406,  406,  497,
+      497,  497,  497,  497,  497,  497,  497,  497,  498,  498,
+      498,  498,  498,  498,  498,  498,  498,  406,  406,  406,
+      406,  406,  406,  423,  276,  423,  423,  423,  423,  423,
+
+      423,  423,  423,  499,  499,  499,  499,  499,  499,  499,
+      499,  499,  512,  274,  512,  512,  512,  575,  575,  513,
+      273,  513,  513,  513,  272,  271,  270,  269,  423,  424,
+      575,  424,  424,  424,  424,  424,  424,  424,  424,  514,
+      268,  514,  514,  514,  515,  267,  515,  515,  515,  251,
+      518,  250,  518,  518,  518,  249,  248,  246,  245,  512,
+      236,  235,  234,  233,  424,  425,  513,  425,  425,  425,
+      425,  425,  425,  425,  425,  516,  232,  229,  516,  516,
+      516,  516,  516,  516,  516,  516,  514,  227,  226,  225,
+      224,  515,  223,  220,  212,  517,  517,  518,  211,  517,
+
+      425,  426,  208,  426,  426,  426,  426,  426,  426,  426,
+      426,  517,  517,  517,  519,  519,  207,  523,  519,  523,
+      523,  523,  523,  523,  523,  523,  523,  200,  199,  193,
+      519,  519,  519,  190,  189,  188,  426,  436,  187,  436,
+      436,  436,  436,  436,  436,  436,  436,  436,  439,  186,
+      439,  439,  439,  439,  439,  439,  439,  439,  439,  184,
+      183,  182,  439,  439,  439,  439,  439,  524,  181,  524,
+      524,  524,  524,  524,  524,  524,  524,  530,  530,  530,
+      530,  530,  530,  530,  530,  439,  439,  439,  439,  439,
+      439,  442,  442,  442,  442,  442,  442,  442,  442,  442,
+
+      180,  179,  178,  442,  442,  442,  442,  442,  525,  177,
+      525,  525,  525,  525,  525,  525,  525,  525,  536,  536,
+      536,  536,  536,  536,  536,  536,  442,  442,  442,  442,
+      442,  442,  454,  454,  454,  454,  454,  454,  454,  454,
+      454,  454,  474,  176,  474,  474,  474,  474,  474,  474,
+      474,  474,  537,  537,  537,  537,  537,  537,  538,  175,
+      538,  538,  538,  538,  538,  538,  538,  538,  540,  540,
+      540,  540,  540,  540,  540,  540,  540,  474,  475,  169,
+      475,  475,  475,  475,  475,  475,  475,  475,  541,  541,
+      541,  541,  541,  541,  541,  541,  541,  542,  542,  542,
+
+      542,  542,  542,  542,  552,  552,  552,  552,  552,  552,
+      552,  552,  168,  475,  489,  158,  489,  489,  489,  489,
+      489,  489,  489,  489,  489,  492,  157,  492,  492,  492,
+      492,  492,  492,  492,  492,  492,  156,  152,  151,  492,
+      492,  492,  492,  492,  553,  553,  553,  553,  553,  553,
+      553,  553,  554,  554,  554,  554,  554,  554,  554,  554,
+      149,  145,  492,  492,  492,  492,  492,  492,  495,  495,
+      495,  495,  495,  495,  495,  495,  138,  134,  132,  130,
+      495,  495,  495,  495,  495,  554,  558,  122,  558,  558,
+      558,  558,  558,  558,  559,  559,  559,  559,  559,  559,
+
+      559,  559,  121,  495,  495,  495,  495,  495,  495,  520,
+      120,  520,  520,  520,  520,  520,  520,  520,  520,  119,
+      561,  558,  561,  561,  561,  561,  561,  561,  561,  561,
+      562,  118,  562,  562,  562,  562,  562,  562,  562,  562,
+      113,  112,  111,  110,  520,  521,  108,  521,  521,  521,
+      521,  521,  521,  521,  521,  563,  107,  563,  563,  563,
+      563,  563,  563,  569,  106,  569,  569,  569,  569,  569,
+      569,  569,  569,  596,  596,  596,  596,  596,  596,  102,
+      521,  522,   98,  522,  522,  522,  522,  522,  522,  522,
+      522,  579,  579,  579,  579,  579,  579,  579,  579,  580,
+
+      580,  580,  580,  580,  580,  580,  580,  581,  581,  581,
+      581,  581,  581,  581,  581,   97,  522,  532,   93,  532,
+      532,  532,  532,  532,  532,  532,  532,  532,  535,   90,
+      535,  535,  535,  535,  535,  535,  535,  535,   82,   81,
+       80,   78,  535,  535,  535,  535,  535,   73,  588,  588,
+      588,  588,  588,  588,  588,  588,  592,   66,  592,  592,
+      592,  592,  592,  592,   59,  535,  535,  535,  535,  535,
+      535,  556,   54,  556,  556,  556,  556,  556,  556,  556,
+      556,  588,  594,  594,  594,  594,  594,  594,  594,  594,
+       51,  592,  595,  595,  595,  595,  595,  595,  595,  595,
+
+       49,   41,   40,   39,   38,   37,  556,  557,   36,  557,
+      557,  557,  557,  557,  557,  557,  557,   33,   29,   23,
+      600,  600,  600,  600,  600,  600,  600,  600,  601,  601,
+      601,  601,  601,  601,  601,  601,   17,   15,   14,   13,
+        0,    0,  557,  576,    0,  576,  576,  576,  576,  576,
+      576,  576,  576,  600,    0,    0,    0,    0,    0,    0,
+        0,  601,  602,  602,  602,  602,  602,  602,  602,  602,
+      604,  604,  604,  604,  604,  604,  604,  604,  576,  577,
+        0,  577,  577,  577,  577,  577,  577,  577,  577,    0,
+        0,    0,    0,    0,    0,  602,  605,  605,  605,  605,
+
+      605,  605,    0,  604,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,  577,  578,    0,  578,  578,  578,
+      578,  578,  578,  578,  578,    0,    0,    0,    0,  605,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+      578,  590,    0,  590,  590,  590,  590,  590,  590,  590,
+      590,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,  590,  591,    0,  591,
+      591,  591,  591,  591,  591,  591,  591,    0,    0,    0,
+
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,  591,  607,  607,  607,  607,  607,  607,  607,
+      607,  607,  607,  607,  607,  607,  607,  607,  607,  608,
+      608,  608,  608,  608,  608,  608,  608,  608,  608,  608,
+      608,  608,  608,  608,  608,  609,  609,  609,  609,  609,
+      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
+      609,  610,  610,  610,  610,  610,  610,  610,  610,  610,
+      610,  610,  610,  610,  610,  610,  610,  611,    0,    0,
+        0,    0,    0,    0,    0,  611,  611,  611,    0,    0,
+
+      611,  611,  611,  612,  612,  612,  612,  612,  612,  612,
+      612,  612,  612,  612,  612,  612,  612,  612,  612,  613,
+        0,    0,    0,    0,  613,    0,    0,  613,  613,  613,
+      613,    0,  613,  613,  613,  614,    0,    0,    0,    0,
+        0,    0,    0,  614,  614,  614,    0,    0,  614,  614,
+      614,  615,    0,    0,  615,  615,    0,  615,    0,  615,
+      615,  615,    0,    0,  615,  615,  615,  616,  616,    0,
+        0,    0,  616,  617,    0,    0,  617,  617,    0,  617,
+        0,  617,  617,  617,    0,    0,  617,  617,  617,  618,
+        0,    0,  618,  618,    0,  618,    0,  618,  618,  618,
+
+        0,  618,    0,  618,  618,  620,    0,    0,  620,    0,
+        0,  620,    0,  620,  620,  620,  620,    0,  620,  620,
+      620,  621,  621,  621,  621,  621,  621,  621,  621,  621,
+      621,  621,  621,  621,  621,  621,  621,  622,  622,    0,
+      622,    0,  622,  622,  622,  622,  622,  622,  622,  622,
+      622,  622,  622,  623,  623,  623,  623,  623,  623,  623,
+      623,  623,  623,  623,  623,  623,  623,  623,  623,  624,
+      624,    0,  624,  624,  624,  624,  624,  624,  624,  624,
+      624,  624,  624,  624,  624,  625,    0,    0,    0,    0,
+      625,    0,    0,  625,  625,  625,    0,    0,  625,  625,
+
+      625,  626,    0,    0,  626,  626,    0,  626,    0,  626,
+      626,  626,    0,    0,  626,  626,  626,  627,  627,    0,
+        0,    0,  627,  628,  628,  628,    0,    0,    0,  628,
+      629,    0,    0,  629,  629,    0,  629,    0,  629,  629,
+      629,    0,    0,  629,  629,  629,  630,  630,  630,  630,
+      630,  630,  630,  630,  630,  630,  630,  630,  630,  630,
+      630,  630,  631,  631,    0,    0,    0,  631,  632,  632,
+      632,    0,    0,    0,  632,  633,  633,    0,    0,    0,
+      633,  634,  634,    0,    0,    0,  634,  635,  635,    0,
+        0,    0,  635,  636,  636,  636,    0,    0,    0,  636,
+
+      637,  637,    0,    0,    0,  637,  638,  638,    0,    0,
+        0,  638,  639,  639,    0,    0,    0,  639,  640,  640,
+      640,    0,    0,    0,  640,  641,  641,  641,  641,    0,
+        0,    0,  641,  642,  642,    0,    0,    0,  642,  643,
+      643,    0,    0,    0,  643,  644,  644,    0,    0,    0,
+      644,  645,  645,  645,    0,    0,    0,  645,  646,  646,
+      646,  646,    0,    0,    0,  646,  647,  647,    0,    0,
+        0,  647,  648,  648,    0,    0,    0,  648,  649,  649,
+      649,    0,    0,    0,  649,  650,  650,  650,  650,    0,
+        0,    0,  650,  651,  651,    0,    0,    0,  651,  652,
+
+        0,  652,  652,    0,    0,    0,  652,  653,  653,  653,
+        0,    0,    0,  653,  654,  654,  654,  654,    0,    0,
+        0,  654,  655,  655,    0,    0,    0,  655,  656,    0,
+      656,  656,    0,    0,    0,  656,  657,  657,  657,    0,
+        0,    0,  657,  658,  658,  658,    0,    0,    0,    0,
+      658,  659,  659,    0,  659,  659,  659,    0,    0,  659,
+      659,  659,    0,    0,  659,  659,  659,  660,  660,    0,
+      660,  660,  660,    0,    0,  660,  660,  660,    0,    0,
+      660,  660,  660,  661,  661,    0,    0,    0,  661,  662,
+        0,  662,  662,    0,    0,    0,  662,  663,  663,    0,
+
+        0,    0,    0,  663,  664,  664,  664,  664,  664,  664,
+      664,  664,  664,  664,  664,  664,  664,  664,  664,  664,
+      665,  665,    0,    0,    0,  665,  666,    0,  666,  666,
+        0,    0,    0,  666,  667,  667,    0,    0,    0,  667,
+      668,    0,  668,    0,    0,    0,    0,  668,  670,  670,
+      670,  670,  670,  670,  670,  670,  670,  670,  670,  670,
+      670,  670,  670,  670,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  606,  606,  606,
+      606
+    } ;
+
+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-2011
+ *     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 <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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_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 */
+#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 <errno.h>
+#include <ctype.h>
+#include "sudoers.h"
+#include "parse.h"
+#include "toke.h"
+#include <gram.h>
+
+extern YYSTYPE yylval;
+extern int parse_error;
+int sudolineno;
+char *sudoers;
+
+static int continued, prev_state, sawspace;
+
+static int _push_include(char *, int);
+static int pop_include(void);
+static char *parse_include(char *);
+
+#ifdef TRACELEXER
+static int sudoers_trace_print(const char *msg);
+#else
+# define sudoers_trace_print NULL
+#endif
+int (*trace_print)(const char *msg) = sudoers_trace_print;
+
+#define        push_include(_p)        (_push_include((_p), FALSE))
+#define        push_includedir(_p)     (_push_include((_p), TRUE))
+#define YY_NO_INPUT 1
+#define YY_NO_UNPUT 1
+#define GOTDEFS 1
+
+#define GOTCMND 2
+
+#define STARTDEFS 3
+
+#define INDEFS 4
+
+#define INSTR 5
+
+#line 1511 "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 119 "toke.l"
+
+#line 1667 "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 >= 607 )
+                                       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] != 3665 );
+
+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 120 "toke.l"
+{
+                           LEXTRACE(", ");
+                           return ',';
+                       }                       /* return ',' */
+       YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 125 "toke.l"
+BEGIN STARTDEFS;
+       YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 127 "toke.l"
+{
+                           BEGIN INDEFS;
+                           LEXTRACE("DEFVAR ");
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           return DEFVAR;
+                       }
+       YY_BREAK
+
+case 4:
+YY_RULE_SETUP
+#line 136 "toke.l"
+{
+                           BEGIN STARTDEFS;
+                           LEXTRACE(", ");
+                           return ',';
+                       }                       /* return ',' */
+       YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 142 "toke.l"
+{
+                           LEXTRACE("= ");
+                           return '=';
+                       }                       /* return '=' */
+       YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 147 "toke.l"
+{
+                           LEXTRACE("+= ");
+                           return '+';
+                       }                       /* return '+' */
+       YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 152 "toke.l"
+{
+                           LEXTRACE("-= ");
+                           return '-';
+                       }                       /* return '-' */
+       YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 157 "toke.l"
+{
+                           LEXTRACE("BEGINSTR ");
+                           yylval.string = NULL;
+                           prev_state = YY_START;
+                           BEGIN INSTR;
+                       }
+       YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 164 "toke.l"
+{
+                           LEXTRACE("WORD(2) ");
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           return WORD;
+                       }
+       YY_BREAK
+
+
+case 10:
+YY_RULE_SETUP
+#line 173 "toke.l"
+{
+                           /* Line continuation char followed by newline. */
+                           ++sudolineno;
+                           continued = TRUE;
+                       }
+       YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 179 "toke.l"
+{
+                           LEXTRACE("ENDSTR ");
+                           BEGIN prev_state;
+
+                           if (yylval.string == NULL) {
+                               LEXTRACE("ERROR "); /* empty string */
+                               return ERROR;
+                           }
+                           if (prev_state == INITIAL) {
+                               switch (yylval.string[0]) {
+                               case '%':
+                                   if (yylval.string[1] == '\0' ||
+                                       (yylval.string[1] == ':' &&
+                                       yylval.string[2] == '\0')) {
+                                       LEXTRACE("ERROR "); /* empty group */
+                                       return ERROR;
+                                   }
+                                   LEXTRACE("USERGROUP ");
+                                   return USERGROUP;
+                               case '+':
+                                   if (yylval.string[1] == '\0') {
+                                       LEXTRACE("ERROR "); /* empty netgroup */
+                                       return ERROR;
+                                   }
+                                   LEXTRACE("NETGROUP ");
+                                   return NETGROUP;
+                               }
+                           }
+                           LEXTRACE("WORD(4) ");
+                           return WORD;
+                       }
+       YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 211 "toke.l"
+{
+                           LEXTRACE("BACKSLASH ");
+                           if (!append(yytext, yyleng))
+                               yyterminate();
+                       }
+       YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 217 "toke.l"
+{
+                           LEXTRACE("STRBODY ");
+                           if (!append(yytext, yyleng))
+                               yyterminate();
+                       }
+       YY_BREAK
+
+
+case 14:
+YY_RULE_SETUP
+#line 225 "toke.l"
+{
+                           /* quoted fnmatch glob char, pass verbatim */
+                           LEXTRACE("QUOTEDCHAR ");
+                           if (!fill_args(yytext, 2, sawspace))
+                               yyterminate();
+                           sawspace = FALSE;
+                       }
+       YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 233 "toke.l"
+{
+                           /* quoted sudoers special char, strip backslash */
+                           LEXTRACE("QUOTEDCHAR ");
+                           if (!fill_args(yytext + 1, 1, sawspace))
+                               yyterminate();
+                           sawspace = FALSE;
+                       }
+       YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 241 "toke.l"
+{
+                           BEGIN INITIAL;
+                           yyless(0);
+                           return COMMAND;
+                       }                       /* end of command line args */
+       YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 247 "toke.l"
+{
+                           LEXTRACE("ARG ");
+                           if (!fill_args(yytext, yyleng, sawspace))
+                               yyterminate();
+                           sawspace = FALSE;
+                       }                       /* a command line arg */
+       YY_BREAK
+
+case 18:
+YY_RULE_SETUP
+#line 255 "toke.l"
+{
+                           char *path;
+
+                           if (continued) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+
+                           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 19:
+YY_RULE_SETUP
+#line 273 "toke.l"
+{
+                           char *path;
+
+                           if (continued) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+
+                           if ((path = parse_include(yytext)) == NULL)
+                               yyterminate();
+
+                           LEXTRACE("INCLUDEDIR\n");
+
+                           /*
+                            * Push current buffer and switch to include file.
+                            * We simply ignore empty directories.
+                            */
+                           if (!push_includedir(path) && parse_error)
+                               yyterminate();
+                       }
+       YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 294 "toke.l"
+{
+                           char deftype;
+                           int n;
+
+                           if (continued) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+
+                           for (n = 0; isblank((unsigned char)yytext[n]); n++)
+                               continue;
+                           n += sizeof("Defaults") - 1;
+                           if ((deftype = yytext[n++]) != '\0') {
+                               while (isblank((unsigned char)yytext[n]))
+                                   n++;
+                           }
+                           BEGIN GOTDEFS;
+                           switch (deftype) {
+                               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 21:
+YY_RULE_SETUP
+#line 334 "toke.l"
+{
+                           int n;
+
+                           if (continued) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+
+                           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 22:
+YY_RULE_SETUP
+#line 360 "toke.l"
+{
+                               /* cmnd does not require passwd for this user */
+                               LEXTRACE("NOPASSWD ");
+                               return NOPASSWD;
+                       }
+       YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 366 "toke.l"
+{
+                               /* cmnd requires passwd for this user */
+                               LEXTRACE("PASSWD ");
+                               return PASSWD;
+                       }
+       YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 372 "toke.l"
+{
+                               LEXTRACE("NOEXEC ");
+                               return NOEXEC;
+                       }
+       YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 377 "toke.l"
+{
+                               LEXTRACE("EXEC ");
+                               return EXEC;
+                       }
+       YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 382 "toke.l"
+{
+                               LEXTRACE("SETENV ");
+                               return SETENV;
+                       }
+       YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 387 "toke.l"
+{
+                               LEXTRACE("NOSETENV ");
+                               return NOSETENV;
+                       }
+       YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 392 "toke.l"
+{
+                               LEXTRACE("LOG_OUTPUT ");
+                               return LOG_OUTPUT;
+                       }
+       YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 397 "toke.l"
+{
+                               LEXTRACE("NOLOG_OUTPUT ");
+                               return NOLOG_OUTPUT;
+                       }
+       YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 402 "toke.l"
+{
+                               LEXTRACE("LOG_INPUT ");
+                               return LOG_INPUT;
+                       }
+       YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 407 "toke.l"
+{
+                               LEXTRACE("NOLOG_INPUT ");
+                               return NOLOG_INPUT;
+                       }
+       YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 412 "toke.l"
+{
+                           /* empty group or netgroup */
+                           LEXTRACE("ERROR ");
+                           return ERROR;
+                       }
+       YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 418 "toke.l"
+{
+                           /* netgroup */
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NETGROUP ");
+                           return NETGROUP;
+                       }
+       YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 426 "toke.l"
+{
+                           /* group */
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("USERGROUP ");
+                           return USERGROUP;
+                       }
+       YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 434 "toke.l"
+{
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NTWKADDR ");
+                           return NTWKADDR;
+                       }
+       YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 441 "toke.l"
+{
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NTWKADDR ");
+                           return NTWKADDR;
+                       }
+       YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 448 "toke.l"
+{
+                           if (!ipv6_valid(yytext)) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NTWKADDR ");
+                           return NTWKADDR;
+                       }
+       YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 459 "toke.l"
+{
+                           if (!ipv6_valid(yytext)) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NTWKADDR ");
+                           return NTWKADDR;
+                       }
+       YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 470 "toke.l"
+{
+                           LEXTRACE("ALL ");
+                           return ALL;
+
+                       }
+       YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 476 "toke.l"
+{
+#ifdef HAVE_SELINUX
+                           LEXTRACE("ROLE ");
+                           return ROLE;
+#else
+                           goto got_alias;
+#endif
+                       }
+       YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 485 "toke.l"
+{
+#ifdef HAVE_SELINUX
+                           LEXTRACE("TYPE ");
+                           return TYPE;
+#else
+                           goto got_alias;
+#endif
+                       }
+       YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 494 "toke.l"
+{
+                       got_alias:
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("ALIAS ");
+                           return ALIAS;
+                       }
+       YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 502 "toke.l"
+{
+                           /* no command args allowed for Defaults!/path */
+                           if (!fill_cmnd(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("COMMAND ");
+                           return COMMAND;
+                       }
+       YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 510 "toke.l"
+{
+                           BEGIN GOTCMND;
+                           LEXTRACE("COMMAND ");
+                           if (!fill_cmnd(yytext, yyleng))
+                               yyterminate();
+                       }                       /* sudo -e */
+       YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 517 "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 46:
+YY_RULE_SETUP
+#line 532 "toke.l"
+{
+                           LEXTRACE("BEGINSTR ");
+                           yylval.string = NULL;
+                           prev_state = YY_START;
+                           BEGIN INSTR;
+                       }
+       YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 539 "toke.l"
+{
+                           /* a word */
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("WORD(5) ");
+                           return WORD;
+                       }
+       YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 547 "toke.l"
+{
+                           LEXTRACE("( ");
+                           return '(';
+                       }
+       YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 552 "toke.l"
+{
+                           LEXTRACE(") ");
+                           return ')';
+                       }
+       YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 557 "toke.l"
+{
+                           LEXTRACE(", ");
+                           return ',';
+                       }                       /* return ',' */
+       YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 562 "toke.l"
+{
+                           LEXTRACE("= ");
+                           return '=';
+                       }                       /* return '=' */
+       YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 567 "toke.l"
+{
+                           LEXTRACE(": ");
+                           return ':';
+                       }                       /* return ':' */
+       YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 572 "toke.l"
+{
+                           if (yyleng & 1) {
+                               LEXTRACE("!");
+                               return '!';     /* return '!' */
+                           }
+                       }
+       YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 579 "toke.l"
+{
+                           if (YY_START == INSTR) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;   /* line break in string */
+                           }
+                           BEGIN INITIAL;
+                           ++sudolineno;
+                           continued = FALSE;
+                           LEXTRACE("\n");
+                           return COMMENT;
+                       }                       /* return newline */
+       YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 591 "toke.l"
+{                      /* throw away space/tabs */
+                           sawspace = TRUE;    /* but remember for fill_args */
+                       }
+       YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 595 "toke.l"
+{
+                           sawspace = TRUE;    /* remember for fill_args */
+                           ++sudolineno;
+                           continued = TRUE;
+                       }                       /* throw away EOL after \ */
+       YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 601 "toke.l"
+{
+                           BEGIN INITIAL;
+                           ++sudolineno;
+                           continued = FALSE;
+                           LEXTRACE("#\n");
+                           return COMMENT;
+                       }                       /* comment, not uid/gid */
+       YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 609 "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 614 "toke.l"
+{
+                           if (YY_START != INITIAL) {
+                               BEGIN INITIAL;
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+                           if (!pop_include())
+                               yyterminate();
+                       }
+       YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 624 "toke.l"
+ECHO;
+       YY_BREAK
+#line 2441 "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 >= 607 )
+                               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 >= 607 )
+                       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 == 606);
+
+       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 */
+
+
+#ifndef YY_NO_INPUT
+#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;
+       }
+#endif /* ifndef YY_NO_INPUT */
+
+
+#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 624 "toke.l"
+
+struct path_list {
+    char *path;
+    struct path_list *next;
+};
+
+struct include_stack {
+    YY_BUFFER_STATE bs;
+    char *path;
+    struct path_list *more; /* more files in case of includedir */
+    int lineno;
+    int keepopen;
+};
+
+static int
+pl_compare(const void *v1, const void *v2)
+{
+    const struct path_list * const *p1 = v1;
+    const struct path_list * const *p2 = v2;
+
+    return strcmp((*p1)->path, (*p2)->path);
+}
+
+static char *
+switch_dir(struct include_stack *stack, char *dirpath)
+{
+    DIR *dir;
+    int i, count = 0;
+    char *path = NULL;
+    struct dirent *dent;
+    struct stat sb;
+    struct path_list *pl, *first = NULL;
+    struct path_list **sorted = NULL;
+
+    if (!(dir = opendir(dirpath))) {
+       if (errno != ENOENT) {
+           char *errbuf;
+           if (asprintf(&errbuf, "%s: %s", dirpath, strerror(errno)) != -1) {
+               yyerror(errbuf);
+               free(errbuf);
+           } else {
+               yyerror("unable to allocate memory");
+           }
+       }
+       goto done;
+    }
+    while ((dent = readdir(dir))) {
+       /* Ignore files that end in '~' or have a '.' in them. */
+       if (dent->d_name[0] == '\0' || dent->d_name[NAMLEN(dent) - 1] == '~'
+           || strchr(dent->d_name, '.') != NULL) {
+           continue;
+       }
+       if (asprintf(&path, "%s/%s", dirpath, dent->d_name) == -1) {
+           closedir(dir);
+           goto bad;
+       }
+       if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)) {
+           efree(path);
+           path = NULL;
+           continue;
+       }
+       pl = malloc(sizeof(*pl));
+       if (pl == NULL)
+           goto bad;
+       pl->path = path;
+       pl->next = first;
+       first = pl;
+       count++;
+    }
+    closedir(dir);
+
+    if (count == 0)
+       goto done;
+
+    /* Sort the list as an array. */
+    sorted = malloc(sizeof(*sorted) * count);
+    if (sorted == NULL)
+       goto bad;
+    pl = first;
+    for (i = 0; i < count; i++) {
+       sorted[i] = pl;
+       pl = pl->next;
+    }
+    qsort(sorted, count, sizeof(*sorted), pl_compare);
+
+    /* Apply sorting to the list. */
+    first = sorted[0];
+    sorted[count - 1]->next = NULL;
+    for (i = 1; i < count; i++)
+       sorted[i - 1]->next = sorted[i];
+    efree(sorted);
+
+    /* Pull out the first element for parsing, leave the rest for later. */
+    if (count) {
+       path = first->path;
+       pl = first->next;
+       efree(first);
+       stack->more = pl;
+    } else {
+       path = NULL;
+    }
+done:
+    efree(dirpath);
+    return path;
+bad:
+    while (first != NULL) {
+       pl = first;
+       first = pl->next;
+       free(pl->path);
+       free(pl);
+    }
+    efree(sorted);
+    efree(dirpath);
+    efree(path);
+    return NULL;
+}
+
+#define MAX_SUDOERS_DEPTH      128
+#define SUDOERS_STACK_INCREMENT        16
+
+static size_t istacksize, idepth;
+static struct include_stack *istack;
+static int keepopen;
+
+void
+init_lexer(void)
+{
+    struct path_list *pl;
+
+    while (idepth) {
+       idepth--;
+       while ((pl = istack[idepth].more) != NULL) {
+           istack[idepth].more = pl->next;
+           efree(pl->path);
+           efree(pl);
+       }
+       efree(istack[idepth].path);
+       if (idepth && !istack[idepth].keepopen)
+           fclose(istack[idepth].bs->yy_input_file);
+       yy_delete_buffer(istack[idepth].bs);
+    }
+    efree(istack);
+    istack = NULL;
+    istacksize = idepth = 0;
+    sudolineno = 1;
+    keepopen = FALSE;
+    sawspace = FALSE;
+    continued = FALSE;
+    prev_state = INITIAL;
+}
+
+static int
+_push_include(char *path, int isdir)
+{
+    struct path_list *pl;
+    FILE *fp;
+
+    /* push current state onto stack */
+    if (idepth >= istacksize) {
+       if (idepth > MAX_SUDOERS_DEPTH) {
+           yyerror("too many levels of includes");
+           return FALSE;
+       }
+       istacksize += SUDOERS_STACK_INCREMENT;
+       istack = (struct include_stack *) realloc(istack,
+           sizeof(*istack) * istacksize);
+       if (istack == NULL) {
+           yyerror("unable to allocate memory");
+           return FALSE;
+       }
+    }
+    if (isdir) {
+       if (!(path = switch_dir(&istack[idepth], path))) {
+           /* switch_dir() called yyerror() for us */
+           return FALSE;
+       }
+       while ((fp = open_sudoers(path, FALSE, &keepopen)) == NULL) {
+           /* Unable to open path in includedir, go to next one, if any. */
+           efree(path);
+           if ((pl = istack[idepth].more) == NULL)
+               return FALSE;
+           path = pl->path;
+           istack[idepth].more = pl->next;
+           efree(pl);
+       }
+    } else {
+       if ((fp = open_sudoers(path, TRUE, &keepopen)) == NULL) {
+           char *errbuf;
+           if (asprintf(&errbuf, "%s: %s", path, strerror(errno)) != -1) {
+               yyerror(errbuf);
+               free(errbuf);
+           } else {
+               yyerror("unable to allocate memory");
+           }
+           return FALSE;
+       }
+       istack[idepth].more = NULL;
+    }
+    /* Push the old (current) file and open the new one. */
+    istack[idepth].path = sudoers; /* push old path */
+    istack[idepth].bs = YY_CURRENT_BUFFER;
+    istack[idepth].lineno = sudolineno;
+    istack[idepth].keepopen = keepopen;
+    idepth++;
+    sudolineno = 1;
+    sudoers = path;
+    yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
+
+    return TRUE;
+}
+
+static int
+pop_include(void)
+{
+    struct path_list *pl;
+    FILE *fp;
+
+    if (idepth == 0)
+       return FALSE;
+
+    if (!keepopen)
+       fclose(YY_CURRENT_BUFFER->yy_input_file);
+    yy_delete_buffer(YY_CURRENT_BUFFER);
+    /* If we are in an include dir, move to the next file. */
+    while ((pl = istack[idepth - 1].more) != NULL) {
+       fp = open_sudoers(pl->path, FALSE, &keepopen);
+       if (fp != NULL) {
+           istack[idepth - 1].more = pl->next;
+           efree(sudoers);
+           sudoers = pl->path;
+           sudolineno = 1;
+           yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
+           efree(pl);
+           break;
+       }
+       /* Unable to open path in include dir, go to next one. */
+       istack[idepth - 1].more = pl->next;
+       efree(pl->path);
+       efree(pl);
+    }
+    /* If no path list, just pop the last dir on the stack. */
+    if (pl == NULL) {
+       idepth--;
+       yy_switch_to_buffer(istack[idepth].bs);
+       efree(sudoers);
+       sudoers = istack[idepth].path;
+       sudolineno = istack[idepth].lineno;
+       keepopen = istack[idepth].keepopen;
+    }
+    return TRUE;
+}
+
+static char *
+parse_include(char *base)
+{
+    char *cp, *ep, *path;
+    int len = 0, subst = 0;
+    size_t shost_len = 0;
+
+    /* Pull out path from #include line. */
+    cp = base + sizeof("#include");
+    if (*cp == 'i')
+       cp += 3; /* includedir */
+    while (isblank((unsigned char) *cp))
+       cp++;
+    ep = cp;
+    while (*ep != '\0' && !isspace((unsigned char) *ep)) {
+       if (ep[0] == '%' && ep[1] == 'h') {
+           shost_len = strlen(user_shost);
+           len += shost_len - 2;
+           subst = 1;
+       }
+       ep++;
+    }
+
+    /* Make a copy of path and return it. */
+    len += (int)(ep - cp);
+    if ((path = malloc(len + 1)) == NULL)
+       yyerror("unable to allocate memory");
+    if (subst) {
+       /* substitute for %h */
+       char *pp = path;
+       while (cp < ep) {
+           if (cp[0] == '%' && cp[1] == 'h') {
+               memcpy(pp, user_shost, shost_len);
+               pp += shost_len;
+               cp += 2;
+               continue;
+           }
+           *pp++ = *cp++;
+       }
+       *pp = '\0';
+    } else {
+       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;
+}
+
+#ifdef TRACELEXER
+static int
+sudoers_trace_print(const char *msg)
+{
+    return fputs(msg, stderr);
+}
+#endif /* TRACELEXER */
diff --git a/plugins/sudoers/toke.h b/plugins/sudoers/toke.h
new file mode 100644 (file)
index 0000000..5e2a24a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2011 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.
+ */
+
+#ifndef _SUDO_TOKE_H
+#define _SUDO_TOKE_H
+
+int append(const char *, int);
+int fill_args(const char *, int, int);
+int fill_cmnd(const char *, int);
+int fill_txt(const char *, int, int);
+int ipv6_valid(const char *s);
+void yyerror(const char *);
+
+#ifndef FLEX_SCANNER
+extern int (*trace_print)(const char *msg);
+#endif
+
+#define fill(a, b)     fill_txt(a, b, 0)
+
+/* realloc() to size + COMMANDARGINC to make room for command args */
+#define COMMANDARGINC   64
+
+#define LEXTRACE(msg)   do { \
+    if (trace_print != NULL) \
+        (*trace_print)(msg); \
+} while (0);
+
+#endif /* _SUDO_TOKE_H */
diff --git a/plugins/sudoers/toke.l b/plugins/sudoers/toke.l
new file mode 100644 (file)
index 0000000..9428049
--- /dev/null
@@ -0,0 +1,934 @@
+%{
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2011
+ *     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 <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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_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 */
+#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 <errno.h>
+#include <ctype.h>
+#include "sudoers.h"
+#include "parse.h"
+#include "toke.h"
+#include <gram.h>
+
+extern YYSTYPE yylval;
+extern int parse_error;
+int sudolineno;
+char *sudoers;
+
+static int continued, prev_state, sawspace;
+
+static int _push_include(char *, int);
+static int pop_include(void);
+static char *parse_include(char *);
+
+#ifdef TRACELEXER
+static int sudoers_trace_print(const char *msg);
+#else
+# define sudoers_trace_print NULL
+#endif
+int (*trace_print)(const char *msg) = sudoers_trace_print;
+
+#define        push_include(_p)        (_push_include((_p), FALSE))
+#define        push_includedir(_p)     (_push_include((_p), TRUE))
+%}
+
+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 noinput
+%option nounput
+%option noyywrap
+
+%s     GOTDEFS
+%x     GOTCMND
+%x     STARTDEFS
+%x     INDEFS
+%x     INSTR
+
+%%
+<GOTDEFS>[[:blank:]]*,[[:blank:]]* {
+                           LEXTRACE(", ");
+                           return ',';
+                       }                       /* return ',' */
+
+<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;
+                           prev_state = YY_START;
+                           BEGIN INSTR;
+                       }
+
+    {ENVAR}            {
+                           LEXTRACE("WORD(2) ");
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           return WORD;
+                       }
+}
+
+<INSTR>{
+    \\[[:blank:]]*\n[[:blank:]]*       {
+                           /* Line continuation char followed by newline. */
+                           ++sudolineno;
+                           continued = TRUE;
+                       }
+
+    \"                 {
+                           LEXTRACE("ENDSTR ");
+                           BEGIN prev_state;
+
+                           if (yylval.string == NULL) {
+                               LEXTRACE("ERROR "); /* empty string */
+                               return ERROR;
+                           }
+                           if (prev_state == INITIAL) {
+                               switch (yylval.string[0]) {
+                               case '%':
+                                   if (yylval.string[1] == '\0' ||
+                                       (yylval.string[1] == ':' &&
+                                       yylval.string[2] == '\0')) {
+                                       LEXTRACE("ERROR "); /* empty group */
+                                       return ERROR;
+                                   }
+                                   LEXTRACE("USERGROUP ");
+                                   return USERGROUP;
+                               case '+':
+                                   if (yylval.string[1] == '\0') {
+                                       LEXTRACE("ERROR "); /* empty netgroup */
+                                       return ERROR;
+                                   }
+                                   LEXTRACE("NETGROUP ");
+                                   return NETGROUP;
+                               }
+                           }
+                           LEXTRACE("WORD(4) ");
+                           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 (continued) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+
+                           if ((path = parse_include(yytext)) == NULL)
+                               yyterminate();
+
+                           LEXTRACE("INCLUDE\n");
+
+                           /* Push current buffer and switch to include file */
+                           if (!push_include(path))
+                               yyterminate();
+                       }
+
+<INITIAL>^#includedir[[:blank:]]+\/.*\n {
+                           char *path;
+
+                           if (continued) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+
+                           if ((path = parse_include(yytext)) == NULL)
+                               yyterminate();
+
+                           LEXTRACE("INCLUDEDIR\n");
+
+                           /*
+                            * Push current buffer and switch to include file.
+                            * We simply ignore empty directories.
+                            */
+                           if (!push_includedir(path) && parse_error)
+                               yyterminate();
+                       }
+
+<INITIAL>^[[:blank:]]*Defaults([:@>\!][[:blank:]]*\!*\"?({ID}|{WORD}))? {
+                           char deftype;
+                           int n;
+
+                           if (continued) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+
+                           for (n = 0; isblank((unsigned char)yytext[n]); n++)
+                               continue;
+                           n += sizeof("Defaults") - 1;
+                           if ((deftype = yytext[n++]) != '\0') {
+                               while (isblank((unsigned char)yytext[n]))
+                                   n++;
+                           }
+                           BEGIN GOTDEFS;
+                           switch (deftype) {
+                               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;
+
+                           if (continued) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+
+                           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;
+                       }
+
+LOG_OUTPUT[[:blank:]]*:        {
+                               LEXTRACE("LOG_OUTPUT ");
+                               return LOG_OUTPUT;
+                       }
+
+NOLOG_OUTPUT[[:blank:]]*:      {
+                               LEXTRACE("NOLOG_OUTPUT ");
+                               return NOLOG_OUTPUT;
+                       }
+
+LOG_INPUT[[:blank:]]*: {
+                               LEXTRACE("LOG_INPUT ");
+                               return LOG_INPUT;
+                       }
+
+NOLOG_INPUT[[:blank:]]*:       {
+                               LEXTRACE("NOLOG_INPUT ");
+                               return NOLOG_INPUT;
+                       }
+
+<INITIAL,GOTDEFS>(\+|\%|\%:) {
+                           /* empty group or netgroup */
+                           LEXTRACE("ERROR ");
+                           return ERROR;
+                       }
+
+\+{WORD}               {
+                           /* netgroup */
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("NETGROUP ");
+                           return NETGROUP;
+                       }
+
+\%:?({WORD}|{ID})      {
+                           /* 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;
+                       }
+
+ALL {
+                           LEXTRACE("ALL ");
+                           return ALL;
+
+                       }
+
+<INITIAL>ROLE {
+#ifdef HAVE_SELINUX
+                           LEXTRACE("ROLE ");
+                           return ROLE;
+#else
+                           goto got_alias;
+#endif
+                       }
+
+<INITIAL>TYPE {
+#ifdef HAVE_SELINUX
+                           LEXTRACE("TYPE ");
+                           return TYPE;
+#else
+                           goto got_alias;
+#endif
+                       }
+
+[[:upper:]][[:upper:][:digit:]_]* {
+                       got_alias:
+                           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>\" {
+                           LEXTRACE("BEGINSTR ");
+                           yylval.string = NULL;
+                           prev_state = YY_START;
+                           BEGIN INSTR;
+                       }
+
+<INITIAL,GOTDEFS>({ID}|{WORD}) {
+                           /* a word */
+                           if (!fill(yytext, yyleng))
+                               yyterminate();
+                           LEXTRACE("WORD(5) ");
+                           return WORD;
+                       }
+
+\(                     {
+                           LEXTRACE("( ");
+                           return '(';
+                       }
+
+\)                     {
+                           LEXTRACE(") ");
+                           return ')';
+                       }
+
+,                      {
+                           LEXTRACE(", ");
+                           return ',';
+                       }                       /* return ',' */
+
+=                      {
+                           LEXTRACE("= ");
+                           return '=';
+                       }                       /* return '=' */
+
+:                      {
+                           LEXTRACE(": ");
+                           return ':';
+                       }                       /* return ':' */
+
+<*>!+                  {
+                           if (yyleng & 1) {
+                               LEXTRACE("!");
+                               return '!';     /* return '!' */
+                           }
+                       }
+
+<*>\n                  {
+                           if (YY_START == INSTR) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;   /* line break in string */
+                           }
+                           BEGIN INITIAL;
+                           ++sudolineno;
+                           continued = FALSE;
+                           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;
+                           continued = TRUE;
+                       }                       /* throw away EOL after \ */
+
+<INITIAL,STARTDEFS,INDEFS>#(-[^\n0-9].*|[^\n0-9-].*)?\n        {
+                           BEGIN INITIAL;
+                           ++sudolineno;
+                           continued = FALSE;
+                           LEXTRACE("#\n");
+                           return COMMENT;
+                       }                       /* comment, not uid/gid */
+
+<*>.                   {
+                           LEXTRACE("ERROR ");
+                           return ERROR;
+                       }       /* parse error */
+
+<*><<EOF>>             {
+                           if (YY_START != INITIAL) {
+                               BEGIN INITIAL;
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+                           if (!pop_include())
+                               yyterminate();
+                       }
+
+%%
+struct path_list {
+    char *path;
+    struct path_list *next;
+};
+
+struct include_stack {
+    YY_BUFFER_STATE bs;
+    char *path;
+    struct path_list *more; /* more files in case of includedir */
+    int lineno;
+    int keepopen;
+};
+
+static int
+pl_compare(const void *v1, const void *v2)
+{
+    const struct path_list * const *p1 = v1;
+    const struct path_list * const *p2 = v2;
+
+    return strcmp((*p1)->path, (*p2)->path);
+}
+
+static char *
+switch_dir(struct include_stack *stack, char *dirpath)
+{
+    DIR *dir;
+    int i, count = 0;
+    char *path = NULL;
+    struct dirent *dent;
+    struct stat sb;
+    struct path_list *pl, *first = NULL;
+    struct path_list **sorted = NULL;
+
+    if (!(dir = opendir(dirpath))) {
+       if (errno != ENOENT) {
+           char *errbuf;
+           if (asprintf(&errbuf, "%s: %s", dirpath, strerror(errno)) != -1) {
+               yyerror(errbuf);
+               free(errbuf);
+           } else {
+               yyerror("unable to allocate memory");
+           }
+       }
+       goto done;
+    }
+    while ((dent = readdir(dir))) {
+       /* Ignore files that end in '~' or have a '.' in them. */
+       if (dent->d_name[0] == '\0' || dent->d_name[NAMLEN(dent) - 1] == '~'
+           || strchr(dent->d_name, '.') != NULL) {
+           continue;
+       }
+       if (asprintf(&path, "%s/%s", dirpath, dent->d_name) == -1) {
+           closedir(dir);
+           goto bad;
+       }
+       if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)) {
+           efree(path);
+           path = NULL;
+           continue;
+       }
+       pl = malloc(sizeof(*pl));
+       if (pl == NULL)
+           goto bad;
+       pl->path = path;
+       pl->next = first;
+       first = pl;
+       count++;
+    }
+    closedir(dir);
+
+    if (count == 0)
+       goto done;
+
+    /* Sort the list as an array. */
+    sorted = malloc(sizeof(*sorted) * count);
+    if (sorted == NULL)
+       goto bad;
+    pl = first;
+    for (i = 0; i < count; i++) {
+       sorted[i] = pl;
+       pl = pl->next;
+    }
+    qsort(sorted, count, sizeof(*sorted), pl_compare);
+
+    /* Apply sorting to the list. */
+    first = sorted[0];
+    sorted[count - 1]->next = NULL;
+    for (i = 1; i < count; i++)
+       sorted[i - 1]->next = sorted[i];
+    efree(sorted);
+
+    /* Pull out the first element for parsing, leave the rest for later. */
+    if (count) {
+       path = first->path;
+       pl = first->next;
+       efree(first);
+       stack->more = pl;
+    } else {
+       path = NULL;
+    }
+done:
+    efree(dirpath);
+    return path;
+bad:
+    while (first != NULL) {
+       pl = first;
+       first = pl->next;
+       free(pl->path);
+       free(pl);
+    }
+    efree(sorted);
+    efree(dirpath);
+    efree(path);
+    return NULL;
+}
+
+#define MAX_SUDOERS_DEPTH      128
+#define SUDOERS_STACK_INCREMENT        16
+
+static size_t istacksize, idepth;
+static struct include_stack *istack;
+static int keepopen;
+
+void
+init_lexer(void)
+{
+    struct path_list *pl;
+
+    while (idepth) {
+       idepth--;
+       while ((pl = istack[idepth].more) != NULL) {
+           istack[idepth].more = pl->next;
+           efree(pl->path);
+           efree(pl);
+       }
+       efree(istack[idepth].path);
+       if (idepth && !istack[idepth].keepopen)
+           fclose(istack[idepth].bs->yy_input_file);
+       yy_delete_buffer(istack[idepth].bs);
+    }
+    efree(istack);
+    istack = NULL;
+    istacksize = idepth = 0;
+    sudolineno = 1;
+    keepopen = FALSE;
+    sawspace = FALSE;
+    continued = FALSE;
+    prev_state = INITIAL;
+}
+
+static int
+_push_include(char *path, int isdir)
+{
+    struct path_list *pl;
+    FILE *fp;
+
+    /* push current state onto stack */
+    if (idepth >= istacksize) {
+       if (idepth > MAX_SUDOERS_DEPTH) {
+           yyerror("too many levels of includes");
+           return FALSE;
+       }
+       istacksize += SUDOERS_STACK_INCREMENT;
+       istack = (struct include_stack *) realloc(istack,
+           sizeof(*istack) * istacksize);
+       if (istack == NULL) {
+           yyerror("unable to allocate memory");
+           return FALSE;
+       }
+    }
+    if (isdir) {
+       if (!(path = switch_dir(&istack[idepth], path))) {
+           /* switch_dir() called yyerror() for us */
+           return FALSE;
+       }
+       while ((fp = open_sudoers(path, FALSE, &keepopen)) == NULL) {
+           /* Unable to open path in includedir, go to next one, if any. */
+           efree(path);
+           if ((pl = istack[idepth].more) == NULL)
+               return FALSE;
+           path = pl->path;
+           istack[idepth].more = pl->next;
+           efree(pl);
+       }
+    } else {
+       if ((fp = open_sudoers(path, TRUE, &keepopen)) == NULL) {
+           char *errbuf;
+           if (asprintf(&errbuf, "%s: %s", path, strerror(errno)) != -1) {
+               yyerror(errbuf);
+               free(errbuf);
+           } else {
+               yyerror("unable to allocate memory");
+           }
+           return FALSE;
+       }
+       istack[idepth].more = NULL;
+    }
+    /* Push the old (current) file and open the new one. */
+    istack[idepth].path = sudoers; /* push old path */
+    istack[idepth].bs = YY_CURRENT_BUFFER;
+    istack[idepth].lineno = sudolineno;
+    istack[idepth].keepopen = keepopen;
+    idepth++;
+    sudolineno = 1;
+    sudoers = path;
+    yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
+
+    return TRUE;
+}
+
+static int
+pop_include(void)
+{
+    struct path_list *pl;
+    FILE *fp;
+
+    if (idepth == 0)
+       return FALSE;
+
+    if (!keepopen)
+       fclose(YY_CURRENT_BUFFER->yy_input_file);
+    yy_delete_buffer(YY_CURRENT_BUFFER);
+    /* If we are in an include dir, move to the next file. */
+    while ((pl = istack[idepth - 1].more) != NULL) {
+       fp = open_sudoers(pl->path, FALSE, &keepopen);
+       if (fp != NULL) {
+           istack[idepth - 1].more = pl->next;
+           efree(sudoers);
+           sudoers = pl->path;
+           sudolineno = 1;
+           yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
+           efree(pl);
+           break;
+       }
+       /* Unable to open path in include dir, go to next one. */
+       istack[idepth - 1].more = pl->next;
+       efree(pl->path);
+       efree(pl);
+    }
+    /* If no path list, just pop the last dir on the stack. */
+    if (pl == NULL) {
+       idepth--;
+       yy_switch_to_buffer(istack[idepth].bs);
+       efree(sudoers);
+       sudoers = istack[idepth].path;
+       sudolineno = istack[idepth].lineno;
+       keepopen = istack[idepth].keepopen;
+    }
+    return TRUE;
+}
+
+static char *
+parse_include(char *base)
+{
+    char *cp, *ep, *path;
+    int len = 0, subst = 0;
+    size_t shost_len = 0;
+
+    /* Pull out path from #include line. */
+    cp = base + sizeof("#include");
+    if (*cp == 'i')
+       cp += 3; /* includedir */
+    while (isblank((unsigned char) *cp))
+       cp++;
+    ep = cp;
+    while (*ep != '\0' && !isspace((unsigned char) *ep)) {
+       if (ep[0] == '%' && ep[1] == 'h') {
+           shost_len = strlen(user_shost);
+           len += shost_len - 2;
+           subst = 1;
+       }
+       ep++;
+    }
+
+    /* Make a copy of path and return it. */
+    len += (int)(ep - cp);
+    if ((path = malloc(len + 1)) == NULL)
+       yyerror("unable to allocate memory");
+    if (subst) {
+       /* substitute for %h */
+       char *pp = path;
+       while (cp < ep) {
+           if (cp[0] == '%' && cp[1] == 'h') {
+               memcpy(pp, user_shost, shost_len);
+               pp += shost_len;
+               cp += 2;
+               continue;
+           }
+           *pp++ = *cp++;
+       }
+       *pp = '\0';
+    } else {
+       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;
+}
+
+#ifdef TRACELEXER
+static int
+sudoers_trace_print(const char *msg)
+{
+    return fputs(msg, stderr);
+}
+#endif /* TRACELEXER */
diff --git a/plugins/sudoers/toke_util.c b/plugins/sudoers/toke_util.c
new file mode 100644 (file)
index 0000000..16636b6
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2011
+ *     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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_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 "sudoers.h"
+#include "parse.h"
+#include "toke.h"
+#include <gram.h>
+
+static int arg_len = 0;
+static int arg_size = 0;
+
+static unsigned char
+hexchar(const char *s)
+{
+    int i;
+    int result = 0;
+
+    s += 2; /* skip \\x */
+    for (i = 0; i < 2; i++) {
+       switch (*s) {
+       case 'A':
+       case 'a':
+           result += 10;
+           break;
+       case 'B':
+       case 'b':
+           result += 11;
+           break;
+       case 'C':
+       case 'c':
+           result += 12;
+           break;
+       case 'D':
+       case 'd':
+           result += 13;
+           break;
+       case 'E':
+       case 'e':
+           result += 14;
+           break;
+       case 'F':
+       case 'f':
+           result += 15;
+           break;
+       default:
+           result += *s - '0';
+           break;
+       }
+       if (i == 0) {
+           result *= 16;
+           s++;
+       }
+    }
+    return (unsigned char)result;
+}
+
+int
+fill_txt(const char *src, int len, int olen)
+{
+    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;
+    while (len--) {
+       if (*src == '\\' && len) {
+           if (src[1] == 'x' && len >= 3 && 
+               isxdigit((unsigned char) src[2]) &&
+               isxdigit((unsigned char) src[3])) {
+               *dst++ = hexchar(src);
+               src += 4;
+               len -= 3;
+           } else {
+               src++;
+               len--;
+               *dst++ = *src++;
+           }
+       } else {
+           *dst++ = *src++;
+       }
+    }
+    *dst = '\0';
+    return TRUE;
+}
+
+int
+append(const char *src, int len)
+{
+    int olen = 0;
+
+    if (yylval.string != NULL)
+       olen = strlen(yylval.string);
+
+    return fill_txt(src, len, olen);
+}
+
+#define SPECIAL(c) \
+    ((c) == ',' || (c) == ':' || (c) == '=' || (c) == ' ' || (c) == '\t' || (c) == '#')
+
+int
+fill_cmnd(const 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;
+}
+
+int
+fill_args(const 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;
+}
+
+/*
+ * 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.
+ */
+int
+ipv6_valid(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/plugins/sudoers/tsgetgrpw.c b/plugins/sudoers/tsgetgrpw.c
new file mode 100644 (file)
index 0000000..7b9ad79
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2005, 2008, 2010-2011 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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <fcntl.h>
+#include <limits.h>
+
+#include "tsgetgrpw.h"
+#include "sudoers.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 setgrfile(const char *);
+void setgrent(void);
+void endgrent(void);
+struct group *getgrent(void);
+struct group *getgrnam(const char *);
+struct group *getgrgid(gid_t);
+
+void setpwfile(const char *);
+void setpwent(void);
+void endpwent(void);
+struct passwd *getpwent(void);
+struct passwd *getpwnam(const char *);
+struct passwd *getpwuid(uid_t);
+
+void
+setpwfile(const char *file)
+{
+    pwfile = file;
+    if (pwf != NULL)
+       endpwent();
+}
+
+void
+setpwent(void)
+{
+    if (pwf == NULL) {
+       pwf = fopen(pwfile, "r");
+       if (pwf != NULL)
+           fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
+    } else {
+       rewind(pwf);
+    }
+    pw_stayopen = 1;
+}
+
+void
+endpwent(void)
+{
+    if (pwf != NULL) {
+       fclose(pwf);
+       pwf = NULL;
+    }
+    pw_stayopen = 0;
+}
+
+struct passwd *
+getpwent(void)
+{
+    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 *
+getpwnam(const char *name)
+{
+    struct passwd *pw;
+
+    if (pwf == NULL) {
+       if ((pwf = fopen(pwfile, "r")) == NULL)
+           return NULL;
+       fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
+    } else {
+       rewind(pwf);
+    }
+    while ((pw = getpwent()) != NULL) {
+       if (strcmp(pw->pw_name, name) == 0)
+           break;
+    }
+    if (!pw_stayopen) {
+       fclose(pwf);
+       pwf = NULL;
+    }
+    return pw;
+}
+
+struct passwd *
+getpwuid(uid_t uid)
+{
+    struct passwd *pw;
+
+    if (pwf == NULL) {
+       if ((pwf = fopen(pwfile, "r")) == NULL)
+           return NULL;
+       fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
+    } else {
+       rewind(pwf);
+    }
+    while ((pw = getpwent()) != NULL) {
+       if (pw->pw_uid == uid)
+           break;
+    }
+    if (!pw_stayopen) {
+       fclose(pwf);
+       pwf = NULL;
+    }
+    return pw;
+}
+
+void
+setgrfile(const char *file)
+{
+    grfile = file;
+    if (grf != NULL)
+       endgrent();
+}
+
+void
+setgrent(void)
+{
+    if (grf == NULL) {
+       grf = fopen(grfile, "r");
+       if (grf != NULL)
+           fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
+    } else {
+       rewind(grf);
+    }
+    gr_stayopen = 1;
+}
+
+void
+endgrent(void)
+{
+    if (grf != NULL) {
+       fclose(grf);
+       grf = NULL;
+    }
+    gr_stayopen = 0;
+}
+
+struct group *
+getgrent(void)
+{
+    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 *
+getgrnam(const char *name)
+{
+    struct group *gr;
+
+    if (grf == NULL) {
+       if ((grf = fopen(grfile, "r")) == NULL)
+           return NULL;
+       fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
+    } else {
+       rewind(grf);
+    }
+    while ((gr = getgrent()) != NULL) {
+       if (strcmp(gr->gr_name, name) == 0)
+           break;
+    }
+    if (!gr_stayopen) {
+       fclose(grf);
+       grf = NULL;
+    }
+    return gr;
+}
+
+struct group *
+getgrgid(gid_t gid)
+{
+    struct group *gr;
+
+    if (grf == NULL) {
+       if ((grf = fopen(grfile, "r")) == NULL)
+           return NULL;
+       fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
+    } else {
+       rewind(grf);
+    }
+    while ((gr = getgrent()) != NULL) {
+       if (gr->gr_gid == gid)
+           break;
+    }
+    if (!gr_stayopen) {
+       fclose(grf);
+       grf = NULL;
+    }
+    return gr;
+}
diff --git a/plugins/sudoers/tsgetgrpw.h b/plugins/sudoers/tsgetgrpw.h
new file mode 100644 (file)
index 0000000..5c380c3
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2010 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>
+
+/*
+ * Define away the system prototypes so we don't have any conflicts.
+ */
+
+#define setgrfile      sys_setgrfile
+#define setgrent       sys_setgrent
+#define endgrent       sys_endgrent
+#define getgrent       sys_getgrent
+#define getgrnam       sys_getgrnam
+#define getgrgid       sys_getgrgid
+
+#define setpwfile      sys_setpwfile
+#define setpwent       sys_setpwent
+#define endpwent       sys_endpwent
+#define getpwent       sys_getpwent
+#define getpwnam       sys_getpwnam
+#define getpwuid       sys_getpwuid
+
+#include <pwd.h>
+#include <grp.h>
+
+#undef setgrfile
+#undef setgrent
+#undef endgrent
+#undef getgrent
+#undef getgrnam
+#undef getgrgid
+
+void setgrfile(const char *);
+void setgrent(void);
+void endgrent(void);
+struct group *getgrent(void);
+struct group *getgrnam(const char *);
+struct group *getgrgid(gid_t);
+
+#undef setpwfile
+#undef setpwent
+#undef endpwent
+#undef getpwent
+#undef getpwnam
+#undef getpwuid
+
+void setpwfile(const char *);
+void setpwent(void);
+void endpwent(void);
+struct passwd *getpwent(void);
+struct passwd *getpwnam(const char *);
+struct passwd *getpwuid(uid_t);
diff --git a/plugins/sudoers/visudo.c b/plugins/sudoers/visudo.c
new file mode 100644 (file)
index 0000000..dd31f62
--- /dev/null
@@ -0,0 +1,1212 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2011
+ *     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.
+ */
+
+/*
+ * Lock the sudoers file for safe editing (ala vipw) and check for parse errors.
+ */
+
+#define _SUDO_MAIN
+
+#ifdef __TANDEM
+# include <floss.h>
+#endif
+
+#include <config.h>
+
+#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>
+#endif
+#include <sys/wait.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <ctype.h>
+#include <pwd.h>
+#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
+
+#include "sudoers.h"
+#include "interfaces.h"
+#include "parse.h"
+#include "redblack.h"
+#include "sudoers_version.h"
+#include <gram.h>
+
+struct sudoersfile {
+    struct sudoersfile *prev, *next;
+    char *path;
+    char *tpath;
+    int fd;
+    int modified;
+    int doedit;
+};
+TQ_DECLARE(sudoersfile)
+
+/*
+ * Function prototypes
+ */
+static void quit(int);
+static char *get_args(char *);
+static char *get_editor(char **);
+static void get_hostname(void);
+static char whatnow(void);
+static int check_aliases(int, int);
+static int check_syntax(char *, int, int);
+static int edit_sudoers(struct sudoersfile *, char *, char *, int);
+static int install_sudoers(struct sudoersfile *, int);
+static int print_unused(void *, void *);
+static int reparse_sudoers(char *, char *, int, int);
+static int run_command(char *, char **);
+static int visudo_printf(int msg_type, const char *fmt, ...);
+static void print_selfref(char *name, int, int, int);
+static void print_undefined(char *name, int, int, int);
+static void setup_signals(void);
+static void help(void) __attribute__((__noreturn__));
+static void usage(int);
+
+void cleanup(int);
+
+extern void yyerror(const char *);
+extern void yyrestart(FILE *);
+
+/*
+ * External globals exported by the parser
+ */
+extern struct rbtree *aliases;
+extern FILE *yyin;
+extern char *sudoers, *errorfile;
+extern int errorlineno, parse_error;
+/* For getopt(3) */
+extern char *optarg;
+extern int optind;
+
+/*
+ * Globals
+ */
+struct interface *interfaces;
+struct sudo_user sudo_user;
+struct passwd *list_pw;
+sudo_printf_t sudo_printf = visudo_printf;
+static struct sudoersfile_list sudoerslist;
+static struct rbtree *alias_freelist;
+
+int
+main(int argc, char *argv[])
+{
+    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
+
+#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
+    setprogname(argc > 0 ? argv[0] : "visudo");
+#endif
+    if (argc < 1)
+       usage(1);
+
+    /*
+     * Arg handling.
+     */
+    checkonly = oldperms = quiet = strict = FALSE;
+    sudoers_path = _PATH_SUDOERS;
+    while ((ch = getopt(argc, argv, "Vcf:sq")) != -1) {
+       switch (ch) {
+           case 'V':
+               (void) printf("%s version %s\n", getprogname(), PACKAGE_VERSION);
+               (void) printf("%s grammar version %d\n", getprogname(), SUDOERS_GRAMMAR_VERSION);
+               exit(0);
+           case 'c':
+               checkonly++;            /* check mode */
+               break;
+           case 'f':
+               sudoers_path = optarg;  /* sudoers file path */
+               oldperms = TRUE;
+               break;
+           case 'h':
+               help();
+               break;
+           case 's':
+               strict++;               /* strict mode */
+               break;
+           case 'q':
+               quiet++;                /* quiet mode */
+               break;
+           default:
+               usage(1);
+       }
+    }
+    argc -= optind;
+    argv += optind;
+    if (argc)
+       usage(1);
+
+    sudo_setpwent();
+    sudo_setgrent();
+
+    /* Mock up a fake sudo_user struct. */
+    user_cmnd = "";
+    if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL)
+       errorx(1, "you don't exist in the passwd database");
+    get_hostname();
+
+    /* Setup defaults data structures. */
+    init_defaults();
+
+    if (checkonly)
+       exit(check_syntax(sudoers_path, quiet, strict));
+
+    /*
+     * 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, TRUE, NULL)) == NULL) {
+       error(1, "%s", sudoers_path);
+    }
+    init_parser(sudoers_path, 0);
+    yyparse();
+    (void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER);
+
+    editor = get_editor(&args);
+
+    /* 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->doedit)
+           continue;
+       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 each sudoers file.
+ * Returns TRUE on success, else FALSE.
+ */
+static int
+edit_sudoers(struct sudoersfile *sp, char *editor, char *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 timeval tv, tv1, tv2;       /* time before and after edit */
+    struct timeval 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 */
+
+#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;
+    mtim_get(&sb, &orig_mtim);
+
+    /* 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';
+               if (write(tfd, buf, 1) != 1)
+                   error(1, "write error");
+           }
+       }
+       (void) close(tfd);
+    }
+    (void) touch(-1, sp->tpath, &orig_mtim);
+
+    /* Find the length of the argument vector */
+    ac = 3 + (lineno > 0);
+    if (args) {
+        int wasblank;
+
+        ac++;
+        for (wasblank = FALSE, cp = args; *cp; cp++) {
+            if (isblank((unsigned char) *cp))
+                wasblank = TRUE;
+            else if (wasblank) {
+                wasblank = FALSE;
+                ac++;
+            }
+        }
+    }
+
+    /* Build up argument vector for the command */
+    av = emalloc2(ac, sizeof(char *));
+    if ((av[0] = strrchr(editor, '/')) != NULL)
+       av[0]++;
+    else
+       av[0] = editor;
+    ac = 1;
+    if (lineno > 0) {
+       (void) snprintf(linestr, sizeof(linestr), "+%d", lineno);
+       av[ac++] = linestr;
+    }
+    if (args) {
+       for ((cp = strtok(args, " \t")); cp; (cp = strtok(NULL, " \t")))
+           av[ac++] = cp;
+    }
+    av[ac++] = sp->tpath;
+    av[ac++] = NULL;
+
+    /*
+     * Do the edit:
+     *  We cannot check the editor's exit value against 0 since
+     *  XPG4 specifies that vi's exit value is a function of the
+     *  number of errors during editing (?!?!).
+     */
+    gettimeofday(&tv1, NULL);
+    if (run_command(editor, av) != -1) {
+       gettimeofday(&tv2, NULL);
+       /*
+        * Sanity checks.
+        */
+       if (stat(sp->tpath, &sb) < 0) {
+           warningx("cannot stat temporary file (%s), %s unchanged",
+               sp->tpath, sp->path);
+           return FALSE;
+       }
+       if (sb.st_size == 0 && orig_size != 0) {
+           warningx("zero length temporary file (%s), %s unchanged",
+               sp->tpath, sp->path);
+           sp->modified = TRUE;
+           return FALSE;
+       }
+    } else {
+       warningx("editor (%s) failed, %s unchanged", editor, sp->path);
+       return FALSE;
+    }
+
+    /* Set modified bit if use changed the file. */
+    modified = TRUE;
+    mtim_get(&sb, &tv);
+    if (orig_size == sb.st_size && timevalcmp(&orig_mtim, &tv, ==)) {
+       /*
+        * If mtime and size match but the user spent no measurable
+        * time in the editor we can't tell if the file was changed.
+        */
+       timevalsub(&tv1, &tv2);
+       if (timevalisset(&tv2))
+           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 int
+reparse_sudoers(char *editor, char *args, int strict, int quiet)
+{
+    struct sudoersfile *sp, *last;
+    FILE *fp;
+    int ch;
+
+    /*
+     * Parse the edited sudoers files and do sanity checking
+     */
+    do {
+       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);
+
+       /* Clean slate for each parse */
+       init_defaults();
+       init_parser(sp->path, quiet);
+
+       /* Parse the sudoers temp file */
+       yyrestart(fp);
+       if (yyparse() && !parse_error) {
+           warningx("unabled to parse temporary file (%s), unknown error",
+               sp->tpath);
+           parse_error = TRUE;
+           errorfile = sp->path;
+       }
+       fclose(yyin);
+       if (!parse_error) {
+           if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER) ||
+               check_aliases(strict, quiet) != 0) {
+               parse_error = TRUE;
+               errorfile = sp->path;
+           }
+       }
+
+       /*
+        * Got an error, prompt the user for what to do now
+        */
+       if (parse_error) {
+           switch (whatnow()) {
+               case 'Q' :      parse_error = FALSE;    /* ignore parse error */
+                               break;
+               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 int
+install_sudoers(struct sudoersfile *sp, int oldperms)
+{
+    struct stat sb;
+
+    /*
+     * Change mode and ownership of temp file so when
+     * we move it to sp->path things are kosher.
+     */
+    if (oldperms) {
+       /* Use perms of the existing file.  */
+#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);
+       if (chown(sp->tpath, sb.st_uid, sb.st_gid) != 0) {
+           warning("unable to set (uid, gid) of %s to (%d, %d)",
+               sp->tpath, sb.st_uid, sb.st_gid);
+       }
+       if (chmod(sp->tpath, sb.st_mode & 0777) != 0) {
+           warning("unable to change mode of %s to 0%o", sp->tpath,
+               (sb.st_mode & 0777));
+       }
+    } else {
+       if (chown(sp->tpath, SUDOERS_UID, SUDOERS_GID) != 0) {
+           warning("unable to set (uid, gid) of %s to (%d, %d)",
+               sp->tpath, SUDOERS_UID, SUDOERS_GID);
+           return FALSE;
+       }
+       if (chmod(sp->tpath, SUDOERS_MODE) != 0) {
+           warning("unable to change mode of %s to 0%o", sp->tpath,
+               SUDOERS_MODE);
+           return FALSE;
+       }
+    }
+
+    /*
+     * Now that sp->tpath is sane (parses ok) it needs to be
+     * 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) {
+       efree(sp->tpath);
+       sp->tpath = NULL;
+    } else {
+       if (errno == EXDEV) {
+           char *av[4];
+           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 */
+           if ((av[0] = strrchr(_PATH_MV, '/')) != NULL)
+               av[0]++;
+           else
+               av[0] = _PATH_MV;
+           av[1] = sp->tpath;
+           av[2] = sp->path;
+           av[3] = NULL;
+
+           /* And run it... */
+           if (run_command(_PATH_MV, av)) {
+               warningx("command failed: '%s %s %s', %s unchanged",
+                   _PATH_MV, sp->tpath, sp->path, sp->path);
+               (void) unlink(sp->tpath);
+               efree(sp->tpath);
+               sp->tpath = NULL;
+               return FALSE;
+           }
+           efree(sp->tpath);
+           sp->tpath = NULL;
+       } else {
+           warning("error renaming %s, %s unchanged", sp->tpath, sp->path);
+           (void) unlink(sp->tpath);
+           return FALSE;
+       }
+    }
+    return TRUE;
+}
+
+/* STUB */
+void
+set_fqdn(void)
+{
+    return;
+}
+
+/* STUB */
+void
+init_envtables(void)
+{
+    return;
+}
+
+/* STUB */
+int
+user_is_exempt(void)
+{
+    return FALSE;
+}
+
+/* STUB */
+void
+sudo_setspent(void)
+{
+    return;
+}
+
+/* STUB */
+void
+sudo_endspent(void)
+{
+    return;
+}
+
+/* STUB */
+int
+group_plugin_query(const char *user, const char *group, const struct passwd *pw)
+{
+    return FALSE;
+}
+
+/*
+ * Assuming a parse error occurred, prompt the user for what they want
+ * to do now.  Returns the first letter of their choice.
+ */
+static char
+whatnow(void)
+{
+    int choice, c;
+
+    for (;;) {
+       (void) fputs("What now? ", stdout);
+       choice = getchar();
+       for (c = choice; c != '\n' && c != EOF;)
+           c = getchar();
+
+       switch (choice) {
+           case EOF:
+               choice = 'x';
+               /* FALLTHROUGH */
+           case 'e':
+           case 'x':
+           case 'Q':
+               return choice;
+           default:
+               (void) puts("Options are:");
+               (void) puts("  (e)dit sudoers file again");
+               (void) puts("  e(x)it without saving changes to sudoers file");
+               (void) puts("  (Q)uit and save changes to sudoers file (DANGER!)\n");
+       }
+    }
+}
+
+/*
+ * Install signal handlers for visudo.
+ */
+static void
+setup_signals(void)
+{
+       sigaction_t sa;
+
+       /*
+        * Setup signal handlers to cleanup nicely.
+        */
+       zero_bytes(&sa, sizeof(sa));
+       sigemptyset(&sa.sa_mask);
+       sa.sa_flags = SA_RESTART;
+       sa.sa_handler = quit;
+       (void) sigaction(SIGTERM, &sa, NULL);
+       (void) sigaction(SIGHUP, &sa, NULL);
+       (void) sigaction(SIGINT, &sa, NULL);
+       (void) sigaction(SIGQUIT, &sa, NULL);
+}
+
+static int
+run_command(char *path, char **argv)
+{
+    int status;
+    pid_t pid, rv;
+
+    switch (pid = fork()) {
+       case -1:
+           error(1, "unable to run %s", path);
+           break;      /* NOTREACHED */
+       case 0:
+           sudo_endpwent();
+           sudo_endgrent();
+           closefrom(STDERR_FILENO + 1);
+           execv(path, argv);
+           warning("unable to run %s", path);
+           _exit(127);
+           break;      /* NOTREACHED */
+    }
+
+    do {
+       rv = waitpid(pid, &status, 0);
+    } while (rv == -1 && errno == EINTR);
+
+    if (rv == -1 || !WIFEXITED(status))
+       return -1;
+    return WEXITSTATUS(status);
+}
+
+static int
+check_syntax(char *sudoers_path, int quiet, int strict)
+{
+    struct stat sb;
+    int error;
+
+    if (strcmp(sudoers_path, "-") == 0) {
+       yyin = stdin;
+       sudoers_path = "stdin";
+    } else if ((yyin = fopen(sudoers_path, "r")) == NULL) {
+       if (!quiet)
+           warning("unable to open %s", sudoers_path);
+       exit(1);
+    }
+    init_parser(sudoers_path, quiet);
+    if (yyparse() && !parse_error) {
+       if (!quiet)
+           warningx("failed to parse %s file, unknown error", sudoers_path);
+       parse_error = TRUE;
+       errorfile = sudoers_path;
+    }
+    if (!parse_error && check_aliases(strict, quiet) != 0) {
+       parse_error = TRUE;
+       errorfile = sudoers_path;
+    }
+    error = parse_error;
+    if (!quiet) {
+       if (parse_error) {
+           if (errorlineno != -1)
+               (void) printf("parse error in %s near line %d\n", errorfile,
+                   errorlineno);
+           else
+               (void) printf("parse error in %s\n", errorfile);
+       } else {
+           (void) printf("%s: parsed OK\n", sudoers_path);
+       }
+    }
+    /* Check mode and owner in strict mode. */
+#ifdef HAVE_FSTAT
+    if (strict && yyin != stdin && fstat(fileno(yyin), &sb) == 0)
+#else
+    if (strict && yyin != stdin && stat(sudoers_path, &sb) == 0)
+#endif
+    {
+       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);
+           }
+       }
+    }
+
+    return error;
+}
+
+/*
+ * 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(const char *path, int doedit, int *keepopen)
+{
+    struct sudoersfile *entry;
+    FILE *fp;
+
+    /* 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->prev = entry;
+       entry->next = NULL;
+       entry->fd = open(entry->path, O_RDWR | O_CREAT, SUDOERS_MODE);
+       entry->tpath = NULL;
+       entry->doedit = doedit;
+       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);
+       tq_append(&sudoerslist, entry);
+    } 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);
+           rewind(fp);
+       }
+    }
+    if (keepopen != NULL)
+       *keepopen = TRUE;
+    return fp;
+}
+
+static char *
+get_editor(char **args)
+{
+    char *Editor, *EditorArgs, *EditorPath, *UserEditor, *UserEditorArgs;
+
+    /*
+     * Check VISUAL and EDITOR environment variables to see which editor
+     * the user wants to use (we may not end up using it though).
+     * If the path is not fully-qualified, make it so and check that
+     * the specified executable actually exists.
+     */
+    UserEditorArgs = NULL;
+    if ((UserEditor = getenv("VISUAL")) == NULL || *UserEditor == '\0')
+       UserEditor = getenv("EDITOR");
+    if (UserEditor && *UserEditor == '\0')
+       UserEditor = NULL;
+    else if (UserEditor) {
+       UserEditorArgs = get_args(UserEditor);
+       if (find_path(UserEditor, &Editor, NULL, getenv("PATH"), 0) == FOUND) {
+           UserEditor = Editor;
+       } else {
+           if (def_env_editor) {
+               /* If we are honoring $EDITOR this is a fatal error. */
+               errorx(1, "specified editor (%s) doesn't exist!", UserEditor);
+           } else {
+               /* Otherwise, just ignore $EDITOR. */
+               UserEditor = NULL;
+           }
+       }
+    }
+
+    /*
+     * See if we can use the user's choice of editors either because
+     * we allow any $EDITOR or because $EDITOR is in the allowable list.
+     */
+    Editor = EditorArgs = EditorPath = NULL;
+    if (def_env_editor && UserEditor) {
+       Editor = UserEditor;
+       EditorArgs = UserEditorArgs;
+    } else if (UserEditor) {
+       struct stat editor_sb;
+       struct stat user_editor_sb;
+       char *base, *userbase;
+
+       if (stat(UserEditor, &user_editor_sb) != 0) {
+           /* Should never happen since we already checked above. */
+           error(1, "unable to stat editor (%s)", UserEditor);
+       }
+       EditorPath = estrdup(def_editor);
+       Editor = strtok(EditorPath, ":");
+       do {
+           EditorArgs = get_args(Editor);
+           /*
+            * Both Editor and UserEditor should be fully qualified but
+            * check anyway...
+            */
+           if ((base = strrchr(Editor, '/')) == NULL)
+               continue;
+           if ((userbase = strrchr(UserEditor, '/')) == NULL) {
+               Editor = NULL;
+               break;
+           }
+           base++, userbase++;
+
+           /*
+            * We compare the basenames first and then use stat to match
+            * for sure.
+            */
+           if (strcmp(base, userbase) == 0) {
+               if (stat(Editor, &editor_sb) == 0 && S_ISREG(editor_sb.st_mode)
+                   && (editor_sb.st_mode & 0000111) &&
+                   editor_sb.st_dev == user_editor_sb.st_dev &&
+                   editor_sb.st_ino == user_editor_sb.st_ino)
+                   break;
+           }
+       } while ((Editor = strtok(NULL, ":")));
+    }
+
+    /*
+     * Can't use $EDITOR, try each element of def_editor until we
+     * find one that exists, is regular, and is executable.
+     */
+    if (Editor == NULL || *Editor == '\0') {
+       efree(EditorPath);
+       EditorPath = estrdup(def_editor);
+       Editor = strtok(EditorPath, ":");
+       do {
+           EditorArgs = get_args(Editor);
+           if (sudo_goodpath(Editor, NULL))
+               break;
+       } while ((Editor = strtok(NULL, ":")));
+
+       /* Bleah, none of the editors existed! */
+       if (Editor == NULL || *Editor == '\0')
+           errorx(1, "no editor found (editor path = %s)", def_editor);
+    }
+    *args = EditorArgs;
+    return Editor;
+}
+
+/*
+ * Split out any command line arguments and return them.
+ */
+static char *
+get_args(char *cmnd)
+{
+    char *args;
+
+    args = cmnd;
+    while (*args && !isblank((unsigned char) *args))
+       args++;
+    if (*args) {
+       *args++ = '\0';
+       while (*args && isblank((unsigned char) *args))
+           args++;
+    }
+    return *args ? args : NULL;
+}
+
+/*
+ * Look up the hostname and set user_host and user_shost.
+ */
+static void
+get_hostname(void)
+{
+    char *p, thost[MAXHOSTNAMELEN + 1];
+
+    if (gethostname(thost, sizeof(thost)) != 0) {
+       user_host = user_shost = "localhost";
+       return;
+    }
+    thost[sizeof(thost) - 1] = '\0';
+    user_host = estrdup(thost);
+
+    if ((p = strchr(user_host, '.'))) {
+       *p = '\0';
+       user_shost = estrdup(user_host);
+       *p = '.';
+    } else {
+       user_shost = user_host;
+    }
+}
+
+static int
+alias_remove_recursive(char *name, int type, int strict, int quiet)
+{
+    struct member *m;
+    struct alias *a;
+    int error = 0;
+
+    if ((a = alias_find(name, type)) != NULL) {
+       tq_foreach_fwd(&a->members, m) {
+           if (m->type == ALIAS) {
+               if (strcmp(name, m->name) == 0) {
+                   print_selfref(m->name, type, strict, quiet);
+                   error = 1;
+               } else {
+                   if (!alias_remove_recursive(m->name, type, strict, quiet))
+                       error = 1;
+               }
+           }
+       }
+    }
+    alias_seqno++;
+    a = alias_remove(name, type);
+    if (a)
+       rbinsert(alias_freelist, a);
+    return error;
+}
+
+/*
+ * Iterate through the sudoers datastructures looking for undefined
+ * aliases or unused aliases.
+ */
+static int
+check_aliases(int strict, int quiet)
+{
+    struct cmndspec *cs;
+    struct member *m, *binding;
+    struct privilege *priv;
+    struct userspec *us;
+    struct defaults *d;
+    int atype, error = 0;
+
+    alias_freelist = rbcreate(alias_compare);
+
+    /* Forward check. */
+    tq_foreach_fwd(&userspecs, us) {
+       tq_foreach_fwd(&us->users, m) {
+           if (m->type == ALIAS) {
+               alias_seqno++;
+               if (alias_find(m->name, USERALIAS) == NULL) {
+                   print_undefined(m->name, USERALIAS, strict, quiet);
+                   error++;
+               }
+           }
+       }
+       tq_foreach_fwd(&us->privileges, priv) {
+           tq_foreach_fwd(&priv->hostlist, m) {
+               if (m->type == ALIAS) {
+                   alias_seqno++;
+                   if (alias_find(m->name, HOSTALIAS) == NULL) {
+                       print_undefined(m->name, HOSTALIAS, strict, quiet);
+                       error++;
+                   }
+               }
+           }
+           tq_foreach_fwd(&priv->cmndlist, cs) {
+               tq_foreach_fwd(&cs->runasuserlist, m) {
+                   if (m->type == ALIAS) {
+                       alias_seqno++;
+                       if (alias_find(m->name, RUNASALIAS) == NULL) {
+                           print_undefined(m->name, RUNASALIAS, strict, quiet);
+                           error++;
+                       }
+                   }
+               }
+               if ((m = cs->cmnd)->type == ALIAS) {
+                   alias_seqno++;
+                   if (alias_find(m->name, CMNDALIAS) == NULL) {
+                       print_undefined(m->name, CMNDALIAS, strict, quiet);
+                       error++;
+                   }
+               }
+           }
+       }
+    }
+
+    /* Reverse check (destructive) */
+    tq_foreach_fwd(&userspecs, us) {
+       tq_foreach_fwd(&us->users, m) {
+           if (m->type == ALIAS) {
+               if (!alias_remove_recursive(m->name, USERALIAS, strict, quiet))
+                   error++;
+           }
+       }
+       tq_foreach_fwd(&us->privileges, priv) {
+           tq_foreach_fwd(&priv->hostlist, m) {
+               if (m->type == ALIAS)
+                   if (!alias_remove_recursive(m->name, HOSTALIAS, strict,
+                       quiet))
+                       error++;
+           }
+           tq_foreach_fwd(&priv->cmndlist, cs) {
+               tq_foreach_fwd(&cs->runasuserlist, m) {
+                   if (m->type == ALIAS)
+                       if (!alias_remove_recursive(m->name, RUNASALIAS,
+                           strict, quiet))
+                           error++;
+               }
+               if ((m = cs->cmnd)->type == ALIAS)
+                   if (!alias_remove_recursive(m->name, CMNDALIAS, strict,
+                       quiet))
+                       error++;
+           }
+       }
+    }
+    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)
+                   if (!alias_remove_recursive(m->name, atype, strict, quiet))
+                       error++;
+           }
+       }
+    }
+    rbdestroy(alias_freelist, alias_free);
+
+    /* If all aliases were referenced we will have an empty tree. */
+    if (!no_aliases() && !quiet)
+       alias_apply(print_unused, strict ? "Error" : "Warning");
+
+    return strict ? error : 0;
+}
+
+static void
+print_undefined(char *name, int type, int strict, int quiet)
+{
+    if (!quiet) {
+       warningx("%s: %s_Alias `%s' referenced but not defined",
+           strict ? "Error" : "Warning",
+           type == HOSTALIAS ? "Host" : type == CMNDALIAS ? "Cmnd" :
+           type == USERALIAS ? "User" : type == RUNASALIAS ? "Runas" :
+           "Unknown", name);
+    }
+}
+
+static void
+print_selfref(name, type, strict, quiet)
+    char *name;
+    int type;
+    int strict;
+    int quiet;
+{
+    if (!quiet) {
+       warningx("%s: %s_Alias `%s' references self",
+           strict ? "Error" : "Warning",
+           type == HOSTALIAS ? "Host" : type == CMNDALIAS ? "Cmnd" :
+           type == USERALIAS ? "User" : type == RUNASALIAS ? "Runas" :
+           "Unknown", name);
+    }
+}
+
+static int
+print_unused(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;
+}
+
+/*
+ * Unlink any sudoers temp files that remain.
+ */
+void
+cleanup(int gotsignal)
+{
+    struct sudoersfile *sp;
+
+    tq_foreach_fwd(&sudoerslist, sp) {
+       if (sp->tpath != NULL)
+           (void) unlink(sp->tpath);
+    }
+    if (!gotsignal) {
+       sudo_endpwent();
+       sudo_endgrent();
+    }
+}
+
+/*
+ * Unlink sudoers temp files (if any) and exit.
+ */
+static void
+quit(int signo)
+{
+    const char *signame, *myname;
+
+    cleanup(signo);
+#define        emsg     " exiting due to signal: "
+    myname = getprogname();
+    signame = strsignal(signo);
+    if (write(STDERR_FILENO, myname, strlen(myname)) == -1 ||
+       write(STDERR_FILENO, emsg, sizeof(emsg) - 1) == -1 ||
+       write(STDERR_FILENO, signame, strlen(signame)) == -1 ||
+       write(STDERR_FILENO, "\n", 1) == -1)
+       /* shut up glibc */;
+    _exit(signo);
+}
+
+static void
+usage(int fatal)
+{
+    (void) fprintf(fatal ? stderr : stdout,
+       "usage: %s [-chqsV] [-f sudoers]\n", getprogname());
+    if (fatal)
+       exit(1);
+}
+
+static void
+help(void)
+{
+    (void) printf("%s - safely edit the sudoers file\n\n", getprogname());
+    usage(0);
+    (void) puts("\nOptions:");
+    (void) puts("  -c          check-only mode");
+    (void) puts("  -f sudoers  specify sudoers file location");
+    (void) puts("  -h          display help message and exit");
+    (void) puts("  -q          less verbose (quiet) syntax error messages");
+    (void) puts("  -s          strict syntax checking");
+    (void) puts("  -V          display version information and exit");
+    exit(0);
+}
+
+static int
+visudo_printf(int msg_type, const char *fmt, ...)
+{
+    va_list ap;
+    FILE *fp;
+            
+    switch (msg_type) {
+    case SUDO_CONV_INFO_MSG:
+       fp = stdout;
+       break;
+    case SUDO_CONV_ERROR_MSG:
+       fp = stderr;
+       break;
+    default:
+       errno = EINVAL;
+       return -1;
+    }
+   
+    va_start(ap, fmt);
+    vfprintf(fp, fmt, ap);
+    va_end(ap);
+   
+    return 0;
+}
diff --git a/pwutil.c b/pwutil.c
deleted file mode 100644 (file)
index 548da4d..0000000
--- a/pwutil.c
+++ /dev/null
@@ -1,743 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-2005, 2007-2011
- *     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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#ifdef HAVE_SETAUTHDB
-# include <usersec.h>
-#endif /* HAVE_SETAUTHDB */
-#include <pwd.h>
-#include <grp.h>
-
-#include "sudo.h"
-#include "redblack.h"
-
-/*
- * 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 *));
-
-#define cmp_grnam      cmp_pwnam
-
-#define ptr_to_item(p) ((struct cache_item *)((char *)(p) - sizeof(struct cache_item)))
-
-struct cache_item {
-    unsigned int refcnt;
-    /* key */
-    union {
-       uid_t uid;
-       gid_t gid;
-       char *name;
-    } k;
-    /* datum */
-    union {
-       struct passwd *pw;
-       struct group *gr;
-    } d;
-};
-
-/*
- * Compare by uid.
- */
-static int
-cmp_pwuid(v1, v2)
-    const void *v1;
-    const void *v2;
-{
-    const struct cache_item *ci1 = (const struct cache_item *) v1;
-    const struct cache_item *ci2 = (const struct cache_item *) v2;
-    return ci1->k.uid - ci2->k.uid;
-}
-
-/*
- * Compare by user name.
- */
-static int
-cmp_pwnam(v1, v2)
-    const void *v1;
-    const void *v2;
-{
-    const struct cache_item *ci1 = (const struct cache_item *) v1;
-    const struct cache_item *ci2 = (const struct cache_item *) v2;
-    return strcmp(ci1->k.name, ci2->k.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 item plus the key and data
- * elements.  If name is non-NULL it is used as the key, else the
- * uid is the key.  Fills in datum from struct password.
- *
- * We would like to fill in the encrypted password too but the
- * call to the shadow function could overwrite the pw buffer (NIS).
- */
-static struct cache_item *
-make_pwitem(pw, name)
-    const struct passwd *pw;
-    const char *name;
-{
-    char *cp;
-    const char *pw_shell;
-    size_t nsize, psize, csize, gsize, dsize, ssize, total;
-    struct cache_item *item;
-    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 cache_item) + 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);
-    /* Treat shell specially since we expand "" -> _PATH_BSHELL */
-    ssize = strlen(pw_shell) + 1;
-    total += ssize;
-    if (name != NULL)
-       total += strlen(name) + 1;
-
-    /* Allocate space for struct item, struct passwd and the strings. */
-    if ((item = malloc(total)) == NULL)
-           return NULL;
-    cp = (char *) item + sizeof(struct cache_item);
-
-    /*
-     * Copy in passwd contents and make strings relative to space
-     * at the end of the buffer.
-     */
-    newpw = (struct passwd *) cp;
-    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);
-    /* Treat shell specially since we expand "" -> _PATH_BSHELL */
-    memcpy(cp, pw_shell, ssize);
-    newpw->pw_shell = cp;
-    cp += ssize;
-
-    /* Set key and datum. */
-    if (name != NULL) {
-       memcpy(cp, name, strlen(name) + 1);
-       item->k.name = cp;
-    } else {
-       item->k.uid = pw->pw_uid;
-    }
-    item->d.pw = newpw;
-    item->refcnt = 1;
-
-    return item;
-}
-
-void
-pw_addref(pw)
-    struct passwd *pw;
-{
-    ptr_to_item(pw)->refcnt++;
-}
-
-static void
-pw_delref_item(v)
-    void *v;
-{
-    struct cache_item *item = v;
-
-    if (--item->refcnt == 0)
-       efree(item);
-}
-
-void
-pw_delref(pw)
-    struct passwd *pw;
-{
-    pw_delref_item(ptr_to_item(pw));
-}
-
-/*
- * 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 cache_item key, *item;
-    struct rbnode *node;
-
-    key.k.uid = uid;
-    if ((node = rbfind(pwcache_byuid, &key)) != NULL) {
-       item = (struct cache_item *) node->data;
-       goto done;
-    }
-    /*
-     * Cache passwd db entry if it exists or a negative response if not.
-     */
-#ifdef HAVE_SETAUTHDB
-    aix_setauthdb(IDtouser(uid));
-#endif
-    if ((key.d.pw = getpwuid(uid)) != NULL) {
-       item = make_pwitem(key.d.pw, NULL);
-       if (rbinsert(pwcache_byuid, item) != NULL)
-           errorx(1, "unable to cache uid %u (%s), already exists",
-               (unsigned int) uid, item->d.pw->pw_name);
-    } else {
-       item = emalloc(sizeof(*item));
-       item->refcnt = 1;
-       item->k.uid = uid;
-       item->d.pw = NULL;
-       if (rbinsert(pwcache_byuid, item) != NULL)
-           errorx(1, "unable to cache uid %u, already exists",
-               (unsigned int) uid);
-    }
-#ifdef HAVE_SETAUTHDB
-    aix_restoreauthdb();
-#endif
-done:
-    item->refcnt++;
-    return item->d.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;
-{
-    struct cache_item key, *item;
-    struct rbnode *node;
-    size_t len;
-
-    key.k.name = (char *) name;
-    if ((node = rbfind(pwcache_byname, &key)) != NULL) {
-       item = (struct cache_item *) node->data;
-       goto done;
-    }
-    /*
-     * Cache passwd db entry if it exists or a negative response if not.
-     */
-#ifdef HAVE_SETAUTHDB
-    aix_setauthdb((char *) name);
-#endif
-    if ((key.d.pw = getpwnam(name)) != NULL) {
-       item = make_pwitem(key.d.pw, name);
-       if (rbinsert(pwcache_byname, item) != NULL)
-           errorx(1, "unable to cache user %s, already exists", name);
-    } else {
-       len = strlen(name) + 1;
-       item = emalloc(sizeof(*item) + len);
-       item->refcnt = 1;
-       item->k.name = (char *) item + sizeof(*item);
-       memcpy(item->k.name, name, len);
-       item->d.pw = NULL;
-       if (rbinsert(pwcache_byname, item) != NULL)
-           errorx(1, "unable to cache user %s, already exists", name);
-    }
-#ifdef HAVE_SETAUTHDB
-    aix_restoreauthdb();
-#endif
-done:
-    item->refcnt++;
-    return item->d.pw;
-}
-
-/*
- * 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 cache_item *item;
-    struct passwd *pw;
-    struct rbnode *node;
-    size_t len, namelen;
-    int i;
-
-    namelen = strlen(user);
-    len = sizeof(*item) + sizeof(*pw) + namelen + 1 /* pw_name */ +
-       sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +
-       sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL);
-
-    for (i = 0; i < 2; i++) {
-       item = emalloc(len);
-       zero_bytes(item, sizeof(*item) + sizeof(*pw));
-       pw = (struct passwd *) ((char *)item + sizeof(*item));
-       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, namelen + 1);
-       pw->pw_passwd = pw->pw_name + namelen + 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));
-
-       item->refcnt = 1;
-       item->d.pw = pw;
-       if (i == 0) {
-           /* Store by uid, overwriting cached version. */
-           item->k.uid = pw->pw_uid;
-           if ((node = rbinsert(pwcache_byuid, item)) != NULL) {
-               pw_delref_item(node->data);
-               node->data = item;
-           }
-       } else {
-           /* Store by name, overwriting cached version. */
-           item->k.name = pw->pw_name;
-           if ((node = rbinsert(pwcache_byname, item)) != NULL) {
-               pw_delref_item(node->data);
-               node->data = item;
-           }
-       }
-    }
-    item->refcnt++;
-    return pw;
-}
-
-void
-sudo_setpwent()
-{
-    setpwent();
-    if (pwcache_byuid == NULL)
-       pwcache_byuid = rbcreate(cmp_pwuid);
-    if (pwcache_byname == NULL)
-       pwcache_byname = rbcreate(cmp_pwnam);
-}
-
-void
-sudo_freepwcache()
-{
-    if (pwcache_byuid != NULL) {
-       rbdestroy(pwcache_byuid, pw_delref_item);
-       pwcache_byuid = NULL;
-    }
-    if (pwcache_byname != NULL) {
-       rbdestroy(pwcache_byname, pw_delref_item);
-       pwcache_byname = NULL;
-    }
-}
-
-void
-sudo_endpwent()
-{
-    endpwent();
-    sudo_freepwcache();
-}
-
-/*
- * Compare by gid.
- */
-static int
-cmp_grgid(v1, v2)
-    const void *v1;
-    const void *v2;
-{
-    const struct cache_item *ci1 = (const struct cache_item *) v1;
-    const struct cache_item *ci2 = (const struct cache_item *) v2;
-    return ci1->k.gid - ci2->k.gid;
-}
-
-/*
- * Dynamically allocate space for a struct item plus the key and data
- * elements.  If name is non-NULL it is used as the key, else the
- * gid is the key.  Fills in datum from struct group.
- */
-static struct cache_item *
-make_gritem(gr, name)
-    const struct group *gr;
-    const char *name;
-{
-    char *cp;
-    size_t nsize, psize, nmem, total, len;
-    struct cache_item *item;
-    struct group *newgr;
-
-    /* Allocate in one big chunk for easy freeing. */
-    nsize = psize = nmem = 0;
-    total = sizeof(struct cache_item) + 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 (name != NULL)
-       total += strlen(name) + 1;
-
-    if ((item = malloc(total)) == NULL)
-           return NULL;
-    cp = (char *) item + sizeof(struct cache_item);
-
-    /*
-     * 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.
-     */
-    newgr = (struct group *)cp;
-    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);
-
-    /* Set key and datum. */
-    if (name != NULL) {
-       memcpy(cp, name, strlen(name) + 1);
-       item->k.name = cp;
-    } else {
-       item->k.gid = gr->gr_gid;
-    }
-    item->d.gr = newgr;
-    item->refcnt = 1;
-
-    return item;
-}
-
-void
-gr_addref(gr)
-    struct group *gr;
-{
-    ptr_to_item(gr)->refcnt++;
-}
-
-static void
-gr_delref_item(v)
-    void *v;
-{
-    struct cache_item *item = v;
-
-    if (--item->refcnt == 0)
-       efree(item);
-}
-
-void
-gr_delref(gr)
-    struct group *gr;
-{
-    gr_delref_item(ptr_to_item(gr));
-}
-
-/*
- * Get a group entry by gid and allocate space for it.
- */
-struct group *
-sudo_getgrgid(gid)
-    gid_t gid;
-{
-    struct cache_item key, *item;
-    struct rbnode *node;
-
-    key.k.gid = gid;
-    if ((node = rbfind(grcache_bygid, &key)) != NULL) {
-       item = (struct cache_item *) node->data;
-       goto done;
-    }
-    /*
-     * Cache group db entry if it exists or a negative response if not.
-     */
-    if ((key.d.gr = getgrgid(gid)) != NULL) {
-       item = make_gritem(key.d.gr, NULL);
-       if (rbinsert(grcache_bygid, item) != NULL)
-           errorx(1, "unable to cache gid %u (%s), already exists",
-               (unsigned int) gid, key.d.gr->gr_name);
-    } else {
-       item = emalloc(sizeof(*item));
-       item->refcnt = 1;
-       item->k.gid = gid;
-       item->d.gr = NULL;
-       if (rbinsert(grcache_bygid, item) != NULL)
-           errorx(1, "unable to cache gid %u, already exists",
-               (unsigned int) gid);
-    }
-done:
-    item->refcnt++;
-    return item->d.gr;
-}
-
-/*
- * Get a group entry by name and allocate space for it.
- */
-struct group *
-sudo_getgrnam(name)
-    const char *name;
-{
-    struct cache_item key, *item;
-    struct rbnode *node;
-    size_t len;
-
-    key.k.name = (char *) name;
-    if ((node = rbfind(grcache_byname, &key)) != NULL) {
-       item = (struct cache_item *) node->data;
-       goto done;
-    }
-    /*
-     * Cache group db entry if it exists or a negative response if not.
-     */
-    if ((key.d.gr = getgrnam(name)) != NULL) {
-       item = make_gritem(key.d.gr, name);
-       if (rbinsert(grcache_byname, item) != NULL)
-           errorx(1, "unable to cache group %s, already exists", name);
-    } else {
-       len = strlen(name) + 1;
-       item = emalloc(sizeof(*item) + len);
-       item->refcnt = 1;
-       item->k.name = (char *) item + sizeof(*item);
-       memcpy(item->k.name, name, len);
-       item->d.gr = NULL;
-       if (rbinsert(grcache_byname, item) != NULL)
-           errorx(1, "unable to cache group %s, already exists", name);
-    }
-done:
-    item->refcnt++;
-    return item->d.gr;
-}
-
-/*
- * Take a gid in string form "#123" and return a faked up group struct.
- */
-struct group *
-sudo_fakegrnam(group)
-    const char *group;
-{
-    struct cache_item *item;
-    struct group *gr;
-    struct rbnode *node;
-    size_t len, namelen;
-    int i;
-
-    namelen = strlen(group);
-    len = sizeof(*item) + sizeof(*gr) + namelen + 1;
-
-    for (i = 0; i < 2; i++) {
-       item = emalloc(len);
-       zero_bytes(item, sizeof(*item) + sizeof(*gr));
-       gr = (struct group *) ((char *)item + sizeof(*item));
-       gr->gr_gid = (gid_t) atoi(group + 1);
-       gr->gr_name = (char *)gr + sizeof(struct group);
-       memcpy(gr->gr_name, group, namelen + 1);
-
-       item->refcnt = 1;
-       item->d.gr = gr;
-       if (i == 0) {
-           /* Store by gid, overwriting cached version. */
-           item->k.gid = gr->gr_gid;
-           if ((node = rbinsert(grcache_bygid, item)) != NULL) {
-               gr_delref_item(node->data);
-               node->data = item;
-           }
-       } else {
-           /* Store by name, overwriting cached version. */
-           item->k.name = gr->gr_name;
-           if ((node = rbinsert(grcache_byname, item)) != NULL) {
-               gr_delref_item(node->data);
-               node->data = item;
-           }
-       }
-    }
-    item->refcnt++;
-    return gr;
-}
-
-void
-sudo_setgrent()
-{
-    setgrent();
-    if (grcache_bygid == NULL)
-       grcache_bygid = rbcreate(cmp_grgid);
-    if (grcache_byname == NULL)
-       grcache_byname = rbcreate(cmp_grnam);
-}
-
-void
-sudo_freegrcache()
-{
-    if (grcache_bygid != NULL) {
-       rbdestroy(grcache_bygid, gr_delref_item);
-       grcache_bygid = NULL;
-    }
-    if (grcache_byname != NULL) {
-       rbdestroy(grcache_byname, gr_delref_item);
-       grcache_byname = NULL;
-    }
-}
-
-void
-sudo_endgrent()
-{
-    endgrent();
-    sudo_freegrcache();
-}
-
-int
-user_in_group(pw, group)
-    struct passwd *pw;
-    const char *group;
-{
-#ifdef HAVE_MBR_CHECK_MEMBERSHIP
-    uuid_t gu, uu;
-    int ismember;
-#else
-    char **gr_mem;
-    int i;
-#endif
-    struct group *grp;
-    int retval = FALSE;
-
-#ifdef HAVE_SETAUTHDB
-    aix_setauthdb(pw->pw_name);
-#endif
-    /* A group name that begins with a '#' may be a gid. */
-    if ((grp = sudo_getgrnam(group)) == NULL && *group == '#')
-       grp = sudo_getgrgid(atoi(group + 1));
-#ifdef HAVE_SETAUTHDB
-    aix_restoreauthdb();
-#endif
-    if (grp == NULL)
-       goto done;
-
-    /* check against user's primary (passwd file) gid */
-    if (grp->gr_gid == pw->pw_gid) {
-       retval = TRUE;
-       goto done;
-    }
-
-#ifdef HAVE_MBR_CHECK_MEMBERSHIP
-    /* If we are matching the invoking user use the stashed uuid. */
-    if (strcmp(pw->pw_name, user_name) == 0) {
-       if (mbr_gid_to_uuid(grp->gr_gid, gu) == 0 &&
-           mbr_check_membership(user_uuid, gu, &ismember) == 0 && ismember) {
-           retval = TRUE;
-           goto done;
-       }
-    } else {
-       if (mbr_uid_to_uuid(pw->pw_uid, uu) == 0 &&
-           mbr_gid_to_uuid(grp->gr_gid, gu) == 0 &&
-           mbr_check_membership(uu, gu, &ismember) == 0 && ismember) {
-           retval = TRUE;
-           goto done;
-       }
-    }
-#else /* HAVE_MBR_CHECK_MEMBERSHIP */
-# ifdef HAVE_GETGROUPS
-    /*
-     * If we are matching the invoking or list user and that user has a
-     * supplementary group vector, check it.
-     */
-    if (user_ngroups > 0 &&
-       strcmp(pw->pw_name, list_pw ? list_pw->pw_name : user_name) == 0) {
-       for (i = 0; i < user_ngroups; i++) {
-           if (grp->gr_gid == user_groups[i]) {
-               retval = TRUE;
-               goto done;
-           }
-       }
-    } else
-# endif /* HAVE_GETGROUPS */
-    {
-       if (grp != NULL && grp->gr_mem != NULL) {
-           for (gr_mem = grp->gr_mem; *gr_mem; gr_mem++) {
-               if (strcmp(*gr_mem, pw->pw_name) == 0) {
-                   retval = TRUE;
-                   goto done;
-               }
-           }
-       }
-    }
-#endif /* HAVE_MBR_CHECK_MEMBERSHIP */
-
-done:
-    if (grp != NULL)
-       gr_delref(grp);
-    return retval;
-}
diff --git a/redblack.c b/redblack.c
deleted file mode 100644 (file)
index fb3611b..0000000
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * Copyright (c) 2004-2005, 2007,2009 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"
-
-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) Every node is either red or black.
- *  2) The root is black.
- *  3) All leaves are black.
- *  4) Both children of each red node are black.
- *  5) 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 && node != rbroot(tree)) {
-       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);
-               node = rbroot(tree); /* exit loop */
-           }
-       } 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);
-               node = rbroot(tree); /* exit loop */
-           }
-       }
-    }
-    node->color = black;
-}
diff --git a/redblack.h b/redblack.h
deleted file mode 100644 (file)
index b1938ca..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.
- */
-
-#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 */
diff --git a/sample.pam b/sample.pam
deleted file mode 100644 (file)
index d56e712..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#%PAM-1.0
-# Sample /etc/pam.d/sudo file for RedHat 9 / Fedora Core.
-#   For other Linux distributions you may want to
-#   use /etc/pam.d/sshd or /etc/pam.d/su as a guide.
-#
-#   There are two basic ways to configure PAM, either via pam_stack
-#   or by explicitly specifying the various methods to use.
-#
-# Here we use pam_stack
-auth       required    pam_stack.so service=system-auth
-account    required    pam_stack.so service=system-auth
-password   required    pam_stack.so service=system-auth
-session    required    pam_stack.so service=system-auth
-#
-# Alternately, you can specify the authentication method directly.
-# Here we use pam_unix for normal password authentication.
-#auth       required   pam_env.so
-#auth       sufficient pam_unix.so
-#account    required   pam_unix.so
-#password   required   pam_cracklib.so retry=3 type=
-#password   required   pam_unix.so nullok use_authtok md5 shadow
-#session    required   pam_limits.so
-#session    required   pam_unix.so
-#
-# Another option is to use SMB for authentication.
-#auth       required   pam_env.so
-#auth       sufficient pam_smb_auth.so
-#account    required   pam_smb_auth.so
-#password   required   pam_smb_auth.so
-#session    required   pam_limits.so
diff --git a/sample.sudoers b/sample.sudoers
deleted file mode 100644 (file)
index 0ef1579..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-#
-# Sample /etc/sudoers file.
-#
-# This file MUST be edited with the 'visudo' command as root.
-#
-# See the sudoers man page for the details on how to write a sudoers file.
-
-##
-# 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
-##
-User_Alias     FULLTIMERS = millert, mikef, dowdy
-User_Alias     PARTTIMERS = bostley, jwfox, crawl
-User_Alias     WEBMASTERS = will, wendy, wim
-
-##
-# Runas alias specification
-##
-Runas_Alias    OP = root, operator
-Runas_Alias    DB = oracle, sybase
-
-##
-# Host alias specification
-##
-Host_Alias     SPARC = bigtime, eclipse, moet, anchor:\
-               SGI = grolsch, dandelion, black:\
-               ALPHA = widget, thalamus, foobar:\
-               HPPA = boa, nag, python
-Host_Alias     CUNETS = 128.138.0.0/255.255.0.0
-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
-
-##
-# Cmnd alias specification
-##
-Cmnd_Alias     DUMPS = /usr/sbin/dump, /usr/sbin/rdump, /usr/sbin/restore, \
-                       /usr/sbin/rrestore, /usr/bin/mt
-Cmnd_Alias     KILL = /usr/bin/kill
-Cmnd_Alias     PRINTING = /usr/sbin/lpc, /usr/bin/lprm
-Cmnd_Alias     SHUTDOWN = /usr/sbin/shutdown
-Cmnd_Alias     HALT = /usr/sbin/halt
-Cmnd_Alias     REBOOT = /usr/sbin/reboot
-Cmnd_Alias     SHELLS = /sbin/sh, /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \
-                        /usr/local/bin/tcsh, /usr/bin/rsh, \
-                        /usr/local/bin/zsh
-Cmnd_Alias     SU = /usr/bin/su
-Cmnd_Alias     VIPW = /usr/sbin/vipw, /usr/bin/passwd, /usr/bin/chsh, \
-                      /usr/bin/chfn
-Cmnd_Alias     PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less
-
-##
-# User specification
-##
-
-# root and users in group wheel can run anything on any machine as any user
-root           ALL = (ALL) ALL
-%wheel         ALL = (ALL) ALL
-
-# full time sysadmins can run anything on any machine without a password
-FULLTIMERS     ALL = NOPASSWD: ALL
-
-# part time sysadmins may run anything but need a password
-PARTTIMERS     ALL = ALL
-
-# jack may run anything on machines in CSNETS
-jack           CSNETS = ALL
-
-# lisa may run any command on any host in CUNETS (a class B network)
-lisa           CUNETS = ALL
-
-# operator may run maintenance commands and anything in /usr/oper/bin/
-operator       ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\
-               sudoedit /etc/printcap, /usr/oper/bin/
-
-# joe may su only to operator
-joe            ALL = /usr/bin/su operator
-
-# pete may change passwords for anyone but root on the hp snakes
-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)
-bob            SPARC = (OP) ALL : SGI = (OP) ALL
-
-# jim may run anything on machines in the biglab netgroup
-jim            +biglab = ALL
-
-# users in the secretaries netgroup need to help manage the printers
-# as well as add and remove users
-+secretaries   ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser
-
-# fred can run commands as oracle or sybase without a password
-fred           ALL = (DB) NOPASSWD: ALL
-
-# on the alphas, john may su to anyone but root and flags are not allowed
-john           ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
-
-# jen can run anything on all machines except the ones
-# in the "SERVERS" Host_Alias
-jen            ALL, !SERVERS = ALL
-
-# jill can run any commands in the directory /usr/bin/, except for
-# those in the SU and SHELLS aliases.
-jill           SERVERS = /usr/bin/, !SU, !SHELLS
-
-# steve can run any command in the directory /usr/local/op_commands/
-# as user operator.
-steve          CSNETS = (operator) /usr/local/op_commands/
-
-# matt needs to be able to kill things on his workstation when
-# they get hung.
-matt           valkyrie = KILL
-
-# users in the WEBMASTERS User_Alias (will, wendy, and wim)
-# may run any command as user www (which owns the web pages)
-# or simply su to www.
-WEBMASTERS     www = (www) ALL, (root) /usr/bin/su www
-
-# anyone can mount/unmount a cd-rom on the machines in the CDROM alias
-ALL            CDROM = NOPASSWD: /sbin/umount /CDROM,\
-               /sbin/mount -o nosuid\,nodev /dev/cd0a /CDROM
diff --git a/sample.syslog.conf b/sample.syslog.conf
deleted file mode 100644 (file)
index 686cd19..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# This is a sample syslog.conf fragment for use with Sudo.
-#
-# By default, sudo logs to "authpriv" if your system supports it, else it
-# uses "auth".  The facility can be set via the --with-logfac configure
-# option or in the sudoers file.
-# To see what syslog facility a sudo binary uses, run `sudo -V' as *root*.
-#
-# NOTES:
-#      The whitespace in the following line is made up of <TAB>
-#       characters, *not* spaces.  You cannot just cut and paste!
-#
-#      If you edit syslog.conf you need to send syslogd a HUP signal.
-#      Ie: kill -HUP process_id
-#
-#      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'
-
-# This logs successful and failed sudo attempts to the file /var/log/auth
-# If your system has the authpriv syslog facility, use authpriv.debug
-auth.debug                                     /var/log/auth
-
-# To log to a remote machine, use something like the following,
-# where "loghost" is the name of the remote machine.
-# If your system has the authpriv syslog facility, use authpriv.debug
-auth.debug                                     @loghost
diff --git a/schema.ActiveDirectory b/schema.ActiveDirectory
deleted file mode 100644 (file)
index cfdc7cb..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-#\r
-# Active Directory Schema for sudo configuration (sudoers)\r
-#\r
-# To extend your Active Directory schema, run one of the following command\r
-# on your Windows DC (default port - Active Directory):\r
-# \r
-#  ldifde -i -f schema.ActiveDirectory -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext\r
-#\r
-# or on your Windows DC if using another port (with Active Directory LightWeight Directory Services / ADAM-Active Directory Application Mode)\r
-# Port 50000 by example (or any other port specified when defining the ADLDS/ADAM instance\r
-#\r
-#  ldifde -i -f schema.ActiveDirectory -t 50000 -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext\r
-#\r
-# or \r
-#\r
-#  ldifde -i -f schema.ActiveDirectory -s server:port -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext\r
-#\r
-# Can add username domain and password\r
-#\r
-# -b username domain password\r
-#\r
-# Can create Log file in current or any directory\r
-#\r
-# -j .\r
-#\r
-\r
-dn: CN=sudoUser,CN=Schema,CN=Configuration,DC=X\r
-changetype: add\r
-objectClass: top\r
-objectClass: attributeSchema\r
-cn: sudoUser\r
-distinguishedName: CN=sudoUser,CN=Schema,CN=Configuration,DC=X\r
-instanceType: 4\r
-attributeID: 1.3.6.1.4.1.15953.9.1.1\r
-attributeSyntax: 2.5.5.5\r
-isSingleValued: FALSE\r
-showInAdvancedViewOnly: TRUE\r
-adminDisplayName: sudoUser\r
-adminDescription: User(s) who may run sudo\r
-oMSyntax: 22\r
-searchFlags: 1\r
-lDAPDisplayName: sudoUser\r
-name: sudoUser\r
-schemaIDGUID:: JrGcaKpnoU+0s+HgeFjAbg==\r
-objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
-\r
-dn: CN=sudoHost,CN=Schema,CN=Configuration,DC=X\r
-changetype: add\r
-objectClass: top\r
-objectClass: attributeSchema\r
-cn: sudoHost\r
-distinguishedName: CN=sudoHost,CN=Schema,CN=Configuration,DC=X\r
-instanceType: 4\r
-attributeID: 1.3.6.1.4.1.15953.9.1.2\r
-attributeSyntax: 2.5.5.5\r
-isSingleValued: FALSE\r
-showInAdvancedViewOnly: TRUE\r
-adminDisplayName: sudoHost\r
-adminDescription: Host(s) who may run sudo\r
-oMSyntax: 22\r
-lDAPDisplayName: sudoHost\r
-name: sudoHost\r
-schemaIDGUID:: d0TTjg+Y6U28g/Y+ns2k4w==\r
-objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
-\r
-dn: CN=sudoCommand,CN=Schema,CN=Configuration,DC=X\r
-changetype: add\r
-objectClass: top\r
-objectClass: attributeSchema\r
-cn: sudoCommand\r
-distinguishedName: CN=sudoCommand,CN=Schema,CN=Configuration,DC=X\r
-instanceType: 4\r
-attributeID: 1.3.6.1.4.1.15953.9.1.3\r
-attributeSyntax: 2.5.5.5\r
-isSingleValued: FALSE\r
-showInAdvancedViewOnly: TRUE\r
-adminDisplayName: sudoCommand\r
-adminDescription: Command(s) to be executed by sudo\r
-oMSyntax: 22\r
-lDAPDisplayName: sudoCommand\r
-name: sudoCommand\r
-schemaIDGUID:: D6QR4P5UyUen3RGYJCHCPg==\r
-objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
-\r
-dn: CN=sudoRunAs,CN=Schema,CN=Configuration,DC=X\r
-changetype: add\r
-objectClass: top\r
-objectClass: attributeSchema\r
-cn: sudoRunAs\r
-distinguishedName: CN=sudoRunAs,CN=Schema,CN=Configuration,DC=X\r
-instanceType: 4\r
-attributeID: 1.3.6.1.4.1.15953.9.1.4\r
-attributeSyntax: 2.5.5.5\r
-isSingleValued: FALSE\r
-showInAdvancedViewOnly: TRUE\r
-adminDisplayName: sudoRunAs\r
-adminDescription: User(s) impersonated by sudo (deprecated)\r
-oMSyntax: 22\r
-lDAPDisplayName: sudoRunAs\r
-name: sudoRunAs\r
-schemaIDGUID:: CP98mCQTyUKKxGrQeM80hQ==\r
-objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
-\r
-dn: CN=sudoOption,CN=Schema,CN=Configuration,DC=X\r
-changetype: add\r
-objectClass: top\r
-objectClass: attributeSchema\r
-cn: sudoOption\r
-distinguishedName: CN=sudoOption,CN=Schema,CN=Configuration,DC=X\r
-instanceType: 4\r
-attributeID: 1.3.6.1.4.1.15953.9.1.5\r
-attributeSyntax: 2.5.5.5\r
-isSingleValued: FALSE\r
-showInAdvancedViewOnly: TRUE\r
-adminDisplayName: sudoOption\r
-adminDescription: Option(s) followed by sudo\r
-oMSyntax: 22\r
-lDAPDisplayName: sudoOption\r
-name: sudoOption\r
-schemaIDGUID:: ojaPzBBlAEmsvrHxQctLnA==\r
-objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
-\r
-dn: CN=sudoRunAsUser,CN=Schema,CN=Configuration,DC=X\r
-changetype: add\r
-objectClass: top\r
-objectClass: attributeSchema\r
-cn: sudoRunAsUser\r
-distinguishedName: CN=sudoRunAsUser,CN=Schema,CN=Configuration,DC=X\r
-instanceType: 4\r
-attributeID: 1.3.6.1.4.1.15953.9.1.6\r
-attributeSyntax: 2.5.5.5\r
-isSingleValued: FALSE\r
-showInAdvancedViewOnly: TRUE\r
-adminDisplayName: sudoRunAsUser\r
-adminDescription: User(s) impersonated by sudo\r
-oMSyntax: 22\r
-lDAPDisplayName: sudoRunAsUser\r
-name: sudoRunAsUser\r
-schemaIDGUID:: 9C52yPYd3RG3jMR2VtiVkw==\r
-objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
-\r
-dn: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,DC=X\r
-changetype: add\r
-objectClass: top\r
-objectClass: attributeSchema\r
-cn: sudoRunAsGroup\r
-distinguishedName: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,DC=X\r
-instanceType: 4\r
-attributeID: 1.3.6.1.4.1.15953.9.1.7\r
-attributeSyntax: 2.5.5.5\r
-isSingleValued: FALSE\r
-showInAdvancedViewOnly: TRUE\r
-adminDisplayName: sudoRunAsGroup\r
-adminDescription: Groups(s) impersonated by sudo\r
-oMSyntax: 22\r
-lDAPDisplayName: sudoRunAsGroup\r
-name: sudoRunAsGroup\r
-schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw==\r
-objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X\r
-\r
-dn: CN=sudoNotBefore,CN=Schema,CN=Configuration,DC=X
-changetype: add
-objectClass: top
-objectClass: attributeSchema
-cn: sudoNotBefore
-distinguishedName: CN=sudoNotBefore,CN=Schema,CN=Configuration,DC=X
-instanceType: 4
-attributeID: 1.3.6.1.4.1.15953.9.1.8
-attributeSyntax: 1.3.6.1.4.1.1466.115.121.1.24
-isSingleValued: TRUE
-showInAdvancedViewOnly: TRUE
-adminDisplayName: sudoNotBefore
-adminDescription: Start of time interval for which the entry is valid
-oMSyntax: 22
-lDAPDisplayName:  sudoNotBefore
-name: sudoNotBefore
-schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw==
-objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
-
-dn: CN=sudoNotAfter,CN=Schema,CN=Configuration,DC=X
-changetype: add
-objectClass: top
-objectClass: attributeSchema
-cn: sudoNotAfter
-distinguishedName: CN=sudoNotAfter,CN=Schema,CN=Configuration,DC=X
-instanceType: 4
-attributeID: 1.3.6.1.4.1.15953.9.1.9
-attributeSyntax: 1.3.6.1.4.1.1466.115.121.1.24
-isSingleValued: TRUE
-showInAdvancedViewOnly: TRUE
-adminDisplayName: sudoNotAfter
-adminDescription: End of time interval for which the entry is valid
-oMSyntax: 22
-lDAPDisplayName:  sudoNotAfter
-name: sudoNotAfter
-schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw==
-objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
-
-dn: CN=sudoOrder,CN=Schema,CN=Configuration,DC=X
-changetype: add
-objectClass: top
-objectClass: attributeSchema
-cn: sudoOrder
-distinguishedName: CN=sudoOrder,CN=Schema,CN=Configuration,DC=X
-instanceType: 4
-attributeID: 1.3.6.1.4.1.15953.9.1.10
-attributeSyntax: 1.3.6.1.4.1.1466.115.121.1.27
-isSingleValued: TRUE
-showInAdvancedViewOnly: TRUE
-adminDisplayName: sudoOrder
-adminDescription: an integer to order the sudoRole entries
-oMSyntax: 22
-lDAPDisplayName:  sudoOrder
-name: sudoOrder
-schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw==
-objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
-
-dn:\r
-changetype: modify\r
-add: schemaUpdateNow\r
-schemaUpdateNow: 1\r
--\r
-\r
-dn: CN=sudoRole,CN=Schema,CN=Configuration,DC=X\r
-changetype: add\r
-objectClass: top\r
-objectClass: classSchema\r
-cn: sudoRole\r
-distinguishedName: CN=sudoRole,CN=Schema,CN=Configuration,DC=X\r
-instanceType: 4\r
-possSuperiors: container\r
-possSuperiors: top\r
-subClassOf: top\r
-governsID: 1.3.6.1.4.1.15953.9.2.1\r
-mayContain: sudoCommand\r
-mayContain: sudoHost\r
-mayContain: sudoOption\r
-mayContain: sudoRunAs\r
-mayContain: sudoRunAsUser\r
-mayContain: sudoRunAsGroup\r
-mayContain: sudoUser\r
-mayContain: sudoNotBefore
-mayContain: sudoNotAfter
-mayContain: sudoOrder
-rDNAttID: cn\r
-showInAdvancedViewOnly: FALSE\r
-adminDisplayName: sudoRole\r
-adminDescription: Sudoer Entries\r
-objectClassCategory: 1\r
-lDAPDisplayName: sudoRole\r
-name: sudoRole\r
-schemaIDGUID:: SQn432lnZ0+ukbdh3+gN3w==\r
-systemOnly: FALSE\r
-objectCategory: CN=Class-Schema,CN=Schema,CN=Configuration,DC=X\r
-defaultObjectCategory: CN=sudoRole,CN=Schema,CN=Configuration,DC=X\r
diff --git a/schema.OpenLDAP b/schema.OpenLDAP
deleted file mode 100644 (file)
index d3e95e0..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-#
-# OpenLDAP schema file for Sudo
-# Save as /etc/openldap/schema/sudo.schema
-#
-
-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 (deprecated)'
-    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 )
-
-attributetype ( 1.3.6.1.4.1.15953.9.1.8
-    NAME 'sudoNotBefore'
-    DESC 'Start of time interval for which the entry is valid'
-    EQUALITY generalizedTimeMatch
-    ORDERING generalizedTimeOrderingMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
-
-attributetype ( 1.3.6.1.4.1.15953.9.1.9
-    NAME 'sudoNotAfter'
-    DESC 'End of time interval for which the entry is valid'
-    EQUALITY generalizedTimeMatch
-    ORDERING generalizedTimeOrderingMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
-
-attributeTypes ( 1.3.6.1.4.1.15953.9.1.10
-    NAME 'sudoOrder'
-    DESC 'an integer to order the sudoRole entries'
-    EQUALITY integerMatch
-    ORDERING integerOrderingMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
-
-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 $ sudoOrder $ sudoNotBefore $ sudoNotAfter $
-           description )
-    )
diff --git a/schema.iPlanet b/schema.iPlanet
deleted file mode 100644 (file)
index e512864..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-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 (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' )
-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' )
-attributeTypes: ( 1.3.6.1.4.1.15953.9.1.8 NAME 'sudoNotBefore' DESC 'Start of time interval for which the entry is valid' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
-attributeTypes: ( 1.3.6.1.4.1.15953.9.1.9 NAME 'sudoNotAfter' DESC 'End of time interval for which the entry is valid' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
-attributeTypes: ( 1.3.6.1.4.1.15953.9.1.10 NAME 'sudoOrder' DESC 'an integer to order the sudoRole entries' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
-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 $ sudoOrder $ sudoNotBefore $ sudoNotAfter $ description ) X-ORIGIN 'SUDO' )
diff --git a/selinux.c b/selinux.c
deleted file mode 100644 (file)
index 2c03e6c..0000000
--- a/selinux.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
- * Copyright (c) 2008 Dan Walsh <dwalsh@redhat.com>
- *
- * Borrowed heavily from newrole source code
- * Authors:
- *     Anthony Colatrella
- *     Tim Fraser
- *     Steve Grubb <sgrubb@redhat.com>
- *     Darrel Goeddel <DGoeddel@trustedcs.com>
- *     Michael Thompson <mcthomps@us.ibm.com>
- *     Dan Walsh <dwalsh@redhat.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/wait.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#ifdef HAVE_LINUX_AUDIT
-#include <libaudit.h>
-#endif
-
-#include <selinux/flask.h>             /* for SECCLASS_CHR_FILE */
-#include <selinux/selinux.h>           /* for is_selinux_enabled() */
-#include <selinux/context.h>           /* for context-mangling functions */
-#include <selinux/get_default_type.h>
-#include <selinux/get_context_list.h>
-
-#include "sudo.h"
-#include "linux_audit.h"
-
-static struct selinux_state {
-    security_context_t old_context;
-    security_context_t new_context;
-    security_context_t tty_context;
-    security_context_t new_tty_context;
-    const char *ttyn;
-    int ttyfd;
-    int enforcing;
-} se_state;
-
-/*
- * This function attempts to revert the relabeling done to the tty.
- * fd             - referencing the opened ttyn
- * ttyn                   - name of tty to restore
- *
- * Returns zero on success, non-zero otherwise
- */
-int
-selinux_restore_tty(void)
-{
-    int retval = 0;
-    security_context_t chk_tty_context = NULL;
-
-    if (se_state.ttyfd == -1 || se_state.new_tty_context == NULL)
-       goto skip_relabel;
-
-    /* Verify that the tty still has the context set by sudo. */
-    if ((retval = fgetfilecon(se_state.ttyfd, &chk_tty_context)) < 0) {
-       warning("unable to fgetfilecon %s", se_state.ttyn);
-       goto skip_relabel;
-    }
-
-    if ((retval = strcmp(chk_tty_context, se_state.new_tty_context))) {
-       warningx("%s changed labels.", se_state.ttyn);
-       goto skip_relabel;
-    }
-
-    if ((retval = fsetfilecon(se_state.ttyfd, se_state.tty_context)) < 0)
-       warning("unable to restore context for %s", se_state.ttyn);
-
-skip_relabel:
-    if (se_state.ttyfd != -1) {
-       close(se_state.ttyfd);
-       se_state.ttyfd = -1;
-    }
-    if (chk_tty_context != NULL) {
-       freecon(chk_tty_context);
-       chk_tty_context = NULL;
-    }
-    return retval;
-}
-
-/*
- * This function attempts to relabel the tty. If this function fails, then
- * the contexts are free'd and -1 is returned. On success, 0 is returned
- * and tty_context and new_tty_context are set.
- *
- * This function will not fail if it can not relabel the tty when selinux is
- * in permissive mode.
- */
-static int
-relabel_tty(const char *ttyn, int ptyfd)
-{
-    security_context_t tty_con = NULL;
-    security_context_t new_tty_con = NULL;
-    int fd;
-
-    se_state.ttyfd = ptyfd;
-
-    /* It is perfectly legal to have no tty. */
-    if (ptyfd == -1 && ttyn == NULL)
-       return 0;
-
-    /* If sudo is not allocating a pty for the command, open current tty. */
-    if (ptyfd == -1) {
-       se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK);
-       if (se_state.ttyfd == -1) {
-           warning("unable to open %s, not relabeling tty", ttyn);
-           if (se_state.enforcing)
-               goto bad;
-       }
-       (void)fcntl(se_state.ttyfd, F_SETFL,
-           fcntl(se_state.ttyfd, F_GETFL, 0) & ~O_NONBLOCK);
-    }
-
-    if (fgetfilecon(se_state.ttyfd, &tty_con) < 0) {
-       warning("unable to get current tty context, not relabeling tty");
-       if (se_state.enforcing)
-           goto bad;
-    }
-
-    if (tty_con && (security_compute_relabel(se_state.new_context, tty_con,
-       SECCLASS_CHR_FILE, &new_tty_con) < 0)) {
-       warning("unable to get new tty context, not relabeling tty");
-       if (se_state.enforcing)
-           goto bad;
-    }
-
-    if (new_tty_con != NULL) {
-       if (fsetfilecon(se_state.ttyfd, new_tty_con) < 0) {
-           warning("unable to set new tty context");
-           if (se_state.enforcing)
-               goto bad;
-       }
-    }
-
-    if (ptyfd != -1) {
-       /* Reopen pty that was relabeled, std{in,out,err} are reset later. */
-       se_state.ttyfd = open(ttyn, O_RDWR|O_NOCTTY, 0);
-       if (se_state.ttyfd == -1) {
-           warning("cannot open %s", ttyn);
-           if (se_state.enforcing)
-               goto bad;
-       }
-       if (dup2(se_state.ttyfd, ptyfd) == -1) {
-           warning("dup2");
-           goto bad;
-       }
-    } else {
-       /* Re-open tty to get new label and reset std{in,out,err} */
-       close(se_state.ttyfd);
-       se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK);
-       if (se_state.ttyfd == -1) {
-           warning("unable to open %s", ttyn);
-           goto bad;
-       }
-       (void)fcntl(se_state.ttyfd, F_SETFL,
-           fcntl(se_state.ttyfd, F_GETFL, 0) & ~O_NONBLOCK);
-       for (fd = STDIN_FILENO; fd <= STDERR_FILENO; fd++) {
-           if (isatty(fd) && dup2(se_state.ttyfd, fd) == -1) {
-               warning("dup2");
-               goto bad;
-           }
-       }
-    }
-    /* Retain se_state.ttyfd so we can restore label when command finishes. */
-    (void)fcntl(se_state.ttyfd, F_SETFD, FD_CLOEXEC);
-
-    se_state.ttyn = ttyn;
-    se_state.tty_context = tty_con;
-    se_state.new_tty_context = new_tty_con;
-    return 0;
-
-bad:
-    if (se_state.ttyfd != -1 && se_state.ttyfd != ptyfd) {
-       close(se_state.ttyfd);
-       se_state.ttyfd = -1;
-    }
-    freecon(tty_con);
-    return -1;
-}
-
-/*
- * Returns a new security context based on the old context and the
- * specified role and type.
- */
-security_context_t
-get_exec_context(security_context_t old_context, const char *role, const char *type)
-{
-    security_context_t new_context = NULL;
-    context_t context = NULL;
-    char *typebuf = NULL;
-    
-    /* We must have a role, the type is optional (we can use the default). */
-    if (!role) {
-       warningx("you must specify a role for type %s", type);
-       errno = EINVAL;
-       return NULL;
-    }
-    if (!type) {
-       if (get_default_type(role, &typebuf)) {
-           warningx("unable to get default type for role %s", role);
-           errno = EINVAL;
-           return NULL;
-       }
-       type = typebuf;
-    }
-    
-    /* 
-     * Expand old_context into a context_t so that we extract and modify 
-     * its components easily. 
-     */
-    context = context_new(old_context);
-    
-    /*
-     * Replace the role and type in "context" with the role and
-     * type we will be running the command as.
-     */
-    if (context_role_set(context, role)) {
-       warning("failed to set new role %s", role);
-       goto bad;
-    }
-    if (context_type_set(context, type)) {
-       warning("failed to set new type %s", type);
-       goto bad;
-    }
-      
-    /*
-     * Convert "context" back into a string and verify it.
-     */
-    new_context = estrdup(context_str(context));
-    if (security_check_context(new_context) < 0) {
-       warningx("%s is not a valid context", new_context);
-       errno = EINVAL;
-       goto bad;
-    }
-
-#ifdef DEBUG
-    warningx("Your new context is %s", new_context);
-#endif
-
-    context_free(context);
-    return new_context;
-
-bad:
-    free(typebuf);
-    context_free(context);
-    freecon(new_context);
-    return NULL;
-}
-
-/* 
- * Set the exec and tty contexts in preparation for fork/exec.
- * Must run as root, before the uid change.
- * If ptyfd is not -1, it indicates we are running
- * in a pty and do not need to reset std{in,out,err}.
- * Returns 0 on success and -1 on failure.
- */
-int
-selinux_setup(const char *role, const char *type, const char *ttyn,
-    int ptyfd)
-{
-    int rval = -1;
-
-    /* Store the caller's SID in old_context. */
-    if (getprevcon(&se_state.old_context)) {
-       warning("failed to get old_context");
-       goto done;
-    }
-
-    se_state.enforcing = security_getenforce();
-    if (se_state.enforcing < 0) {
-       warning("unable to determine enforcing mode.");
-       goto done;
-    }
-
-#ifdef DEBUG
-    warningx("your old context was %s", se_state.old_context);
-#endif
-    se_state.new_context = get_exec_context(se_state.old_context, role, type);
-    if (!se_state.new_context)
-       goto done;
-    
-    if (relabel_tty(ttyn, ptyfd) < 0) {
-       warning("unable to setup tty context for %s", se_state.new_context);
-       goto done;
-    }
-
-#ifdef DEBUG
-    if (se_state.ttyfd != -1) {
-       warningx("your old tty context is %s", se_state.tty_context);
-       warningx("your new tty context is %s", se_state.new_tty_context);
-    }
-#endif
-
-#ifdef HAVE_LINUX_AUDIT
-    linux_audit_role_change(se_state.old_context, se_state.new_context,
-       se_state.ttyn);
-#endif
-
-    rval = 0;
-
-done:
-    return rval;
-}
-
-void
-selinux_execve(const char *path, char *argv[], char *envp[])
-{
-    if (setexeccon(se_state.new_context)) {
-       warning("unable to set exec context to %s", se_state.new_context);
-       if (se_state.enforcing)
-           return;
-    }
-
-#ifdef HAVE_SETKEYCREATECON
-    if (setkeycreatecon(se_state.new_context)) {
-       warning("unable to set key creation context to %s", se_state.new_context);
-       if (se_state.enforcing)
-           return;
-    }
-#endif /* HAVE_SETKEYCREATECON */
-
-    /* We use the "spare" slot in argv to store sesh. */
-    --argv;
-    argv[0] = *argv[1] == '-' ? "-sesh" : "sesh";
-    argv[1] = (char *)path;
-
-    execve(_PATH_SUDO_SESH, argv, envp);
-}
diff --git a/sesh.c b/sesh.c
deleted file mode 100644 (file)
index 4001614..0000000
--- a/sesh.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.
- * 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 <err.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "missing.h"
-
-int
-main (int argc, char **argv)
-{
-    char *cp, *cmnd;
-
-    if (argc < 2)
-       errx(EXIT_FAILURE, "requires at least one argument");
-
-    /* Shift argv and make a copy of the command to execute. */
-    argv++;
-    argc--;
-    cmnd = strdup(argv[0]);
-    if (cmnd == NULL)
-       err(EXIT_FAILURE, NULL);
-
-    /* If invoked as a login shell, modify argv[0] accordingly. */
-    if (argv[0][0] == '-') {
-       if ((cp = strrchr(argv[0], '/')) == NULL)
-           cp = argv[0];
-       *cp = '-';
-    }
-    execv(cmnd, argv);
-    warn("unable to execute %s", argv[0]);
-    _exit(EXIT_FAILURE);
-}
diff --git a/set_perms.c b/set_perms.c
deleted file mode 100644 (file)
index 355baad..0000000
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- * Copyright (c) 1994-1996,1998-2010 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/param.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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <errno.h>
-#include <grp.h>
-#ifdef HAVE_LOGIN_CAP_H
-# include <login_cap.h>
-#endif
-#ifdef HAVE_PROJECT_H
-# include <project.h>
-# include <sys/task.h>
-#endif
-
-#include "sudo.h"
-
-#ifdef __TANDEM
-# define ROOT_UID      65535
-#else
-# define ROOT_UID      0
-#endif
-
-/*
- * Prototypes
- */
-static void runas_setup                __P((void));
-static void runas_setgroups    __P((void));
-static void restore_groups     __P((void));
-
-static int current_perm = -1;
-
-#ifdef HAVE_SETRESUID
-/*
- * Set real and effective and saved uids and gids based on perm.
- * We always retain a saved uid of 0 unless we are headed for an exec().
- * We only flip the effective gid since it only changes for PERM_SUDOERS.
- * This version of set_perms() works fine with the "stay_setuid" option.
- */
-int
-set_perms(perm)
-    int perm;
-{
-    const char *errstr;
-    int noexit;
-
-    noexit = ISSET(perm, PERM_NOEXIT);
-    CLR(perm, PERM_MASK);
-
-    if (perm == current_perm)
-       return 1;
-
-    switch (perm) {
-       case PERM_ROOT:
-                               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();
-                               break;
-
-       case PERM_USER:
-                               (void) setresgid(-1, user_gid, -1);
-                               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)) {
-                                   errstr = "setresuid(user_uid, user_uid, user_uid)";
-                                   goto bad;
-                               }
-                               break;
-                               
-       case PERM_RUNAS:
-                               runas_setgroups();
-                               (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:
-                               /* headed for exec(), assume euid == ROOT_UID */
-                               runas_setup();
-                               if (setresuid(def_stay_setuid ?
-                                   user_uid : runas_pw->pw_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))
-                                   error(1, "unable to change to sudoers gid");
-
-                               /*
-                                * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
-                                * is group readable we use a non-zero
-                                * uid in order to avoid NFS lossage.
-                                * Using uid 1 is a bit bogus but should
-                                * work on all OS's.
-                                */
-                               if (SUDOERS_UID == 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)) {
-                                       errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)";
-                                       goto bad;
-                                   }
-                               }
-                               break;
-       case PERM_TIMESTAMP:
-                               if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID)) {
-                                   errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)";
-                                   goto bad;
-                               }
-                               break;
-    }
-
-    current_perm = perm;
-    return 1;
-bad:
-    warningx("%s: %s", errstr,
-       errno == EAGAIN ? "too many processes" : strerror(errno));
-    if (noexit)
-       return 0;
-    exit(1);
-}
-
-#else
-# ifdef HAVE_SETREUID
-
-/*
- * Set real and effective uids and gids based on perm.
- * We always retain a real or effective uid of ROOT_UID unless
- * we are headed for an exec().
- * This version of set_perms() works fine with the "stay_setuid" option.
- */
-int
-set_perms(perm)
-    int perm;
-{
-    const char *errstr;
-    int noexit;
-
-    noexit = ISSET(perm, PERM_NOEXIT);
-    CLR(perm, PERM_MASK);
-
-    if (perm == current_perm)
-       return 1;
-
-    switch (perm) {
-       case PERM_ROOT:
-                               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();
-                               break;
-
-       case PERM_USER:
-                               (void) setregid(-1, user_gid);
-                               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)) {
-                                   errstr = "setreuid(user_uid, user_uid)";
-                                   goto bad;
-                               }
-                               break;
-                               
-       case PERM_RUNAS:
-                               runas_setgroups();
-                               (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)) {
-                                   errstr = "unable to change to runas uid";
-                                   goto bad;
-                               }
-                               break;
-
-       case PERM_SUDOERS:
-                               /* assume euid == ROOT_UID, ruid == user */
-                               if (setregid(-1, SUDOERS_GID))
-                                   error(1, "unable to change to sudoers gid");
-
-                               /*
-                                * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
-                                * is group readable we use a non-zero
-                                * uid in order to avoid NFS lossage.
-                                * Using uid 1 is a bit bogus but should
-                                * work on all OS's.
-                                */
-                               if (SUDOERS_UID == ROOT_UID) {
-                                   if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1)) {
-                                       errstr = "setreuid(ROOT_UID, 1)";
-                                       goto bad;
-                                   }
-                               } else {
-                                   if (setreuid(ROOT_UID, SUDOERS_UID)) {
-                                       errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
-                                       goto bad;
-                                   }
-                               }
-                               break;
-       case PERM_TIMESTAMP:
-                               if (setreuid(ROOT_UID, timestamp_uid)) {
-                                   errstr = "setreuid(ROOT_UID, timestamp_uid)";
-                                   goto bad;
-                               }
-                               break;
-    }
-
-    current_perm = perm;
-    return 1;
-bad:
-    warningx("%s: %s", errstr,
-       errno == EAGAIN ? "too many processes" : strerror(errno));
-    if (noexit)
-       return 0;
-    exit(1);
-}
-
-# else /* !HAVE_SETRESUID && !HAVE_SETREUID */
-# ifdef HAVE_SETEUID
-
-/*
- * Set real and effective uids and gids based on perm.
- * NOTE: does not support the "stay_setuid" option.
- */
-int
-set_perms(perm)
-    int perm;
-{
-    const char *errstr;
-    int noexit;
-
-    noexit = ISSET(perm, PERM_NOEXIT);
-    CLR(perm, PERM_MASK);
-
-    if (perm == current_perm)
-       return 1;
-
-    /*
-     * Since we only have setuid() and seteuid() and semantics
-     * for these calls differ on various systems, we set
-     * real and effective uids to ROOT_UID initially to be safe.
-     */
-    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:
-                               /* uid set above */
-                               (void) setegid(user_gid);
-                               if (current_perm == PERM_RUNAS)
-                                   restore_groups();
-                               break;
-
-       case PERM_USER:
-                               (void) setegid(user_gid);
-                               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)) {
-                                   errstr = "setuid(user_uid)";
-                                   goto bad;
-                               }
-                               break;
-                               
-       case PERM_RUNAS:
-                               runas_setgroups();
-                               (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)) {
-                                   errstr = "unable to change to runas uid";
-                                   goto bad;
-                               }
-                               break;
-
-       case PERM_SUDOERS:
-                               if (setegid(SUDOERS_GID))
-                                   error(1, "unable to change to sudoers gid");
-
-                               /*
-                                * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE
-                                * is group readable we use a non-zero
-                                * uid in order to avoid NFS lossage.
-                                * Using uid 1 is a bit bogus but should
-                                * work on all OS's.
-                                */
-                               if (SUDOERS_UID == ROOT_UID) {
-                                   if ((SUDOERS_MODE & 040) && seteuid(1)) {
-                                       errstr = "seteuid(1)";
-                                       goto bad;
-                                   }
-                               } else {
-                                   if (seteuid(SUDOERS_UID)) {
-                                       errstr = "seteuid(SUDOERS_UID)";
-                                       goto bad;
-                                   }
-                               }
-                               break;
-       case PERM_TIMESTAMP:
-                               if (seteuid(timestamp_uid)) {
-                                   errstr = "seteuid(timestamp_uid)";
-                                   goto bad;
-                               }
-                               break;
-    }
-
-    current_perm = perm;
-    return 1;
-bad:
-    warningx("%s: %s", errstr,
-       errno == EAGAIN ? "too many processes" : strerror(errno));
-    if (noexit)
-       return 0;
-    exit(1);
-}
-
-# else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
-
-/*
- * Set uids and gids based on perm via setuid() and setgid().
- * NOTE: does not support the "stay_setuid" or timestampowner options.
- *       Also, SUDOERS_UID and SUDOERS_GID are not used.
- */
-int
-set_perms(perm)
-    int perm;
-{
-    const char *errstr;
-    int noexit;
-
-    noexit = ISSET(perm, PERM_NOEXIT);
-    CLR(perm, PERM_MASK);
-
-    if (perm == current_perm)
-       return 1;
-
-    switch (perm) {
-       case PERM_ROOT:
-                               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)) {
-                                   errstr = "setuid(user_uid)";
-                                   goto bad;
-                               }
-                               break;
-                               
-       case PERM_FULL_RUNAS:
-                               runas_setup();
-                               if (setuid(runas_pw->pw_uid)) {
-                                   errstr = "unable to change to runas uid";
-                                   goto bad;
-                               }
-                               break;
-
-       case PERM_USER:
-       case PERM_SUDOERS:
-       case PERM_RUNAS:
-       case PERM_TIMESTAMP:
-                               /* Unsupported since we can't set euid. */
-                               break;
-    }
-
-    current_perm = perm;
-    return 1;
-bad:
-    warningx("%s: %s", errstr,
-       errno == EAGAIN ? "too many processes" : strerror(errno));
-    if (noexit)
-       return 0;
-    exit(1);
-}
-#  endif /* HAVE_SETEUID */
-# endif /* HAVE_SETREUID */
-#endif /* HAVE_SETRESUID */
-
-#ifdef HAVE_INITGROUPS
-static void
-runas_setgroups()
-{
-    static int ngroups = -1;
-# ifdef HAVE_GETGROUPS
-    static GETGROUPS_T *groups;
-# endif
-    static struct passwd *pw;
-    struct passwd *opw = pw;
-
-    if (def_preserve_groups)
-       return;
-
-    /*
-     * Use stashed copy of runas groups if available, else initgroups and stash.
-     */
-    pw = runas_pw ? runas_pw : sudo_user.pw;
-    if (pw != opw) {
-# ifdef HAVE_SETAUTHDB
-       aix_setauthdb(pw->pw_name);
-# endif
-       if (initgroups(pw->pw_name, pw->pw_gid) < 0)
-           log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
-# ifdef HAVE_GETGROUPS
-       if (groups) {
-           efree(groups);
-           groups = NULL;
-       }
-       if ((ngroups = getgroups(0, NULL)) > 0) {
-           groups = emalloc2(ngroups, sizeof(GETGROUPS_T));
-           if (getgroups(ngroups, groups) < 0)
-               log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
-       }
-#  ifdef HAVE_SETAUTHDB
-       aix_restoreauthdb();
-#  endif
-    } else {
-       if (setgroups(ngroups, groups) < 0)
-           log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
-# endif /* HAVE_GETGROUPS */
-    }
-}
-
-static void
-restore_groups()
-{
-    if (user_ngroups >= 0 && setgroups(user_ngroups, user_groups) < 0)
-       log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
-}
-
-#else
-
-static void
-runas_setgroups()
-{
-    /* STUB */
-}
-
-static void
-restore_groups()
-{
-    /* STUB */
-}
-
-#endif /* HAVE_INITGROUPS */
-
-#ifdef HAVE_PROJECT_H
-static void
-set_project(pw)
-    struct passwd *pw;
-{
-    struct project proj;
-    char buf[PROJECT_BUFSZ];
-    int errval;
-
-    /*
-     * Collect the default project for the user and settaskid
-     */
-    setprojent();
-    if (getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf)) != NULL) {
-       errval = setproject(proj.pj_name, pw->pw_name, TASK_NORMAL);
-       switch(errval) {
-       case 0:
-           break;
-       case SETPROJ_ERR_TASK:
-           switch (errno) {
-           case EAGAIN:
-               warningx("resource control limit has been reached");
-               break;
-           case ESRCH:
-               warningx("user \"%s\" is not a member of project \"%s\"",
-                   pw->pw_name, proj.pj_name);
-               break;
-           case EACCES:
-               warningx("the invoking task is final");
-               break;
-           default:
-               warningx("could not join project \"%s\"", proj.pj_name);
-           }
-       case SETPROJ_ERR_POOL:
-           switch (errno) {
-           case EACCES:
-               warningx("no resource pool accepting default bindings "
-                   "exists for project \"%s\"", proj.pj_name);
-               break;
-           case ESRCH:
-               warningx("specified resource pool does not exist for "
-                   "project \"%s\"", proj.pj_name);
-               break;
-           default:
-               warningx("could not bind to default resource pool for "
-                   "project \"%s\"", proj.pj_name);
-           }
-           break;
-       default:
-           if (errval <= 0) {
-               warningx("setproject failed for project \"%s\"", proj.pj_name);
-           } else {
-               warningx("warning, resource control assignment failed for "
-                   "project \"%s\"", proj.pj_name);
-           }
-       }
-    } else {
-       warning("getdefaultproj");
-    }
-    endprojent();
-}
-#endif /* HAVE_PROJECT_H */
-
-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_PROJECT_H
-       set_project(runas_pw);
-#endif
-#ifdef HAVE_GETUSERATTR
-       aix_prep_user(runas_pw->pw_name, user_ttypath);
-#endif
-#ifdef HAVE_PAM
-       pam_begin_session(runas_pw);
-#endif /* HAVE_PAM */
-
-#ifdef HAVE_LOGIN_CAP_H
-       if (def_use_loginclass) {
-           /*
-             * We only use setusercontext() to set the nice value and rlimits.
-            */
-           flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
-           if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
-               if (runas_pw->pw_uid != ROOT_UID)
-                   error(1, "unable to set user context");
-               else
-                   warning("unable to set user context");
-           }
-       }
-#endif /* HAVE_LOGIN_CAP_H */
-       /*
-        * Initialize group vector
-        */
-       runas_setgroups();
-#ifdef HAVE_SETEUID
-       if (setegid(gid))
-           warning("cannot set egid to runas gid");
-#endif
-       if (setgid(gid))
-           warning("cannot set gid to runas gid");
-    }
-}
diff --git a/setsid.c b/setsid.c
deleted file mode 100644 (file)
index 79271c8..0000000
--- a/setsid.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2010 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 <sys/ioctl.h>
-
-#include <fcntl.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-
-#include <pathnames.h>
-#include "missing.h"
-
-pid_t
-setsid()
-{
-    int fd;
-
-#ifdef SETPGRP_VOID
-    if (setpgrp() == -1)
-#else
-    if (setpgrp(0, 0) == -1)
-#endif
-       return -1;
-# ifdef TIOCNOTTY
-    if ((fd = open(_PATH_TTY, O_RDWR, 0644)) != -1) {
-        (void) ioctl(fd, TIOCNOTTY, NULL);
-        close(fd);
-    }
-# endif
-    return getpid();
-}
diff --git a/sigaction.c b/sigaction.c
deleted file mode 100644 (file)
index 9285dda..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 2001-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.
- *
- * 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 <signal.h>
-#include <errno.h>
-
-#include "missing.h"
-
-int
-sigaction(signo, sa, osa)
-    int signo;
-    const sigaction_t *sa;
-    sigaction_t *osa;
-{
-    sigaction_t nsa;
-    int error;
-
-    /* We must reverse SV_INTERRUPT since it is the opposite of SA_RESTART */
-    if (sa) {
-       nsa = *sa;
-       nsa.sa_flags ^= SV_INTERRUPT;
-       sa = &nsa;
-    }
-
-    error = sigvec(signo, sa, osa);
-    if (!error && osa)
-       osa->sa_flags ^= SV_INTERRUPT;          /* flip SV_INTERRUPT as above */
-
-    return error;
-}
-
-int
-sigemptyset(set)
-    sigset_t *set;
-{
-
-    *set = 0;
-    return 0;
-}
-
-int
-sigfillset(set)
-    sigset_t *set;
-{
-
-    *set = ~0;;
-    return 0;
-}
-
-int
-sigaddset(set, signo)
-    sigset_t *set;
-    int signo;
-{
-
-    if (signo <= 0 || signo >= NSIG) {
-       errno = EINVAL;
-       return -1;
-    }
-
-    SET(*set, sigmask(signo));
-    return 0;
-}
-
-int
-sigdelset(set, signo)
-    sigset_t *set;
-    int signo;
-{
-
-    if (signo <= 0 || signo >= NSIG) {
-       errno = EINVAL;
-       return -1;
-    }
-
-    CLR(*set, sigmask(signo));
-    return 0;
-}
-
-int
-sigismember(set, signo)
-    sigset_t *set;
-    int signo;
-{
-
-    return ISSET(*set, sigmask(signo));
-}
-
-int
-sigprocmask(how, set, oset)
-    int how;
-    const sigset_t *set;
-    sigset_t *oset;
-{
-    int mask;
-
-    /* If 'set' is NULL the user just wants the current signal mask. */
-    if (set == 0)
-       mask = sigblock(0);
-    else
-       switch (how) {
-           case SIG_BLOCK:
-               mask = sigblock(*set);
-               break;
-           case SIG_UNBLOCK:
-               mask = sigsetmask(sigblock(0) & ~(*set));
-               break;
-           case SIG_SETMASK:
-               mask = sigsetmask(*set);
-               break;
-           default:
-               return -1;
-       }
-
-    if (mask == -1)
-       return -1;
-    if (oset)
-       *oset = mask;
-    return 0;
-}
diff --git a/siglist.in b/siglist.in
deleted file mode 100644 (file)
index f149eb5..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-# List of signals used to build sys_siglist (see mksiglist.c)
-# Adapted from pdksh; public domain
-#
-# Note that if a system has multiple defines for the same signal
-# (eg, SIGABRT vs SIGIOT, SIGCHLD vs SIGCLD), only the first one
-# will be seen, so the order in this list is important.
-#
-    HUP     Hangup
-    INT     Interrupt
-    QUIT    Quit
-    ILL     Illegal instruction
-    TRAP    Trace trap
-# before IOT (ABRT is posix and ABRT is sometimes the same as IOT)
-    ABRT    Abort
-    IOT     IOT instruction
-    EMT     EMT trap
-    FPE     Floating point exception
-    KILL    Killed
-# before BUS (Older Linux doesn't really have a BUS, but defines it to UNUSED)
-    UNUSED  Unused
-    BUS     Bus error
-    SEGV    Memory fault
-    SYS     Bad system call
-    PIPE    Broken pipe
-    ALRM    Alarm clock
-    TERM    Terminated
-    STKFLT  Stack fault
-# before POLL (POLL is sometimes the same as IO)
-    IO      I/O possible
-    XCPU    CPU time limit exceeded
-    XFSZ    File size limit exceeded
-    VTALRM  Virtual timer expired
-    PROF    Profiling timer expired
-    WINCH   Window size change
-    LOST    File lock lost
-    USR1    User defined signal 1
-    USR2    User defined signal 2
-    PWR     Power-fail/Restart
-    POLL    Pollable event occurred
-    STOP    Stopped (signal)
-    TSTP    Stopped
-    CONT    Continued
-# before CLD (CHLD is posix and CHLD is sometimes the same as CLD)
-    CHLD    Child exited
-    CLD     Child exited
-    TTIN    Stopped (tty input)
-    TTOU    Stopped (tty output)
-    INFO    Information request
-    URG     Urgent I/O condition
-# Solaris (svr4?) signals
-    WAITING No runnable LWPs
-    LWP            Inter-LWP signal
-    FREEZE  Checkpoint freeze
-    THAW    Checkpoint thaw
-    CANCEL  Thread cancellation
diff --git a/snprintf.c b/snprintf.c
deleted file mode 100644 (file)
index 3035232..0000000
+++ /dev/null
@@ -1,774 +0,0 @@
-/*
- * Copyright (c) 1999-2005, 2008, 2010
- *     Todd C. Miller <Todd.Miller@courtesan.com>
- * Copyright (c) 1990, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * 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.
- *
- * From: @(#)vfprintf.c        8.1 (Berkeley) 6/4/93
- */
-
-/*
- * v?snprintf/v?asprintf based on 4.4BSD stdio.
- * NOTE: does not support floating point.
- */
-
-#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_STDINT_H
-# include <stdint.h>
-#endif
-#ifdef HAVE_STRING_H
-# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
-#  include <memory.h>
-# endif
-# include <string.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
-# include <malloc.h>
-#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
-#include <limits.h>
-
-#ifdef __STDC__
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
-
-#include "missing.h"
-
-static int xxxprintf    __P((char **, size_t, int, const char *, va_list));
-
-/*
- * Some systems may not have these defined in <limits.h>
- */
-#ifndef ULONG_MAX
-# define ULONG_MAX     ((unsigned long)-1)
-#endif
-#ifndef LONG_MAX
-# define LONG_MAX      (ULONG_MAX / 2)
-#endif
-#ifdef HAVE_LONG_LONG_INT
-# ifndef ULLONG_MAX
-#  ifdef UQUAD_MAX
-#   define ULLONG_MAX  UQUAD_MAX
-#  else
-#   define ULLONG_MAX  ((unsigned long long)-1)
-#  endif
-# endif
-# ifndef LLONG_MAX
-#  ifdef QUAD_MAX
-#   define LLONG_MAX   QUAD_MAX
-#  else
-#   define LLONG_MAX   (ULLONG_MAX / 2)
-#  endif
-# endif
-#endif /* HAVE_LONG_LONG_INT */
-
-/*
- * Macros for converting digits to letters and vice versa
- */
-#define        to_digit(c)     ((c) - '0')
-#define is_digit(c)    ((unsigned int)to_digit(c) <= 9)
-#define        to_char(n)      ((n) + '0')
-
-/*
- * Flags used during conversion.
- */
-#define        ALT             0x001           /* alternate form */
-#define        HEXPREFIX       0x002           /* add 0x or 0X prefix */
-#define        LADJUST         0x004           /* left adjustment */
-#define        LONGDBL         0x008           /* long double; unimplemented */
-#define        LONGINT         0x010           /* long integer */
-#define        QUADINT         0x020           /* quad integer */
-#define        SHORTINT        0x040           /* short integer */
-#define        ZEROPAD         0x080           /* zero (as opposed to blank) pad */
-
-#define BUF            68
-
-#ifndef HAVE_MEMCHR
-void *
-memchr(s, c, n)
-       const void *s;
-       unsigned char c;
-       size_t n;
-{
-       if (n != 0) {
-               const unsigned char *p = s;
-
-               do {
-                       if (*p++ == c)
-                               return (void *)(p - 1);
-               } while (--n != 0);
-       }
-       return NULL;
-}
-#endif /* !HAVE_MEMCHR */
-
-/*
- * Convert an unsigned long to ASCII for printf purposes, returning
- * a pointer to the first character of the string representation.
- * Octal numbers can be forced to have a leading zero; hex numbers
- * use the given digits.
- */
-static char *
-__ultoa(val, endp, base, octzero, xdigs)
-       unsigned long val;
-       char *endp;
-       int base, octzero;
-       char *xdigs;
-{
-       char *cp = endp;
-       long sval;
-
-       /*
-        * Handle the three cases separately, in the hope of getting
-        * better/faster code.
-        */
-       switch (base) {
-       case 10:
-               if (val < 10) { /* many numbers are 1 digit */
-                       *--cp = to_char(val);
-                       return cp;
-               }
-               /*
-                * On many machines, unsigned arithmetic is harder than
-                * signed arithmetic, so we do at most one unsigned mod and
-                * divide; this is sufficient to reduce the range of
-                * the incoming value to where signed arithmetic works.
-                */
-               if (val > LONG_MAX) {
-                       *--cp = to_char(val % 10);
-                       sval = val / 10;
-               } else
-                       sval = val;
-               do {
-                       *--cp = to_char(sval % 10);
-                       sval /= 10;
-               } while (sval != 0);
-               break;
-
-       case 8:
-               do {
-                       *--cp = to_char(val & 7);
-                       val >>= 3;
-               } while (val);
-               if (octzero && *cp != '0')
-                       *--cp = '0';
-               break;
-
-       case 16:
-               do {
-                       *--cp = xdigs[val & 15];
-                       val >>= 4;
-               } while (val);
-               break;
-
-       default:                        /* oops */
-               abort();
-       }
-       return cp;
-}
-
-/* Identical to __ultoa, but for quads. */
-#ifdef HAVE_LONG_LONG_INT
-# if SIZEOF_LONG_INT == 8
-#  define __uqtoa(v, e, b, o, x) __ultoa((unsigned long)(v), (e), (b), (o), (x))
-# else
-static char *
-__uqtoa(val, endp, base, octzero, xdigs)
-       unsigned long long val;
-       char *endp;
-       int base, octzero;
-       char *xdigs;
-{
-       char *cp = endp;
-       long long sval;
-
-       /* quick test for small values; __ultoa is typically much faster */
-       /* (perhaps instead we should run until small, then call __ultoa?) */
-       if (val <= (unsigned long long)ULONG_MAX)
-               return __ultoa((unsigned long)val, endp, base, octzero, xdigs);
-       switch (base) {
-       case 10:
-               if (val < 10) {
-                       *--cp = to_char(val % 10);
-                       return cp;
-               }
-               if (val > LLONG_MAX) {
-                       *--cp = to_char(val % 10);
-                       sval = val / 10;
-               } else
-                       sval = val;
-               do {
-                       *--cp = to_char(sval % 10);
-                       sval /= 10;
-               } while (sval != 0);
-               break;
-
-       case 8:
-               do {
-                       *--cp = to_char(val & 7);
-                       val >>= 3;
-               } while (val);
-               if (octzero && *cp != '0')
-                       *--cp = '0';
-               break;
-
-       case 16:
-               do {
-                       *--cp = xdigs[val & 15];
-                       val >>= 4;
-               } while (val);
-               break;
-
-       default:                        /* oops */
-               abort();
-       }
-       return cp;
-}
-# endif /* !SIZEOF_LONG_INT */
-#endif /* HAVE_LONG_LONG_INT */
-
-/*
- * Actual printf innards.
- */
-static int
-xxxprintf(strp, strsize, alloc, fmt0, ap)
-       char **strp;
-       size_t strsize;
-       int alloc;
-       const char *fmt0;
-       va_list ap;
-{
-       char *fmt;              /* format string */
-       int ch;                 /* character from fmt */
-       int n;                  /* handy integer (short term usage) */
-       char *cp;               /* handy char pointer (short term usage) */
-       int flags;              /* flags as above */
-       int ret;                /* return value accumulator */
-       int width;              /* width from format (%8d), or 0 */
-       int prec;               /* precision from format (%.3d), or -1 */
-       char sign;              /* sign prefix (' ', '+', '-', or \0) */
-       unsigned long ulval = 0; /* integer arguments %[diouxX] */
-#ifdef HAVE_LONG_LONG_INT
-       unsigned long long uqval = 0; /* %q (quad) integers */
-#endif
-       int base;               /* base for [diouxX] conversion */
-       int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
-       int fieldsz;            /* field size expanded by sign, etc */
-       int realsz;             /* field size expanded by dprec */
-       int size;               /* size of converted field or string */
-       char *xdigs = "";       /* digits for [xX] conversion */
-       char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
-       char ox[2];             /* space for 0x hex-prefix */
-       char *str;              /* pointer to string to fill */
-       char *estr;             /* pointer to last char in str */
-
-       /*
-        * Choose PADSIZE to trade efficiency vs. size.  If larger printf
-        * fields occur frequently, increase PADSIZE and make the initialisers
-        * below longer.
-        */
-#define        PADSIZE 16              /* pad chunk size */
-       static char blanks[PADSIZE] =
-        {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
-       static char zeroes[PADSIZE] =
-        {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
-
-       /* Print chars to "str", (allocate as needed if alloc is set). */
-#define        PRINT(ptr, len) do { \
-       const char *p = ptr; \
-       const char *endp = ptr + len; \
-       while (p < endp && (str < estr || alloc)) { \
-               if (alloc && str >= estr) { \
-                       char *t; \
-                       strsize = (strsize << 1) + 1; \
-                       if (!(t = (char *)realloc(*strp, strsize))) { \
-                               free(str); \
-                               *strp = NULL; \
-                               ret = -1; \
-                               goto done; \
-                       } \
-                       str = t + (str - *strp); \
-                       estr = t + strsize - 1; \
-                       *strp = t; \
-               } \
-               *str++ = *p++; \
-       } \
-} while (0)
-
-       /* BEWARE, PAD uses `n'. */
-#define        PAD(plen, pstr) do { \
-       if ((n = (plen)) > 0) { \
-               while (n > PADSIZE) { \
-                       PRINT(pstr, PADSIZE); \
-                       n -= PADSIZE; \
-               } \
-               PRINT(pstr, n); \
-       } \
-} while (0)
-
-       /*
-        * To extend shorts properly, we need both signed and unsigned
-        * argument extraction methods.
-        */
-#define        SARG() \
-       (flags&LONGINT ? va_arg(ap, long) : \
-           flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
-           (long)va_arg(ap, int))
-#define        UARG() \
-       (flags&LONGINT ? va_arg(ap, unsigned long) : \
-           flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
-           (unsigned long)va_arg(ap, unsigned int))
-
-       fmt = (char *)fmt0;
-       ret = 0;
-
-       if (alloc) {
-               strsize = 128;
-               *strp = str = (char *)malloc(strsize);
-               if (str == NULL) {
-                       ret = -1;
-                       goto done;
-               }
-               estr = str + 127;
-       } else {
-               str = *strp;
-               if (strsize)
-                       estr = str + strsize - 1;
-               else
-                       estr = NULL;
-       }
-
-       /*
-        * Scan the format for conversions (`%' character).
-        */
-       for (;;) {
-               for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
-                       /* void */;
-               if ((n = fmt - cp) != 0) {
-                       PRINT(cp, n);
-                       ret += n;
-               }
-               if (ch == '\0')
-                       goto done;
-               fmt++;          /* skip over '%' */
-
-               flags = 0;
-               dprec = 0;
-               width = 0;
-               prec = -1;
-               sign = '\0';
-
-rflag:         ch = *fmt++;
-reswitch:      switch (ch) {
-               case ' ':
-                       /*
-                        * ``If the space and + flags both appear, the space
-                        * flag will be ignored.''
-                        *      -- ANSI X3J11
-                        */
-                       if (!sign)
-                               sign = ' ';
-                       goto rflag;
-               case '#':
-                       flags |= ALT;
-                       goto rflag;
-               case '*':
-                       /*
-                        * ``A negative field width argument is taken as a
-                        * - flag followed by a positive field width.''
-                        *      -- ANSI X3J11
-                        * They don't exclude field widths read from args.
-                        */
-                       if ((width = va_arg(ap, int)) >= 0)
-                               goto rflag;
-                       width = -width;
-                       /* FALLTHROUGH */
-               case '-':
-                       flags |= LADJUST;
-                       goto rflag;
-               case '+':
-                       sign = '+';
-                       goto rflag;
-               case '.':
-                       if ((ch = *fmt++) == '*') {
-                               n = va_arg(ap, int);
-                               prec = n < 0 ? -1 : n;
-                               goto rflag;
-                       }
-                       n = 0;
-                       while (is_digit(ch)) {
-                               n = 10 * n + to_digit(ch);
-                               ch = *fmt++;
-                       }
-                       prec = n < 0 ? -1 : n;
-                       goto reswitch;
-               case '0':
-                       /*
-                        * ``Note that 0 is taken as a flag, not as the
-                        * beginning of a field width.''
-                        *      -- ANSI X3J11
-                        */
-                       flags |= ZEROPAD;
-                       goto rflag;
-               case '1': case '2': case '3': case '4':
-               case '5': case '6': case '7': case '8': case '9':
-                       n = 0;
-                       do {
-                               n = 10 * n + to_digit(ch);
-                               ch = *fmt++;
-                       } while (is_digit(ch));
-                       width = n;
-                       goto reswitch;
-               case 'h':
-                       flags |= SHORTINT;
-                       goto rflag;
-               case 'l':
-                       flags |= LONGINT;
-                       goto rflag;
-#ifdef HAVE_LONG_LONG_INT
-               case 'q':
-                       flags |= QUADINT;
-                       goto rflag;
-#endif /* HAVE_LONG_LONG_INT */
-               case 'c':
-                       *(cp = buf) = va_arg(ap, int);
-                       size = 1;
-                       sign = '\0';
-                       break;
-               case 'D':
-                       flags |= LONGINT;
-                       /*FALLTHROUGH*/
-               case 'd':
-               case 'i':
-#ifdef HAVE_LONG_LONG_INT
-                       if (flags & QUADINT) {
-                               uqval = va_arg(ap, long long);
-                               if ((long long)uqval < 0) {
-                                       uqval = -uqval;
-                                       sign = '-';
-                               }
-                       }
-                       else
-#endif /* HAVE_LONG_LONG_INT */
-                       {
-                               ulval = SARG();
-                               if ((long)ulval < 0) {
-                                       ulval = -ulval;
-                                       sign = '-';
-                               }
-                       }
-                       base = 10;
-                       goto number;
-               case 'n':
-#ifdef HAVE_LONG_LONG_INT
-                       if (flags & QUADINT)
-                               *va_arg(ap, long long *) = ret;
-                       else
-#endif /* HAVE_LONG_LONG_INT */
-                       if (flags & LONGINT)
-                               *va_arg(ap, long *) = ret;
-                       else if (flags & SHORTINT)
-                               *va_arg(ap, short *) = ret;
-                       else
-                               *va_arg(ap, int *) = ret;
-                       continue;       /* no output */
-               case 'O':
-                       flags |= LONGINT;
-                       /*FALLTHROUGH*/
-               case 'o':
-#ifdef HAVE_LONG_LONG_INT
-                       if (flags & QUADINT)
-                               uqval = va_arg(ap, unsigned long long);
-                       else
-#endif /* HAVE_LONG_LONG_INT */
-                               ulval = UARG();
-                       base = 8;
-                       goto nosign;
-               case 'p':
-                       /*
-                        * ``The argument shall be a pointer to void.  The
-                        * value of the pointer is converted to a sequence
-                        * of printable characters, in an implementation-
-                        * defined manner.''
-                        *      -- ANSI X3J11
-                        */
-                       ulval = (unsigned long)va_arg(ap, void *);
-                       base = 16;
-                       xdigs = "0123456789abcdef";
-                       flags = (flags & ~QUADINT) | HEXPREFIX;
-                       ch = 'x';
-                       goto nosign;
-               case 's':
-                       if ((cp = va_arg(ap, char *)) == NULL)
-                               cp = "(null)";
-                       if (prec >= 0) {
-                               /*
-                                * can't use strlen; can only look for the
-                                * NUL in the first `prec' characters, and
-                                * strlen() will go further.
-                                */
-                               char *p = memchr(cp, 0, prec);
-
-                               if (p != NULL) {
-                                       size = p - cp;
-                                       if (size > prec)
-                                               size = prec;
-                               } else
-                                       size = prec;
-                       } else
-                               size = strlen(cp);
-                       sign = '\0';
-                       break;
-               case 'U':
-                       flags |= LONGINT;
-                       /*FALLTHROUGH*/
-               case 'u':
-#ifdef HAVE_LONG_LONG_INT
-                       if (flags & QUADINT)
-                               uqval = va_arg(ap, unsigned long long);
-                       else
-#endif /* HAVE_LONG_LONG_INT */
-                               ulval = UARG();
-                       base = 10;
-                       goto nosign;
-               case 'X':
-                       xdigs = "0123456789ABCDEF";
-                       goto hex;
-               case 'x':
-                       xdigs = "0123456789abcdef";
-hex:
-#ifdef HAVE_LONG_LONG_INT
-                       if (flags & QUADINT)
-                               uqval = va_arg(ap, unsigned long long);
-                       else
-#endif /* HAVE_LONG_LONG_INT */
-                               ulval = UARG();
-                       base = 16;
-                       /* leading 0x/X only if non-zero */
-                       if (flags & ALT &&
-#ifdef HAVE_LONG_LONG_INT
-                           (flags & QUADINT ? uqval != 0 : ulval != 0))
-#else
-                           ulval != 0)
-#endif /* HAVE_LONG_LONG_INT */
-                               flags |= HEXPREFIX;
-
-                       /* unsigned conversions */
-nosign:                        sign = '\0';
-                       /*
-                        * ``... diouXx conversions ... if a precision is
-                        * specified, the 0 flag will be ignored.''
-                        *      -- ANSI X3J11
-                        */
-number:                        if ((dprec = prec) >= 0)
-                               flags &= ~ZEROPAD;
-
-                       /*
-                        * ``The result of converting a zero value with an
-                        * explicit precision of zero is no characters.''
-                        *      -- ANSI X3J11
-                        */
-                       cp = buf + BUF;
-#ifdef HAVE_LONG_LONG_INT
-                       if (flags & QUADINT) {
-                               if (uqval != 0 || prec != 0)
-                                       cp = __uqtoa(uqval, cp, base,
-                                           flags & ALT, xdigs);
-                       }
-                       else
-#endif /* HAVE_LONG_LONG_INT */
-                       {
-                               if (ulval != 0 || prec != 0)
-                                       cp = __ultoa(ulval, cp, base,
-                                           flags & ALT, xdigs);
-                       }
-                       size = buf + BUF - cp;
-                       break;
-               default:        /* "%?" prints ?, unless ? is NUL */
-                       if (ch == '\0')
-                               goto done;
-                       /* pretend it was %c with argument ch */
-                       cp = buf;
-                       *cp = ch;
-                       size = 1;
-                       sign = '\0';
-                       break;
-               }
-
-               /*
-                * All reasonable formats wind up here.  At this point, `cp'
-                * points to a string which (if not flags&LADJUST) should be
-                * padded out to `width' places.  If flags&ZEROPAD, it should
-                * first be prefixed by any sign or other prefix; otherwise,
-                * it should be blank padded before the prefix is emitted.
-                * After any left-hand padding and prefixing, emit zeroes
-                * required by a decimal [diouxX] precision, then print the
-                * string proper, then emit zeroes required by any leftover
-                * floating precision; finally, if LADJUST, pad with blanks.
-                *
-                * Compute actual size, so we know how much to pad.
-                * fieldsz excludes decimal prec; realsz includes it.
-                */
-               fieldsz = size;
-               if (sign)
-                       fieldsz++;
-               else if (flags & HEXPREFIX)
-                       fieldsz += 2;
-               realsz = dprec > fieldsz ? dprec : fieldsz;
-
-               /* right-adjusting blank padding */
-               if ((flags & (LADJUST|ZEROPAD)) == 0)
-                       PAD(width - realsz, blanks);
-
-               /* prefix */
-               if (sign) {
-                       PRINT(&sign, 1);
-               } else if (flags & HEXPREFIX) {
-                       ox[0] = '0';
-                       ox[1] = ch;
-                       PRINT(ox, 2);
-               }
-
-               /* right-adjusting zero padding */
-               if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
-                       PAD(width - realsz, zeroes);
-
-               /* leading zeroes from decimal precision */
-               PAD(dprec - fieldsz, zeroes);
-
-               /* the string or number proper */
-               PRINT(cp, size);
-
-               /* left-adjusting padding (always blank) */
-               if (flags & LADJUST)
-                       PAD(width - realsz, blanks);
-
-               /* finally, adjust ret */
-               ret += width > realsz ? width : realsz;
-       }
-done:
-       if (strsize)
-               *str = '\0';
-       return ret;
-       /* NOTREACHED */
-}
-
-#ifndef HAVE_VSNPRINTF
-int
-vsnprintf(str, n, fmt, ap)
-       char *str;
-       size_t n;
-       const char *fmt;
-       va_list ap;
-{
-
-       return xxxprintf(&str, n, 0, fmt, ap);
-}
-#endif /* HAVE_VSNPRINTF */
-
-#ifndef HAVE_SNPRINTF
-int
-#ifdef __STDC__
-snprintf(char *str, size_t n, char const *fmt, ...)
-#else
-snprintf(str, n, fmt, va_alist)
-       char *str;
-       size_t n;
-       char const *fmt;
-       va_dcl
-#endif
-{
-       int ret;
-       va_list ap;
-
-#ifdef __STDC__
-       va_start(ap, fmt);
-#else
-       va_start(ap);
-#endif
-       ret = xxxprintf(&str, n, 0, fmt, ap);
-       va_end(ap);
-       return ret;
-}
-#endif /* HAVE_SNPRINTF */
-
-#ifndef HAVE_VASPRINTF
-int
-vasprintf(str, fmt, ap)
-       char **str;
-       const char *fmt;
-       va_list ap;
-{
-
-       return xxxprintf(str, 0, 1, fmt, ap);
-}
-#endif /* HAVE_VASPRINTF */
-
-#ifndef HAVE_ASPRINTF
-int
-#ifdef __STDC__
-asprintf(char **str, char const *fmt, ...)
-#else
-asprintf(str, fmt, va_alist)
-       char **str;
-       char const *fmt;
-       va_dcl
-#endif
-{
-       int ret;
-       va_list ap;
-
-#ifdef __STDC__
-       va_start(ap, fmt);
-#else
-       va_start(ap);
-#endif
-       ret = xxxprintf(str, 0, 1, fmt, ap);
-       va_end(ap);
-       return ret;
-}
-#endif /* HAVE_ASPRINTF */
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644 (file)
index 0000000..c1b15bc
--- /dev/null
@@ -0,0 +1,189 @@
+#
+# Copyright (c) 2011 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.
+#
+# @configure_input@
+#
+
+#### Start of system configuration section. ####
+
+srcdir = @srcdir@
+devdir = @devdir@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+incdir = $(top_srcdir)/include
+
+# Compiler & tools to use
+CC = @CC@
+LIBTOOL = @LIBTOOL@ @LT_STATIC@
+
+# Our install program supports extra flags...
+INSTALL = $(SHELL) $(top_srcdir)/install-sh -c
+
+# Libraries
+LT_LIBS = $(top_builddir)/common/libcommon.la $(LIBOBJDIR)libreplace.la
+LIBS = @LIBS@ @SUDO_LIBS@ @GETGROUPS_LIB@ @NET_LIBS@ $(LT_LIBS)
+
+# C preprocessor flags
+CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(srcdir) -I. @CPPFLAGS@
+
+# Usually -O and/or -g
+CFLAGS = @CFLAGS@
+
+# Flags to pass to the link stage
+LDFLAGS = @LDFLAGS@
+
+# Where to install things...
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+sbindir = @sbindir@
+sysconfdir = @sysconfdir@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
+localstatedir = @localstatedir@
+noexecfile = @NOEXECFILE@
+noexecdir = @NOEXECDIR@
+
+# User and group ids the installed files should be "owned" by
+install_uid = 0
+install_gid = 0
+
+# OS dependent defines
+DEFS = @OSDEFS@ -D_PATH_SUDO_CONF=\"$(sysconfdir)/sudo.conf\"
+
+#### End of system configuration section. ####
+
+SHELL = @SHELL@
+
+PROGS = @PROGS@
+
+OBJS = conversation.o error.o exec.o exec_pty.o get_pty.o net_ifs.o \
+       load_plugins.o parse_args.o sudo.o sudo_edit.o tgetpass.o \
+       ttysize.o utmp.o @SUDO_OBJS@
+
+LIBOBJDIR = $(top_builddir)/@ac_config_libobj_dir@/
+
+VERSION = @PACKAGE_VERSION@
+
+SUDODEP = $(srcdir)/sudo.h $(incdir)/sudo_plugin.h $(incdir)/alloc.h \
+         $(incdir)/error.h $(incdir)/list.h $(incdir)/missing.h \
+         $(top_builddir)/pathnames.h $(top_builddir)/config.h
+
+all: $(PROGS)
+
+Makefile: $(srcdir)/Makefile.in
+       (cd $(top_builddir) && ./config.status --file src/Makefile)
+
+.SUFFIXES: .c .h .lo .o
+
+.c.o:
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $<
+
+.c.lo:
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $<
+
+sudo: $(OBJS) $(LT_LIBS)
+       $(LIBTOOL) --mode=link $(CC) -o $@ $(OBJS) $(LDFLAGS) $(LIBS) -static-libtool-libs
+
+libsudo_noexec.la: sudo_noexec.lo
+       $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ sudo_noexec.lo -avoid-version -rpath $(noexecdir)
+
+sesh: sesh.o
+       $(CC) -o $@ sesh.o
+
+# Dependencies
+# XXX - SUDODEP is overkill for some of these
+conversation.o: $(srcdir)/conversation.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/conversation.c
+error.o: $(srcdir)/error.c $(incdir)/missing.h $(incdir)/error.h $(top_builddir)/config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/error.c
+exec.o: $(srcdir)/exec.c $(SUDODEP) $(srcdir)/sudo_exec.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/exec.c
+exec_pty.o: $(srcdir)/exec_pty.c $(SUDODEP) $(srcdir)/sudo_exec.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/exec_pty.c
+get_pty.o: $(srcdir)/get_pty.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/get_pty.c
+net_ifs.o: $(srcdir)/net_ifs.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/net_ifs.c
+load_plugins.o: $(srcdir)/load_plugins.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/load_plugins.c
+parse_args.o: $(srcdir)/parse_args.c sudo_usage.h $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/parse_args.c
+preload.o: $(srcdir)/preload.c $(incdir)/sudo_plugin.h $(top_builddir)/config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/preload.c
+selinux.o: $(srcdir)/selinux.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/selinux.c
+sesh.o: $(srcdir)/sesh.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sesh.c
+sudo.o: $(srcdir)/sudo.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudo.c
+sudo_edit.o: $(srcdir)/sudo_edit.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudo_edit.c
+sudo_noexec.lo: $(srcdir)/sudo_noexec.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudo_noexec.c
+tgetpass.o: $(srcdir)/tgetpass.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/tgetpass.c
+ttysize.o: $(srcdir)/ttysize.c $(incdir)/missing.h $(top_builddir)/config.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/ttysize.c
+utmp.o: $(srcdir)/utmp.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/utmp.c
+
+pre-install:
+
+install: install-dirs install-binaries @INSTALL_NOEXEC@
+
+install-dirs:
+       $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir) \
+           $(DESTDIR)$(noexecdir)
+
+install-binaries: install-dirs $(PROGS)
+       $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 04111 sudo $(DESTDIR)$(bindir)/sudo
+       rm -f $(DESTDIR)$(bindir)/sudoedit
+       ln $(DESTDIR)$(bindir)/sudo $(DESTDIR)$(bindir)/sudoedit
+       if [ -f sesh ]; then $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0111 sesh $(DESTDIR)$(libexecdir)/sesh; fi
+
+install-doc:
+
+install-includes:
+
+# We install sudo_noexec by hand so we can avoid a "lib" prefix
+# and a version number.  Since we use LD_PRELOAD, neither is needed.
+install-noexec: install-dirs libsudo_noexec.la
+       if [ -f .libs/lib$(noexecfile) ]; then $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0755 .libs/lib$(noexecfile) $(DESTDIR)$(noexecdir)/$(noexecfile); fi
+
+install-plugin:
+
+uninstall:
+       -rm -f  $(DESTDIR)$(bindir)/sudo $(DESTDIR)$(bindir)/sudoedit \
+               $(DESTDIR)$(libexecdir)/sesh \
+               $(DESTDIR)$(noexecdir)/$(noexecfile) \
+
+check:
+
+clean:
+       -$(LIBTOOL) --mode=clean rm -f $(PROGS) *.lo *.o *.la *.a stamp-* core *.core core.*
+
+mostlyclean: clean
+
+distclean: clean
+       -rm -rf Makefile .libs sudo_usage.h
+
+clobber: distclean
+
+realclean: distclean
+       rm -f TAGS tags
+
+cleandir: realclean
diff --git a/src/conversation.c b/src/conversation.c
new file mode 100644 (file)
index 0000000..fa40f79
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1999-2005, 2007-2010 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/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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <errno.h>
+
+#include "sudo.h"
+#include "sudo_plugin.h"
+
+extern int tgetpass_flags; /* XXX */
+
+/*
+ * Sudo conversation function.
+ */
+int
+sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
+    struct sudo_conv_reply replies[])
+{
+    struct sudo_conv_reply *repl;
+    const struct sudo_conv_message *msg;
+    char *pass;
+    int n, flags = tgetpass_flags;
+
+    for (n = 0; n < num_msgs; n++) {
+       msg = &msgs[n];
+       repl = &replies[n];
+       switch (msg->msg_type & 0xff) {
+           case SUDO_CONV_PROMPT_ECHO_ON:
+           case SUDO_CONV_PROMPT_MASK:
+               if (msg->msg_type == SUDO_CONV_PROMPT_ECHO_ON)
+                   SET(flags, TGP_ECHO);
+               else
+                   SET(flags, TGP_MASK);
+               /* FALLTHROUGH */
+           case SUDO_CONV_PROMPT_ECHO_OFF:
+               if (ISSET(msg->msg_type, SUDO_CONV_PROMPT_ECHO_OK))
+                   SET(flags, TGP_NOECHO_TRY);
+               /* Read the password unless interrupted. */
+               pass = tgetpass(msg->msg, msg->timeout, flags);
+               if (pass == NULL)
+                   goto err;
+               repl->reply = estrdup(pass);
+               zero_bytes(pass, strlen(pass));
+               break;
+           case SUDO_CONV_INFO_MSG:
+               if (msg->msg)
+                   (void) fputs(msg->msg, stdout);
+               break;
+           case SUDO_CONV_ERROR_MSG:
+               if (msg->msg)
+                   (void) fputs(msg->msg, stderr);
+               break;
+           default:
+               goto err;
+       }
+    }
+
+    return 0;
+
+err:
+    /* Zero and free allocated memory and return an error. */
+    do {
+       repl = &replies[n];
+       if (repl->reply != NULL) {
+           zero_bytes(repl->reply, strlen(repl->reply));
+           free(repl->reply);
+           repl->reply = NULL;
+       }
+    } while (n--);
+
+    return -1;
+}
+
+int
+_sudo_printf(int msg_type, const char *fmt, ...)
+{
+    va_list ap;
+    FILE *fp;
+    int len;
+
+    switch (msg_type) {
+    case SUDO_CONV_INFO_MSG:
+       fp = stdout;
+       break;
+    case SUDO_CONV_ERROR_MSG:
+       fp = stderr;
+       break;
+    default:
+       errno = EINVAL;
+       return -1;
+    }
+
+    va_start(ap, fmt);
+    len = vfprintf(fp, fmt, ap);
+    va_end(ap);
+
+    return len;
+}
diff --git a/src/error.c b/src/error.c
new file mode 100644 (file)
index 0000000..8e26789
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2004-2005, 2010 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "missing.h"
+#include "error.h"
+
+static void _warning(int, const char *, va_list);
+       void cleanup(int);
+
+void
+error(int eval, const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       _warning(1, fmt, ap);
+       va_end(ap);
+       cleanup(0);
+       exit(eval);
+}
+
+void
+errorx(int eval, const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       _warning(0, fmt, ap);
+       va_end(ap);
+       cleanup(0);
+       exit(eval);
+}
+
+void
+warning(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       _warning(1, fmt, ap);
+       va_end(ap);
+}
+
+void
+warningx(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       _warning(0, fmt, ap);
+       va_end(ap);
+}
+
+static void
+_warning(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/src/exec.c b/src/exec.c
new file mode 100644 (file)
index 0000000..510ce11
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ * Copyright (c) 2009-2011 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>
+#ifdef HAVE_SYS_SYSMACROS_H
+# include <sys/sysmacros.h>
+#endif
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#ifdef HAVE_SETLOCALE
+# include <locale.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <termios.h>
+
+#include "sudo.h"
+#include "sudo_exec.h"
+#include "sudo_plugin.h"
+#include "sudo_plugin_int.h"
+
+/* Shared with exec_pty.c for use with handler(). */
+int signal_pipe[2];
+
+/* We keep a tailq of signals to forward to child. */
+struct sigforward {
+    struct sigforward *prev, *next;
+    int signo;
+};
+TQ_DECLARE(sigforward)
+static struct sigforward_list sigfwd_list;
+
+static int handle_signals(int fd, pid_t child, int log_io,
+    struct command_status *cstat);
+static void forward_signals(int fd);
+static void schedule_signal(int signo);
+
+/*
+ * Like execve(2) but falls back to running through /bin/sh
+ * ala execvp(3) if we get ENOEXEC.
+ */
+int
+my_execve(const char *path, char *const argv[], char *const envp[])
+{
+    execve(path, argv, envp);
+    if (errno == ENOEXEC) {
+       int argc;
+       char **nargv;
+
+       for (argc = 0; argv[argc] != NULL; argc++)
+           continue;
+       nargv = emalloc2(argc + 2, sizeof(char *));
+       nargv[0] = "sh";
+       nargv[1] = (char *)path;
+       memcpy(nargv + 2, argv + 1, argc * sizeof(char *));
+       execve(_PATH_BSHELL, nargv, envp);
+       efree(nargv);
+    }
+    return -1;
+}
+
+/*
+ * Fork and execute a command, returns the child's pid.
+ * Sends errno back on sv[1] if execve() fails.
+ */
+static int fork_cmnd(struct command_details *details, int sv[2])
+{
+    struct command_status cstat;
+    sigaction_t sa;
+    pid_t child;
+
+    zero_bytes(&sa, sizeof(sa));
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
+    sa.sa_handler = handler;
+    sigaction(SIGCONT, &sa, NULL);
+
+    child = fork();
+    switch (child) {
+    case -1:
+       error(1, "fork");
+       break;
+    case 0:
+       /* child */
+       close(sv[0]);
+       close(signal_pipe[0]);
+       close(signal_pipe[1]);
+       fcntl(sv[1], F_SETFD, FD_CLOEXEC);
+       restore_signals();
+       if (exec_setup(details, NULL, -1) == TRUE) {
+           /* headed for execve() */
+           if (details->closefrom >= 0)
+               closefrom(details->closefrom);
+#ifdef HAVE_SELINUX
+           if (ISSET(details->flags, CD_RBAC_ENABLED))
+               selinux_execve(details->command, details->argv, details->envp);
+           else
+#endif
+               my_execve(details->command, details->argv, details->envp);
+       }
+       cstat.type = CMD_ERRNO;
+       cstat.val = errno;
+       send(sv[1], &cstat, sizeof(cstat), 0);
+       _exit(1);
+    }
+    return child;
+}
+
+static struct signal_state {
+    int signo;
+    sigaction_t sa;
+} saved_signals[] = {
+    { SIGALRM },
+    { SIGCHLD },
+    { SIGCONT },
+    { SIGHUP },
+    { SIGINT },
+    { SIGPIPE },
+    { SIGQUIT },
+    { SIGTERM },
+    { SIGTSTP },
+    { SIGTTIN },
+    { SIGTTOU },
+    { SIGUSR1 },
+    { SIGUSR2 },
+    { -1 }
+};
+
+/*
+ * Save signal handler state so it can be restored before exec.
+ */
+void
+save_signals(void)
+{
+    struct signal_state *ss;
+
+    for (ss = saved_signals; ss->signo != -1; ss++)
+       sigaction(ss->signo, NULL, &ss->sa);
+}
+
+/*
+ * Restore signal handlers to initial state.
+ */
+void
+restore_signals(void)
+{
+    struct signal_state *ss;
+
+    for (ss = saved_signals; ss->signo != -1; ss++)
+       sigaction(ss->signo, &ss->sa, NULL);
+}
+
+/*
+ * Execute a command, potentially in a pty with I/O loggging.
+ * This is a little bit tricky due to how POSIX job control works and
+ * we fact that we have two different controlling terminals to deal with.
+ */
+int
+sudo_execve(struct command_details *details, struct command_status *cstat)
+{
+    int maxfd, n, nready, sv[2], log_io = FALSE;
+    const char *utmp_user = NULL;
+    fd_set *fdsr, *fdsw;
+    sigaction_t sa;
+    pid_t child;
+
+    /* If running in background mode, fork and exit. */
+    if (ISSET(details->flags, CD_BACKGROUND)) {
+       switch (fork()) {
+           case -1:
+               cstat->type = CMD_ERRNO;
+               cstat->val = errno;
+               return -1;
+           case 0:
+               /* child continues */   
+               break;
+           default:
+               /* parent exits */
+               exit(0);
+       }
+    }
+
+    /*
+     * If we have an I/O plugin or the policy plugin has requested one, we
+     * need to allocate a pty.  It is OK to set log_io in the pty-only case
+     * as the tailqueue plugin will be empty and no I/O logging will occur.
+     */
+    if (!tq_empty(&io_plugins) || ISSET(details->flags, CD_USE_PTY)) {
+       log_io = TRUE;
+       if (!ISSET(details->flags, CD_BACKGROUND)) {
+           if (ISSET(details->flags, CD_SET_UTMP))
+               utmp_user = details->utmp_user ? details->utmp_user : user_details.username;
+           sudo_debug(8, "allocate pty for I/O logging");
+           pty_setup(details->euid, user_details.tty, utmp_user);
+       }
+    }
+
+    /*
+     * We communicate with the child over a bi-directional pair of sockets.
+     * Parent sends signal info to child and child sends back wait status.
+     */
+    if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1)
+       error(1, "cannot create sockets");
+
+    /*
+     * We use a pipe to atomically handle signal notification within
+     * the select() loop.
+     */
+    if (pipe_nonblock(signal_pipe) != 0)
+       error(1, "cannot create pipe");
+
+    zero_bytes(&sa, sizeof(sa));
+    sigemptyset(&sa.sa_mask);
+
+    /*
+     * Signals for forward to the child process (excluding SIGALRM and SIGCHLD).
+     * Note: HP-UX select() will not be interrupted if SA_RESTART set.
+     */
+    sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
+    sa.sa_handler = handler;
+    sigaction(SIGALRM, &sa, NULL);
+    sigaction(SIGCHLD, &sa, NULL);
+    sigaction(SIGHUP, &sa, NULL);
+    sigaction(SIGINT, &sa, NULL);
+    sigaction(SIGPIPE, &sa, NULL);
+    sigaction(SIGQUIT, &sa, NULL);
+    sigaction(SIGTERM, &sa, NULL);
+    sigaction(SIGUSR1, &sa, NULL);
+    sigaction(SIGUSR2, &sa, NULL);
+
+    /* Max fd we will be selecting on. */
+    maxfd = MAX(sv[0], signal_pipe[0]);
+
+    /*
+     * Child will run the command in the pty, parent will pass data
+     * to and from pty.  Adjusts maxfd as needed.
+     */
+    if (log_io)
+       child = fork_pty(details, sv, &maxfd);
+    else
+       child = fork_cmnd(details, sv);
+    close(sv[1]);
+
+    /* Set command timeout if specified. */
+    if (ISSET(details->flags, CD_SET_TIMEOUT))
+       alarm(details->timeout);
+
+#ifdef HAVE_SETLOCALE
+    /*
+     * I/O logging must be in the C locale for floating point numbers
+     * to be logged consistently.
+     */
+    setlocale(LC_ALL, "C");
+#endif
+
+    /*
+     * In the event loop we pass input from user tty to master
+     * and pass output from master to stdout and IO plugin.
+     */
+    fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
+    fdsw = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
+    for (;;) {
+       zero_bytes(fdsw, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
+       zero_bytes(fdsr, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
+
+       FD_SET(signal_pipe[0], fdsr);
+       FD_SET(sv[0], fdsr);
+       if (!tq_empty(&sigfwd_list))
+           FD_SET(sv[0], fdsw);
+       if (log_io)
+           fd_set_iobs(fdsr, fdsw); /* XXX - better name */
+       nready = select(maxfd + 1, fdsr, fdsw, NULL, NULL);
+       if (nready == -1) {
+           if (errno == EINTR)
+               continue;
+           error(1, "select failed");
+       }
+       if (FD_ISSET(sv[0], fdsw)) {
+           forward_signals(sv[0]);
+       }
+       if (FD_ISSET(signal_pipe[0], fdsr)) {
+           n = handle_signals(signal_pipe[0], child, log_io, cstat);
+           if (n == 0) {
+               /* Child has exited, cstat is set, we are done. */
+               goto done;
+           }
+           if (n == -1) {
+               /* Error reading signal_pipe[0], should not happen. */
+               break;
+           }
+           /* Restart event loop so signals get sent to child immediately. */
+           continue;
+       }
+       if (FD_ISSET(sv[0], fdsr)) {
+           /* read child status */
+           n = recv(sv[0], cstat, sizeof(*cstat), 0);
+           if (n == -1) {
+               if (errno == EINTR)
+                   continue;
+               /*
+                * If not logging I/O we will receive ECONNRESET when
+                * the command is executed.  It is safe to ignore this.
+                */
+               if (log_io && errno != EAGAIN) {
+                   cstat->type = CMD_ERRNO;
+                   cstat->val = errno;
+                   break;
+               }
+           }
+           if (cstat->type == CMD_WSTATUS) {
+               if (WIFSTOPPED(cstat->val)) {
+                   /* Suspend parent and tell child how to resume on return. */
+                   sudo_debug(8, "child stopped, suspending parent");
+                   n = suspend_parent(WSTOPSIG(cstat->val));
+                   schedule_signal(n);
+                   continue;
+               } else {
+                   /* Child exited or was killed, either way we are done. */
+                   break;
+               }
+           } else if (cstat->type == CMD_ERRNO) {
+               /* Child was unable to execute command or broken pipe. */
+               break;
+           }
+       }
+
+       if (perform_io(fdsr, fdsw, cstat) != 0) {
+           /* I/O error, kill child if still alive and finish. */
+           schedule_signal(SIGKILL);
+           forward_signals(sv[0]);
+           break;
+       }
+    }
+
+    if (log_io) {
+       /* Flush any remaining output and free pty-related memory. */
+       pty_close(cstat);
+   }
+
+#ifdef HAVE_SELINUX
+    if (ISSET(details->flags, CD_RBAC_ENABLED)) {
+       /* This is probably not needed in log_io mode. */
+       if (selinux_restore_tty() != 0)
+           warningx("unable to restore tty label");
+    }
+#endif
+
+done:
+    efree(fdsr);
+    efree(fdsw);
+    while (!tq_empty(&sigfwd_list)) {
+       struct sigforward *sigfwd = tq_first(&sigfwd_list);
+       tq_remove(&sigfwd_list, sigfwd);
+       efree(sigfwd);
+    }
+
+    return cstat->type == CMD_ERRNO ? -1 : 0;
+}
+
+/*
+ * Read signals on fd written to by handler().
+ * Returns -1 on error, 0 on child exit, else 1.
+ */
+static int
+handle_signals(int fd, pid_t child, int log_io, struct command_status *cstat)
+{
+    unsigned char signo;
+    ssize_t nread;
+    int status;
+    pid_t pid;
+
+    for (;;) {
+       /* read signal pipe */
+       nread = read(signal_pipe[0], &signo, sizeof(signo));
+       if (nread <= 0) {
+           /* It should not be possible to get EOF but just in case. */
+           if (nread == 0)
+               errno = ECONNRESET;
+           /* Restart if interrupted by signal so the pipe doesn't fill. */
+           if (errno == EINTR)
+               continue;
+           /* If pipe is empty, we are done. */
+           if (errno == EAGAIN)
+               break;
+           sudo_debug(9, "error reading signal pipe %s", strerror(errno));
+           cstat->type = CMD_ERRNO;
+           cstat->val = errno;
+           return -1;
+       }
+       sudo_debug(9, "received signal %d", signo);
+       if (signo == SIGCHLD) {
+           /*
+            * If logging I/O, child is the intermediate process,
+            * otherwise it is the command itself.
+            */
+           do {
+               pid = waitpid(child, &status, WUNTRACED|WNOHANG);
+           } while (pid == -1 && errno == EINTR);
+           if (pid == child) {
+               /* If not logging I/O and child has exited we are done. */
+               if (!log_io) {
+                   if (WIFSTOPPED(status)) {
+                       /*
+                        * Save the controlling terminal's process group
+                        * so we can restore it after we resume.
+                        */
+                       pid_t saved_pgrp = (pid_t)-1;
+                       int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
+                       if (fd != -1)
+                           saved_pgrp = tcgetpgrp(fd);
+                       if (kill(getpid(), WSTOPSIG(status)) != 0)
+                           warning("kill(%d, %d)", getpid(), WSTOPSIG(status));
+                       if (fd != -1) {
+                           if (saved_pgrp != (pid_t)-1)
+                               (void)tcsetpgrp(fd, saved_pgrp);
+                           close(fd);
+                       }
+                   } else {
+                       /* Child has exited, we are done. */
+                       cstat->type = CMD_WSTATUS;
+                       cstat->val = status;
+                       return 0;
+                   }
+               }
+               /* Else we get ECONNRESET on sv[0] if child dies. */
+           }
+       } else {
+           if (log_io) {
+               /* Schedule signo to be forwared to the child. */
+               schedule_signal(signo);
+           } else {
+               /* Nothing listening on sv[0], send directly. */
+               if (signo == SIGALRM)
+                   terminate_child(child, FALSE);
+               else if (kill(child, signo) != 0)
+                   warning("kill(%d, %d)", child, signo);
+           }
+       }
+    }
+    return 1;
+}
+
+/*
+ * Forward signals in sigfwd_list to child listening on fd.
+ */
+static void
+forward_signals(int sock)
+{
+    struct sigforward *sigfwd;
+    struct command_status cstat;
+    ssize_t nsent;
+
+    while (!tq_empty(&sigfwd_list)) {
+       sigfwd = tq_first(&sigfwd_list);
+       sudo_debug(9, "sending signal %d to child over backchannel",
+           sigfwd->signo);
+       cstat.type = CMD_SIGNO;
+       cstat.val = sigfwd->signo;
+       do {
+           nsent = send(sock, &cstat, sizeof(cstat), 0);
+       } while (nsent == -1 && errno == EINTR);
+       tq_remove(&sigfwd_list, sigfwd);
+       efree(sigfwd);
+       if (nsent != sizeof(cstat)) {
+           if (errno == EPIPE) {
+               /* Other end of socket gone, empty out sigfwd_list. */
+               while (!tq_empty(&sigfwd_list)) {
+                   sigfwd = tq_first(&sigfwd_list);
+                   tq_remove(&sigfwd_list, sigfwd);
+                   efree(sigfwd);
+               }
+           }
+           break;
+       }
+    }
+}
+
+/*
+ * Schedule a signal to be forwared.
+ */
+static void
+schedule_signal(int signo)
+{
+    struct sigforward *sigfwd;
+
+    sigfwd = emalloc(sizeof(*sigfwd));
+    sigfwd->prev = sigfwd;
+    sigfwd->next = NULL;
+    sigfwd->signo = signo;
+    tq_append(&sigfwd_list, sigfwd);
+}
+
+/*
+ * Generic handler for signals passed from parent -> child.
+ * The other end of signal_pipe is checked in the main event loop.
+ */
+void
+handler(int s)
+{
+    unsigned char signo = (unsigned char)s;
+
+    /*
+     * The pipe is non-blocking, if we overflow the kernel's pipe
+     * buffer we drop the signal.  This is not a problem in practice.
+     */
+    if (write(signal_pipe[1], &signo, sizeof(signo)) == -1)
+       /* shut up glibc */;
+}
+
+/*
+ * Open a pipe and make both ends non-blocking.
+ * Returns 0 on success and -1 on error.
+ */
+int
+pipe_nonblock(int fds[2])
+{
+    int flags, rval;
+
+    rval = pipe(fds);
+    if (rval != -1) {
+       flags = fcntl(fds[0], F_GETFL, 0);
+       if (flags != -1 && !ISSET(flags, O_NONBLOCK))
+           rval = fcntl(fds[0], F_SETFL, flags | O_NONBLOCK);
+       if (rval != -1) {
+           flags = fcntl(fds[1], F_GETFL, 0);
+           if (flags != -1 && !ISSET(flags, O_NONBLOCK))
+               rval = fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
+       }
+       if (rval == -1) {
+           close(fds[0]);
+           close(fds[1]);
+       }
+    }
+
+    return rval;
+}
diff --git a/src/exec_pty.c b/src/exec_pty.c
new file mode 100644 (file)
index 0000000..914d55f
--- /dev/null
@@ -0,0 +1,1170 @@
+/*
+ * Copyright (c) 2009-2011 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>
+#ifdef HAVE_SYS_SYSMACROS_H
+# include <sys/sysmacros.h>
+#endif
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <termios.h>
+
+#include "sudo.h"
+#include "sudo_exec.h"
+#include "sudo_plugin.h"
+#include "sudo_plugin_int.h"
+
+#define SFD_STDIN      0
+#define SFD_STDOUT     1
+#define SFD_STDERR     2
+#define SFD_MASTER     3
+#define SFD_SLAVE      4
+#define SFD_USERTTY    5
+
+#define TERM_COOKED    0
+#define TERM_RAW       1
+
+/* Compatibility with older tty systems. */
+#if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
+# define TIOCGWINSZ    TIOCGSIZE
+# define TIOCSWINSZ    TIOCSSIZE
+# define winsize       ttysize
+#endif
+
+struct io_buffer {
+    struct io_buffer *next;
+    int len; /* buffer length (how much produced) */
+    int off; /* write position (how much already consumed) */
+    int rfd;  /* reader (producer) */
+    int wfd; /* writer (consumer) */
+    int (*action)(const char *buf, unsigned int len);
+    char buf[16 * 1024];
+};
+
+static char slavename[PATH_MAX];
+static int foreground;
+static int io_fds[6] = { -1, -1, -1, -1, -1, -1};
+static int pipeline = FALSE;
+static int tty_initialized;
+static int ttymode = TERM_COOKED;
+static pid_t ppgrp, child, child_pgrp;
+static sigset_t ttyblock;
+static struct io_buffer *iobufs;
+
+static void flush_output(void);
+static int exec_monitor(struct command_details *details, int backchannel);
+static void exec_pty(struct command_details *detail);
+static void sigwinch(int s);
+static void sync_ttysize(int src, int dst);
+static void deliver_signal(pid_t pid, int signo);
+static int safe_close(int fd);
+
+/*
+ * Cleanup hook for error()/errorx()
+ */
+void
+cleanup(int gotsignal)
+{
+    if (!tq_empty(&io_plugins))
+       term_restore(io_fds[SFD_USERTTY], 0);
+#ifdef HAVE_SELINUX
+    selinux_restore_tty();
+#endif
+    utmp_logout(slavename, 0); /* XXX - only if CD_SET_UTMP */
+}
+
+/*
+ * Allocate a pty if /dev/tty is a tty.
+ * Fills in io_fds[SFD_USERTTY], io_fds[SFD_MASTER], io_fds[SFD_SLAVE]
+ * and slavename globals.
+ */
+void
+pty_setup(uid_t uid, const char *tty, const char *utmp_user)
+{
+    io_fds[SFD_USERTTY] = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
+    if (io_fds[SFD_USERTTY] != -1) {
+       if (!get_pty(&io_fds[SFD_MASTER], &io_fds[SFD_SLAVE],
+           slavename, sizeof(slavename), uid))
+           error(1, "Can't get pty");
+       /* Add entry to utmp/utmpx? */
+       if (utmp_user != NULL)
+           utmp_login(tty, slavename, io_fds[SFD_SLAVE], utmp_user);
+    }
+}
+
+/* Call I/O plugin tty input log method. */
+static int
+log_ttyin(const char *buf, unsigned int n)
+{
+    struct plugin_container *plugin;
+    sigset_t omask;
+    int rval = TRUE;
+
+    sigprocmask(SIG_BLOCK, &ttyblock, &omask);
+
+    tq_foreach_fwd(&io_plugins, plugin) {
+       if (plugin->u.io->log_ttyin) {
+           if (!plugin->u.io->log_ttyin(buf, n)) {
+               rval = FALSE;
+               break;
+           }
+       }
+    }
+
+    sigprocmask(SIG_SETMASK, &omask, NULL);
+    return rval;
+}
+
+/* Call I/O plugin stdin log method. */
+static int
+log_stdin(const char *buf, unsigned int n)
+{
+    struct plugin_container *plugin;
+    sigset_t omask;
+    int rval = TRUE;
+
+    sigprocmask(SIG_BLOCK, &ttyblock, &omask);
+
+    tq_foreach_fwd(&io_plugins, plugin) {
+       if (plugin->u.io->log_stdin) {
+           if (!plugin->u.io->log_stdin(buf, n)) {
+               rval = FALSE;
+               break;
+           }
+       }
+    }
+
+    sigprocmask(SIG_SETMASK, &omask, NULL);
+    return rval;
+}
+
+/* Call I/O plugin tty output log method. */
+static int
+log_ttyout(const char *buf, unsigned int n)
+{
+    struct plugin_container *plugin;
+    sigset_t omask;
+    int rval = TRUE;
+
+    sigprocmask(SIG_BLOCK, &ttyblock, &omask);
+
+    tq_foreach_fwd(&io_plugins, plugin) {
+       if (plugin->u.io->log_ttyout) {
+           if (!plugin->u.io->log_ttyout(buf, n)) {
+               rval = FALSE;
+               break;
+           }
+       }
+    }
+
+    sigprocmask(SIG_SETMASK, &omask, NULL);
+    return rval;
+}
+
+/* Call I/O plugin stdout log method. */
+static int
+log_stdout(const char *buf, unsigned int n)
+{
+    struct plugin_container *plugin;
+    sigset_t omask;
+    int rval = TRUE;
+
+    sigprocmask(SIG_BLOCK, &ttyblock, &omask);
+
+    tq_foreach_fwd(&io_plugins, plugin) {
+       if (plugin->u.io->log_stdout) {
+           if (!plugin->u.io->log_stdout(buf, n)) {
+               rval = FALSE;
+               break;
+           }
+       }
+    }
+
+    sigprocmask(SIG_SETMASK, &omask, NULL);
+    return rval;
+}
+
+/* Call I/O plugin stderr log method. */
+static int
+log_stderr(const char *buf, unsigned int n)
+{
+    struct plugin_container *plugin;
+    sigset_t omask;
+    int rval = TRUE;
+
+    sigprocmask(SIG_BLOCK, &ttyblock, &omask);
+
+    tq_foreach_fwd(&io_plugins, plugin) {
+       if (plugin->u.io->log_stderr) {
+           if (!plugin->u.io->log_stderr(buf, n)) {
+               rval = FALSE;
+               break;
+           }
+       }
+    }
+
+    sigprocmask(SIG_SETMASK, &omask, NULL);
+    return rval;
+}
+
+/*
+ * Check whether we are running in the foregroup.
+ * Updates the foreground global and does lazy init of the
+ * the pty slave as needed.
+ */
+static void
+check_foreground(void)
+{
+    if (io_fds[SFD_USERTTY] != -1) {
+       foreground = tcgetpgrp(io_fds[SFD_USERTTY]) == ppgrp;
+       if (foreground && !tty_initialized) {
+           if (term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE])) {
+               tty_initialized = 1;
+               sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]);
+           }
+       }
+    }
+}
+
+/*
+ * Suspend sudo if the underlying command is suspended.
+ * Returns SIGCONT_FG if the child should be resume in the
+ * foreground or SIGCONT_BG if it is a background process.
+ */
+int
+suspend_parent(int signo)
+{
+    sigaction_t sa, osa;
+    int n, oldmode = ttymode, rval = 0;
+
+    switch (signo) {
+    case SIGTTOU:
+    case SIGTTIN:
+       /*
+        * If we are the foreground process, just resume the child.
+        * Otherwise, re-send the signal with the handler disabled.
+        */
+       if (!foreground)
+           check_foreground();
+       if (foreground) {
+           if (ttymode != TERM_RAW) {
+               do {
+                   n = term_raw(io_fds[SFD_USERTTY], 0);
+               } while (!n && errno == EINTR);
+               ttymode = TERM_RAW;
+           }
+           rval = SIGCONT_FG; /* resume child in foreground */
+           break;
+       }
+       ttymode = TERM_RAW;
+       /* FALLTHROUGH */
+    case SIGSTOP:
+    case SIGTSTP:
+       /* Flush any remaining output before suspending. */
+       flush_output();
+
+       /* Restore original tty mode before suspending. */
+       if (oldmode != TERM_COOKED) {
+           do {
+               n = term_restore(io_fds[SFD_USERTTY], 0);
+           } while (!n && errno == EINTR);
+       }
+
+       /* Suspend self and continue child when we resume. */
+       sa.sa_handler = SIG_DFL;
+       sigaction(signo, &sa, &osa);
+       sudo_debug(8, "kill parent %d", signo);
+       if (killpg(ppgrp, signo) != 0)
+           warning("killpg(%d, %d)", ppgrp, signo);
+
+       /* Check foreground/background status on resume. */
+       check_foreground();
+
+       /*
+        * Only modify term if we are foreground process and either
+        * the old tty mode was not cooked or child got SIGTT{IN,OU}
+        */
+       sudo_debug(8, "parent is in %sground, ttymode %d -> %d",
+           foreground ? "fore" : "back", oldmode, ttymode);
+
+       if (ttymode != TERM_COOKED) {
+           if (foreground) {
+               /* Set raw mode. */
+               do {
+                   n = term_raw(io_fds[SFD_USERTTY], 0);
+               } while (!n && errno == EINTR);
+           } else {
+               /* Background process, no access to tty. */
+               ttymode = TERM_COOKED;
+           }
+       }
+
+       sigaction(signo, &osa, NULL);
+       rval = ttymode == TERM_RAW ? SIGCONT_FG : SIGCONT_BG;
+       break;
+    }
+
+    return rval;
+}
+
+/*
+ * Kill child with increasing urgency.
+ */
+void
+terminate_child(pid_t pid, int use_pgrp)
+{
+    /*
+     * Note that SIGCHLD will interrupt the sleep()
+     */
+    if (use_pgrp) {
+       killpg(pid, SIGHUP);
+       killpg(pid, SIGTERM);
+       sleep(2);
+       killpg(pid, SIGKILL);
+    } else {
+       kill(pid, SIGHUP);
+       kill(pid, SIGTERM);
+       sleep(2);
+       kill(pid, SIGKILL);
+    }
+}
+
+static struct io_buffer *
+io_buf_new(int rfd, int wfd, int (*action)(const char *, unsigned int),
+    struct io_buffer *head)
+{
+    struct io_buffer *iob;
+
+    iob = emalloc(sizeof(*iob));
+    zero_bytes(iob, sizeof(*iob));
+    iob->rfd = rfd;
+    iob->wfd = wfd;
+    iob->action = action;
+    iob->next = head;
+    return iob;
+}
+
+/*
+ * Read/write iobufs depending on fdsr and fdsw.
+ * Returns the number of errors.
+ */
+int
+perform_io(fd_set *fdsr, fd_set *fdsw, struct command_status *cstat)
+{
+    struct io_buffer *iob;
+    int n, errors = 0;
+
+    for (iob = iobufs; iob; iob = iob->next) {
+       if (iob->rfd != -1 && FD_ISSET(iob->rfd, fdsr)) {
+           do {
+               n = read(iob->rfd, iob->buf + iob->len,
+                   sizeof(iob->buf) - iob->len);
+           } while (n == -1 && errno == EINTR);
+           switch (n) {
+               case -1:
+                   if (errno == EAGAIN)
+                       break;
+                   if (errno != ENXIO && errno != EBADF) {
+                       errors++;
+                       break;
+                   }
+                   /* FALLTHROUGH */
+               case 0:
+                   /* got EOF or pty has gone away */
+                   safe_close(iob->rfd);
+                   iob->rfd = -1;
+                   break;
+               default:
+                   if (!iob->action(iob->buf + iob->len, n))
+                       terminate_child(child, TRUE);
+                   iob->len += n;
+                   break;
+           }
+       }
+       if (iob->wfd != -1 && FD_ISSET(iob->wfd, fdsw)) {
+           do {
+               n = write(iob->wfd, iob->buf + iob->off,
+                   iob->len - iob->off);
+           } while (n == -1 && errno == EINTR);
+           if (n == -1) {
+               if (errno == EPIPE || errno == ENXIO || errno == EBADF) {
+                   /* other end of pipe closed or pty revoked */
+                   if (iob->rfd != -1) {
+                       safe_close(iob->rfd);
+                       iob->rfd = -1;
+                   }
+                   safe_close(iob->wfd);
+                   iob->wfd = -1;
+                   continue;
+               }
+               if (errno != EAGAIN)
+                   errors++;
+           } else {
+               iob->off += n;
+           }
+       }
+    }
+    if (errors && cstat != NULL) {
+       cstat->type = CMD_ERRNO;
+       cstat->val = errno;
+    }
+    return errors;
+}
+
+/*
+ * Fork a monitor process which runs the actual command as its own child
+ * process with std{in,out,err} hooked up to the pty or pipes as appropriate.
+ * Returns the child pid.
+ */
+int
+fork_pty(struct command_details *details, int sv[], int *maxfd)
+{
+    struct command_status cstat;
+    struct io_buffer *iob;
+    int io_pipe[3][2], n;
+    sigaction_t sa;
+        
+    ppgrp = getpgrp(); /* parent's pgrp, so child can signal us */
+     
+    zero_bytes(&sa, sizeof(sa));
+    sigemptyset(&sa.sa_mask);
+    if (io_fds[SFD_USERTTY] != -1) {
+       sa.sa_flags = SA_RESTART;
+       sa.sa_handler = sigwinch;
+       sigaction(SIGWINCH, &sa, NULL);
+    }
+
+    /* So we can block tty-generated signals */
+    sigemptyset(&ttyblock);
+    sigaddset(&ttyblock, SIGINT);
+    sigaddset(&ttyblock, SIGQUIT);
+    sigaddset(&ttyblock, SIGTSTP);
+    sigaddset(&ttyblock, SIGTTIN);
+    sigaddset(&ttyblock, SIGTTOU);
+
+    /*
+     * Setup stdin/stdout/stderr for child, to be duped after forking.
+     */
+    io_fds[SFD_STDIN] = io_fds[SFD_SLAVE];
+    io_fds[SFD_STDOUT] = io_fds[SFD_SLAVE];
+    io_fds[SFD_STDERR] = io_fds[SFD_SLAVE];
+
+    /* Copy /dev/tty -> pty master */
+    if (io_fds[SFD_USERTTY] != -1) {
+       iobufs = io_buf_new(io_fds[SFD_USERTTY], io_fds[SFD_MASTER],
+           log_ttyin, iobufs);
+
+       /* Copy pty master -> /dev/tty */
+       iobufs = io_buf_new(io_fds[SFD_MASTER], io_fds[SFD_USERTTY],
+           log_ttyout, iobufs);
+
+       /* Are we the foreground process? */
+       foreground = tcgetpgrp(io_fds[SFD_USERTTY]) == ppgrp;
+    }
+
+    /*
+     * If either stdin, stdout or stderr is not a tty we use a pipe
+     * to interpose ourselves instead of duping the pty fd.
+     */
+    memset(io_pipe, 0, sizeof(io_pipe));
+    if (io_fds[SFD_STDIN] == -1 || !isatty(STDIN_FILENO)) {
+       pipeline = TRUE;
+       if (pipe(io_pipe[STDIN_FILENO]) != 0)
+           error(1, "unable to create pipe");
+       iobufs = io_buf_new(STDIN_FILENO, io_pipe[STDIN_FILENO][1],
+           log_stdin, iobufs);
+       io_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0];
+    }
+    if (io_fds[SFD_STDOUT] == -1 || !isatty(STDOUT_FILENO)) {
+       pipeline = TRUE;
+       if (pipe(io_pipe[STDOUT_FILENO]) != 0)
+           error(1, "unable to create pipe");
+       iobufs = io_buf_new(io_pipe[STDOUT_FILENO][0], STDOUT_FILENO,
+           log_stdout, iobufs);
+       io_fds[SFD_STDOUT] = io_pipe[STDOUT_FILENO][1];
+    }
+    if (io_fds[SFD_STDERR] == -1 || !isatty(STDERR_FILENO)) {
+       if (pipe(io_pipe[STDERR_FILENO]) != 0)
+           error(1, "unable to create pipe");
+       iobufs = io_buf_new(io_pipe[STDERR_FILENO][0], STDERR_FILENO,
+           log_stderr, iobufs);
+       io_fds[SFD_STDERR] = io_pipe[STDERR_FILENO][1];
+    }
+
+    /* Job control signals to relay from parent to child. */
+    sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
+    sa.sa_handler = handler;
+    sigaction(SIGTSTP, &sa, NULL);
+
+    if (foreground) {
+       /* Copy terminal attrs from user tty -> pty slave. */
+       if (term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE])) {
+           tty_initialized = 1;
+           sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]);
+       }
+
+       /* Start out in raw mode if we are not part of a pipeline. */
+       if (!pipeline) {
+           ttymode = TERM_RAW;
+           do {
+               n = term_raw(io_fds[SFD_USERTTY], 0);
+           } while (!n && errno == EINTR);
+           if (!n)
+               error(1, "Can't set terminal to raw mode");
+       }
+    }
+
+    child = fork();
+    switch (child) {
+    case -1:
+       error(1, "fork");
+       break;
+    case 0:
+       /* child */
+       close(sv[0]);
+       close(signal_pipe[0]);
+       close(signal_pipe[1]);
+       fcntl(sv[1], F_SETFD, FD_CLOEXEC);
+       if (exec_setup(details, slavename, io_fds[SFD_SLAVE]) == TRUE) {
+           /* Close the other end of the stdin/stdout/stderr pipes and exec. */
+           if (io_pipe[STDIN_FILENO][1])
+               close(io_pipe[STDIN_FILENO][1]);
+           if (io_pipe[STDOUT_FILENO][0])
+               close(io_pipe[STDOUT_FILENO][0]);
+           if (io_pipe[STDERR_FILENO][0])
+               close(io_pipe[STDERR_FILENO][0]);
+           exec_monitor(details, sv[1]);
+       }
+       cstat.type = CMD_ERRNO;
+       cstat.val = errno;
+       send(sv[1], &cstat, sizeof(cstat), 0);
+       _exit(1);
+    }
+
+    /* Close the other end of the stdin/stdout/stderr pipes. */
+    if (io_pipe[STDIN_FILENO][0])
+       close(io_pipe[STDIN_FILENO][0]);
+    if (io_pipe[STDOUT_FILENO][1])
+       close(io_pipe[STDOUT_FILENO][1]);
+    if (io_pipe[STDERR_FILENO][1]) 
+       close(io_pipe[STDERR_FILENO][1]);
+
+    for (iob = iobufs; iob; iob = iob->next) {
+       /* Determine maxfd */
+       if (iob->rfd > *maxfd)
+           *maxfd = iob->rfd;
+       if (iob->wfd > *maxfd)
+           *maxfd = iob->wfd;
+
+       /* Set non-blocking mode. */
+       n = fcntl(iob->rfd, F_GETFL, 0);
+       if (n != -1 && !ISSET(n, O_NONBLOCK))
+           (void) fcntl(iob->rfd, F_SETFL, n | O_NONBLOCK);
+       n = fcntl(iob->wfd, F_GETFL, 0);
+       if (n != -1 && !ISSET(n, O_NONBLOCK))
+           (void) fcntl(iob->wfd, F_SETFL, n | O_NONBLOCK);
+    }
+
+    return child;
+}
+
+void
+pty_close(struct command_status *cstat)
+{
+    int n;
+
+    /* Flush any remaining output (the plugin already got it) */
+    if (io_fds[SFD_USERTTY] != -1) {
+       n = fcntl(io_fds[SFD_USERTTY], F_GETFL, 0);
+       if (n != -1 && ISSET(n, O_NONBLOCK)) {
+           CLR(n, O_NONBLOCK);
+           (void) fcntl(io_fds[SFD_USERTTY], F_SETFL, n);
+       }
+    }
+    flush_output();
+
+    if (io_fds[SFD_USERTTY] != -1) {
+       do {
+           n = term_restore(io_fds[SFD_USERTTY], 0);
+       } while (!n && errno == EINTR);
+    }
+
+    /* If child was signalled, write the reason to stdout like the shell. */
+    if (cstat->type == CMD_WSTATUS && WIFSIGNALED(cstat->val)) {
+       int signo = WTERMSIG(cstat->val);
+       if (signo && signo != SIGINT && signo != SIGPIPE) {
+           const char *reason = strsignal(signo);
+           n = io_fds[SFD_USERTTY] != -1 ?
+               io_fds[SFD_USERTTY] : STDOUT_FILENO;
+           if (write(n, reason, strlen(reason)) != -1) {
+               if (WCOREDUMP(cstat->val)) {
+                   if (write(n, " (core dumped)", 14) == -1)
+                       /* shut up glibc */;
+               }
+               if (write(n, "\n", 1) == -1)
+                   /* shut up glibc */;
+           }
+       }
+    }
+    utmp_logout(slavename, cstat->type == CMD_WSTATUS ? cstat->val : 0); /* XXX - only if CD_SET_UTMP */
+}
+
+/*
+ * Fill in fdsr and fdsw based on the io buffers list.
+ * Called prior to select().
+ */
+void
+fd_set_iobs(fd_set *fdsr, fd_set *fdsw)
+{
+    struct io_buffer *iob;
+
+    for (iob = iobufs; iob; iob = iob->next) {
+       if (iob->rfd == -1 && iob->wfd == -1)
+           continue;
+       if (iob->off == iob->len) {
+           iob->off = iob->len = 0;
+           /* Forward the EOF from reader to writer. */
+           if (iob->rfd == -1) {
+               safe_close(iob->wfd);
+               iob->wfd = -1;
+           }
+       }
+       /* Don't read/write /dev/tty if we are not in the foreground. */
+       if (iob->rfd != -1 &&
+           (ttymode == TERM_RAW || iob->rfd != io_fds[SFD_USERTTY])) {
+           if (iob->len != sizeof(iob->buf))
+               FD_SET(iob->rfd, fdsr);
+       }
+       if (iob->wfd != -1 &&
+           (foreground || iob->wfd != io_fds[SFD_USERTTY])) {
+           if (iob->len > iob->off)
+               FD_SET(iob->wfd, fdsw);
+       }
+    }
+}
+
+static void
+deliver_signal(pid_t pid, int signo)
+{
+    int status;
+
+    /* Handle signal from parent. */
+    sudo_debug(8, "signal %d from parent", signo);
+    switch (signo) {
+    case SIGALRM:
+       terminate_child(pid, TRUE);
+       break;
+    case SIGCONT_FG:
+       /* Continue in foreground, grant it controlling tty. */
+       do {
+           status = tcsetpgrp(io_fds[SFD_SLAVE], child_pgrp);
+       } while (status == -1 && errno == EINTR);
+       killpg(pid, SIGCONT);
+       break;
+    case SIGCONT_BG:
+       /* Continue in background, I take controlling tty. */
+       do {
+           status = tcsetpgrp(io_fds[SFD_SLAVE], getpid());
+       } while (status == -1 && errno == EINTR);
+       killpg(pid, SIGCONT);
+       break;
+    case SIGKILL:
+       _exit(1); /* XXX */
+       /* NOTREACHED */
+    default:
+       /* Relay signal to child. */
+       killpg(pid, signo);
+       break;
+    }
+}
+
+/*
+ * Send status to parent over socketpair.
+ * Return value is the same as send(2).
+ */
+static int
+send_status(int fd, struct command_status *cstat)
+{
+    int n = -1;
+
+    if (cstat->type != CMD_INVALID) {
+       do {
+           n = send(fd, cstat, sizeof(*cstat), 0);
+       } while (n == -1 && errno == EINTR);
+       if (n != sizeof(*cstat)) {
+           sudo_debug(8, "unable to send status to parent: %s", strerror(errno));
+       } else {
+           sudo_debug(8, "sent status to parent");
+       }
+       cstat->type = CMD_INVALID; /* prevent re-sending */
+    }
+    return n;
+}
+
+/*
+ * Wait for child status after receiving SIGCHLD.
+ * If the child was stopped, the status is send back to the parent.
+ * Otherwise, cstat is filled in but not sent.
+ * Returns TRUE if child is still alive, else FALSE.
+ */
+static int
+handle_sigchld(int backchannel, struct command_status *cstat)
+{
+    int status, alive = TRUE;
+    pid_t pid;
+
+    /* read child status */
+    do {
+       pid = waitpid(child, &status, WUNTRACED|WNOHANG);
+    } while (pid == -1 && errno == EINTR);
+    if (pid == child) {
+       if (cstat->type != CMD_ERRNO) {
+           cstat->type = CMD_WSTATUS;
+           cstat->val = status;
+           if (WIFSTOPPED(status)) {
+               sudo_debug(8, "command stopped, signal %d",
+                   WSTOPSIG(status));
+               do {
+                   child_pgrp = tcgetpgrp(io_fds[SFD_SLAVE]);
+               } while (child_pgrp == -1 && errno == EINTR);
+               if (send_status(backchannel, cstat) == -1)
+                   return alive; /* XXX */
+           } else if (WIFSIGNALED(status)) {
+               sudo_debug(8, "command killed, signal %d",
+                   WTERMSIG(status));
+           } else {
+               sudo_debug(8, "command exited: %d",
+                   WEXITSTATUS(status));
+           }
+       }
+       if (!WIFSTOPPED(status))
+           alive = FALSE;
+    }
+    return alive;
+}
+
+/*
+ * Monitor process that creates a new session with the controlling tty,
+ * resets signal handlers and forks a child to call exec_pty().
+ * Waits for status changes from the command and relays them to the
+ * parent and relays signals from the parent to the command.
+ * Returns an error if fork(2) fails, else calls _exit(2).
+ */
+static int
+exec_monitor(struct command_details *details, int backchannel)
+{
+    struct command_status cstat;
+    struct timeval tv;
+    fd_set *fdsr;
+    sigaction_t sa;
+    int errpipe[2], maxfd, n, status;
+    int alive = TRUE;
+    unsigned char signo;
+
+    /* Close unused fds. */
+    if (io_fds[SFD_MASTER] != -1)
+       close(io_fds[SFD_MASTER]);
+    if (io_fds[SFD_USERTTY] != -1)
+       close(io_fds[SFD_USERTTY]);
+
+    /*
+     * We use a pipe to atomically handle signal notification within
+     * the select() loop.
+     */
+    if (pipe_nonblock(signal_pipe) != 0)
+       error(1, "cannot create pipe");
+
+    /* Reset SIGWINCH and SIGALRM. */
+    zero_bytes(&sa, sizeof(sa));
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = SA_RESTART;
+    sa.sa_handler = SIG_DFL;
+    sigaction(SIGWINCH, &sa, NULL);
+    sigaction(SIGALRM, &sa, NULL);
+
+    /* Ignore any SIGTTIN or SIGTTOU we get. */
+    sa.sa_handler = SIG_IGN;
+    sigaction(SIGTTIN, &sa, NULL);
+    sigaction(SIGTTOU, &sa, NULL);
+
+    /* Note: HP-UX select() will not be interrupted if SA_RESTART set */
+    sa.sa_flags = SA_INTERRUPT;
+    sa.sa_handler = handler;
+    sigaction(SIGCHLD, &sa, NULL);
+
+    /*
+     * Start a new session with the parent as the session leader
+     * and the slave pty as the controlling terminal.
+     * This allows us to be notified when the child has been suspended.
+     */
+    if (setsid() == -1) {
+       warning("setsid");
+       goto bad;
+    }
+    if (io_fds[SFD_SLAVE] != -1) {
+#ifdef TIOCSCTTY
+       if (ioctl(io_fds[SFD_SLAVE], TIOCSCTTY, NULL) != 0)
+           error(1, "unable to set controlling tty");
+#else
+       /* Set controlling tty by reopening slave. */
+       if ((n = open(slavename, O_RDWR)) >= 0)
+           close(n);
+#endif
+    }
+
+    /*
+     * If stdin/stdout is not a tty, start command in the background
+     * since it might be part of a pipeline that reads from /dev/tty.
+     * In this case, we rely on the command receiving SIGTTOU or SIGTTIN
+     * when it needs access to the controlling tty.
+     */
+    if (pipeline)
+       foreground = 0;
+
+    /* Start command and wait for it to stop or exit */
+    if (pipe(errpipe) == -1)
+       error(1, "unable to create pipe");
+    child = fork();
+    if (child == -1) {
+       warning("Can't fork");
+       goto bad;
+    }
+    if (child == 0) {
+       /* We pass errno back to our parent via pipe on exec failure. */
+       close(backchannel);
+       close(signal_pipe[0]);
+       close(signal_pipe[1]);
+       close(errpipe[0]);
+       fcntl(errpipe[1], F_SETFD, FD_CLOEXEC);
+       restore_signals();
+
+       /* setup tty and exec command */
+       exec_pty(details);
+       cstat.type = CMD_ERRNO;
+       cstat.val = errno;
+       if (write(errpipe[1], &cstat, sizeof(cstat)) == -1)
+           /* shut up glibc */;
+       _exit(1);
+    }
+    close(errpipe[1]);
+
+    /* If any of stdin/stdout/stderr are pipes, close them in parent. */
+    if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE])
+       close(io_fds[SFD_STDIN]);
+    if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE])
+       close(io_fds[SFD_STDOUT]);
+    if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE])
+       close(io_fds[SFD_STDERR]);
+
+    /*
+     * Put child in its own process group.  If we are starting the command
+     * in the foreground, assign its pgrp to the tty.
+     */
+    child_pgrp = child;
+    setpgid(child, child_pgrp);
+    if (foreground) {
+       do {
+           status = tcsetpgrp(io_fds[SFD_SLAVE], child_pgrp);
+       } while (status == -1 && errno == EINTR);
+    }
+
+    /* Wait for errno on pipe, signal on backchannel or for SIGCHLD */
+    maxfd = MAX(MAX(errpipe[0], signal_pipe[0]), backchannel);
+    fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
+    zero_bytes(fdsr, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
+    zero_bytes(&cstat, sizeof(cstat));
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+    for (;;) {
+       /* Check for signal on backchannel or errno on errpipe. */
+       FD_SET(backchannel, fdsr);
+       FD_SET(signal_pipe[0], fdsr);
+       if (errpipe[0] != -1)
+           FD_SET(errpipe[0], fdsr);
+       maxfd = MAX(MAX(errpipe[0], signal_pipe[0]), backchannel);
+
+       /* If command exited we just poll, there may be data on errpipe. */
+       n = select(maxfd + 1, fdsr, NULL, NULL, alive ? NULL : &tv);
+       if (n <= 0) {
+           if (n == 0)
+               goto done;
+           if (errno == EINTR)
+               continue;
+           error(1, "select failed");
+       }
+
+       if (FD_ISSET(signal_pipe[0], fdsr)) {
+           n = read(signal_pipe[0], &signo, sizeof(signo));
+           if (n == -1) {
+               if (errno == EINTR || errno == EAGAIN)
+                   continue;
+               warning("error reading from signal pipe");
+               goto done;
+           }
+           /*
+            * Handle SIGCHLD specially and deliver other signals
+            * directly to the child.
+            */
+           if (signo == SIGCHLD)
+               alive = handle_sigchld(backchannel, &cstat);
+           else
+               deliver_signal(child, signo);
+           continue;
+       }
+       if (errpipe[0] != -1 && FD_ISSET(errpipe[0], fdsr)) {
+           /* read errno or EOF from command pipe */
+           n = read(errpipe[0], &cstat, sizeof(cstat));
+           if (n == -1) {
+               if (errno == EINTR)
+                   continue;
+               warning("error reading from pipe");
+               goto done;
+           }
+           /* Got errno or EOF, either way we are done with errpipe. */
+           FD_CLR(errpipe[0], fdsr);
+           close(errpipe[0]);
+           errpipe[0] = -1;
+       }
+       if (FD_ISSET(backchannel, fdsr)) {
+           struct command_status cstmp;
+
+           /* read command from backchannel, should be a signal */
+           n = recv(backchannel, &cstmp, sizeof(cstmp), 0);
+           if (n == -1) {
+               if (errno == EINTR)
+                   continue;
+               warning("error reading from socketpair");
+               goto done;
+           }
+           if (cstmp.type != CMD_SIGNO) {
+               warningx("unexpected reply type on backchannel: %d", cstmp.type);
+               continue;
+           }
+           deliver_signal(child, cstmp.val);
+       }
+    }
+
+done:
+    if (alive) {
+       /* XXX An error occurred, should send an error back. */
+       kill(child, SIGKILL);
+    } else {
+       /* Send parent status. */
+       send_status(backchannel, &cstat);
+    }
+    _exit(1);
+
+bad:
+    return errno;
+}
+
+/*
+ * Flush any output buffered in iobufs or readable from the fds.
+ * Does not read from /dev/tty.
+ */
+static void
+flush_output(void)
+{
+    struct io_buffer *iob;
+    struct timeval tv;
+    fd_set *fdsr, *fdsw;
+    int nready, nwriters, maxfd = -1;
+
+    /* Determine maxfd */
+    for (iob = iobufs; iob; iob = iob->next) {
+       if (iob->rfd > maxfd)
+           maxfd = iob->rfd;
+       if (iob->wfd > maxfd)
+           maxfd = iob->wfd;
+    }
+    if (maxfd == -1)
+       return;
+
+    fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
+    fdsw = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
+    for (;;) {
+       zero_bytes(fdsw, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
+       zero_bytes(fdsr, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
+
+       nwriters = 0;
+       for (iob = iobufs; iob; iob = iob->next) {
+           /* Don't read from /dev/tty while flushing. */
+           if (io_fds[SFD_USERTTY] != -1 && iob->rfd == io_fds[SFD_USERTTY])
+               continue;
+           if (iob->rfd == -1 && iob->wfd == -1)
+               continue;
+           if (iob->off == iob->len) {
+               iob->off = iob->len = 0;
+               /* Forward the EOF from reader to writer. */
+               if (iob->rfd == -1) {
+                   safe_close(iob->wfd);
+                   iob->wfd = -1;
+               }
+           }
+           if (iob->rfd != -1) {
+               if (iob->len != sizeof(iob->buf))
+                   FD_SET(iob->rfd, fdsr);
+           }
+           if (iob->wfd != -1) {
+               if (iob->len > iob->off) {
+                   nwriters++;
+                   FD_SET(iob->wfd, fdsw);
+               }
+           }
+       }
+
+       /* Don't sleep in select if there are no buffers that need writing. */
+       tv.tv_sec = 0;
+       tv.tv_usec = 0;
+       nready = select(maxfd + 1, fdsr, fdsw, NULL, nwriters ? NULL : &tv);
+       if (nready <= 0) {
+           if (nready == 0)
+               break; /* all I/O flushed */
+           if (errno == EINTR)
+               continue;
+           error(1, "select failed");
+       }
+       if (perform_io(fdsr, fdsw, NULL) != 0)
+           break;
+    }
+    efree(fdsr);
+    efree(fdsw);
+}
+
+/*
+ * Sets up std{in,out,err} and executes the actual command.
+ * Returns only if execve() fails.
+ */
+static void
+exec_pty(struct command_details *details)
+{
+    pid_t self = getpid();
+
+    /* Set child process group here too to avoid a race. */
+    setpgid(0, self);
+
+    /* Wire up standard fds, note that stdout/stderr may be pipes. */
+    if (dup2(io_fds[SFD_STDIN], STDIN_FILENO) == -1 ||
+       dup2(io_fds[SFD_STDOUT], STDOUT_FILENO) == -1 ||
+       dup2(io_fds[SFD_STDERR], STDERR_FILENO) == -1)
+       error(1, "dup2");
+
+    /* Wait for parent to grant us the tty if we are foreground. */
+    if (foreground) {
+       while (tcgetpgrp(io_fds[SFD_SLAVE]) != self)
+           ; /* spin */
+    }
+
+    /* We have guaranteed that the slave fd is > 2 */
+    if (io_fds[SFD_SLAVE] != -1)
+       close(io_fds[SFD_SLAVE]);
+    if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE])
+       close(io_fds[SFD_STDIN]);
+    if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE])
+       close(io_fds[SFD_STDOUT]);
+    if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE])
+       close(io_fds[SFD_STDERR]);
+
+    if (details->closefrom >= 0)
+       closefrom(details->closefrom);
+#ifdef HAVE_SELINUX
+    if (ISSET(details->flags, CD_RBAC_ENABLED))
+       selinux_execve(details->command, details->argv, details->envp);
+    else
+#endif
+       my_execve(details->command, details->argv, details->envp);
+}
+
+/*
+ * Propagates tty size change signals to pty being used by the command.
+ */
+static void
+sync_ttysize(int src, int dst)
+{
+#ifdef TIOCGWINSZ
+    struct winsize wsize;
+    pid_t pgrp;
+
+    if (ioctl(src, TIOCGWINSZ, &wsize) == 0) {
+           ioctl(dst, TIOCSWINSZ, &wsize);
+           if ((pgrp = tcgetpgrp(dst)) != -1)
+               killpg(pgrp, SIGWINCH);
+    }
+#endif
+}
+
+/*
+ * Handler for SIGWINCH in parent.
+ */
+static void
+sigwinch(int s)
+{
+    int serrno = errno;
+
+    sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]);
+    errno = serrno;
+}
+
+/*
+ * Only close the fd if it is not /dev/tty or std{in,out,err}.
+ * Return value is the same as send(2).
+ */
+static int
+safe_close(int fd)
+{
+    /* Avoid closing /dev/tty or std{in,out,err}. */
+    if (fd < 3 || fd == io_fds[SFD_USERTTY]) {
+       errno = EINVAL;
+       return -1;
+    }
+    return close(fd);
+}
diff --git a/src/get_pty.c b/src/get_pty.c
new file mode 100644 (file)
index 0000000..4bac6b9
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2009-2011 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 <sys/stat.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_STROPTS_H
+#include <sys/stropts.h>
+#endif /* HAVE_SYS_STROPTS_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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+
+#ifdef HAVE_UTIL_H
+# include <util.h>
+#endif
+#ifdef HAVE_PTY_H
+# include <pty.h>
+#endif
+
+#include "sudo.h"
+
+#if defined(HAVE_OPENPTY)
+int
+get_pty(int *master, int *slave, char *name, size_t namesz, uid_t ttyuid)
+{
+    struct group *gr;
+    gid_t ttygid = -1;
+
+    if ((gr = getgrnam("tty")) != NULL)
+       ttygid = gr->gr_gid;
+
+    if (openpty(master, slave, name, NULL, NULL) != 0)
+       return 0;
+    if (chown(name, ttyuid, ttygid) != 0)
+       return 0;
+    return 1;
+}
+
+#elif defined(HAVE__GETPTY)
+int
+get_pty(int *master, int *slave, char *name, size_t namesz, uid_t ttyuid)
+{
+    char *line;
+
+    /* IRIX-style dynamic ptys (may fork) */
+    line = _getpty(master, O_RDWR, S_IRUSR|S_IWUSR|S_IWGRP, 0);
+    if (line == NULL)
+       return 0;
+    *slave = open(line, O_RDWR|O_NOCTTY, 0);
+    if (*slave == -1) {
+       close(*master);
+       return 0;
+    }
+    (void) chown(line, ttyuid, -1);
+    strlcpy(name, line, namesz);
+    return 1;
+}
+#elif defined(HAVE_GRANTPT)
+# ifndef HAVE_POSIX_OPENPT
+static int
+posix_openpt(int oflag)
+{
+    int fd;
+
+#  ifdef _AIX
+    fd = open("/dev/ptc", oflag);
+#  else
+    fd = open("/dev/ptmx", oflag);
+#  endif
+    return fd;
+}
+# endif /* HAVE_POSIX_OPENPT */
+
+int
+get_pty(int *master, int *slave, char *name, size_t namesz, uid_t ttyuid)
+{
+    char *line;
+
+    *master = posix_openpt(O_RDWR|O_NOCTTY);
+    if (*master == -1)
+       return 0;
+
+    (void) grantpt(*master); /* may fork */
+    if (unlockpt(*master) != 0) {
+       close(*master);
+       return 0;
+    }
+    line = ptsname(*master);
+    if (line == NULL) {
+       close(*master);
+       return 0;
+    }
+    *slave = open(line, O_RDWR|O_NOCTTY, 0);
+    if (*slave == -1) {
+       close(*master);
+       return 0;
+    }
+# if defined(I_PUSH) && !defined(_AIX)
+    ioctl(*slave, I_PUSH, "ptem");     /* pseudo tty emulation module */
+    ioctl(*slave, I_PUSH, "ldterm");   /* line discipline module */
+# endif
+    (void) chown(line, ttyuid, -1);
+    strlcpy(name, line, namesz);
+    return 1;
+}
+
+#else /* Old-style BSD ptys */
+
+static char line[] = "/dev/ptyXX";
+
+int
+get_pty(int *master, int *slave, char *name, size_t namesz, uid_t ttyuid)
+{
+    char *bank, *cp;
+    struct group *gr;
+    gid_t ttygid = -1;
+
+    if ((gr = getgrnam("tty")) != NULL)
+       ttygid = gr->gr_gid;
+
+    for (bank = "pqrs"; *bank != '\0'; bank++) {
+       line[sizeof("/dev/ptyX") - 2] = *bank;
+       for (cp = "0123456789abcdef"; *cp != '\0'; cp++) {
+           line[sizeof("/dev/ptyXX") - 2] = *cp;
+           *master = open(line, O_RDWR|O_NOCTTY, 0);
+           if (*master == -1) {
+               if (errno == ENOENT)
+                   return 0; /* out of ptys */
+               continue; /* already in use */
+           }
+           line[sizeof("/dev/p") - 2] = 't';
+           (void) chown(line, ttyuid, ttygid);
+           (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
+# ifdef HAVE_REVOKE
+           (void) revoke(line);
+# endif
+           *slave = open(line, O_RDWR|O_NOCTTY, 0);
+           if (*slave != -1) {
+                   strlcpy(name, line, namesz);
+                   return 1; /* success */
+           }
+           (void) close(*master);
+       }
+    }
+    return 0;
+}
+#endif /* HAVE_OPENPTY */
diff --git a/src/load_plugins.c b/src/load_plugins.c
new file mode 100644 (file)
index 0000000..68be423
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2009-2011 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 <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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_DLOPEN
+# include <dlfcn.h>
+#else
+# include "compat/dlfcn.h"
+#endif
+#include <errno.h>
+
+#include "sudo.h"
+#include "sudo_plugin.h"
+#include "sudo_plugin_int.h"
+
+#ifndef RTLD_LOCAL
+# define RTLD_LOCAL    0
+#endif
+
+const char *noexec_path = _PATH_SUDO_NOEXEC;
+
+/*
+ * Read in /etc/sudo.conf
+ * Returns a list of plugins.
+ */
+static struct plugin_info_list *
+sudo_read_conf(const char *conf_file)
+{
+    FILE *fp;
+    char *cp, *name, *path;
+    struct plugin_info *info;
+    static struct plugin_info_list pil; /* XXX */
+
+    if ((fp = fopen(conf_file, "r")) == NULL)
+       goto done;
+
+    while ((cp = sudo_parseln(fp)) != NULL) {
+       /* Skip blank or comment lines */
+       if (*cp == '\0')
+           continue;
+
+       /* Look for a line starting with "Path" */
+       if (strncasecmp(cp, "Path", 4) == 0) {
+           /* Parse line */
+           if ((name = strtok(cp + 4, " \t")) == NULL ||
+               (path = strtok(NULL, " \t")) == NULL) {
+               continue;
+           }
+           if (strcasecmp(name, "askpass") == 0)
+               askpass_path = estrdup(path);
+           else if (strcasecmp(name, "noexec") == 0)
+               noexec_path = estrdup(path);
+           continue;
+       }
+
+       /* Look for a line starting with "Plugin" */
+       if (strncasecmp(cp, "Plugin", 6) == 0) {
+           /* Parse line */
+           if ((name = strtok(cp + 6, " \t")) == NULL ||
+               (path = strtok(NULL, " \t")) == NULL) {
+               continue;
+           }
+           info = emalloc(sizeof(*info));
+           info->symbol_name = estrdup(name);
+           info->path = estrdup(path);
+           info->prev = info;
+           info->next = NULL;
+           tq_append(&pil, info);
+           continue;
+       }
+    }
+    fclose(fp);
+
+done:
+    if (tq_empty(&pil)) {
+       /* Default policy plugin */
+       info = emalloc(sizeof(*info));
+       info->symbol_name = "sudoers_policy";
+       info->path = SUDOERS_PLUGIN;
+       info->prev = info;
+       info->next = NULL;
+       tq_append(&pil, info);
+
+       /* Default I/O plugin */
+       info = emalloc(sizeof(*info));
+       info->symbol_name = "sudoers_io";
+       info->path = SUDOERS_PLUGIN;
+       info->prev = info;
+       info->next = NULL;
+       tq_append(&pil, info);
+    }
+
+    return &pil;
+}
+
+/*
+ * Load the plugins listed in conf_file.
+ */
+int
+sudo_load_plugins(const char *conf_file,
+    struct plugin_container *policy_plugin,
+    struct plugin_container_list *io_plugins)
+{
+    struct generic_plugin *plugin;
+    struct plugin_container *container;
+    struct plugin_info *info;
+    struct plugin_info_list *plugin_list;
+    struct stat sb;
+    void *handle;
+    char path[PATH_MAX];
+    int rval = FALSE;
+
+    /* Parse sudo.conf */
+    plugin_list = sudo_read_conf(conf_file);
+
+    tq_foreach_fwd(plugin_list, info) {
+       if (info->path[0] == '/') {
+           if (strlcpy(path, info->path, sizeof(path)) >= sizeof(path)) {
+               warningx("%s: %s", info->path, strerror(ENAMETOOLONG));
+               goto done;
+           }
+       } else {
+           if (snprintf(path, sizeof(path), "%s%s", _PATH_SUDO_PLUGIN_DIR,
+               info->path) >= sizeof(path)) {
+               warningx("%s%s: %s", _PATH_SUDO_PLUGIN_DIR, info->path,
+                   strerror(ENAMETOOLONG));
+               goto done;
+           }
+       }
+       if (stat(path, &sb) != 0) {
+           warning("%s", path);
+           goto done;
+       }
+       if (sb.st_uid != ROOT_UID) {
+           warningx("%s must be owned by uid %d", path, ROOT_UID);
+           goto done;
+       }
+       if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
+           warningx("%s must be only be writable by owner", path);
+           goto done;
+       }
+
+       /* Open plugin and map in symbol */
+       handle = dlopen(path, RTLD_LAZY|RTLD_LOCAL);
+       if (!handle) {
+           warningx("unable to dlopen %s: %s", path, dlerror());
+           goto done;
+       }
+       plugin = dlsym(handle, info->symbol_name);
+       if (!plugin) {
+           warningx("unable to find symbol %s in %s", info->symbol_name, path);
+           goto done;
+       }
+
+       if (plugin->type != SUDO_POLICY_PLUGIN && plugin->type != SUDO_IO_PLUGIN) {
+           warningx("%s: unknown policy type %d", path, plugin->type);
+           goto done;
+       }
+       if (SUDO_API_VERSION_GET_MAJOR(plugin->version) != SUDO_API_VERSION_MAJOR) {
+           warningx("%s: incompatible policy major version %d, expected %d",
+               path, SUDO_API_VERSION_GET_MAJOR(plugin->version),
+               SUDO_API_VERSION_MAJOR);
+           goto done;
+       }
+       if (plugin->type == SUDO_POLICY_PLUGIN) {
+           if (policy_plugin->handle) {
+               warningx("only a single policy plugin may be loaded");
+               goto done;
+           }
+           policy_plugin->handle = handle;
+           policy_plugin->name = info->symbol_name;
+           policy_plugin->u.generic = plugin;
+       } else if (plugin->type == SUDO_IO_PLUGIN) {
+           container = emalloc(sizeof(*container));
+           container->prev = container;
+           container->next = NULL;
+           container->handle = handle;
+           container->name = info->symbol_name;
+           container->u.generic = plugin;
+           tq_append(io_plugins, container);
+       }
+    }
+    if (policy_plugin->handle == NULL) {
+       warningx("%s: at least one policy plugin must be specified", conf_file);
+       goto done;
+    }
+    if (policy_plugin->u.policy->check_policy == NULL) {
+       warningx("policy plugin %s does not include a check_policy method",
+           policy_plugin->name);
+       goto done;
+    }
+
+    rval = TRUE;
+
+done:
+    return rval;
+}
diff --git a/src/net_ifs.c b/src/net_ifs.c
new file mode 100644 (file)
index 0000000..f6de080
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2010
+ *     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.
+ */
+
+/*
+ * Suppress a warning w/ gcc on Digital UN*X.
+ * The system headers should really do this....
+ */
+#if defined(__osf__) && !defined(__cplusplus)
+struct mbuf;
+struct rtentry;
+#endif
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFCONF)
+# include <sys/sockio.h>
+#endif
+#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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <netdb.h>
+#include <errno.h>
+#ifdef _ISC
+# include <sys/stream.h>
+# include <sys/sioctl.h>
+# include <sys/stropts.h>
+# define STRSET(cmd, param, len) {strioctl.ic_cmd=(cmd);\
+                                strioctl.ic_dp=(param);\
+                                strioctl.ic_timout=0;\
+                                strioctl.ic_len=(len);}
+#endif /* _ISC */
+#ifdef _MIPS
+# include <net/soioctl.h>
+#endif /* _MIPS */
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#ifdef HAVE_GETIFADDRS
+# include <ifaddrs.h>
+#endif
+
+#include "missing.h"
+#include "alloc.h"
+#include "error.h"
+
+/* Minix apparently lacks IFF_LOOPBACK */
+#ifndef IFF_LOOPBACK
+# define IFF_LOOPBACK  0
+#endif
+
+#ifndef INET6_ADDRSTRLEN
+# define INET6_ADDRSTRLEN 46
+#endif
+
+#ifdef HAVE_GETIFADDRS
+
+/*
+ * Fill in the interfaces string with the machine's ip addresses and netmasks
+ * and return the number of interfaces found.
+ */
+int
+get_net_ifs(char **addrinfo)
+{
+    struct ifaddrs *ifa, *ifaddrs;
+    struct sockaddr_in *sin;
+#ifdef HAVE_IN6_ADDR
+    struct sockaddr_in6 *sin6;
+    char addrbuf[INET6_ADDRSTRLEN];
+#endif
+    int ailen, i, len, num_interfaces = 0;
+    char *cp;
+
+    if (getifaddrs(&ifaddrs))
+       return 0;
+
+    /* Allocate space for the interfaces info string. */
+    for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) {
+       /* Skip interfaces marked "down" and "loopback". */
+       if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
+           !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
+           continue;
+
+       switch (ifa->ifa_addr->sa_family) {
+           case AF_INET:
+#ifdef HAVE_IN6_ADDR
+           case AF_INET6:
+#endif
+               num_interfaces++;
+               break;
+       }
+    }
+    if (num_interfaces == 0)
+       return 0;
+    ailen = num_interfaces * 2 * INET6_ADDRSTRLEN;
+    *addrinfo = cp = emalloc(ailen);
+
+    /* Store the IP addr/netmask pairs. */
+    for (ifa = ifaddrs, i = 0; ifa != NULL; ifa = ifa -> ifa_next) {
+       /* Skip interfaces marked "down" and "loopback". */
+       if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
+           !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
+               continue;
+
+       switch (ifa->ifa_addr->sa_family) {
+           case AF_INET:
+               sin = (struct sockaddr_in *)ifa->ifa_addr;
+               len = snprintf(cp, ailen - (*addrinfo - cp),
+                   "%s%s/", cp == *addrinfo ? "" : " ",
+                   inet_ntoa(sin->sin_addr));
+               if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
+                   warningx("load_interfaces: overflow detected");
+                   goto done;
+               }
+               cp += len;
+
+               sin = (struct sockaddr_in *)ifa->ifa_netmask;
+               len = snprintf(cp, ailen - (*addrinfo - cp),
+                   "%s", inet_ntoa(sin->sin_addr));
+               if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
+                   warningx("load_interfaces: overflow detected");
+                   goto done;
+               }
+               cp += len;
+               break;
+#ifdef HAVE_IN6_ADDR
+           case AF_INET6:
+               sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+               inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf));
+               len = snprintf(cp, ailen - (*addrinfo - cp),
+                   "%s%s/", cp == *addrinfo ? "" : " ", addrbuf);
+               if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
+                   warningx("load_interfaces: overflow detected");
+                   goto done;
+               }
+               cp += len;
+
+               sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask;
+               inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf));
+               len = snprintf(cp, ailen - (*addrinfo - cp), "%s", addrbuf);
+               if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
+                   warningx("load_interfaces: overflow detected");
+                   goto done;
+               }
+               cp += len;
+               break;
+#endif /* HAVE_IN6_ADDR */
+       }
+    }
+
+done:
+#ifdef HAVE_FREEIFADDRS
+    freeifaddrs(ifaddrs);
+#else
+    efree(ifaddrs);
+#endif
+    return num_interfaces;
+}
+
+#elif defined(SIOCGIFCONF) && !defined(STUB_LOAD_INTERFACES)
+
+/*
+ * Allocate and fill in the interfaces global variable with the
+ * machine's ip addresses and netmasks.
+ */
+int
+get_net_ifs(char **addrinfo)
+{
+    struct ifconf *ifconf;
+    struct ifreq *ifr, ifr_tmp;
+    struct sockaddr_in *sin;
+    int ailen, i, len, n, sock, num_interfaces = 0;
+    size_t buflen = sizeof(struct ifconf) + BUFSIZ;
+    char *cp, *previfname = "", *ifconf_buf = NULL;
+#ifdef _ISC
+    struct strioctl strioctl;
+#endif /* _ISC */
+
+    sock = socket(AF_INET, SOCK_DGRAM, 0);
+    if (sock < 0)
+       error(1, "cannot open socket");
+
+    /*
+     * Get interface configuration or return.
+     */
+    for (;;) {
+       ifconf_buf = emalloc(buflen);
+       ifconf = (struct ifconf *) ifconf_buf;
+       ifconf->ifc_len = buflen - sizeof(struct ifconf);
+       ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf));
+
+#ifdef _ISC
+       STRSET(SIOCGIFCONF, (caddr_t) ifconf, buflen);
+       if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0)
+#else
+       /* Note that some kernels return EINVAL if the buffer is too small */
+       if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL)
+#endif /* _ISC */
+           goto done;
+
+       /* Break out of loop if we have a big enough buffer. */
+       if (ifconf->ifc_len + sizeof(struct ifreq) < buflen)
+           break;
+       buflen += BUFSIZ;
+       efree(ifconf_buf);
+    }
+
+    /* Allocate space for the maximum number of interfaces that could exist. */
+    if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0)
+       return 0;
+    ailen = n * 2 * INET6_ADDRSTRLEN;
+    *addrinfo = cp = emalloc(ailen);
+
+    /* For each interface, store the ip address and netmask. */
+    for (i = 0; i < ifconf->ifc_len; ) {
+       /* Get a pointer to the current interface. */
+       ifr = (struct ifreq *) &ifconf->ifc_buf[i];
+
+       /* Set i to the subscript of the next interface. */
+       i += sizeof(struct ifreq);
+#ifdef HAVE_SA_LEN
+       if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
+           i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
+#endif /* HAVE_SA_LEN */
+
+       /* Skip duplicates and interfaces with NULL addresses. */
+       sin = (struct sockaddr_in *) &ifr->ifr_addr;
+       if (sin->sin_addr.s_addr == 0 ||
+           strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0)
+           continue;
+
+       if (ifr->ifr_addr.sa_family != AF_INET)
+               continue;
+
+#ifdef SIOCGIFFLAGS
+       memset(&ifr_tmp, 0, 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
+           ifr_tmp = *ifr;
+       
+       /* Skip interfaces marked "down" and "loopback". */
+       if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) ||
+           ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK))
+               continue;
+
+       sin = (struct sockaddr_in *) &ifr->ifr_addr;
+       len = snprintf(cp, ailen - (*addrinfo - cp),
+           "%s%s/", cp == *addrinfo ? "" : " ",
+           inet_ntoa(sin->sin_addr));
+       if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
+           warningx("load_interfaces: overflow detected");
+           goto done;
+       }
+       cp += len;
+
+       /* Stash the name of the interface we saved. */
+       previfname = ifr->ifr_name;
+
+       /* Get the netmask. */
+       memset(&ifr_tmp, 0, sizeof(ifr_tmp));
+       strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
+#ifdef _ISC
+       STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp));
+       if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) {
+#else
+       if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) < 0) {
+#endif /* _ISC */
+           sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
+           sin->sin_addr.s_addr = htonl(IN_CLASSC_NET);
+       }
+       sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
+       len = snprintf(cp, ailen - (*addrinfo - cp),
+           "%s", inet_ntoa(sin->sin_addr));
+       if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
+           warningx("load_interfaces: overflow detected");
+           goto done;
+       }
+       cp += len;
+       num_interfaces++;
+    }
+
+done:
+    efree(ifconf_buf);
+    (void) close(sock);
+
+    return num_interfaces;
+}
+
+#else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */
+
+/*
+ * Stub function for those without SIOCGIFCONF or getifaddrs()
+ */
+int
+get_net_ifs(char **addrinfo)
+{
+    return 0;
+}
+
+#endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */
diff --git a/src/parse_args.c b/src/parse_args.c
new file mode 100644 (file)
index 0000000..e9f09e4
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * Copyright (c) 1993-1996, 1998-2011 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/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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <ctype.h>
+#include <grp.h>
+#include <pwd.h>
+
+#include <sudo_usage.h>
+#include "sudo.h"
+#include "lbuf.h"
+
+/* For getopt(3) */
+extern char *optarg;
+extern int optind;
+
+int tgetpass_flags;
+
+/*
+ * Local functions.
+ */
+static void help(void) __attribute__((__noreturn__));
+static void usage_excl(int);
+
+/*
+ * Mapping of command line flags to name/value settings.
+ */
+static struct sudo_settings {
+    const char *name;
+    const char *value;
+} sudo_settings[] = {
+#define ARG_BSDAUTH_TYPE 0
+    { "bsdauth_type" },
+#define ARG_LOGIN_CLASS 1
+    { "login_class" },
+#define ARG_DEBUG_LEVEL 2
+    { "debug_level" },
+#define ARG_PRESERVE_ENVIRONMENT 3
+    { "preserve_environment" },
+#define ARG_RUNAS_GROUP 4
+    { "runas_group" },
+#define ARG_SET_HOME 5
+    { "set_home" },
+#define ARG_USER_SHELL 6
+    { "run_shell" },
+#define ARG_LOGIN_SHELL 7
+    { "login_shell" },
+#define ARG_IGNORE_TICKET 8
+    { "ignore_ticket" },
+#define ARG_PROMPT 9
+    { "prompt" },
+#define ARG_SELINUX_ROLE 10
+    { "selinux_role" },
+#define ARG_SELINUX_TYPE 11
+    { "selinux_type" },
+#define ARG_RUNAS_USER 12
+    { "runas_user" },
+#define ARG_PROGNAME 13
+    { "progname" },
+#define ARG_IMPLIED_SHELL 14
+    { "implied_shell" },
+#define ARG_PRESERVE_GROUPS 15
+    { "preserve_groups" },
+#define ARG_NONINTERACTIVE 16
+    { "noninteractive" },
+#define ARG_SUDOEDIT 17
+    { "sudoedit" },
+#define ARG_CLOSEFROM 18
+    { "closefrom" },
+#define ARG_NET_ADDRS 19
+    { "network_addrs" },
+#define NUM_SETTINGS 20
+    { NULL }
+};
+
+/*
+ * Command line argument parsing.
+ * Sets nargc and nargv which corresponds to the argc/argv we'll use
+ * for the command to be run (if we are running one).
+ */
+int
+parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
+    char ***env_addp)
+{
+    int mode = 0;              /* what mode is sudo to be run in? */
+    int flags = 0;             /* mode flags */
+    int valid_flags, ch;
+    int i, j;
+    char *cp, **env_add, **settings;
+    int nenv = 0;
+    int env_size = 32;
+
+    env_add = emalloc2(env_size, sizeof(char *));
+
+    /* Pass progname to plugin so it can call setprogname() */
+    sudo_settings[ARG_PROGNAME].value = getprogname();
+
+    /* First, check to see if we were invoked as "sudoedit". */
+    if (strcmp(getprogname(), "sudoedit") == 0) {
+       mode = MODE_EDIT;
+       sudo_settings[ARG_SUDOEDIT].value = "true";
+    }
+
+    /* Load local IP addresses and masks. */
+    if (get_net_ifs(&cp) > 0)
+       sudo_settings[ARG_NET_ADDRS].value = cp;
+
+    /* 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')
+
+    /* Returns true if next option is an environment variable */
+#define is_envar (optind < argc && argv[optind][0] != '/' && \
+           strchr(argv[optind], '=') != NULL)
+
+    /* Flags allowed when running a command */
+    valid_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|
+                 MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_SHELL;
+    /* XXX - should fill in settings at the end to avoid dupes */
+    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:D:Eeg:HhiKklnPp:r:Sst:U:u:Vv")) != -1) {
+           switch (ch) {
+               case 'A':
+                   SET(tgetpass_flags, TGP_ASKPASS);
+                   break;
+#ifdef HAVE_BSD_AUTH_H
+               case 'a':
+                   sudo_settings[ARG_BSDAUTH_TYPE].value = optarg;
+                   break;
+#endif
+               case 'b':
+                   SET(flags, MODE_BACKGROUND);
+                   break;
+               case 'C':
+                   if (atoi(optarg) < 3) {
+                       warningx("the argument to -C must be a number greater than or equal to 3");
+                       usage(1);
+                   }
+                   sudo_settings[ARG_CLOSEFROM].value = optarg;
+                   break;
+#ifdef HAVE_LOGIN_CAP_H
+               case 'c':
+                   sudo_settings[ARG_LOGIN_CLASS].value = optarg;
+                   break;
+#endif
+               case 'D':
+                   if ((debug_level = atoi(optarg)) < 1 || debug_level > 9) {
+                       warningx("the argument to -D must be between 1 and 9 inclusive");
+                       usage(1);
+                   }
+                   sudo_settings[ARG_DEBUG_LEVEL].value = optarg;
+                   break;
+               case 'E':
+                   sudo_settings[ARG_PRESERVE_ENVIRONMENT].value = "true";
+                   break;
+               case 'e':
+                   if (mode && mode != MODE_EDIT)
+                       usage_excl(1);
+                   mode = MODE_EDIT;
+                   sudo_settings[ARG_SUDOEDIT].value = "true";
+                   valid_flags = MODE_NONINTERACTIVE;
+                   break;
+               case 'g':
+                   runas_group = optarg;
+                   sudo_settings[ARG_RUNAS_GROUP].value = optarg;
+                   break;
+               case 'H':
+                   sudo_settings[ARG_SET_HOME].value = "true";
+                   break;
+               case 'h':
+                   if (mode && mode != MODE_HELP) {
+                       if (strcmp(getprogname(), "sudoedit") != 0)
+                           usage_excl(1);
+                   }
+                   mode = MODE_HELP;
+                   valid_flags = 0;
+                   break;
+               case 'i':
+                   sudo_settings[ARG_LOGIN_SHELL].value = "true";
+                   SET(flags, MODE_LOGIN_SHELL);
+                   break;
+               case 'k':
+                   sudo_settings[ARG_IGNORE_TICKET].value = "true";
+                   break;
+               case 'K':
+                   sudo_settings[ARG_IGNORE_TICKET].value = "true";
+                   if (mode && mode != MODE_KILL)
+                       usage_excl(1);
+                   mode = MODE_KILL;
+                   valid_flags = 0;
+                   break;
+               case 'l':
+                   if (mode) {
+                       if (mode == MODE_LIST)
+                           SET(flags, MODE_LONG_LIST);
+                       else
+                           usage_excl(1);
+                   }
+                   mode = MODE_LIST;
+                   valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST;
+                   break;
+               case 'n':
+                   SET(flags, MODE_NONINTERACTIVE);
+                   sudo_settings[ARG_NONINTERACTIVE].value = "true";
+                   break;
+               case 'P':
+                   sudo_settings[ARG_PRESERVE_GROUPS].value = "true";
+                   break;
+               case 'p':
+                   sudo_settings[ARG_PROMPT].value = optarg;
+                   break;
+#ifdef HAVE_SELINUX
+               case 'r':
+                   sudo_settings[ARG_SELINUX_ROLE].value = optarg;
+                   break;
+               case 't':
+                   sudo_settings[ARG_SELINUX_TYPE].value = optarg;
+                   break;
+#endif
+               case 'S':
+                   SET(tgetpass_flags, TGP_STDIN);
+                   break;
+               case 's':
+                   sudo_settings[ARG_USER_SHELL].value = "true";
+                   SET(flags, MODE_SHELL);
+                   break;
+               case 'U':
+                   if ((getpwnam(optarg)) == NULL)
+                       errorx(1, "unknown user: %s", optarg);
+                   list_user = optarg;
+                   break;
+               case 'u':
+                   runas_user = optarg;
+                   sudo_settings[ARG_RUNAS_USER].value = optarg;
+                   break;
+               case 'v':
+                   if (mode && mode != MODE_VALIDATE)
+                       usage_excl(1);
+                   mode = MODE_VALIDATE;
+                   valid_flags = MODE_NONINTERACTIVE;
+                   break;
+               case 'V':
+                   if (mode && mode != MODE_VERSION)
+                       usage_excl(1);
+                   mode = MODE_VERSION;
+                   valid_flags = 0;
+                   break;
+               default:
+                   usage(1);
+           }
+       } else if (!got_end_of_args && is_envar) {
+           if (nenv == env_size - 2) {
+               env_size *= 2;
+               env_add = erealloc3(env_add, env_size, sizeof(char *));
+           }
+           env_add[nenv++] = argv[optind];
+
+           /* Crank optind and resume getopt. */
+           optind++;
+       } else {
+           /* Not an option or an environment variable -- we're done. */
+           break;
+       }
+    }
+    env_add[nenv] = NULL;
+
+    argc -= optind;
+    argv += optind;
+
+    if (!mode) {
+       /* Defer -k mode setting until we know whether it is a flag or not */
+       if (sudo_settings[ARG_IGNORE_TICKET].value != NULL) {
+           if (argc == 0) {
+               mode = MODE_INVALIDATE; /* -k by itself */
+               sudo_settings[ARG_IGNORE_TICKET].value = NULL;
+               valid_flags = 0;
+           }
+       }
+       if (!mode)
+           mode = MODE_RUN;            /* running a command */
+    }
+
+    if (argc > 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 ((flags & valid_flags) != flags)
+       usage(1);
+    if (mode == MODE_EDIT &&
+       (ISSET(flags, MODE_PRESERVE_ENV) || env_add[0] != NULL)) {
+       if (ISSET(mode, MODE_PRESERVE_ENV))
+           warningx("the `-E' option is not valid in edit mode");
+       if (env_add[0] != NULL)
+           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 | MODE_VALIDATE)) {
+       usage(1);
+    }
+    if (list_user != NULL && mode != MODE_LIST && mode != MODE_CHECK) {
+       warningx("the `-U' option may only be used with the `-l' option");
+       usage(1);
+    }
+    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 ((argc == 0 && mode == MODE_EDIT) ||
+       (argc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
+       usage(1);
+    if (argc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL)) {
+       SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
+       sudo_settings[ARG_IMPLIED_SHELL].value = "true";
+    }
+
+    if (mode == MODE_HELP)
+       help();
+
+    /*
+     * For shell mode we need to rewrite argv
+     */
+    if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) {
+       char **av;
+       int ac;
+
+       if (argc == 0) {
+           /* just the shell */
+           ac = argc + 1;
+           av = emalloc2(ac + 1, sizeof(char *));
+           memcpy(av + 1, argv, argc * sizeof(char *));
+       } else {
+           /* shell -c "command" */
+           char *src, *dst, *end;
+           size_t cmnd_size = (size_t) (argv[argc - 1] - argv[0]) +
+                   strlen(argv[argc - 1]) + 1;
+           ac = 3;
+           av = emalloc2(ac + 1, sizeof(char *));
+           av[1] = "-c";
+           av[2] = dst = emalloc(cmnd_size);
+           src = argv[0];
+           for (end = src + cmnd_size - 1; src < end; src++, dst++)
+               *dst = *src == '\0' ? ' ' : *src;
+           *dst = '\0';
+       }
+       av[0] = (char *)user_details.shell; /* plugin may override shell */
+       av[ac] = NULL;
+
+       argv = av;
+       argc = ac;
+    }
+
+    /*
+     * Format setting_pairs into settings array.
+     */
+    settings = emalloc2(NUM_SETTINGS + 1, sizeof(char *));
+    for (i = 0, j = 0; i < NUM_SETTINGS; i++) {
+       if (sudo_settings[i].value) {
+           sudo_debug(9, "settings: %s=%s", sudo_settings[i].name,
+               sudo_settings[i].value);
+           settings[j] = fmt_string(sudo_settings[i].name,
+               sudo_settings[i].value);
+           if (settings[j] == NULL)
+               errorx(1, "unable to allocate memory");
+           j++;
+       }
+    }
+    settings[j] = NULL;
+
+    if (mode == MODE_EDIT) {
+#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID)
+       /* Must have the command in argv[0]. */
+       argc++;
+       argv--;
+       argv[0] = "sudoedit";
+#else
+       errorx(1, "sudoedit is not supported on this platform");
+#endif
+    }
+
+    *settingsp = settings;
+    *env_addp = env_add;
+    *nargc = argc;
+    *nargv = argv;
+    return mode | flags;
+}
+
+static int
+usage_err(const char *buf)
+{
+    return fputs(buf, stderr);
+}
+
+static int
+usage_out(const char *buf)
+{
+    return fputs(buf, stdout);
+}
+
+/*
+ * Give usage message and exit.
+ * The actual usage strings are in sudo_usage.h for configure substitution.
+ */
+void
+usage(int fatal)
+{
+    struct lbuf lbuf;
+    char *uvec[6];
+    int i, ulen;
+
+    /*
+     * Use usage vectors appropriate to the progname.
+     */
+    if (strcmp(getprogname(), "sudoedit") == 0) {
+       uvec[0] = SUDO_USAGE5 + 3;
+       uvec[1] = NULL;
+    } else {
+       uvec[0] = SUDO_USAGE1;
+       uvec[1] = SUDO_USAGE2;
+       uvec[2] = SUDO_USAGE3;
+       uvec[3] = SUDO_USAGE4;
+       uvec[4] = SUDO_USAGE5;
+       uvec[5] = NULL;
+    }
+
+    /*
+     * Print usage and wrap lines as needed, depending on the
+     * tty width.
+     */
+    ulen = (int)strlen(getprogname()) + 8;
+    lbuf_init(&lbuf, fatal ? usage_err : usage_out, ulen, NULL,
+       user_details.ts_cols);
+    for (i = 0; uvec[i] != NULL; i++) {
+       lbuf_append(&lbuf, "usage: ", getprogname(), uvec[i], NULL);
+       lbuf_print(&lbuf);
+    }
+    lbuf_destroy(&lbuf);
+    if (fatal)
+       exit(1);
+}
+
+/*
+ * Tell which options are mutually exclusive and exit.
+ */
+static void
+usage_excl(int fatal)
+{
+    warningx("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified");
+    usage(fatal);
+}
+
+static void
+help(void)
+{
+    struct lbuf lbuf;
+    int indent = 16;
+    const char *pname = getprogname();
+
+    lbuf_init(&lbuf, usage_out, indent, NULL, user_details.ts_cols);
+    if (strcmp(pname, "sudoedit") == 0)
+       lbuf_append(&lbuf, pname,  " - edit files as another user\n\n", NULL);
+    else
+       lbuf_append(&lbuf, pname,  " - execute a command as another user\n\n", NULL);
+    lbuf_print(&lbuf);
+
+    usage(0);
+
+    lbuf_append(&lbuf, "\nOptions:\n", NULL);
+#ifdef HAVE_BSD_AUTH_H
+    lbuf_append(&lbuf,
+       "  -A            use helper program for password prompting\n", NULL);
+#endif
+    lbuf_append(&lbuf,
+       "  -a type       use specified BSD authentication type\n", NULL);
+    lbuf_append(&lbuf,
+       "  -b            run command in the background\n", NULL);
+    lbuf_append(&lbuf,
+       "  -C fd         close all file descriptors >= fd\n", NULL);
+#ifdef HAVE_LOGIN_CAP_H
+    lbuf_append(&lbuf,
+       "  -c class      run command with specified login class\n", NULL);
+#endif
+    lbuf_append(&lbuf,
+       "  -E            preserve user environment when executing command\n",
+       NULL);
+    lbuf_append(&lbuf,
+       "  -e            edit files instead of running a command\n", NULL);
+    lbuf_append(&lbuf,
+       "  -g group      execute command as the specified group\n", NULL);
+    lbuf_append(&lbuf,
+       "  -H            set HOME variable to target user's home dir.\n",
+       NULL);
+    lbuf_append(&lbuf,
+       "  -h            display help message and exit\n", NULL);
+    lbuf_append(&lbuf,
+       "  -i [command]  run a login shell as target user\n", NULL);
+    lbuf_append(&lbuf,
+       "  -K            remove timestamp file completely\n", NULL);
+    lbuf_append(&lbuf,
+       "  -k            invalidate timestamp file\n", NULL);
+    lbuf_append(&lbuf,
+       "  -l[l] command list user's available commands\n", NULL);
+    lbuf_append(&lbuf,
+       "  -n            non-interactive mode, will not prompt user\n", NULL);
+    lbuf_append(&lbuf,
+       "  -P            preserve group vector instead of setting to target's\n",
+       NULL);
+    lbuf_append(&lbuf,
+       "  -p prompt     use specified password prompt\n", NULL);
+#ifdef HAVE_SELINUX
+    lbuf_append(&lbuf,
+       "  -r role       create SELinux security context with specified role\n",
+       NULL);
+#endif
+    lbuf_append(&lbuf,
+       "  -S            read password from standard input\n", NULL);
+    lbuf_append(&lbuf,
+       "  -s [command]  run a shell as target user\n", NULL);
+#ifdef HAVE_SELINUX
+    lbuf_append(&lbuf,
+       "  -t type       create SELinux security context with specified role\n",
+       NULL);
+#endif
+    lbuf_append(&lbuf,
+       "  -U user       when listing, list specified user's privileges\n",
+       NULL);
+    lbuf_append(&lbuf,
+       "  -u user       run command (or edit file) as specified user\n", NULL);
+    lbuf_append(&lbuf,
+       "  -V            display version information and exit\n", NULL);
+    lbuf_append(&lbuf,
+       "  -v            update user's timestamp without running a command\n",
+       NULL);
+    lbuf_append(&lbuf,
+       "  --            stop processing command line arguments\n", NULL);
+    lbuf_print(&lbuf);
+    lbuf_destroy(&lbuf);
+    exit(0);
+}
diff --git a/src/preload.c b/src/preload.c
new file mode 100644 (file)
index 0000000..9e77f0b
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2010 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 "sudo_plugin.h"
+
+extern struct policy_plugin sudoers_policy;
+extern struct io_plugin sudoers_io;
+
+struct sudo_preload_table {
+    const char *name;
+    void *address;
+} sudo_preload_table[] = {
+    { "sudoers_policy", (void *) &sudoers_policy},
+    { "sudoers_io", (void *) &sudoers_io},
+    { NULL, NULL }
+};
diff --git a/src/selinux.c b/src/selinux.c
new file mode 100644 (file)
index 0000000..b5c3dc8
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2008 Dan Walsh <dwalsh@redhat.com>
+ *
+ * Borrowed heavily from newrole source code
+ * Authors:
+ *     Anthony Colatrella
+ *     Tim Fraser
+ *     Steve Grubb <sgrubb@redhat.com>
+ *     Darrel Goeddel <DGoeddel@trustedcs.com>
+ *     Michael Thompson <mcthomps@us.ibm.com>
+ *     Dan Walsh <dwalsh@redhat.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/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <selinux/flask.h>             /* for SECCLASS_CHR_FILE */
+#include <selinux/selinux.h>           /* for is_selinux_enabled() */
+#include <selinux/context.h>           /* for context-mangling functions */
+#include <selinux/get_default_type.h>
+#include <selinux/get_context_list.h>
+
+#ifdef HAVE_LINUX_AUDIT
+# include <libaudit.h>
+#endif
+
+#include "sudo.h"
+
+static struct selinux_state {
+    security_context_t old_context;
+    security_context_t new_context;
+    security_context_t tty_context;
+    security_context_t new_tty_context;
+    const char *ttyn;
+    int ttyfd;
+    int enforcing;
+} se_state;
+
+#ifdef HAVE_LINUX_AUDIT
+static int
+audit_role_change(const security_context_t old_context,
+    const security_context_t new_context, const char *ttyn)
+{
+    int au_fd, rc;
+    char *message;
+
+    au_fd = audit_open();
+    if (au_fd == -1) {
+        /* Kernel may not have audit support. */
+        if (errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT
+)
+            error(1, "unable to open audit system");
+       return -1;
+    }
+
+    /* audit role change using the same format as newrole(1) */
+    easprintf(&message, "newrole: old-context=%s new-context=%s",
+       old_context, new_context);
+    rc = audit_log_user_message(au_fd, AUDIT_USER_ROLE_CHANGE,
+       message, NULL, NULL, ttyn, 1);
+    if (rc <= 0)
+       warning("unable to send audit message");
+
+    efree(message);
+    close(au_fd);
+
+    return rc;
+}
+#endif
+
+/*
+ * This function attempts to revert the relabeling done to the tty.
+ * fd             - referencing the opened ttyn
+ * ttyn                   - name of tty to restore
+ *
+ * Returns zero on success, non-zero otherwise
+ */
+int
+selinux_restore_tty(void)
+{
+    int retval = 0;
+    security_context_t chk_tty_context = NULL;
+
+    if (se_state.ttyfd == -1 || se_state.new_tty_context == NULL)
+       goto skip_relabel;
+
+    /* Verify that the tty still has the context set by sudo. */
+    if ((retval = fgetfilecon(se_state.ttyfd, &chk_tty_context)) < 0) {
+       warning("unable to fgetfilecon %s", se_state.ttyn);
+       goto skip_relabel;
+    }
+
+    if ((retval = strcmp(chk_tty_context, se_state.new_tty_context))) {
+       warningx("%s changed labels.", se_state.ttyn);
+       goto skip_relabel;
+    }
+
+    if ((retval = fsetfilecon(se_state.ttyfd, se_state.tty_context)) < 0)
+       warning("unable to restore context for %s", se_state.ttyn);
+
+skip_relabel:
+    if (se_state.ttyfd != -1) {
+       close(se_state.ttyfd);
+       se_state.ttyfd = -1;
+    }
+    if (chk_tty_context != NULL) {
+       freecon(chk_tty_context);
+       chk_tty_context = NULL;
+    }
+    return retval;
+}
+
+/*
+ * This function attempts to relabel the tty. If this function fails, then
+ * the contexts are free'd and -1 is returned. On success, 0 is returned
+ * and tty_context and new_tty_context are set.
+ *
+ * This function will not fail if it can not relabel the tty when selinux is
+ * in permissive mode.
+ */
+static int
+relabel_tty(const char *ttyn, int ptyfd)
+{
+    security_context_t tty_con = NULL;
+    security_context_t new_tty_con = NULL;
+    int fd;
+
+    se_state.ttyfd = ptyfd;
+
+    /* It is perfectly legal to have no tty. */
+    if (ptyfd == -1 && ttyn == NULL)
+       return 0;
+
+    /* If sudo is not allocating a pty for the command, open current tty. */
+    if (ptyfd == -1) {
+       se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK);
+       if (se_state.ttyfd == -1) {
+           warning("unable to open %s, not relabeling tty", ttyn);
+           if (se_state.enforcing)
+               goto bad;
+       }
+       (void)fcntl(se_state.ttyfd, F_SETFL,
+           fcntl(se_state.ttyfd, F_GETFL, 0) & ~O_NONBLOCK);
+    }
+
+    if (fgetfilecon(se_state.ttyfd, &tty_con) < 0) {
+       warning("unable to get current tty context, not relabeling tty");
+       if (se_state.enforcing)
+           goto bad;
+    }
+
+    if (tty_con && (security_compute_relabel(se_state.new_context, tty_con,
+       SECCLASS_CHR_FILE, &new_tty_con) < 0)) {
+       warning("unable to get new tty context, not relabeling tty");
+       if (se_state.enforcing)
+           goto bad;
+    }
+
+    if (new_tty_con != NULL) {
+       if (fsetfilecon(se_state.ttyfd, new_tty_con) < 0) {
+           warning("unable to set new tty context");
+           if (se_state.enforcing)
+               goto bad;
+       }
+    }
+
+    if (ptyfd != -1) {
+       /* Reopen pty that was relabeled, std{in,out,err} are reset later. */
+       se_state.ttyfd = open(ttyn, O_RDWR|O_NOCTTY, 0);
+       if (se_state.ttyfd == -1) {
+           warning("cannot open %s", ttyn);
+           if (se_state.enforcing)
+               goto bad;
+       }
+       if (dup2(se_state.ttyfd, ptyfd) == -1) {
+           warning("dup2");
+           goto bad;
+       }
+    } else {
+       /* Re-open tty to get new label and reset std{in,out,err} */
+       close(se_state.ttyfd);
+       se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK);
+       if (se_state.ttyfd == -1) {
+           warning("unable to open %s", ttyn);
+           goto bad;
+       }
+       (void)fcntl(se_state.ttyfd, F_SETFL,
+           fcntl(se_state.ttyfd, F_GETFL, 0) & ~O_NONBLOCK);
+       for (fd = STDIN_FILENO; fd <= STDERR_FILENO; fd++) {
+           if (isatty(fd) && dup2(se_state.ttyfd, fd) == -1) {
+               warning("dup2");
+               goto bad;
+           }
+       }
+    }
+    /* Retain se_state.ttyfd so we can restore label when command finishes. */
+    (void)fcntl(se_state.ttyfd, F_SETFD, FD_CLOEXEC);
+
+    se_state.ttyn = ttyn;
+    se_state.tty_context = tty_con;
+    se_state.new_tty_context = new_tty_con;
+    return 0;
+
+bad:
+    if (se_state.ttyfd != -1 && se_state.ttyfd != ptyfd) {
+       close(se_state.ttyfd);
+       se_state.ttyfd = -1;
+    }
+    freecon(tty_con);
+    return -1;
+}
+
+/*
+ * Returns a new security context based on the old context and the
+ * specified role and type.
+ */
+security_context_t
+get_exec_context(security_context_t old_context, const char *role, const char *type)
+{
+    security_context_t new_context = NULL;
+    context_t context = NULL;
+    char *typebuf = NULL;
+    
+    /* We must have a role, the type is optional (we can use the default). */
+    if (!role) {
+       warningx("you must specify a role for type %s", type);
+       errno = EINVAL;
+       return NULL;
+    }
+    if (!type) {
+       if (get_default_type(role, &typebuf)) {
+           warningx("unable to get default type for role %s", role);
+           errno = EINVAL;
+           return NULL;
+       }
+       type = typebuf;
+    }
+    
+    /* 
+     * Expand old_context into a context_t so that we extract and modify 
+     * its components easily. 
+     */
+    context = context_new(old_context);
+    
+    /*
+     * Replace the role and type in "context" with the role and
+     * type we will be running the command as.
+     */
+    if (context_role_set(context, role)) {
+       warning("failed to set new role %s", role);
+       goto bad;
+    }
+    if (context_type_set(context, type)) {
+       warning("failed to set new type %s", type);
+       goto bad;
+    }
+      
+    /*
+     * Convert "context" back into a string and verify it.
+     */
+    new_context = estrdup(context_str(context));
+    if (security_check_context(new_context) < 0) {
+       warningx("%s is not a valid context", new_context);
+       errno = EINVAL;
+       goto bad;
+    }
+
+#ifdef DEBUG
+    warningx("Your new context is %s", new_context);
+#endif
+
+    context_free(context);
+    return new_context;
+
+bad:
+    free(typebuf);
+    context_free(context);
+    freecon(new_context);
+    return NULL;
+}
+
+/* 
+ * Set the exec and tty contexts in preparation for fork/exec.
+ * Must run as root, before the uid change.
+ * If ptyfd is not -1, it indicates we are running
+ * in a pty and do not need to reset std{in,out,err}.
+ * Returns 0 on success and -1 on failure.
+ */
+int
+selinux_setup(const char *role, const char *type, const char *ttyn,
+    int ptyfd)
+{
+    int rval = -1;
+
+    /* Store the caller's SID in old_context. */
+    if (getprevcon(&se_state.old_context)) {
+       warning("failed to get old_context");
+       goto done;
+    }
+
+    se_state.enforcing = security_getenforce();
+    if (se_state.enforcing < 0) {
+       warning("unable to determine enforcing mode.");
+       goto done;
+    }
+
+#ifdef DEBUG
+    warningx("your old context was %s", se_state.old_context);
+#endif
+    se_state.new_context = get_exec_context(se_state.old_context, role, type);
+    if (!se_state.new_context)
+       goto done;
+    
+    if (relabel_tty(ttyn, ptyfd) < 0) {
+       warning("unable to setup tty context for %s", se_state.new_context);
+       goto done;
+    }
+
+#ifdef DEBUG
+    if (se_state.ttyfd != -1) {
+       warningx("your old tty context is %s", se_state.tty_context);
+       warningx("your new tty context is %s", se_state.new_tty_context);
+    }
+#endif
+
+#ifdef HAVE_LINUX_AUDIT
+    audit_role_change(se_state.old_context, se_state.new_context,
+       se_state.ttyn);
+#endif
+
+    rval = 0;
+
+done:
+    return rval;
+}
+
+void
+selinux_execve(const char *path, char *argv[], char *envp[])
+{
+    char **nargv;
+    int argc, serrno;
+
+    if (setexeccon(se_state.new_context)) {
+       warning("unable to set exec context to %s", se_state.new_context);
+       if (se_state.enforcing)
+           return;
+    }
+
+#ifdef HAVE_SETKEYCREATECON
+    if (setkeycreatecon(se_state.new_context)) {
+       warning("unable to set key creation context to %s", se_state.new_context);
+       if (se_state.enforcing)
+           return;
+    }
+#endif /* HAVE_SETKEYCREATECON */
+
+    for (argc = 0; argv[argc] != NULL; argc++)
+       continue;
+
+    /* Build new argv with sesh as argv[0]. */
+    nargv = emalloc2(argc + 2, sizeof(char *));
+    nargv[0] = *argv[0] == '-' ? "-sesh" : "sesh";
+    nargv[1] = (char *)path;
+    memcpy(&nargv[2], &argv[1], argc * sizeof(char *)); /* copies NULL */
+
+    execve(_PATH_SUDO_SESH, nargv, envp);
+    serrno = errno;
+    free(nargv);
+    errno = serrno;
+}
diff --git a/src/sesh.c b/src/sesh.c
new file mode 100644 (file)
index 0000000..e0aef78
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2008, 2010 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 <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "missing.h"
+
+int
+main (int argc, char *argv[])
+{
+    char *cp, *cmnd;
+
+    if (argc < 2)
+       errx(EXIT_FAILURE, "requires at least one argument");
+
+    /* Shift argv and make a copy of the command to execute. */
+    argv++;
+    argc--;
+    cmnd = strdup(argv[0]);
+    if (cmnd == NULL)
+       err(EXIT_FAILURE, NULL);
+
+    /* If invoked as a login shell, modify argv[0] accordingly. */
+    if (argv[0][0] == '-') {
+       if ((cp = strrchr(argv[0], '/')) == NULL)
+           cp = argv[0];
+       *cp = '-';
+    }
+    execv(cmnd, argv);
+    warn("unable to execute %s", argv[0]);
+    _exit(EXIT_FAILURE);
+}
diff --git a/src/sudo.c b/src/sudo.c
new file mode 100644 (file)
index 0000000..1f9b565
--- /dev/null
@@ -0,0 +1,1205 @@
+/*
+ * Copyright (c) 2009-2011 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.
+ */
+
+#ifdef __TANDEM
+# include <floss.h>
+#endif
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_H */
+#include <sys/time.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 */
+#ifdef HAVE_STRING_H
+# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <grp.h>
+#include <pwd.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#ifdef HAVE_SETLOCALE
+# include <locale.h>
+#endif
+#ifdef HAVE_LOGIN_CAP_H
+# include <login_cap.h>
+#endif
+#ifdef HAVE_PROJECT_H
+# include <project.h>
+# include <sys/task.h>
+#endif
+#ifdef HAVE_SELINUX
+# include <selinux/selinux.h>
+#endif
+#ifdef HAVE_SETAUTHDB
+# include <usersec.h>
+#endif /* HAVE_SETAUTHDB */
+#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
+# ifdef __hpux
+#  undef MAXINT
+#  include <hpsecurity.h>
+# else
+#  include <sys/security.h>
+# endif /* __hpux */
+# include <prot.h>
+#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
+#ifdef HAVE_PRIV_SET
+# include <priv.h>
+#endif
+
+#include "sudo.h"
+#include "sudo_plugin.h"
+#include "sudo_plugin_int.h"
+#include <sudo_usage.h>
+
+/*
+ * Local variables
+ */
+struct plugin_container policy_plugin;
+struct plugin_container_list io_plugins;
+struct user_details user_details;
+const char *list_user, *runas_user, *runas_group; /* extern for parse_args.c */
+int debug_level;
+
+/*
+ * Local functions
+ */
+static void fix_fds(void);
+static void disable_coredumps(void);
+static char **get_user_info(struct user_details *);
+static void command_info_to_details(char * const info[],
+    struct command_details *details);
+static int policy_open(struct plugin_container *plugin, char * const settings[],
+    char * const user_info[], char * const user_env[]);
+static void policy_close(struct plugin_container *plugin, int exit_status,
+    int error);
+static int iolog_open(struct plugin_container *plugin, char * const settings[],
+    char * const user_info[], char * const command_details[],
+    int argc, char * const argv[], char * const user_env[]);
+static void iolog_close(struct plugin_container *plugin, int exit_status,
+    int error);
+static char *escape_cmnd(const char *src);
+
+/* Policy plugin convenience functions. */
+static int policy_open(struct plugin_container *plugin, char * const settings[],
+    char * const user_info[], char * const user_env[]);
+static void policy_close(struct plugin_container *plugin, int exit_status,
+    int error);
+static int policy_show_version(struct plugin_container *plugin, int verbose);
+static int policy_check(struct plugin_container *plugin, int argc,
+    char * const argv[], char *env_add[], char **command_info[],
+    char **argv_out[], char **user_env_out[]);
+static int policy_list(struct plugin_container *plugin, int argc,
+    char * const argv[], int verbose, const char *list_user);
+static int policy_validate(struct plugin_container *plugin);
+static void policy_invalidate(struct plugin_container *plugin, int remove);
+static int policy_init_session(struct plugin_container *plugin,
+    struct passwd *pwd);
+
+/* I/O log plugin convenience functions. */
+static int iolog_open(struct plugin_container *plugin, char * const settings[],
+    char * const user_info[], char * const command_details[],
+    int argc, char * const argv[], char * const user_env[]);
+static void iolog_close(struct plugin_container *plugin, int exit_status,
+    int error);
+static int iolog_show_version(struct plugin_container *plugin, int verbose);
+
+#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
+static struct rlimit corelimit;
+#endif /* RLIMIT_CORE && !SUDO_DEVEL */
+#if defined(__linux__)
+static struct rlimit nproclimit;
+#endif
+
+int
+main(int argc, char *argv[], char *envp[])
+{
+    int nargc, sudo_mode, exitcode = 0;
+    char **nargv, **settings, **env_add;
+    char **user_info, **command_info, **argv_out, **user_env_out;
+    struct plugin_container *plugin, *next;
+    struct command_details command_details;
+    sigset_t mask;
+    int ok;
+#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
+    extern char *malloc_options;
+    malloc_options = "AFGJPR";
+#endif
+
+#ifdef HAVE_SETLOCALE
+    setlocale(LC_ALL, "");
+#endif
+
+#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
+    if (argc > 0)
+       setprogname(argv[0]);
+#endif
+
+    /* Must be done before we do any password lookups */
+#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
+    (void) set_auth_parameters(argc, argv);
+# ifdef HAVE_INITPRIVS
+    initprivs();
+# endif
+#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
+
+    if (geteuid() != 0)
+       errorx(1, "must be setuid root");
+
+    /* Reset signal mask, disable core dumps and make sure fds 0-2 are open. */
+    (void) sigemptyset(&mask);
+    (void) sigprocmask(SIG_SETMASK, &mask, NULL);
+    disable_coredumps();
+    fix_fds();
+
+    /* Fill in user_info with user name, uid, cwd, etc. */
+    memset(&user_details, 0, sizeof(user_details));
+    user_info = get_user_info(&user_details);
+
+    /* Parse command line arguments. */
+    sudo_mode = parse_args(argc, argv, &nargc, &nargv, &settings, &env_add);
+    sudo_debug(9, "sudo_mode %d", sudo_mode);
+
+    /* Print sudo version early, in case of plugin init failure. */
+    if (ISSET(sudo_mode, MODE_VERSION)) {
+       printf("Sudo version %s\n", PACKAGE_VERSION);
+       if (user_details.uid == ROOT_UID)
+           (void) printf("Configure args: %s\n", CONFIGURE_ARGS);
+    }
+
+    /* Read sudo.conf and load plugins. */
+    if (!sudo_load_plugins(_PATH_SUDO_CONF, &policy_plugin, &io_plugins))
+       errorx(1, "fatal error, unable to load plugins");
+
+    /* Open policy plugin. */
+    ok = policy_open(&policy_plugin, settings, user_info, envp);
+    if (ok != TRUE) {
+       if (ok == -2)
+           usage(1);
+       else
+           errorx(1, "unable to initialize policy plugin");
+    }
+
+    switch (sudo_mode & MODE_MASK) {
+       case MODE_VERSION:
+           policy_show_version(&policy_plugin, !user_details.uid);
+           tq_foreach_fwd(&io_plugins, plugin) {
+               ok = iolog_open(plugin, settings, user_info, NULL,
+                   nargc, nargv, envp);
+               if (ok == TRUE)
+                   iolog_show_version(plugin, !user_details.uid);
+           }
+           break;
+       case MODE_VALIDATE:
+       case MODE_VALIDATE|MODE_INVALIDATE:
+           ok = policy_validate(&policy_plugin);
+           exit(ok != TRUE);
+       case MODE_KILL:
+       case MODE_INVALIDATE:
+           policy_invalidate(&policy_plugin, sudo_mode == MODE_KILL);
+           exit(0);
+           break;
+       case MODE_CHECK:
+       case MODE_CHECK|MODE_INVALIDATE:
+       case MODE_LIST:
+       case MODE_LIST|MODE_INVALIDATE:
+           ok = policy_list(&policy_plugin, nargc, nargv,
+               ISSET(sudo_mode, MODE_LONG_LIST), list_user);
+           exit(ok != TRUE);
+       case MODE_EDIT:
+       case MODE_RUN:
+           ok = policy_check(&policy_plugin, nargc, nargv, env_add,
+               &command_info, &argv_out, &user_env_out);
+           sudo_debug(8, "policy plugin returns %d", ok);
+           if (ok != TRUE) {
+               if (ok == -2)
+                   usage(1);
+               exit(1); /* plugin printed error message */
+           }
+           /* Open I/O plugins once policy plugin succeeds. */
+           for (plugin = io_plugins.first; plugin != NULL; plugin = next) {
+               next = plugin->next;
+               ok = iolog_open(plugin, settings, user_info,
+                   command_info, nargc, nargv, envp);
+               switch (ok) {
+               case TRUE:
+                   break;
+               case FALSE:
+                   /* I/O plugin asked to be disabled, remove from list. */
+                   tq_remove(&io_plugins, plugin);
+                   break;
+               case -2:
+                   usage(1);
+                   break;
+               default:
+                   errorx(1, "error initializing I/O plugin %s", plugin->name);
+               }
+           }
+           command_info_to_details(command_info, &command_details);
+           command_details.argv = argv_out;
+           command_details.envp = user_env_out;
+           if (ISSET(sudo_mode, MODE_BACKGROUND))
+               SET(command_details.flags, CD_BACKGROUND);
+           /* Restore coredumpsize resource limit before running. */
+#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
+           (void) setrlimit(RLIMIT_CORE, &corelimit);
+#endif /* RLIMIT_CORE && !SUDO_DEVEL */
+           if (ISSET(command_details.flags, CD_SUDOEDIT)) {
+               exitcode = sudo_edit(&command_details);
+           } else {
+               if (ISSET(sudo_mode, MODE_SHELL)) {
+                   /* Escape meta chars if running a shell with args. */
+                   if (argv_out[1] != NULL && strcmp(argv_out[1], "-c") == 0 &&
+                       argv_out[2] != NULL && argv_out[3] == NULL)
+                       argv_out[2] = escape_cmnd(argv_out[2]);
+               }
+               exitcode = run_command(&command_details);
+           }
+           /* The close method was called by sudo_edit/run_command. */
+           break;
+       default:
+           errorx(1, "unexpected sudo mode 0x%x", sudo_mode);
+    }
+    exit(exitcode);
+}
+
+/*
+ * Ensure that stdin, stdout and stderr are open; set to /dev/null if not.
+ * Some operating systems do this automatically in the kernel or libc.
+ */
+static void
+fix_fds(void)
+{
+    int miss[3], devnull = -1;
+
+    /*
+     * stdin, stdout and stderr must be open; set them to /dev/null
+     * if they are closed.
+     */
+    miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1;
+    miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1;
+    miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1;
+    if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) {
+       if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) == -1)
+           error(1, "unable to open %s", _PATH_DEVNULL);
+       if (miss[STDIN_FILENO] && dup2(devnull, STDIN_FILENO) == -1)
+           error(1, "dup2");
+       if (miss[STDOUT_FILENO] && dup2(devnull, STDOUT_FILENO) == -1)
+           error(1, "dup2");
+       if (miss[STDERR_FILENO] && dup2(devnull, STDERR_FILENO) == -1)
+           error(1, "dup2");
+       if (devnull > STDERR_FILENO)
+           close(devnull);
+    }
+}
+
+static char *
+get_user_groups(struct user_details *ud)
+{
+    char *gid_list = NULL;
+#ifdef HAVE_GETGROUPS
+    size_t glsize;
+    char *cp;
+    int i, len;
+
+    if ((ud->ngroups = getgroups(0, NULL)) <= 0)
+       return NULL;
+
+    ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T));
+    if (getgroups(ud->ngroups, ud->groups) < 0)
+       error(1, "can't get group vector");
+    glsize = sizeof("groups=") - 1 + (ud->ngroups * (MAX_UID_T_LEN + 1));
+    gid_list = emalloc(glsize);
+    memcpy(gid_list, "groups=", sizeof("groups=") - 1);
+    cp = gid_list + sizeof("groups=") - 1;
+    for (i = 0; i < ud->ngroups; i++) {
+       /* XXX - check rval */
+       len = snprintf(cp, glsize - (cp - gid_list), "%s%u",
+           i ? "," : "", (unsigned int)ud->groups[i]);
+       cp += len;
+    }
+#endif
+    return gid_list;
+}
+
+/*
+ * Return user information as an array of name=value pairs.
+ * and fill in struct user_details (which shares the same strings).
+ */
+static char **
+get_user_info(struct user_details *ud)
+{
+    char cwd[PATH_MAX];
+    char host[MAXHOSTNAMELEN];
+    char **user_info, *cp;
+    struct passwd *pw;
+    int i = 0;
+
+    /* XXX - bound check number of entries */
+    user_info = emalloc2(32, sizeof(char *));
+
+    ud->uid = getuid();
+    ud->euid = geteuid();
+    ud->gid = getgid();
+    ud->egid = getegid();
+
+    pw = getpwuid(ud->uid);
+    if (pw == NULL)
+       errorx(1, "unknown uid %u: who are you?", (unsigned int)ud->uid);
+
+    user_info[i] = fmt_string("user", pw->pw_name);
+    if (user_info[i] == NULL)
+       errorx(1, "unable to allocate memory");
+    ud->username = user_info[i] + sizeof("user=") - 1;
+
+    /* Stash user's shell for use with the -s flag; don't pass to plugin. */
+    if ((ud->shell = getenv("SHELL")) == NULL || ud->shell[0] == '\0') {
+       ud->shell = pw->pw_shell[0] ? pw->pw_shell : _PATH_BSHELL;
+    }
+    ud->shell = estrdup(ud->shell);
+
+    easprintf(&user_info[++i], "uid=%u", (unsigned int)ud->uid);
+    easprintf(&user_info[++i], "euid=%u", (unsigned int)ud->euid);
+    easprintf(&user_info[++i], "gid=%u", (unsigned int)ud->gid);
+    easprintf(&user_info[++i], "egid=%u", (unsigned int)ud->egid);
+
+    if ((cp = get_user_groups(ud)) != NULL)
+       user_info[++i] = cp;
+
+    if (getcwd(cwd, sizeof(cwd)) != NULL) {
+       user_info[++i] = fmt_string("cwd", cwd);
+       if (user_info[i] == NULL)
+           errorx(1, "unable to allocate memory");
+       ud->cwd = user_info[i] + sizeof("cwd=") - 1;
+    }
+
+    if ((cp = ttyname(STDIN_FILENO)) || (cp = ttyname(STDOUT_FILENO)) ||
+       (cp = ttyname(STDERR_FILENO))) {
+       user_info[++i] = fmt_string("tty", cp);
+       if (user_info[i] == NULL)
+           errorx(1, "unable to allocate memory");
+       ud->tty = user_info[i] + sizeof("tty=") - 1;
+    }
+
+    if (gethostname(host, sizeof(host)) == 0)
+       host[sizeof(host) - 1] = '\0';
+    else
+       strlcpy(host, "localhost", sizeof(host));
+    user_info[++i] = fmt_string("host", host);
+    if (user_info[i] == NULL)
+       errorx(1, "unable to allocate memory");
+    ud->host = user_info[i] + sizeof("host=") - 1;
+
+    get_ttysize(&ud->ts_lines, &ud->ts_cols);
+    easprintf(&user_info[++i], "lines=%d", ud->ts_lines);
+    easprintf(&user_info[++i], "cols=%d", ud->ts_cols);
+
+    user_info[++i] = NULL;
+
+    return user_info;
+}
+
+/*
+ * Convert a command_info array into a command_details structure.
+ */
+static void
+command_info_to_details(char * const info[], struct command_details *details)
+{
+    int i;
+    long lval;
+    unsigned long ulval;
+    char *cp, *ep;
+
+    memset(details, 0, sizeof(*details));
+    details->closefrom = -1;
+
+#define SET_STRING(s, n) \
+    if (strncmp(s, info[i], sizeof(s) - 1) == 0 && info[i][sizeof(s) - 1]) { \
+       details->n = info[i] + sizeof(s) - 1; \
+       break; \
+    }
+
+    for (i = 0; info[i] != NULL; i++) {
+       sudo_debug(9, "command info: %s", info[i]);
+       switch (info[i][0]) {
+           case 'c':
+               SET_STRING("chroot=", chroot)
+               SET_STRING("command=", command)
+               SET_STRING("cwd=", cwd)
+               if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) {
+                   cp = info[i] + sizeof("closefrom=") - 1;
+                   if (*cp == '\0')
+                       break;
+                   errno = 0;
+                   lval = strtol(cp, &ep, 0);
+                   if (*cp != '\0' && *ep == '\0' &&
+                       !(errno == ERANGE &&
+                       (lval == LONG_MAX || lval == LONG_MIN)) &&
+                       lval < INT_MAX && lval > INT_MIN) {
+                       details->closefrom = (int)lval;
+                   }
+                   break;
+               }
+               break;
+           case 'l':
+               SET_STRING("login_class=", login_class)
+               break;
+           case 'n':
+               /* XXX - bounds check  -NZERO to NZERO (inclusive). */
+               if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) {
+                   cp = info[i] + sizeof("nice=") - 1;
+                   if (*cp == '\0')
+                       break;
+                   errno = 0;
+                   lval = strtol(cp, &ep, 0);
+                   if (*cp != '\0' && *ep == '\0' &&
+                       !(errno == ERANGE &&
+                       (lval == LONG_MAX || lval == LONG_MIN)) &&
+                       lval < INT_MAX && lval > INT_MIN) {
+                       details->priority = (int)lval;
+                       SET(details->flags, CD_SET_PRIORITY);
+                   }
+                   break;
+               }
+               if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) {
+                   if (atobool(info[i] + sizeof("noexec=") - 1) == TRUE)
+                       SET(details->flags, CD_NOEXEC);
+                   break;
+               }
+               /* XXX - deprecated */
+               if (strncmp("noexec_file=", info[i], sizeof("noexec_file=") - 1) == 0) {
+                   noexec_path = info[i] + sizeof("noexec_file=") - 1;
+                   break;
+               }
+               break;
+           case 'p':
+               if (strncmp("preserve_groups=", info[i], sizeof("preserve_groups=") - 1) == 0) {
+                   if (atobool(info[i] + sizeof("preserve_groups=") - 1) == TRUE)
+                       SET(details->flags, CD_PRESERVE_GROUPS);
+                   break;
+               }
+               break;
+           case 'r':
+               if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) {
+                   cp = info[i] + sizeof("runas_egid=") - 1;
+                   if (*cp == '\0')
+                       break;
+                   errno = 0;
+                   ulval = strtoul(cp, &ep, 0);
+                   if (*cp != '\0' && *ep == '\0' &&
+                       (errno != ERANGE || ulval != ULONG_MAX)) {
+                       details->egid = (gid_t)ulval;
+                       SET(details->flags, CD_SET_EGID);
+                   }
+                   break;
+               }
+               if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) {
+                   cp = info[i] + sizeof("runas_euid=") - 1;
+                   if (*cp == '\0')
+                       break;
+                   errno = 0;
+                   ulval = strtoul(cp, &ep, 0);
+                   if (*cp != '\0' && *ep == '\0' &&
+                       (errno != ERANGE || ulval != ULONG_MAX)) {
+                       details->euid = (uid_t)ulval;
+                       SET(details->flags, CD_SET_EUID);
+                   }
+                   break;
+               }
+               if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) {
+                   cp = info[i] + sizeof("runas_gid=") - 1;
+                   if (*cp == '\0')
+                       break;
+                   errno = 0;
+                   ulval = strtoul(cp, &ep, 0);
+                   if (*cp != '\0' && *ep == '\0' &&
+                       (errno != ERANGE || ulval != ULONG_MAX)) {
+                       details->gid = (gid_t)ulval;
+                       SET(details->flags, CD_SET_GID);
+                   }
+                   break;
+               }
+               if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) {
+                   int j;
+
+                   /* count groups, alloc and fill in */
+                   cp = info[i] + sizeof("runas_groups=") - 1;
+                   if (*cp == '\0')
+                       break;
+                   for (;;) {
+                       details->ngroups++;
+                       if ((cp = strchr(cp, ',')) == NULL)
+                           break;
+                       cp++;
+                   }
+                   if (details->ngroups != 0) {
+                       details->groups =
+                           emalloc2(details->ngroups, sizeof(GETGROUPS_T));
+                       cp = info[i] + sizeof("runas_groups=") - 1;
+                       for (j = 0; j < details->ngroups;) {
+                           errno = 0;
+                           ulval = strtoul(cp, &ep, 0);
+                           if (*cp == '\0' || (*ep != ',' && *ep != '\0') ||
+                               (ulval == ULONG_MAX && errno == ERANGE)) {
+                               break;
+                           }
+                           details->groups[j++] = (gid_t)ulval;
+                           cp = ep + 1;
+                       }
+                       details->ngroups = j;
+                   }
+                   break;
+               }
+               if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) {
+                   cp = info[i] + sizeof("runas_uid=") - 1;
+                   if (*cp == '\0')
+                       break;
+                   errno = 0;
+                   ulval = strtoul(cp, &ep, 0);
+                   if (*cp != '\0' && *ep == '\0' &&
+                       (errno != ERANGE || ulval != ULONG_MAX)) {
+                       details->uid = (uid_t)ulval;
+                       SET(details->flags, CD_SET_UID);
+                   }
+                   break;
+               }
+               break;
+           case 's':
+               SET_STRING("selinux_role=", selinux_role)
+               SET_STRING("selinux_type=", selinux_type)
+               if (strncmp("set_utmp=", info[i], sizeof("set_utmp=") - 1) == 0) {
+                   if (atobool(info[i] + sizeof("set_utmp=") - 1) == TRUE)
+                       SET(details->flags, CD_SET_UTMP);
+                   break;
+               }
+               if (strncmp("sudoedit=", info[i], sizeof("sudoedit=") - 1) == 0) {
+                   if (atobool(info[i] + sizeof("sudoedit=") - 1) == TRUE)
+                       SET(details->flags, CD_SUDOEDIT);
+                   break;
+               }
+               break;
+           case 't':
+               if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) {
+                   cp = info[i] + sizeof("timeout=") - 1;
+                   if (*cp == '\0')
+                       break;
+                   errno = 0;
+                   lval = strtol(cp, &ep, 0);
+                   if (*cp != '\0' && *ep == '\0' &&
+                       !(errno == ERANGE &&
+                       (lval == LONG_MAX || lval == LONG_MIN)) &&
+                       lval <= INT_MAX && lval >= 0) {
+                       details->timeout = (int)lval;
+                       SET(details->flags, CD_SET_TIMEOUT);
+                   }
+                   break;
+               }
+               break;
+           case 'u':
+               if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) {
+                   cp = info[i] + sizeof("umask=") - 1;
+                   if (*cp == '\0')
+                       break;
+                   errno = 0;
+                   ulval = strtoul(cp, &ep, 8);
+                   if (*cp != '\0' && *ep == '\0' &&
+                       (errno != ERANGE || ulval != ULONG_MAX)) {
+                       details->umask = (uid_t)ulval;
+                       SET(details->flags, CD_SET_UMASK);
+                   }
+                   break;
+               }
+               if (strncmp("use_pty=", info[i], sizeof("use_pty=") - 1) == 0) {
+                   if (atobool(info[i] + sizeof("use_pty=") - 1) == TRUE)
+                       SET(details->flags, CD_USE_PTY);
+                   break;
+               }
+               SET_STRING("utmp_user=", utmp_user)
+               break;
+       }
+    }
+
+    if (!ISSET(details->flags, CD_SET_EUID))
+       details->euid = details->uid;
+
+#ifdef HAVE_SELINUX
+    if (details->selinux_role != NULL && is_selinux_enabled() > 0)
+       SET(details->flags, CD_RBAC_ENABLED);
+#endif
+}
+
+/*
+ * Disable core dumps to avoid dropping a core with user password in it.
+ * We will reset this limit before executing the command.
+ * Not all operating systems disable core dumps for setuid processes.
+ */
+static void
+disable_coredumps(void)
+{
+#if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL))
+    struct rlimit rl;
+#endif
+
+#if defined(__linux__)
+    /*
+     * Unlimit the number of processes since Linux's setuid() will
+     * apply resource limits when changing uid and return EAGAIN if
+     * nproc would be violated by the uid switch.
+     */
+    (void) getrlimit(RLIMIT_NPROC, &nproclimit);
+    rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
+    if (setrlimit(RLIMIT_NPROC, &rl)) {
+       memcpy(&rl, &nproclimit, sizeof(struct rlimit));
+       rl.rlim_cur = rl.rlim_max;
+       (void)setrlimit(RLIMIT_NPROC, &rl);
+    }
+#endif /* __linux__ */
+#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
+    /*
+     * Turn off core dumps.
+     */
+    (void) getrlimit(RLIMIT_CORE, &corelimit);
+    memcpy(&rl, &corelimit, sizeof(struct rlimit));
+    rl.rlim_cur = 0;
+    (void) setrlimit(RLIMIT_CORE, &rl);
+#endif /* RLIMIT_CORE && !SUDO_DEVEL */
+}
+
+#ifdef HAVE_PROJECT_H
+static void
+set_project(struct passwd *pw)
+{
+    struct project proj;
+    char buf[PROJECT_BUFSZ];
+    int errval;
+
+    /*
+     * Collect the default project for the user and settaskid
+     */
+    setprojent();
+    if (getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf)) != NULL) {
+       errval = setproject(proj.pj_name, pw->pw_name, TASK_NORMAL);
+       switch(errval) {
+       case 0:
+           break;
+       case SETPROJ_ERR_TASK:
+           switch (errno) {
+           case EAGAIN:
+               warningx("resource control limit has been reached");
+               break;
+           case ESRCH:
+               warningx("user \"%s\" is not a member of project \"%s\"",
+                   pw->pw_name, proj.pj_name);
+               break;
+           case EACCES:
+               warningx("the invoking task is final");
+               break;
+           default:
+               warningx("could not join project \"%s\"", proj.pj_name);
+           }
+       case SETPROJ_ERR_POOL:
+           switch (errno) {
+           case EACCES:
+               warningx("no resource pool accepting default bindings "
+                   "exists for project \"%s\"", proj.pj_name);
+               break;
+           case ESRCH:
+               warningx("specified resource pool does not exist for "
+                   "project \"%s\"", proj.pj_name);
+               break;
+           default:
+               warningx("could not bind to default resource pool for "
+                   "project \"%s\"", proj.pj_name);
+           }
+           break;
+       default:
+           if (errval <= 0) {
+               warningx("setproject failed for project \"%s\"", proj.pj_name);
+           } else {
+               warningx("warning, resource control assignment failed for "
+                   "project \"%s\"", proj.pj_name);
+           }
+       }
+    } else {
+       warning("getdefaultproj");
+    }
+    endprojent();
+}
+#endif /* HAVE_PROJECT_H */
+
+/*
+ * Disable execution of child processes in the command we are about
+ * to run.  On systems with privilege sets, we can remove the exec
+ * privilege.  On other systems we use LD_PRELOAD and the like.
+ */
+static void
+disable_execute(struct command_details *details)
+{
+    char *cp, **ev, **nenvp;
+    int env_len = 0, env_size = 128;
+
+#ifdef HAVE_PRIV_SET
+    /* Solaris privileges, remove PRIV_PROC_EXEC post-execve. */
+    if (priv_set(PRIV_OFF, PRIV_LIMIT, "PRIV_PROC_EXEC", NULL) == 0)
+       return;
+    warning("unable to remove PRIV_PROC_EXEC from PRIV_LIMIT");
+#endif /* HAVE_PRIV_SET */
+
+    nenvp = emalloc2(env_size, sizeof(char *));
+    for (ev = details->envp; *ev != NULL; ev++) {
+       if (env_len + 2 > env_size) {
+           env_size += 128;
+           nenvp = erealloc3(nenvp, env_size, sizeof(char *));
+       }
+       /*
+        * Prune out existing preloaded libraries.
+        * XXX - should save and append instead of replacing.
+        */
+#if defined(__darwin__) || defined(__APPLE__)
+       if (strncmp(*ev, "DYLD_INSERT_LIBRARIES=", sizeof("DYLD_INSERT_LIBRARIES=") - 1) == 0)
+           continue;
+       if (strncmp(*ev, "DYLD_FORCE_FLAT_NAMESPACE=", sizeof("DYLD_INSERT_LIBRARIES=") - 1) == 0)
+           continue;
+#elif defined(__osf__) || defined(__sgi)
+       if (strncmp(*ev, "_RLD_LIST=", sizeof("_RLD_LIST=") - 1) == 0)
+           continue;
+#elif defined(_AIX)
+       if (strncmp(*ev, "LDR_PRELOAD=", sizeof("LDR_PRELOAD=") - 1) == 0)
+           continue;
+#else
+       if (strncmp(*ev, "LD_PRELOAD=", sizeof("LD_PRELOAD=") - 1) == 0)
+           continue;
+#endif
+       nenvp[env_len++] = *ev;
+    }
+
+    /*
+     * Preload a noexec file?  For a list of LD_PRELOAD-alikes, see
+     * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
+     * XXX - need to support 32-bit and 64-bit variants
+     */
+#if defined(__darwin__) || defined(__APPLE__)
+    nenvp[env_len++] = "DYLD_FORCE_FLAT_NAMESPACE=";
+    cp = fmt_string("DYLD_INSERT_LIBRARIES", noexec_path);
+#elif defined(__osf__) || defined(__sgi)
+    easprintf(&cp, "_RLD_LIST=%s:DEFAULT", noexec_path);
+#elif defined(_AIX)
+    cp = fmt_string("LDR_PRELOAD", noexec_path);
+#else
+    cp = fmt_string("LD_PRELOAD", noexec_path);
+#endif
+    if (cp == NULL)
+       error(1, NULL);
+    nenvp[env_len++] = cp;
+    nenvp[env_len] = NULL;
+
+    details->envp = nenvp;
+}
+
+/*
+ * Setup the execution environment immediately prior to the call to execve()
+ * Returns TRUE on success and FALSE on failure.
+ */
+int
+exec_setup(struct command_details *details, const char *ptyname, int ptyfd)
+{
+    int rval = FALSE;
+    struct passwd *pw;
+
+#ifdef HAVE_SETAUTHDB
+    aix_setauthdb(IDtouser(details->euid));
+#endif
+    pw = getpwuid(details->euid);
+#ifdef HAVE_SETAUTHDB
+    aix_restoreauthdb();
+#endif
+
+    /*
+     * Call policy plugin's session init before other setup occurs.
+     * The session init code is expected to print an error as needed.
+     */
+    if (policy_init_session(&policy_plugin, pw) != TRUE)
+       goto done;
+
+#ifdef HAVE_SELINUX
+    if (ISSET(details->flags, CD_RBAC_ENABLED)) {
+       if (selinux_setup(details->selinux_role, details->selinux_type,
+           ptyname ? ptyname : user_details.tty, ptyfd) == -1)
+           goto done;
+    }
+#endif
+
+    if (pw != NULL) {
+#ifdef HAVE_PROJECT_H
+       set_project(pw);
+#endif
+#ifdef HAVE_GETUSERATTR
+       aix_prep_user(pw->pw_name, ptyname ? ptyname : user_details.tty);
+#endif
+#ifdef HAVE_LOGIN_CAP_H
+       if (details->login_class) {
+           int flags;
+           login_cap_t *lc;
+
+           /*
+            * We only use setusercontext() to set the nice value and rlimits.
+            */
+           lc = login_getclass((char *)details->login_class);
+           if (!lc) {
+               warningx("unknown login class %s", details->login_class);
+               errno = ENOENT;
+               goto done;
+           }
+           flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
+           if (setusercontext(lc, pw, pw->pw_uid, flags)) {
+               if (pw->pw_uid != ROOT_UID) {
+                   warning("unable to set user context");
+                   goto done;
+               } else
+                   warning("unable to set user context");
+           }
+       }
+#endif /* HAVE_LOGIN_CAP_H */
+    }
+
+    /*
+     * Set groups, including supplementary group vector.
+     */
+#ifdef HAVE_SETEUID
+    if (ISSET(details->flags, CD_SET_EGID) && setegid(details->egid)) {
+       warning("unable to set egid to runas gid %u", details->egid);
+       goto done;
+    }
+#endif
+    if (ISSET(details->flags, CD_SET_GID) && setgid(details->gid)) {
+       warning("unable to set gid to runas gid %u", details->gid);
+       goto done;
+    }
+
+    if (!ISSET(details->flags, CD_PRESERVE_GROUPS)) {
+#ifdef HAVE_GETGROUPS
+       if (details->ngroups >= 0) {
+           if (setgroups(details->ngroups, details->groups) < 0) {
+               warning("unable to set supplementary group IDs");
+               goto done;
+           }
+       }
+#else
+       if (pw && initgroups(pw->pw_name, pw->pw_gid) < 0) {
+           warning("unable to set supplementary group IDs");
+           goto done;
+       }
+#endif
+    }
+
+    if (ISSET(details->flags, CD_SET_PRIORITY)) {
+       if (setpriority(PRIO_PROCESS, 0, details->priority) != 0) {
+           warning("unable to set process priority");
+           goto done;
+       }
+    }
+    if (ISSET(details->flags, CD_SET_UMASK))
+       (void) umask(details->umask);
+    if (details->chroot) {
+       if (chroot(details->chroot) != 0 || chdir("/") != 0) {
+           warning("unable to change root to %s", details->chroot);
+           goto done;
+       }
+    }
+
+    if (ISSET(details->flags, CD_NOEXEC))
+       disable_execute(details);
+
+#ifdef HAVE_SETRESUID
+    if (setresuid(details->uid, details->euid, details->euid) != 0) {
+       warning("unable to change to runas uid (%u, %u)", details->uid,
+           details->euid);
+       goto done;
+    }
+#elif HAVE_SETREUID
+    if (setreuid(details->uid, details->euid) != 0) {
+       warning("unable to change to runas uid (%u, %u)", details->uid,
+           details->euid);
+       goto done;
+    }
+#else
+    if (seteuid(details->euid) != 0 || setuid(details->euid) != 0) {
+       warning("unable to change to runas uid (%u, %u)", details->uid,
+           details->euid);
+       goto done;
+    }
+#endif /* !HAVE_SETRESUID && !HAVE_SETREUID */
+
+    /*
+     * Only change cwd if we have chroot()ed or the policy modules
+     * specifies a different cwd.  Must be done after uid change.
+     */
+    if (details->cwd) {
+       if (details->chroot || strcmp(details->cwd, user_details.cwd) != 0) {
+           /* Note: cwd is relative to the new root, if any. */
+           if (chdir(details->cwd) != 0) {
+               warning("unable to change directory to %s", details->cwd);
+               goto done;
+           }
+       }
+    }
+
+    /*
+     * Restore nproc resource limit if pam_limits didn't do it for us.
+     * We must do this *after* the uid change to avoid potential EAGAIN
+     * from setuid().
+     */
+#if defined(__linux__)
+    {
+       struct rlimit rl;
+       if (getrlimit(RLIMIT_NPROC, &rl) == 0) {
+           if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY)
+               (void) setrlimit(RLIMIT_NPROC, &nproclimit);
+       }
+    }
+#endif
+
+    rval = TRUE;
+
+done:
+    return rval;
+}
+
+/*
+ * Escape any non-alpha numeric or blank characters to make sure
+ * they are not interpreted specially by the shell.
+ */
+static char *
+escape_cmnd(const char *src)
+{
+    char *cmnd, *dst;
+
+    /* Worst case scenario, we have to escape everything. */
+    cmnd = dst = emalloc((2 * strlen(src)) + 1);
+    while (*src != '\0') {
+       if (!isalnum((unsigned char)*src) && !isspace((unsigned char)*src) &&
+           *src != '_' && *src != '-') {
+           /* quote potential meta character */
+           *dst++ = '\\';
+       }
+       *dst++ = *src++;
+    }
+    *dst++ = '\0';
+
+    return cmnd;
+}
+
+/*
+ * Run the command and wait for it to complete.
+ */
+int
+run_command(struct command_details *details)
+{
+    struct plugin_container *plugin;
+    struct command_status cstat;
+    int exitcode = 1;
+
+    cstat.type = CMD_INVALID;
+    cstat.val = 0;
+
+    sudo_execve(details, &cstat);
+
+    switch (cstat.type) {
+    case CMD_ERRNO:
+       /* exec_setup() or execve() returned an error. */
+       sudo_debug(9, "calling policy close with errno");
+       policy_close(&policy_plugin, 0, cstat.val);
+       tq_foreach_fwd(&io_plugins, plugin) {
+           sudo_debug(9, "calling I/O close with errno");
+           iolog_close(plugin, 0, cstat.val);
+       }
+       exitcode = 1;
+       break;
+    case CMD_WSTATUS:
+       /* Command ran, exited or was killed. */
+       sudo_debug(9, "calling policy close with wait status");
+       policy_close(&policy_plugin, cstat.val, 0);
+       tq_foreach_fwd(&io_plugins, plugin) {
+           sudo_debug(9, "calling I/O close with wait status");
+           iolog_close(plugin, cstat.val, 0);
+       }
+       if (WIFEXITED(cstat.val))
+           exitcode = WEXITSTATUS(cstat.val);
+       else if (WIFSIGNALED(cstat.val))
+           exitcode = WTERMSIG(cstat.val) | 128;
+       break;
+    default:
+       warningx("unexpected child termination condition: %d", cstat.type);
+       break;
+    }
+    return exitcode;
+}
+
+static int
+policy_open(struct plugin_container *plugin, char * const settings[],
+    char * const user_info[], char * const user_env[])
+{
+    return plugin->u.policy->open(SUDO_API_VERSION, sudo_conversation,
+       _sudo_printf, settings, user_info, user_env);
+}
+
+static void
+policy_close(struct plugin_container *plugin, int exit_status, int error)
+{
+    plugin->u.policy->close(exit_status, error);
+}
+
+static int
+policy_show_version(struct plugin_container *plugin, int verbose)
+{
+    return plugin->u.policy->show_version(verbose);
+}
+
+static int
+policy_check(struct plugin_container *plugin, int argc, char * const argv[],
+    char *env_add[], char **command_info[], char **argv_out[],
+    char **user_env_out[])
+{
+    return plugin->u.policy->check_policy(argc, argv, env_add, command_info,
+       argv_out, user_env_out);
+}
+
+static int
+policy_list(struct plugin_container *plugin, int argc, char * const argv[],
+    int verbose, const char *list_user)
+{
+    if (plugin->u.policy->list == NULL) {
+       warningx("policy plugin %s does not support listing privileges",
+           plugin->name);
+       return FALSE;
+    }
+    return plugin->u.policy->list(argc, argv, verbose, list_user);
+}
+
+static int
+policy_validate(struct plugin_container *plugin)
+{
+    if (plugin->u.policy->validate == NULL) {
+       warningx("policy plugin %s does not support the -v flag",
+           plugin->name);
+       return FALSE;
+    }
+    return plugin->u.policy->validate();
+}
+
+static void
+policy_invalidate(struct plugin_container *plugin, int remove)
+{
+    if (plugin->u.policy->invalidate == NULL) {
+       errorx(1, "policy plugin %s does not support the -k/-K flags",
+           plugin->name);
+    }
+    plugin->u.policy->invalidate(remove);
+}
+
+static int
+policy_init_session(struct plugin_container *plugin, struct passwd *pwd)
+{
+    if (plugin->u.policy->init_session)
+       return plugin->u.policy->init_session(pwd);
+    return TRUE;
+}
+
+static int
+iolog_open(struct plugin_container *plugin, char * const settings[],
+    char * const user_info[], char * const command_info[],
+    int argc, char * const argv[], char * const user_env[])
+{
+    int rval;
+
+    /*
+     * Backwards compatibility for API major 1, minor 0
+     */
+    switch (plugin->u.generic->version) {
+    case SUDO_API_MKVERSION(1, 0):
+       rval = plugin->u.io_1_0->open(plugin->u.io_1_0->version,
+           sudo_conversation, _sudo_printf, settings, user_info, argc, argv,
+           user_env);
+       break;
+    default:
+       rval = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation,
+           _sudo_printf, settings, user_info, command_info, argc, argv,
+           user_env);
+    }
+    return rval;
+}
+
+static void
+iolog_close(struct plugin_container *plugin, int exit_status, int error)
+{
+    plugin->u.io->close(exit_status, error);
+}
+
+static int
+iolog_show_version(struct plugin_container *plugin, int verbose)
+{
+    return plugin->u.io->show_version(verbose);
+}
+
+/*
+ * Simple debugging/logging.
+ */
+void
+sudo_debug(int level, const char *fmt, ...)
+{
+    va_list ap;
+    char *fmt2;
+
+    if (level > debug_level)
+       return;
+
+    /* Backet fmt with program name and a newline to make it a single write */
+    easprintf(&fmt2, "%s: %s\n", getprogname(), fmt);
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt2, ap);
+    va_end(ap);
+    efree(fmt2);
+}
diff --git a/src/sudo.h b/src/sudo.h
new file mode 100644 (file)
index 0000000..46a68f1
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 1993-1996, 1998-2005, 2007-2011
+ *     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.
+ *
+ * $Sudo: sudo.h,v 1.290 2009/12/12 16:12:26 millert Exp $
+ */
+
+#ifndef _SUDO_SUDO_H
+#define _SUDO_SUDO_H
+
+#include <limits.h>
+
+#include <pathnames.h>
+#include "missing.h"
+#include "alloc.h"
+#include "error.h"
+#include "fileops.h"
+#include "list.h"
+
+#ifdef __TANDEM
+# define ROOT_UID       65535
+#else
+# define ROOT_UID       0
+#endif
+
+/*
+ * Pseudo-boolean values
+ */
+#undef TRUE
+#define TRUE                     1
+#undef FALSE
+#define FALSE                    0
+
+/*
+ * Various modes sudo can be in (based on arguments) in hex
+ */
+#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_MASK              0x0000ffff
+
+/* Mode flags */
+/* XXX - prune this */
+#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
+#define MODE_LONG_LIST         0x01000000
+
+/*
+ * We used to use the system definition of PASS_MAX or _PASSWD_LEN,
+ * but that caused problems with various alternate authentication
+ * methods.  So, we just define our own and assume that it is >= the
+ * system max.
+ */
+#define SUDO_PASS_MAX  256
+
+/*
+ * Flags for tgetpass()
+ */
+#define TGP_NOECHO     0x00            /* turn echo off reading pw (default) */
+#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 */
+#define TGP_MASK       0x08            /* mask user input when reading */
+#define TGP_NOECHO_TRY 0x10            /* turn off echo if possible */
+
+struct user_details {
+    uid_t uid;
+    uid_t euid;
+    uid_t gid;
+    uid_t egid;
+    const char *username;
+    const char *cwd;
+    const char *tty;
+    const char *host;
+    const char *shell;
+    GETGROUPS_T *groups;
+    int ngroups;
+    int ts_cols;
+    int ts_lines;
+};
+
+#define CD_SET_UID             0x0001
+#define CD_SET_EUID            0x0002
+#define CD_SET_GID             0x0004
+#define CD_SET_EGID            0x0008
+#define CD_PRESERVE_GROUPS     0x0010
+#define CD_NOEXEC              0x0020
+#define CD_SET_PRIORITY                0x0040
+#define CD_SET_UMASK           0x0080
+#define CD_SET_TIMEOUT         0x0100
+#define CD_SUDOEDIT            0x0200
+#define CD_BACKGROUND          0x0400
+#define CD_RBAC_ENABLED                0x0800
+#define CD_USE_PTY             0x1000
+#define CD_SET_UTMP            0x2000
+
+struct command_details {
+    uid_t uid;
+    uid_t euid;
+    gid_t gid;
+    gid_t egid;
+    mode_t umask;
+    int priority;
+    int timeout;
+    int ngroups;
+    int closefrom;
+    int flags;
+    GETGROUPS_T *groups;
+    const char *command;
+    const char *cwd;
+    const char *login_class;
+    const char *chroot;
+    const char *selinux_role;
+    const char *selinux_type;
+    const char *utmp_user;
+    char **argv;
+    char **envp;
+};
+
+/* Status passed between parent and child via socketpair */
+struct command_status {
+#define CMD_INVALID 0
+#define CMD_ERRNO 1
+#define CMD_WSTATUS 2
+#define CMD_SIGNO 3
+    int type;
+    int val;
+};
+
+struct timeval;
+
+/* For error() and errorx() (XXX - needed?) */
+void cleanup(int);
+
+/* tgetpass.c */
+char *tgetpass(const char *, int, int);
+int tty_present(void);
+extern const char *askpass_path;
+extern const char *noexec_path;
+
+/* zero_bytes.c */
+void zero_bytes(volatile void *, size_t);
+
+/* exec.c */
+int sudo_execve(struct command_details *details, struct command_status *cstat);
+void save_signals(void);
+void restore_signals(void);
+
+/* term.c */
+int term_cbreak(int);
+int term_copy(int, int);
+int term_noecho(int);
+int term_raw(int, int);
+int term_restore(int, int);
+
+/* fmt_string.h */
+char *fmt_string(const char *var, const char *value);
+
+/* atobool.c */
+int atobool(const char *str);
+
+/* parse_args.c */
+int parse_args(int argc, char **argv, int *nargc, char ***nargv,
+    char ***settingsp, char ***env_addp);
+extern int tgetpass_flags;
+
+/* get_pty.c */
+int get_pty(int *master, int *slave, char *name, size_t namesz, uid_t uid);
+
+/* ttysize.c */
+void get_ttysize(int *rowp, int *colp);
+
+/* sudo.c */
+int exec_setup(struct command_details *details, const char *ptyname, int ptyfd);
+int run_command(struct command_details *details);
+void sudo_debug(int level, const char *format, ...) __printflike(2, 3);
+extern int debug_level;
+extern const char *list_user, *runas_user, *runas_group;
+extern struct user_details user_details;
+
+/* sudo_edit.c */
+int sudo_edit(struct command_details *details);
+
+/* parse_args.c */
+void usage(int);
+
+/* selinux.c */
+int selinux_restore_tty(void);
+int selinux_setup(const char *role, const char *type, const char *ttyn,
+    int ttyfd);
+void selinux_execve(const char *path, char *argv[], char *envp[]);
+
+/* aix.c */
+void aix_prep_user(char *user, const char *tty);
+void aix_restoreauthdb(void);
+void aix_setauthdb(char *user);
+
+/* interfaces.c */
+int get_net_ifs(char **addrinfo);
+
+#ifndef errno
+extern int errno;
+#endif
+
+#endif /* _SUDO_SUDO_H */
diff --git a/src/sudo_edit.c b/src/sudo_edit.c
new file mode 100644 (file)
index 0000000..0be9d31
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2004-2008, 2010-2011 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>
+
+#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID)
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/socket.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <ctype.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+
+#include "sudo.h"
+
+static void
+switch_user(uid_t euid, gid_t egid, int ngroups, GETGROUPS_T *groups)
+{
+    int serrno = errno;
+
+    /* When restoring root, change euid first; otherwise change it last. */
+    if (euid == ROOT_UID) {
+       if (seteuid(ROOT_UID) != 0)
+           error(1, "seteuid(ROOT_UID)");
+    }
+    if (ngroups != -1) {
+       if (setgroups(ngroups, groups) != 0)
+           error(1, "setgroups");
+    }
+    if (setegid(egid) != 0)
+       error(1, "setegid(%d)", (int)egid);
+    if (euid != ROOT_UID) {
+       if (seteuid(euid) != 0)
+           error(1, "seteuid(%d)", (int)euid);
+    }
+
+    errno = serrno;
+}
+
+/*
+ * Wrapper to allow users to edit privileged files with their own uid.
+ */
+int
+sudo_edit(struct command_details *command_details)
+{
+    struct command_details editor_details;
+    ssize_t nread, nwritten;
+    const char *tmpdir;
+    char *cp, *suff, **nargv, **ap, **files = NULL;
+    char buf[BUFSIZ];
+    int rc, i, j, ac, ofd, tfd, nargc, rval, tmplen;
+    int editor_argc = 0, nfiles = 0;
+    struct stat sb;
+    struct timeval tv, tv1, tv2;
+    struct tempfile {
+       char *tfile;
+       char *ofile;
+       struct timeval omtim;
+       off_t osize;
+    } *tf;
+
+    /*
+     * Set real, effective and saved uids to root.
+     * We will change the euid as needed below.
+     */
+    if (setuid(ROOT_UID) != 0) {
+       warning("unable to change to uid to root (%u)", ROOT_UID);
+       return 1;
+    }
+
+    /*
+     * Find our temporary directory, one of /var/tmp, /usr/tmp, or /tmp
+     */
+    if (stat(_PATH_VARTMP, &sb) == 0 && S_ISDIR(sb.st_mode))
+       tmpdir = _PATH_VARTMP;
+#ifdef _PATH_USRTMP
+    else if (stat(_PATH_USRTMP, &sb) == 0 && S_ISDIR(sb.st_mode))
+       tmpdir = _PATH_USRTMP;
+#endif
+    else
+       tmpdir = _PATH_TMP;
+    tmplen = strlen(tmpdir);
+    while (tmplen > 0 && tmpdir[tmplen - 1] == '/')
+       tmplen--;
+
+    /*
+     * The user's editor must be separated from the files to be
+     * edited by a "--" option.
+     */
+    for (ap = command_details->argv; *ap != NULL; ap++) {
+       if (files)
+           nfiles++;
+       else if (strcmp(*ap, "--") == 0)
+           files = ap + 1;
+       else
+           editor_argc++;
+    }
+    if (nfiles == 0) {
+       warningx("plugin error: missing file list for sudoedit");
+       return 1;
+    }
+
+    /*
+     * For each file specified by the user, make a temporary version
+     * and copy the contents of the original to it.
+     */
+    tf = emalloc2(nfiles, sizeof(*tf));
+    zero_bytes(tf, nfiles * sizeof(*tf));
+    for (i = 0, j = 0; i < nfiles; i++) {
+       rc = -1;
+       switch_user(command_details->euid, command_details->egid,
+           command_details->ngroups, command_details->groups);
+       if ((ofd = open(files[i], O_RDONLY, 0644)) != -1 || errno == ENOENT) {
+           if (ofd == -1) {
+               zero_bytes(&sb, sizeof(sb));            /* new file */
+               rc = 0;
+           } else {
+#ifdef HAVE_FSTAT
+               rc = fstat(ofd, &sb);
+#else
+               rc = stat(tf[j].ofile, &sb);
+#endif
+           }
+       }
+       switch_user(ROOT_UID, user_details.egid,
+           user_details.ngroups, user_details.groups);
+       if (rc || (ofd != -1 && !S_ISREG(sb.st_mode))) {
+           if (rc)
+               warning("%s", files[i]);
+           else
+               warningx("%s: not a regular file", files[i]);
+           if (ofd != -1)
+               close(ofd);
+           continue;
+       }
+       tf[j].ofile = files[i];
+       tf[j].osize = sb.st_size;
+       mtim_get(&sb, &tf[j].omtim);
+       if ((cp = strrchr(tf[j].ofile, '/')) != NULL)
+           cp++;
+       else
+           cp = tf[j].ofile;
+       suff = strrchr(cp, '.');
+       if (suff != NULL) {
+           easprintf(&tf[j].tfile, "%.*s/%.*sXXXXXXXX%s", tmplen, tmpdir,
+               (int)(size_t)(suff - cp), cp, suff);
+       } else {
+           easprintf(&tf[j].tfile, "%.*s/%s.XXXXXXXX", tmplen, tmpdir, cp);
+       }
+       if (seteuid(user_details.uid) != 0)
+           error(1, "seteuid(%d)", (int)user_details.uid);
+       tfd = mkstemps(tf[j].tfile, suff ? strlen(suff) : 0);
+       if (seteuid(ROOT_UID) != 0)
+           error(1, "seteuid(ROOT_UID)");
+       if (tfd == -1) {
+           warning("mkstemps");
+           goto cleanup;
+       }
+       if (ofd != -1) {
+           while ((nread = read(ofd, buf, sizeof(buf))) != 0) {
+               if ((nwritten = write(tfd, buf, nread)) != nread) {
+                   if (nwritten == -1)
+                       warning("%s", tf[j].tfile);
+                   else
+                       warningx("%s: short write", tf[j].tfile);
+                   goto cleanup;
+               }
+           }
+           close(ofd);
+       }
+       /*
+        * We always update the stashed mtime because the time
+        * resolution of the filesystem the temporary file is on may
+        * not match that of the filesystem where the file to be edited
+        * resides.  It is OK if touch() fails since we only use the info
+        * to determine whether or not a file has been modified.
+        */
+       (void) touch(tfd, NULL, &tf[j].omtim);
+#ifdef HAVE_FSTAT
+       rc = fstat(tfd, &sb);
+#else
+       rc = stat(tf[j].tfile, &sb);
+#endif
+       if (!rc)
+           mtim_get(&sb, &tf[j].omtim);
+       close(tfd);
+       j++;
+    }
+    if ((nfiles = j) == 0)
+       return 1;                       /* no files readable, you lose */
+
+    /*
+     * Allocate space for the new argument vector and fill it in.
+     * We concatenate the editor with its args and the file list
+     * to create a new argv.
+     */
+    nargc = editor_argc + nfiles;
+    nargv = (char **) emalloc2(nargc + 1, sizeof(char *));
+    for (ac = 0; ac < editor_argc; ac++)
+       nargv[ac] = command_details->argv[ac];
+    for (i = 0; i < nfiles && ac < nargc; )
+       nargv[ac++] = tf[i++].tfile;
+    nargv[ac] = NULL;
+
+    /*
+     * Run the editor with the invoking user's creds,
+     * keeping track of the time spent in the editor.
+     */
+    gettimeofday(&tv1, NULL);
+    memcpy(&editor_details, command_details, sizeof(editor_details));
+    editor_details.uid = user_details.uid;
+    editor_details.euid = user_details.uid;
+    editor_details.gid = user_details.gid;
+    editor_details.egid = user_details.gid;
+    editor_details.ngroups = user_details.ngroups;
+    editor_details.groups = user_details.groups;
+    editor_details.argv = nargv;
+    rval = run_command(&editor_details);
+    gettimeofday(&tv2, NULL);
+
+    /* Copy contents of temp files to real ones */
+    for (i = 0; i < nfiles; i++) {
+       rc = -1;
+       if (seteuid(user_details.uid) != 0)
+           error(1, "seteuid(%d)", (int)user_details.uid);
+       if ((tfd = open(tf[i].tfile, O_RDONLY, 0644)) != -1) {
+#ifdef HAVE_FSTAT
+           rc = fstat(tfd, &sb);
+#else
+           rc = stat(tf[i].tfile, &sb);
+#endif
+       }
+       if (seteuid(ROOT_UID) != 0)
+           error(1, "seteuid(ROOT_UID)");
+       if (rc || !S_ISREG(sb.st_mode)) {
+           if (rc)
+               warning("%s", tf[i].tfile);
+           else
+               warningx("%s: not a regular file", tf[i].tfile);
+           warningx("%s left unmodified", tf[i].ofile);
+           if (tfd != -1)
+               close(tfd);
+           continue;
+       }
+       mtim_get(&sb, &tv);
+       if (tf[i].osize == sb.st_size && timevalcmp(&tf[i].omtim, &tv, ==)) {
+           /*
+            * If mtime and size match but the user spent no measurable
+            * time in the editor we can't tell if the file was changed.
+            */
+           timevalsub(&tv1, &tv2);
+           if (timevalisset(&tv2)) {
+               warningx("%s unchanged", tf[i].ofile);
+               unlink(tf[i].tfile);
+               close(tfd);
+               continue;
+           }
+       }
+       switch_user(command_details->euid, command_details->egid,
+           command_details->ngroups, command_details->groups);
+       ofd = open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT, 0644);
+       switch_user(ROOT_UID, user_details.egid,
+           user_details.ngroups, user_details.groups);
+       if (ofd == -1) {
+           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)
+                   warning("%s", tf[i].ofile);
+               else
+                   warningx("%s: short write", tf[i].ofile);
+               break;
+           }
+       }
+       if (nread == 0) {
+           /* success, got EOF */
+           unlink(tf[i].tfile);
+       } else if (nread < 0) {
+           warning("unable to read temporary file");
+           warningx("contents of edit session left in %s", tf[i].tfile);
+       } else {
+           warning("unable to write to %s", tf[i].ofile);
+           warningx("contents of edit session left in %s", tf[i].tfile);
+       }
+       close(ofd);
+    }
+
+    return rval;
+cleanup:
+    /* Clean up temp files and return. */
+    for (i = 0; i < nfiles; i++) {
+       if (tf[i].tfile != NULL)
+           unlink(tf[i].tfile);
+    }
+    return 1;
+}
+
+#else /* HAVE_SETRESUID || HAVE_SETREUID || HAVE_SETEUID */
+
+/*
+ * Must have the ability to change the effective uid to use sudoedit.
+ */
+int
+sudo_edit(struct command_details *command_details)
+{
+    return 1;
+}
+
+#endif /* HAVE_SETRESUID || HAVE_SETREUID || HAVE_SETEUID */
diff --git a/src/sudo_exec.h b/src/sudo_exec.h
new file mode 100644 (file)
index 0000000..744dd6a
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010-2011 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.
+ */
+
+#ifndef _SUDO_EXEC_H
+#define _SUDO_EXEC_H
+
+/*
+ * Special values to indicate whether continuing in foreground or background.
+ */
+#define SIGCONT_FG     -2
+#define SIGCONT_BG     -3
+
+/*
+ * Symbols shared between exec.c and exec_pty.c
+ */
+
+/* exec.c */
+int my_execve(const char *path, char *const argv[], char *const envp[]);
+int pipe_nonblock(int fds[2]);
+
+/* exec_pty.c */
+int fork_pty(struct command_details *details, int sv[], int *maxfd);
+int perform_io(fd_set *fdsr, fd_set *fdsw, struct command_status *cstat);
+int suspend_parent(int signo);
+void fd_set_iobs(fd_set *fdsr, fd_set *fdsw);
+void handler(int s);
+void pty_close(struct command_status *cstat);
+void pty_setup(uid_t uid, const char *tty, const char *utmp_user);
+void terminate_child(pid_t pid, int use_pgrp);
+extern int signal_pipe[2];
+
+/* utmp.c */
+int utmp_login(const char *from_line, const char *to_line, int ttyfd,
+    const char *user);
+int utmp_logout(const char *line, int status);
+
+#endif /* _SUDO_EXEC_H */
diff --git a/src/sudo_noexec.c b/src/sudo_noexec.c
new file mode 100644 (file)
index 0000000..2c18c60
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2004-2005, 2010-2011 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 <errno.h>
+#ifndef HAVE_TIMESPEC
+# include <time.h>
+#endif
+#include <stdarg.h>
+
+#include "missing.h"
+
+/*
+ * Dummy versions of the execve() family of syscalls.  We don't need
+ * to stub out all of them, just the ones that correspond to actual
+ * system calls (which varies by OS).  Note that it is still possible
+ * to access the real syscalls via the syscall() interface but very
+ * few programs actually do that.
+ */
+
+#ifndef errno
+extern int errno;
+#endif
+
+#define DUMMY_BODY                             \
+{                                              \
+    errno = EACCES;                            \
+    return -1;                                 \
+}
+
+#define DUMMY2(fn, t1, t2)                     \
+int                                            \
+fn(t1 a1, t2 a2)                               \
+DUMMY_BODY
+
+#define DUMMY3(fn, t1, t2, t3)                 \
+int                                            \
+fn(t1 a1, t2 a2, t3 a3)                                \
+DUMMY_BODY
+
+#define DUMMY_VA(fn, t1, t2)                   \
+int                                            \
+fn(t1 a1, t2 a2, ...)                          \
+DUMMY_BODY
+
+DUMMY_VA(execl, const char *, const char *)
+DUMMY_VA(_execl, const char *, const char *)
+DUMMY_VA(__execl, const char *, const char *)
+DUMMY_VA(execle, const char *, const char *)
+DUMMY_VA(_execle, const char *, const char *)
+DUMMY_VA(__execle, const char *, const char *)
+DUMMY_VA(execlp, const char *, const char *)
+DUMMY_VA(_execlp, const char *, const char *)
+DUMMY_VA(__execlp, const char *, const char *)
+DUMMY2(execv, const char *, char * const *)
+DUMMY2(_execv, const char *, char * const *)
+DUMMY2(__execv, const char *, char * const *)
+DUMMY2(execvp, const char *, char * const *)
+DUMMY2(_execvp, const char *, char * const *)
+DUMMY2(__execvp, const char *, char * const *)
+DUMMY3(execvP, const char *, const char *, char * const *)
+DUMMY3(_execvP, const char *, const char *, char * const *)
+DUMMY3(__execvP, const char *, const char *, char * const *)
+DUMMY3(execve, const char *, char * const *, char * const *)
+DUMMY3(_execve, const char *, char * const *, char * const *)
+DUMMY3(__execve, const char *, char * const *, char * const *)
+DUMMY3(fexecve, int , char * const *, char * const *)
+DUMMY3(_fexecve, int , char * const *, char * const *)
+DUMMY3(__fexecve, int , char * const *, char * const *)
diff --git a/src/sudo_plugin_int.h b/src/sudo_plugin_int.h
new file mode 100644 (file)
index 0000000..772cde9
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2010-2011 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.
+ */
+
+#ifndef _SUDO_PLUGIN_INT_H
+#define _SUDO_PLUGIN_INT_H
+
+/*
+ * All plugin structures start with a type and a version.
+ */
+struct generic_plugin {
+    unsigned int type;
+    unsigned int version;
+    /* the rest depends on the type... */
+};
+
+/*
+ * Backwards-compatible structures for API bumps.
+ */
+struct io_plugin_1_0 {
+    unsigned int type;
+    unsigned int version;
+    int (*open)(unsigned int version, sudo_conv_t conversation,
+        sudo_printf_t sudo_printf, char * const settings[],
+        char * const user_info[], int argc, char * const argv[],
+        char * const user_env[]);
+    void (*close)(int exit_status, int error);
+    int (*show_version)(int verbose);
+    int (*log_ttyin)(const char *buf, unsigned int len);
+    int (*log_ttyout)(const char *buf, unsigned int len);
+    int (*log_stdin)(const char *buf, unsigned int len);
+    int (*log_stdout)(const char *buf, unsigned int len);
+    int (*log_stderr)(const char *buf, unsigned int len);
+};
+
+/*
+ * Sudo plugin internals.
+ */
+
+struct plugin_info {
+    struct plugin_info *prev; /* required */
+    struct plugin_info *next; /* required */
+    const char *path;
+    const char *symbol_name;
+};
+TQ_DECLARE(plugin_info)
+
+struct plugin_container {
+    struct plugin_container *prev; /* required */
+    struct plugin_container *next; /* required */
+    const char *name;
+    void *handle;
+    union {
+       struct generic_plugin *generic;
+       struct policy_plugin *policy;
+       struct io_plugin *io;
+       struct io_plugin_1_0 *io_1_0;
+    } u;
+};
+TQ_DECLARE(plugin_container)
+
+extern struct plugin_container_list policy_plugins;
+extern struct plugin_container_list io_plugins;
+
+int sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
+    struct sudo_conv_reply replies[]);
+int _sudo_printf(int msg_type, const char *fmt, ...);
+
+int sudo_load_plugins(const char *conf_file,
+    struct plugin_container *policy_plugin,
+    struct plugin_container_list *io_plugins);
+
+#endif /* _SUDO_PLUGIN_INT_H */
diff --git a/src/sudo_usage.h.in b/src/sudo_usage.h.in
new file mode 100644 (file)
index 0000000..4f6288b
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2007-2010 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.
+ */
+
+#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 " [-D level] -h | -K | -k | -V"
+#define SUDO_USAGE2 " -v [-AknS] @BSDAUTH_USAGE@[-D level] [-g groupname|#gid] [-p prompt] [-u user name|#uid]"
+#define SUDO_USAGE3 " -l[l] [-AknS] @BSDAUTH_USAGE@[-D level] [-g groupname|#gid] [-p prompt] [-U user name] [-u user name|#uid] [-g groupname|#gid] [command]"
+#define SUDO_USAGE4 " [-AbEHknPS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] [-D level] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u user name|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] [<command>]"
+#define SUDO_USAGE5 " -e [-AknS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] [-D level] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u user name|#uid] file ..."
+
+/*
+ * Configure script arguments used to build sudo.
+ */
+#define CONFIGURE_ARGS "@CONFIGURE_ARGS@"
+
+#endif /* _SUDO_USAGE_H */
diff --git a/src/tgetpass.c b/src/tgetpass.c
new file mode 100644 (file)
index 0000000..bbd5652
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 1996, 1998-2005, 2007-2011
+ *     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.
+ */
+
+#ifdef __TANDEM
+# include <floss.h>
+#endif
+
+#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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+
+#include "sudo.h"
+
+static volatile sig_atomic_t signo[NSIG];
+
+static void handler(int);
+static char *getln(int, char *, size_t, int);
+static char *sudo_askpass(const char *, const char *);
+
+#ifdef _PATH_SUDO_ASKPASS
+const char *askpass_path = _PATH_SUDO_ASKPASS;
+#else
+const char *askpass_path;
+#endif
+
+/*
+ * Like getpass(3) but with timeout and echo flags.
+ */
+char *
+tgetpass(const char *prompt, int timeout, int flags)
+{
+    sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
+    sigaction_t savetstp, savettin, savettou, savepipe;
+    char *pass;
+    static const char *askpass;
+    static char buf[SUDO_PASS_MAX + 1];
+    int i, input, output, save_errno, neednl = 0, need_restart;
+
+    (void) fflush(stdout);
+
+    if (askpass == NULL) {
+       askpass = getenv("SUDO_ASKPASS");
+       if (askpass == NULL || *askpass == '\0')
+           askpass = askpass_path;
+    }
+
+    /* If no tty present and we need to disable echo, try askpass. */
+    if (!ISSET(flags, TGP_STDIN|TGP_ECHO|TGP_ASKPASS|TGP_NOECHO_TRY) &&
+       !tty_present()) {
+       if (askpass == NULL || getenv("DISPLAY") == NULL) {
+           warningx("no tty present and no askpass program specified");
+           return NULL;
+       }
+       SET(flags, TGP_ASKPASS);
+    }
+
+    /* If using a helper program to get the password, run it instead. */
+    if (ISSET(flags, TGP_ASKPASS)) {
+       if (askpass == NULL || *askpass == '\0')
+           errorx(1, "no askpass program specified, try setting SUDO_ASKPASS");
+       return sudo_askpass(askpass, prompt);
+    }
+
+restart:
+    for (i = 0; i < NSIG; i++)
+       signo[i] = 0;
+    pass = NULL;
+    save_errno = 0;
+    need_restart = 0;
+    /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
+    if (ISSET(flags, TGP_STDIN) ||
+       (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
+       input = STDIN_FILENO;
+       output = STDERR_FILENO;
+    }
+
+    /*
+     * If we are using a tty but are not the foreground pgrp this will
+     * generate SIGTTOU, so do it *before* installing the signal handlers.
+     */
+    if (!ISSET(flags, TGP_ECHO)) {
+       if (ISSET(flags, TGP_MASK))
+           neednl = term_cbreak(input);
+       else
+           neednl = term_noecho(input);
+    }
+
+    /*
+     * 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;
+    (void) sigaction(SIGALRM, &sa, &savealrm);
+    (void) sigaction(SIGINT, &sa, &saveint);
+    (void) sigaction(SIGHUP, &sa, &savehup);
+    (void) sigaction(SIGQUIT, &sa, &savequit);
+    (void) sigaction(SIGTERM, &sa, &saveterm);
+    (void) sigaction(SIGTSTP, &sa, &savetstp);
+    (void) sigaction(SIGTTIN, &sa, &savettin);
+    (void) sigaction(SIGTTOU, &sa, &savettou);
+
+    /* Ignore SIGPIPE in case stdin is a pipe and TGP_STDIN is set */
+    sa.sa_handler = SIG_IGN;
+    (void) sigaction(SIGPIPE, &sa, &savepipe);
+
+    if (prompt) {
+       if (write(output, prompt, strlen(prompt)) == -1)
+           goto restore;
+    }
+
+    if (timeout > 0)
+       alarm(timeout);
+    pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK));
+    alarm(0);
+    save_errno = errno;
+
+    if (neednl || pass == NULL) {
+       if (write(output, "\n", 1) == -1)
+           goto restore;
+    }
+
+restore:
+    /* Restore old tty settings and signals. */
+    if (!ISSET(flags, TGP_ECHO))
+       term_restore(input, 1);
+    (void) sigaction(SIGALRM, &savealrm, NULL);
+    (void) sigaction(SIGINT, &saveint, NULL);
+    (void) sigaction(SIGHUP, &savehup, NULL);
+    (void) sigaction(SIGQUIT, &savequit, NULL);
+    (void) sigaction(SIGTERM, &saveterm, NULL);
+    (void) sigaction(SIGTSTP, &savetstp, NULL);
+    (void) sigaction(SIGTTIN, &savettin, NULL);
+    (void) sigaction(SIGTTOU, &savettou, NULL);
+    (void) sigaction(SIGTTOU, &savepipe, NULL);
+    if (input != STDIN_FILENO)
+       (void) close(input);
+
+    /*
+     * If we were interrupted by a signal, resend it to ourselves
+     * now that we have restored the signal handlers.
+     */
+    for (i = 0; i < NSIG; i++) {
+       if (signo[i]) {
+           kill(getpid(), i);
+           switch (i) {
+               case SIGTSTP:
+               case SIGTTIN:
+               case SIGTTOU:
+                   need_restart = 1;
+                   break;
+           }
+       }
+    }
+    if (need_restart)
+       goto restart;
+
+    if (save_errno)
+       errno = save_errno;
+    return pass;
+}
+
+/*
+ * Fork a child and exec sudo-askpass to get the password from the user.
+ */
+static char *
+sudo_askpass(const char *askpass, 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 */
+       if (dup2(pfd[1], STDOUT_FILENO) == -1) {
+           warning("dup2");
+           _exit(255);
+       }
+       (void) setuid(ROOT_UID);
+       if (setgid(user_details.gid)) {
+           warning("unable to set gid to %u", (unsigned int)user_details.gid);
+           _exit(255);
+       }
+       if (setuid(user_details.uid)) {
+           warning("unable to set uid to %u", (unsigned int)user_details.uid);
+           _exit(255);
+       }
+       closefrom(STDERR_FILENO + 1);
+       execl(askpass, askpass, prompt, (char *)NULL);
+       warning("unable to run %s", askpass);
+       _exit(255);
+    }
+
+    /* Ignore SIGPIPE in case child exits prematurely */
+    zero_bytes(&sa, sizeof(sa));
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = SA_INTERRUPT;
+    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), 0);
+    (void) close(pfd[0]);
+    (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
+
+    return pass;
+}
+
+extern int term_erase, term_kill;
+
+static char *
+getln(int fd, char *buf, size_t bufsiz, int feedback)
+{
+    size_t left = bufsiz;
+    ssize_t nr = -1;
+    char *cp = buf;
+    char c = '\0';
+
+    if (left == 0) {
+       errno = EINVAL;
+       return NULL;                    /* sanity */
+    }
+
+    while (--left) {
+       nr = read(fd, &c, 1);
+       if (nr != 1 || c == '\n' || c == '\r')
+           break;
+       if (feedback) {
+           if (c == term_kill) {
+               while (cp > buf) {
+                   if (write(fd, "\b \b", 3) == -1)
+                       break;
+                   --cp;
+               }
+               left = bufsiz;
+               continue;
+           } else if (c == term_erase) {
+               if (cp > buf) {
+                   if (write(fd, "\b \b", 3) == -1)
+                       break;
+                   --cp;
+                   left++;
+               }
+               continue;
+           }
+           if (write(fd, "*", 1) == -1)
+               /* shut up glibc */;
+       }
+       *cp++ = c;
+    }
+    *cp = '\0';
+    if (feedback) {
+       /* erase stars */
+       while (cp > buf) {
+           if (write(fd, "\b \b", 3) == -1)
+               break;
+           --cp;
+       }
+    }
+
+    return nr == 1 ? buf : NULL;
+}
+
+static void
+handler(int s)
+{
+    if (s != SIGALRM)
+       signo[s] = 1;
+}
+
+int
+tty_present(void)
+{
+    int fd;
+
+    if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1)
+       close(fd);
+    return fd != -1;
+}
diff --git a/src/ttysize.c b/src/ttysize.c
new file mode 100644 (file)
index 0000000..81972d1
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010 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/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_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <termios.h>
+
+#include "missing.h"
+
+/* Compatibility with older tty systems. */
+#if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
+# define TIOCGWINSZ    TIOCGSIZE
+# define winsize       ttysize
+# define ws_col                ts_cols
+# define ws_row                ts_lines
+#endif
+
+void
+get_ttysize(int *rowp, int *colp)
+{
+    char *p;
+#ifdef TIOCGWINSZ
+    struct winsize wsize;
+
+    if (ioctl(STDERR_FILENO, TIOCGWINSZ, &wsize) == 0 &&
+       wsize.ws_row != 0 && wsize.ws_col  != 0) {
+       *rowp = wsize.ws_row;
+       *colp = wsize.ws_col;
+       return;
+    }
+#endif
+
+    /* Fall back on $LINES and $COLUMNS. */
+    if ((p = getenv("LINES")) == NULL || (*rowp = atoi(p)) <= 0)
+       *rowp = 24;
+    if ((p = getenv("COLUMNS")) == NULL || (*colp = atoi(p)) <= 0)
+       *colp = 80;
+}
diff --git a/src/utmp.c b/src/utmp.c
new file mode 100644 (file)
index 0000000..dc6d45f
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2011 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 <sys/time.h>
+#include <sys/wait.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>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
+#ifdef HAVE_UTMPX_H
+# include <utmpx.h>
+#else
+# include <utmp.h>
+#endif /* HAVE_UTMPX_H */
+#ifdef HAVE_GETTTYENT
+# include <ttyent.h>
+#endif
+#include <fcntl.h>
+
+#include "sudo.h"
+#include "sudo_exec.h"
+
+/*
+ * Simplify handling of utmp vs. utmpx
+ */
+#if !defined(HAVE_GETUTXID) && defined(HAVE_GETUTID)
+# define getutxline(u) getutline(u)
+# define pututxline(u) pututline(u)
+# define setutxent     setutent(u)
+# define endutxent     endutent(u)
+#endif /* !HAVE_GETUTXID && HAVE_GETUTID */
+
+#ifdef HAVE_GETUTXID
+typedef struct utmpx sudo_utmp_t;
+#else
+typedef struct utmp sudo_utmp_t;
+/* Older systems have ut_name, not us_user */
+# if !defined(HAVE_STRUCT_UTMP_UT_USER) && !defined(ut_user)
+#  define ut_user ut_name
+# endif
+#endif
+
+/* HP-UX has __e_termination and __e_exit, others lack the __ */
+#if defined(HAVE_STRUCT_UTMPX_UT_EXIT_E_TERMINATION) || defined(HAVE_STRUCT_UTMP_UT_EXIT_E_TERMINATION)
+# undef  __e_termination
+# define __e_termination       e_termination
+# undef  __e_exit
+# define __e_exit              e_exit
+#endif
+
+#if defined(HAVE_GETUTXID) || defined(HAVE_GETUTID)
+/*
+ * Create ut_id from the new ut_line and the old ut_id.
+ */
+static void
+utmp_setid(sudo_utmp_t *old, sudo_utmp_t *new)
+{
+    const char *line = new->ut_line;
+    size_t idlen;
+
+    /* Skip over "tty" in the id if old entry did too. */
+    if (strncmp(line, "tty", 3) == 0) {
+       idlen = MIN(sizeof(old->ut_id), 3);
+       if (strncmp(old->ut_id, "tty", idlen) != 0)
+           line += 3;
+    }
+    
+    /* Store as much as will fit, skipping parts of the beginning as needed. */
+    idlen = strlen(line);
+    if (idlen > sizeof(new->ut_id)) {
+       line += idlen - sizeof(new->ut_id);
+       idlen = sizeof(new->ut_id);
+    }
+    strncpy(new->ut_id, line, idlen);
+}
+#endif /* HAVE_GETUTXID || HAVE_GETUTID */
+
+/*
+ * Store time in utmp structure.
+ */
+static void
+utmp_settime(sudo_utmp_t *ut)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+
+#if defined(HAVE_STRUCT_UTMP_UT_TV) || defined(HAVE_STRUCT_UTMPX_UT_TV)
+    ut->ut_tv.tv_sec = tv.tv_sec;
+    ut->ut_tv.tv_usec = tv.tv_usec;
+#else
+    ut->ut_time = tv.tv_sec;
+#endif
+}
+
+/*
+ * Fill in a utmp entry, using an old entry as a template if there is one.
+ */
+static void
+utmp_fill(const char *line, const char *user, sudo_utmp_t *ut_old,
+    sudo_utmp_t *ut_new)
+{
+    if (ut_old == NULL) {
+       memset(ut_new, 0, sizeof(*ut_new));
+       if (user == NULL) {
+           strncpy(ut_new->ut_user, user_details.username,
+               sizeof(ut_new->ut_user));
+       }
+    } else if (ut_old != ut_new) {
+       memcpy(ut_new, ut_old, sizeof(*ut_new));
+    }
+    if (user != NULL)
+       strncpy(ut_new->ut_user, user, sizeof(ut_new->ut_user));
+    strncpy(ut_new->ut_line, line, sizeof(ut_new->ut_line));
+#if defined(HAVE_STRUCT_UTMPX_UT_ID) || defined(HAVE_STRUCT_UTMP_UT_ID)
+    utmp_setid(ut_old, ut_new);
+#endif
+#if defined(HAVE_STRUCT_UTMPX_UT_PID) || defined(HAVE_STRUCT_UTMP_UT_PID)
+    ut_new->ut_pid = getpid();
+#endif
+    utmp_settime(ut_new);
+#if defined(HAVE_STRUCT_UTMPX_UT_TYPE) || defined(HAVE_STRUCT_UTMP_UT_TYPE)
+    ut_new->ut_type = USER_PROCESS;
+#endif
+}
+
+/*
+ * There are two basic utmp file types:
+ *
+ *  POSIX:  sequential access with new entries appended to the end.
+ *         Manipulated via {get,put}utent()/{get,put}getutxent().
+ *
+ *  Legacy: sparse file indexed by ttyslot() * sizeof(struct utmp)
+ */
+#if defined(HAVE_GETUTXID) || defined(HAVE_GETUTID)
+int
+utmp_login(const char *from_line, const char *to_line, int ttyfd,
+    const char *user)
+{
+    sudo_utmp_t utbuf, *ut_old = NULL;
+    int rval = FALSE;
+
+    /* Strip off /dev/ prefix from line as needed. */
+    if (strncmp(to_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+       to_line += sizeof(_PATH_DEV) - 1;
+    setutxent();
+    if (from_line != NULL) {
+       if (strncmp(from_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+           from_line += sizeof(_PATH_DEV) - 1;
+
+       /* Lookup old line. */
+       memset(&utbuf, 0, sizeof(utbuf));
+       strncpy(utbuf.ut_line, from_line, sizeof(utbuf.ut_line));
+       ut_old = getutxline(&utbuf);
+    }
+    utmp_fill(to_line, user, ut_old, &utbuf);
+    if (pututxline(&utbuf) != NULL)
+       rval = TRUE;
+    endutxent();
+
+    return rval;
+}
+
+int
+utmp_logout(const char *line, int status)
+{
+    int rval = FALSE;
+    sudo_utmp_t *ut, utbuf;
+
+    /* Strip off /dev/ prefix from line as needed. */
+    if (strncmp(line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+       line += sizeof(_PATH_DEV) - 1;
+   
+    memset(&utbuf, 0, sizeof(utbuf));
+    strncpy(utbuf.ut_line, line, sizeof(utbuf.ut_line));
+    if ((ut = getutxline(&utbuf)) != NULL) {
+       memset(ut->ut_user, 0, sizeof(ut->ut_user));
+# if defined(HAVE_STRUCT_UTMPX_UT_TYPE) || defined(HAVE_STRUCT_UTMP_UT_TYPE)
+       ut->ut_type = DEAD_PROCESS;
+# endif
+# if defined(HAVE_STRUCT_UTMPX_UT_EXIT) || defined(HAVE_STRUCT_UTMP_UT_EXIT)
+       ut->ut_exit.__e_exit = WEXITSTATUS(status);
+       ut->ut_exit.__e_termination = WIFEXITED(status) ? WEXITSTATUS(status) : 0;
+# endif
+       utmp_settime(ut);
+       if (pututxline(ut) != NULL)
+           rval = TRUE;
+    }
+    return rval;
+}
+
+#else /* !HAVE_GETUTXID && !HAVE_GETUTID */
+
+/*
+ * Find the slot for the specified line (tty name and file descriptor).
+ * Returns a slot suitable for seeking into utmp on success or <= 0 on error.
+ * If getttyent() is available we can use that to compute the slot.
+ */
+# ifdef HAVE_GETTTYENT
+static int
+utmp_slot(const char *line, int ttyfd)
+{
+    int slot = 1;
+    struct ttyent *tty;
+
+    setttyent();
+    while ((tty = getttyent()) != NULL) {
+       if (strcmp(line, tty->ty_name) == 0)
+           break;
+       slot++;
+    }
+    endttyent();
+    return tty ? slot : 0;
+}
+# else
+static int
+utmp_slot(const char *line, int ttyfd)
+{
+    int sfd, slot;
+
+    /*
+     * Temporarily point stdin to the tty since ttyslot()
+     * doesn't take an argument.
+     */
+    if ((sfd = dup(STDIN_FILENO)) == -1)
+       error(1, "Can't save stdin");
+    if (dup2(ttyfd, STDIN_FILENO) == -1)
+       error(1, "Can't dup2 stdin");
+    slot = ttyslot();
+    if (dup2(sfd, STDIN_FILENO) == -1)
+       error(1, "Can't restore stdin");
+    close(sfd);
+
+    return slot;
+}
+# endif /* HAVE_GETTTYENT */
+
+int
+utmp_login(const char *from_line, const char *to_line, int ttyfd,
+    const char *user)
+{
+    sudo_utmp_t utbuf, *ut_old = NULL;
+    int slot, rval = FALSE;
+    FILE *fp;
+
+    /* Strip off /dev/ prefix from line as needed. */
+    if (strncmp(to_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+       to_line += sizeof(_PATH_DEV) - 1;
+
+    /* Find slot for new entry. */
+    slot = utmp_slot(to_line, ttyfd);
+    if (slot <= 0)
+       goto done;
+
+    if ((fp = fopen(_PATH_UTMP, "r+")) == NULL)
+       goto done;
+
+    if (from_line != NULL) {
+       if (strncmp(from_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+           from_line += sizeof(_PATH_DEV) - 1;
+
+       /* Lookup old line. */
+       while (fread(&utbuf, sizeof(utbuf), 1, fp) == 1) {
+# ifdef HAVE_STRUCT_UTMP_UT_ID
+           if (utbuf.ut_type != LOGIN_PROCESS && utbuf.ut_type != USER_PROCESS)
+               continue;
+# endif
+           if (utbuf.ut_user[0] &&
+               !strncmp(utbuf.ut_line, from_line, sizeof(utbuf.ut_line))) {
+               ut_old = &utbuf;
+               break;
+           }
+       }
+    }
+    utmp_fill(to_line, user, ut_old, &utbuf);
+    if (fseek(fp, slot * (long)sizeof(utbuf), SEEK_SET) == 0) {
+       if (fwrite(&utbuf, sizeof(utbuf), 1, fp) == 1)
+           rval = TRUE;
+    }
+    fclose(fp);
+
+done:
+    return rval;
+}
+
+int
+utmp_logout(const char *line, int status)
+{
+    sudo_utmp_t utbuf;
+    int rval = FALSE;
+    FILE *fp;
+
+    if ((fp = fopen(_PATH_UTMP, "r+")) == NULL)
+       return rval;
+
+    /* Strip off /dev/ prefix from line as needed. */
+    if (strncmp(line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+       line += sizeof(_PATH_DEV) - 1;
+   
+    while (fread(&utbuf, sizeof(utbuf), 1, fp) == 1) {
+       if (!strncmp(utbuf.ut_line, line, sizeof(utbuf.ut_line))) {
+           memset(utbuf.ut_user, 0, sizeof(utbuf.ut_user));
+# if defined(HAVE_STRUCT_UTMP_UT_TYPE)
+           utbuf.ut_type = DEAD_PROCESS;
+# endif
+           utmp_settime(&utbuf);
+           /* Back up and overwrite record. */
+           if (fseek(fp, 0L - (long)sizeof(utbuf), SEEK_CUR) == 0) {
+               if (fwrite(&utbuf, sizeof(utbuf), 1, fp) == 1)
+                   rval = TRUE;
+           }
+           break;
+       }
+    }
+    fclose(fp);
+
+    return rval;
+}
+#endif /* HAVE_GETUTXID || HAVE_GETUTID */
diff --git a/strcasecmp.c b/strcasecmp.c
deleted file mode 100644 (file)
index 9ab451c..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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 <config.h>
-
-#include <sys/types.h>
-
-#include "missing.h"
-
-/*
- * Case insensitive string compare routines, same semantics as str[n]cmp()
- * (assumes ASCII..).
- * Derived from a public domain implementation included with the pdksh shell.
- */
-static const char ichars[256] = {
-          0,  0x1,  0x2,  0x3,  0x4,  0x5,  0x6,  0x7,
-        0x8,  0x9,  0xa,  0xb,  0xc,  0xd,  0xe,  0xf,
-       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
-       0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
-       0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
-       0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-       0x40,  'a',  'b',  'c',  'd',  'e',  'f',  'g',
-        'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
-        'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
-        'x',  'y',  'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
-       0x60,  'a',  'b',  'c',  'd',  'e',  'f',  'g',
-        'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
-        'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
-        'x',  'y',  'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
-       0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
-       0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
-       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
-       0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
-       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
-       0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
-       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
-       0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
-       0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
-       0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
-       0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
-       0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
-       0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
-       0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
-       0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
-       0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
-};
-
-int
-strcasecmp(s1, s2)
-       const char *s1;
-       const char *s2;
-{
-       const unsigned char *us1 = (const unsigned char *) s1;
-       const unsigned char *us2 = (const unsigned char *) s2;
-
-       while (ichars[*us1] == ichars[*us2++]) {
-               if (*us1++ == '\0')
-                       return 0;
-       }
-       return ichars[*us1] - ichars[*--us2];
-}
-
-int
-strncasecmp(s1, s2, n)
-       const char *s1;
-       const char *s2;
-       size_t n;
-{
-       const unsigned char *us1 = (const unsigned char *) s1;
-       const unsigned char *us2 = (const unsigned char *) s2;
-
-       while (n != 0 && ichars[*us1] == ichars[*us2++]) {
-               if (*us1++ == '\0')
-                       return 0;
-               n--;
-       }
-       return n ? ichars[*us1] - ichars[*--us2] : 0;
-}
diff --git a/strerror.c b/strerror.c
deleted file mode 100644 (file)
index 88b888b..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 1999-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.
- *
- * 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 <stdio.h>
-#include <errno.h>
-
-#include "missing.h"
-
-/*
- * Map errno -> error string.
- */
-char *
-strerror(n)
-    int n;
-{
-    extern int sys_nerr;
-    extern char *sys_errlist[];
-
-    if (n > 0 && n < sys_nerr)
-       return sys_errlist[n];
-    errno = EINVAL;
-    return "Unknown error";
-}
diff --git a/strlcat.c b/strlcat.c
deleted file mode 100644 (file)
index 77f6c86..0000000
--- a/strlcat.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*     $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $     */
-
-/*
- * Copyright (c) 1998, 2003-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 <config.h>
-
-#include <sys/types.h>
-#include <string.h>
-
-#include "missing.h"
-
-/*
- * Appends src to string dst of size siz (unlike strncat, siz is the
- * full size of dst, not space left).  At most siz-1 characters
- * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
- * Returns strlen(src) + MIN(siz, strlen(initial dst)).
- * If retval >= siz, truncation occurred.
- */
-size_t
-strlcat(dst, src, siz)
-       char *dst;
-       const char *src;
-       size_t siz;
-{
-       char *d = dst;
-       const char *s = src;
-       size_t n = siz;
-       size_t dlen;
-
-       /* Find the end of dst and adjust bytes left but don't go past end */
-       while (n-- != 0 && *d != '\0')
-               d++;
-       dlen = d - dst;
-       n = siz - dlen;
-
-       if (n == 0)
-               return dlen + strlen(s);
-       while (*s != '\0') {
-               if (n != 1) {
-                       *d++ = *s;
-                       n--;
-               }
-               s++;
-       }
-       *d = '\0';
-
-       return dlen + (s - src);        /* count does not include NUL */
-}
diff --git a/strlcpy.c b/strlcpy.c
deleted file mode 100644 (file)
index df2e677..0000000
--- a/strlcpy.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*     $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $     */
-
-/*
- * Copyright (c) 1998, 2003-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 <config.h>
-
-#include <sys/types.h>
-
-#include "missing.h"
-
-/*
- * Copy src to string dst of size siz.  At most siz-1 characters
- * will be copied.  Always NUL terminates (unless siz == 0).
- * Returns strlen(src); if retval >= siz, truncation occurred.
- */
-size_t
-strlcpy(dst, src, siz)
-       char *dst;
-       const char *src;
-       size_t siz;
-{
-       char *d = dst;
-       const char *s = src;
-       size_t n = siz;
-
-       /* Copy as many bytes as will fit */
-       if (n != 0 && --n != 0) {
-               do {
-                       if ((*d++ = *s++) == 0)
-                               break;
-               } while (--n != 0);
-       }
-
-       /* Not enough room in dst, add NUL and traverse rest of src */
-       if (n == 0) {
-               if (siz != 0)
-                       *d = '\0';              /* NUL-terminate dst */
-               while (*s++)
-                       ;
-       }
-
-       return s - src - 1;     /* count does not include NUL */
-}
diff --git a/strsignal.c b/strsignal.c
deleted file mode 100644 (file)
index a551429..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2009-2010 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 <stdio.h>
-#include <signal.h>
-
-#include "missing.h"
-
-#if defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST == 1
-# define my_sys_siglist        sys_siglist
-#elif defined(HAVE_DECL__SYS_SIGLIST) && HAVE_DECL__SYS_SIGLIST == 1
-# define my_sys_siglist        _sys_siglist
-#elif defined(HAVE_DECL___SYS_SIGLIST) && HAVE_DECL___SYS_SIGLIST == 1
-# define my_sys_siglist        __sys_siglist
-#else
-extern const char *const my_sys_siglist[NSIG];
-#endif
-
-/*
- * Get signal description string
- */
-char *
-strsignal(signo)
-    int signo;
-{
-    if (signo > 0 && signo < NSIG)
-       return (char *)my_sys_siglist[signo];
-    return "Unknown signal";
-}
diff --git a/sudo.c b/sudo.c
deleted file mode 100644 (file)
index 0dc2e78..0000000
--- a/sudo.c
+++ /dev/null
@@ -1,1335 +0,0 @@
-/*
- * Copyright (c) 1993-1996, 1998-2010 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.
- *
- * For a brief history of sudo, please see the HISTORY file included
- * with this distribution.
- */
-
-#define _SUDO_MAIN
-
-#ifdef __TANDEM
-# include <floss.h>
-#endif
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#ifdef HAVE_SETRLIMIT
-# include <sys/time.h>
-# include <sys/resource.h>
-#endif
-#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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <grp.h>
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-#ifdef HAVE_SETLOCALE
-# include <locale.h>
-#endif
-#include <netinet/in.h>
-#include <netdb.h>
-#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
-# ifdef __hpux
-#  undef MAXINT
-#  include <hpsecurity.h>
-# else
-#  include <sys/security.h>
-# endif /* __hpux */
-# include <prot.h>
-#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
-#ifdef HAVE_LOGIN_CAP_H
-# include <login_cap.h>
-# ifndef LOGIN_DEFROOTCLASS
-#  define LOGIN_DEFROOTCLASS   "daemon"
-# endif
-#endif
-#ifdef HAVE_MBR_CHECK_MEMBERSHIP
-# include <membership.h>
-#endif
-
-#include "sudo.h"
-#include "lbuf.h"
-#include "interfaces.h"
-#include <sudo_usage.h>
-
-#ifdef USING_NONUNIX_GROUPS
-# include "nonunix.h"
-#endif
-
-#if defined(HAVE_PAM) && !defined(NO_PAM_SESSION)
-# define CMND_WAIT     TRUE
-#else
-# define CMND_WAIT     FALSE
-#endif
-
-/*
- * Prototypes
- */
-static void init_vars                  __P((char **));
-static int set_cmnd                    __P((int));
-static void initial_setup              __P((void));
-static void set_loginclass             __P((struct passwd *));
-static void set_runasgr                        __P((char *));
-static void set_runaspw                        __P((char *));
-static void show_version               __P((void));
-static void create_admin_success_flag  __P((void));
-extern int sudo_edit                   __P((int, char **, char **));
-int run_command __P((const char *path, char *argv[], char *envp[], uid_t uid, int dowait)); /* XXX should be in sudo.h */
-
-/*
- * Globals
- */
-int Argc, NewArgc;
-char **Argv, **NewArgv;
-char *prev_user;
-int user_closefrom = -1;
-struct sudo_user sudo_user;
-struct passwd *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 */
-#if defined(__linux__)
-static struct rlimit nproclimit;
-#endif
-#ifdef HAVE_LOGIN_CAP_H
-login_cap_t *lc;
-#endif /* HAVE_LOGIN_CAP_H */
-sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
-char *runas_user;
-char *runas_group;
-static struct sudo_nss_list *snl;
-int sudo_mode;
-
-/* For getopt(3) */
-extern char *optarg;
-extern int optind;
-
-int
-main(argc, argv, envp)
-    int argc;
-    char *argv[];
-    char *envp[];
-{
-    int sources = 0, validated;
-    int fd, cmnd_status, pwflag, rc = 0;
-    sigaction_t sa;
-    struct sudo_nss *nss;
-#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
-    extern char *malloc_options;
-    malloc_options = "AFGJPR";
-#endif
-
-#ifdef HAVE_SETLOCALE
-    setlocale(LC_ALL, "");
-#endif
-
-    Argv = argv;
-    if ((Argc = argc) < 1)
-       usage(1);
-
-    /* Must be done as the first thing... */
-#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
-    (void) set_auth_parameters(Argc, Argv);
-# ifdef HAVE_INITPRIVS
-    initprivs();
-# endif
-#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
-
-    if (geteuid() != 0)
-       errorx(1, "must be setuid root");
-
-    /*
-     * Signal setup:
-     * Ignore keyboard-generated signals so the user cannot interrupt
-     *  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;
-    (void) sigaction(SIGINT, &sa, &saved_sa_int);
-    (void) sigaction(SIGQUIT, &sa, &saved_sa_quit);
-    (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
-
-    /* Initialize environment functions (including replacements). */
-    env_init(FALSE);
-
-    /*
-     * Turn off core dumps and make sure fds 0-2 are open.
-     */
-    initial_setup();
-    sudo_setpwent();
-    sudo_setgrent();
-
-    /* Parse our arguments. */
-    sudo_mode = parse_args(Argc, Argv);
-
-    /* Setup defaults data structures. */
-    init_defaults();
-
-    /* Load the list of local ip addresses and netmasks.  */
-    load_interfaces();
-
-    pwflag = 0;
-    if (ISSET(sudo_mode, MODE_SHELL))
-       user_cmnd = "shell";
-    else if (ISSET(sudo_mode, MODE_EDIT))
-       user_cmnd = "sudoedit";
-    else {
-       switch (sudo_mode) {
-           case MODE_VERSION:
-               show_version();
-               break;
-           case MODE_HELP:
-               help();
-               break;
-           case MODE_VALIDATE:
-           case MODE_VALIDATE|MODE_INVALIDATE:
-               user_cmnd = "validate";
-               pwflag = I_VERIFYPW;
-               break;
-           case MODE_KILL:
-           case MODE_INVALIDATE:
-               user_cmnd = "kill";
-               pwflag = -1;
-               break;
-           case MODE_LISTDEFS:
-               list_options();
-               exit(0);
-               break;
-           case MODE_LIST:
-           case MODE_LIST|MODE_INVALIDATE:
-               user_cmnd = "list";
-               pwflag = I_LISTPW;
-               break;
-           case MODE_CHECK:
-           case MODE_CHECK|MODE_INVALIDATE:
-               pwflag = I_LISTPW;
-               break;
-       }
-    }
-
-    /* Must have a command to run... */
-    if (user_cmnd == NULL && NewArgc == 0)
-       usage(1);
-
-    init_vars(envp);                   /* XXX - move this later? */
-
-#ifdef USING_NONUNIX_GROUPS
-    sudo_nonunix_groupcheck_init();    /* initialise nonunix groups impl */
-#endif /* USING_NONUNIX_GROUPS */
-
-    /* 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++;
-           if (nss->setdefs(nss) != 0)
-               log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
-       }
-    }
-    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");
-
-    if (def_fqdn)
-       set_fqdn();     /* deferred until after sudoers is parsed */
-
-    /* Set login class if applicable. */
-    set_loginclass(sudo_user.pw);
-
-    /* Update initial shell now that runas is set. */
-    if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
-       NewArgv[0] = estrdup(runas_pw->pw_shell);
-
-    /* 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);
-    }
-
-    /* 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);
-
-       if (ISSET(validated, VALIDATE_OK)) {
-           /* Handle "= auth" in netsvc.conf */
-           if (nss->ret_if_found)
-               break;
-       } else {
-           /* Handle [NOTFOUND=return] */
-           if (nss->ret_if_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.
-     */
-    if (def_timestampowner) {
-       struct passwd *pw;
-
-       if (*def_timestampowner == '#')
-           pw = sudo_getpwuid(atoi(def_timestampowner + 1));
-       else
-           pw = sudo_getpwnam(def_timestampowner);
-       if (!pw)
-           log_error(0, "timestamp owner (%s): No such user",
-               def_timestampowner);
-       timestamp_uid = pw->pw_uid;
-       pw_delref(pw);
-    }
-
-    /* If given the -P option, set the "preserve_groups" flag. */
-    if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
-       def_preserve_groups = TRUE;
-
-    /* If no command line args and "set_home" is not set, error out. */
-    if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs)
-       usage(1);
-
-    /* Bail if a tty is required and we don't have one.  */
-    if (def_requiretty) {
-       if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
-           audit_failure(NewArgv, "no tty");
-           log_error(NO_MAIL, "sorry, you must have a tty to run sudo");
-       } else
-           (void) close(fd);
-    }
-
-    /* Use askpass value from sudoers unless user specified their own. */
-    if (def_askpass && !user_askpass)
-       user_askpass = def_askpass;
-
-    /*
-     * We don't reset the environment for sudoedit or if the user
-     * specified the -E command line flag and they have setenv privs.
-     */
-    if (ISSET(sudo_mode, MODE_EDIT) ||
-        (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv))
-        def_env_reset = FALSE;
-
-    /* Build a new environment that avoids any nasty bits. */
-    rebuild_env(def_noexec);
-
-    /* Require a password if sudoers says so.  */
-    if (def_authenticate)
-       check_user(validated, sudo_mode);
-
-    /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
-    /* 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) {
-                   if (sudo_user.pw != NULL)
-                       pw_delref(sudo_user.pw);
-                   sudo_user.pw = pw;
-#ifdef HAVE_MBR_CHECK_MEMBERSHIP
-                   mbr_uid_to_uuid(user_uid, user_uuid);
-#endif
-           }
-       }
-    }
-
-    if (ISSET(validated, VALIDATE_OK)) {
-       /* Create Ubuntu-style dot file to indicate sudo was successful. */
-       create_admin_success_flag();
-
-       /* Finally tell the user if the command did not exist. */
-       if (cmnd_status == NOT_FOUND_DOT) {
-           audit_failure(NewArgv, "command in current directory");
-           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) {
-           audit_failure(NewArgv, "%s: command not found", user_cmnd);
-           errorx(1, "%s: command not found", user_cmnd);
-       }
-
-       /* If user specified env vars make sure sudoers allows it. */
-       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");
-           else
-               validate_env_vars(sudo_user.env_vars);
-       }
-
-#ifdef _PATH_SUDO_IO_LOGDIR
-       /* Get next session ID so we can log it. */
-       if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT)) && (def_log_input || def_log_output))
-           io_nextid();
-#endif
-       log_allowed(validated);
-       if (ISSET(sudo_mode, MODE_CHECK))
-           rc = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw);
-       else if (ISSET(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);
-
-#ifdef USING_NONUNIX_GROUPS
-       /* Finished with the groupcheck code */
-       sudo_nonunix_groupcheck_cleanup();
-#endif
-
-       /* Deferred exit due to sudo_ldap_close() */
-       if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) {
-           if (list_pw != NULL)
-               pw_delref(list_pw);
-           exit(rc);
-       }
-
-       /* Must audit before uid change. */
-       audit_success(NewArgv);
-
-       if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
-           char *p;
-
-           /* Convert /bin/sh -> -sh so shell knows it is a login shell */
-           if ((p = strrchr(NewArgv[0], '/')) == NULL)
-               p = NewArgv[0];
-           *p = '-';
-           NewArgv[0] = p;
-
-#if defined(__linux__) || defined(_AIX)
-           /* Insert system-wide environment variables. */
-           read_env_file(_PATH_ENVIRONMENT, TRUE);
-#endif
-       }
-
-       if (ISSET(sudo_mode, MODE_RUN)) {
-           /* Insert system-wide environment variables. */
-           if (def_env_file)
-               read_env_file(def_env_file, FALSE);
-
-           /* Insert user-specified environment variables. */
-           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);
-
-       if (ISSET(sudo_mode, MODE_EDIT)) {
-           exit(sudo_edit(NewArgc, NewArgv, envp));
-       } else {
-           exit(run_command(safe_cmnd, NewArgv, env_get(), runas_pw->pw_uid,
-               CMND_WAIT));
-       }
-    } else if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) {
-       audit_failure(NewArgv, "No user or host");
-       log_denial(validated, 1);
-       exit(1);
-    } else {
-       if (def_path_info) {
-           /*
-            * We'd like to not leak path info at all here, but that can
-            * *really* confuse the users.  To really close the leak we'd
-            * have to say "not allowed to run foo" even when the problem
-            * is just "no foo in path" since the user can trivially set
-            * their path to just contain a single dir.
-            */
-           log_denial(validated,
-               !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND));
-           if (cmnd_status == NOT_FOUND)
-               warningx("%s: command not found", user_cmnd);
-           else if (cmnd_status == NOT_FOUND_DOT)
-               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_denial(validated, 1);
-       }
-       audit_failure(NewArgv, "validation failure");
-       exit(1);
-    }
-    exit(0);   /* not reached */
-}
-
-/*
- * Escape any non-alpha numeric or blank characters to make sure
- * they are not interpreted specially by the shell.
- */
-static char *
-escape_cmnd(src)
-    const char *src;
-{
-    char *cmnd, *dst;
-
-    /* Worst case scenario, we have to escape everything. */
-    cmnd = dst = emalloc((2 * strlen(src)) + 1);
-    while (*src != '\0') {
-       if (!isalnum((unsigned char)*src) && !isspace((unsigned char)*src) &&
-           *src != '_' && *src != '-') {
-           /* quote potential meta character */
-           *dst++ = '\\';
-       }
-       *dst++ = *src++;
-    }
-    *dst++ = '\0';
-
-    return cmnd;
-}
-
-/*
- * Initialize timezone, set umask, fill in ``sudo_user'' struct and
- * load the ``interfaces'' array.
- */
-static void
-init_vars(envp)
-    char **envp;
-{
-    char *p, **ep, thost[MAXHOSTNAMELEN + 1];
-    int nohostname;
-
-    /* Sanity check command from user. */
-    if (user_cmnd == NULL && strlen(NewArgv[0]) >= PATH_MAX)
-       errorx(1, "%s: File name too long", NewArgv[0]);
-
-#ifdef HAVE_TZSET
-    (void) tzset();            /* set the timezone if applicable */
-#endif /* HAVE_TZSET */
-
-    /* Default value for cmnd and cwd, overridden later. */
-    if (user_cmnd == NULL)
-       user_cmnd = NewArgv[0];
-    (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
-
-    /*
-     * We avoid gethostbyname() if possible since we don't want
-     * sudo to block if DNS or NIS is hosed.
-     * "host" is the (possibly fully-qualified) hostname and
-     * "shost" is the unqualified form of the hostname.
-     */
-    nohostname = gethostname(thost, sizeof(thost));
-    if (nohostname) {
-       user_host = user_shost = "localhost";
-    } else {
-       thost[sizeof(thost) - 1] = '\0';
-       user_host = estrdup(thost);
-       if ((p = strchr(user_host, '.'))) {
-           *p = '\0';
-           user_shost = estrdup(user_host);
-           *p = '.';
-       } else {
-           user_shost = user_host;
-       }
-    }
-
-    if ((p = ttyname(STDIN_FILENO)) || (p = ttyname(STDOUT_FILENO)) ||
-       (p = ttyname(STDERR_FILENO))) {
-       user_tty = user_ttypath = estrdup(p);
-       if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
-           user_tty += sizeof(_PATH_DEV) - 1;
-    } else
-       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;
-               break;
-           case 'S':
-               if (strncmp("SHELL=", *ep, 6) == 0)
-                   user_shell = *ep + 6;
-               else if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0)
-                   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;
-           }
-    }
-
-    /*
-     * Stash a local copy of the user's struct passwd.
-     */
-    if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL) {
-       /* Need to make a fake struct passwd for logging to work. */
-       struct passwd pw;
-       char pw_name[MAX_UID_T_LEN + 1];
-
-       pw.pw_uid = getuid();
-       (void) snprintf(pw_name, sizeof(pw_name), "%u",
-           (unsigned int) pw.pw_uid);
-       pw.pw_name = pw_name;
-       sudo_user.pw = &pw;
-
-       /*
-        * 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.
-        */
-       if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE)
-           errorx(1, "unknown uid: %s", pw_name);
-       log_error(0, "unknown uid: %s", pw_name);
-    }
-#ifdef HAVE_MBR_CHECK_MEMBERSHIP
-    mbr_uid_to_uuid(user_uid, user_uuid);
-#endif
-    if (user_shell == NULL || *user_shell == '\0')
-       user_shell = estrdup(sudo_user.pw->pw_shell);
-
-    /* It is now safe to use log_error() and set_perms() */
-
-#ifdef HAVE_GETGROUPS
-    if ((user_ngroups = getgroups(0, NULL)) > 0) {
-       user_groups = emalloc2(user_ngroups, sizeof(GETGROUPS_T));
-       if (getgroups(user_ngroups, user_groups) < 0)
-           log_error(USE_ERRNO|MSG_ONLY, "can't get group vector");
-    }
-#endif
-
-    if (nohostname)
-       log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
-
-    /*
-     * Get current working directory.  Try as user, fall back to root.
-     */
-    set_perms(PERM_USER);
-    if (!getcwd(user_cwd, sizeof(user_cwd))) {
-       set_perms(PERM_ROOT);
-       if (!getcwd(user_cwd, sizeof(user_cwd))) {
-           warningx("cannot get working directory");
-           (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
-       }
-    } else
-       set_perms(PERM_ROOT);
-
-    /*
-     * If in shell or edit mode, or if running a pseudo-command
-     * such as "list", we need to redo NewArgv and NewArgc.
-     */
-    if (ISSET(sudo_mode, MODE_SHELL)) {
-       char **av;
-
-       /* Allocate an extra slot for execve() failure (ENOEXEC). */
-       av = (char **) emalloc2(5, sizeof(char *));
-       av++;
-
-       av[0] = user_shell;     /* may be updated later */
-       if (NewArgc > 0) {
-           size_t cmnd_size;
-           char *cmnd, *src, *dst, *end;
-           cmnd_size = (size_t) (NewArgv[NewArgc - 1] - NewArgv[0]) +
-                   strlen(NewArgv[NewArgc - 1]) + 1;
-           cmnd = dst = emalloc(cmnd_size);
-           src = NewArgv[0];
-           for (end = src + cmnd_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;
-    } else if (ISSET(sudo_mode, MODE_EDIT) || NewArgc == 0) {
-       NewArgv--;
-       NewArgc++;
-       NewArgv[0] = user_cmnd;
-    }
-}
-
-/*
- * 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;
-    char *path = user_path;
-
-    /* Resolve the path and return. */
-    rval = FOUND;
-    user_stat = emalloc(sizeof(struct stat));
-    if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
-       if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
-           if (def_secure_path && !user_is_exempt())
-               path = def_secure_path;
-           set_perms(PERM_RUNAS);
-           rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
-               def_ignore_dot);
-           set_perms(PERM_ROOT);
-           if (rval != FOUND) {
-               /* Failed as root, try as invoking user. */
-               set_perms(PERM_USER);
-               rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
-                   def_ignore_dot);
-               set_perms(PERM_ROOT);
-           }
-       }
-
-       /* set user_args */
-       if (NewArgc > 1) {
-           char *to, **from;
-           size_t size, n;
-
-           /* If we didn't realloc NewArgv it is contiguous so just count. */
-           if (!ISSET(sudo_mode, MODE_SHELL)) {
-               size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
-                       strlen(NewArgv[NewArgc-1]) + 1;
-           } else {
-               for (size = 0, from = NewArgv + 1; *from; from++)
-                   size += strlen(*from) + 1;
-           }
-
-           /* Alloc and build up user_args. */
-           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';
-       }
-    }
-    if ((user_base = strrchr(user_cmnd, '/')) != NULL)
-       user_base++;
-    else
-       user_base = user_cmnd;
-
-    if (!update_defaults(SETDEF_CMND))
-       log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
-
-    if (!runas_user && !runas_group)
-       set_runaspw(def_runas_default); /* may have been updated above */
-
-    return rval;
-}
-
-/*
- * Setup the execution environment immediately prior to the call to execve()
- * Returns TRUE on success and FALSE on failure.
- */
-int
-exec_setup(rbac_enabled, ttyname, ttyfd)
-    int rbac_enabled;
-    const char *ttyname;
-    int ttyfd;
-{
-    int rval = FALSE;
-
-#ifdef HAVE_SELINUX
-    if (rbac_enabled) {
-       if (selinux_setup(user_role, user_type, ttyname, ttyfd) == -1)
-          goto done;
-    }
-#endif
-
-    /*
-     * For sudoedit, the command runas a the user with no additional setup.
-     */
-    if (ISSET(sudo_mode, MODE_EDIT)) {
-       set_perms(PERM_FULL_USER);
-       rval = TRUE;
-       goto done;
-    }
-
-    /*
-     * Set umask based on sudoers.
-     * If user's umask is more restrictive, OR in those bits too
-     * unless umask_override is set.
-     */
-    if (def_umask != 0777) {
-       if (def_umask_override) {
-           umask(def_umask);
-       } else {
-           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)
-    (void) setrlimit(RLIMIT_CORE, &corelimit);
-#endif /* RLIMIT_CORE && !SUDO_DEVEL */
-
-    if (ISSET(sudo_mode, MODE_RUN))
-       set_perms(PERM_FULL_RUNAS);
-
-    if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
-       /* Change to target user's homedir. */
-       if (chdir(runas_pw->pw_dir) == -1) {
-           warning("unable to change directory to %s", runas_pw->pw_dir);
-           goto done;
-       }
-    }
-
-    /*
-     * Restore nproc resource limit if pam_limits didn't do it for us.
-     * We must do this *after* the uid change to avoid potential EAGAIN
-     * from setuid().
-     */
-#if defined(__linux__)
-    {
-       struct rlimit rl;
-       if (getrlimit(RLIMIT_NPROC, &rl) == 0) {
-           if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY)
-               (void) setrlimit(RLIMIT_NPROC, &nproclimit);
-       }
-    }
-#endif
-
-    /* Close the password and group files and free up memory. */
-    sudo_endpwent();
-    sudo_endgrent();
-    pw_delref(sudo_user.pw);
-    pw_delref(runas_pw);
-    if (runas_gr != NULL)
-       gr_delref(runas_gr);
-
-    rval = TRUE;
-
-done:
-    return rval;
-}
-
-/*
- * Run the command and wait for it to complete.
- */
-int
-run_command(path, argv, envp, uid, dowait)
-    const char *path;
-    char *argv[];
-    char *envp[];
-    uid_t uid;
-    int dowait;
-{
-    struct command_status cstat;
-    int exitcode = 1;
-
-#ifdef PROFILING
-    exit(0);
-#endif
-
-    cstat.type = CMD_INVALID;
-    cstat.val = 0;
-
-    /* Escape meta chars if running a shell with args. */
-    if (ISSET(sudo_mode, MODE_SHELL) && argv[1] != NULL) {
-       char *cmnd = argv[2];
-       argv[2] = escape_cmnd(cmnd);
-       efree(cmnd);
-    }
-
-    sudo_execve(path, argv, envp, uid, &cstat, dowait,
-       ISSET(sudo_mode, MODE_BACKGROUND));
-
-    switch (cstat.type) {
-    case CMD_ERRNO:
-       /* exec_setup() or execve() returned an error. */
-       warningx("unable to execute %s: %s", path, strerror(cstat.val));
-       exitcode = 127;
-       break;
-    case CMD_WSTATUS:
-       /* Command ran, exited or was killed. */
-       if (WIFEXITED(cstat.val))
-           exitcode = WEXITSTATUS(cstat.val);
-       else if (WIFSIGNALED(cstat.val))
-           exitcode = WTERMSIG(cstat.val) | 128;
-       break;
-    default:
-       warningx("unexpected child termination condition: %d", cstat.type);
-       break;
-    }
-#ifdef HAVE_PAM
-    pam_end_session();
-#endif /* HAVE_PAM */
-#ifdef _PATH_SUDO_IO_LOGDIR
-    io_log_close();
-#endif
-    sudo_endpwent();
-    sudo_endgrent();
-    pw_delref(sudo_user.pw);
-    pw_delref(runas_pw);
-    if (runas_gr != NULL)
-       gr_delref(runas_gr);
-    return exitcode;
-}
-
-/*
- * Open sudoers and sanity check mode/owner/type.
- * Returns a handle to the sudoers file or NULL on error.
- */
-FILE *
-open_sudoers(sudoers, doedit, keepopen)
-    const char *sudoers;
-    int doedit;
-    int *keepopen;
-{
-    struct stat statbuf;
-    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(sudoers, &statbuf)) == 0 &&
-       SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 &&
-       (statbuf.st_mode & 0007777) == 0400) {
-
-       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(sudoers, (uid_t) -1, SUDOERS_GID) == 0) {
-                   warningx("set group on %s", sudoers);
-                   statbuf.st_gid = SUDOERS_GID;
-               } else
-                   warning("unable to set group on %s", sudoers);
-           }
-       } else
-           warning("unable to fix mode on %s", sudoers);
-    }
-
-    /*
-     * Sanity checks on sudoers file.  Must be done as sudoers
-     * file owner.  We already did a stat as root, so use that
-     * data if we can't stat as sudoers file owner.
-     */
-    set_perms(PERM_SUDOERS);
-
-    if (rootstat != 0 && stat_sudoers(sudoers, &statbuf) != 0)
-       log_error(USE_ERRNO|NO_EXIT, "can't stat %s", sudoers);
-    else if (!S_ISREG(statbuf.st_mode))
-       log_error(NO_EXIT, "%s is not a regular file", sudoers);
-    else if ((statbuf.st_mode & 07577) != SUDOERS_MODE)
-       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(NO_EXIT, "%s is owned by uid %u, should be %u", sudoers,
-           (unsigned int) statbuf.st_uid, (unsigned int) SUDOERS_UID);
-    else if (statbuf.st_gid != SUDOERS_GID)
-       log_error(NO_EXIT, "%s is owned by gid %u, should be %u", sudoers,
-           (unsigned int) statbuf.st_gid, (unsigned int) SUDOERS_GID);
-    else if ((fp = fopen(sudoers, "r")) == NULL)
-       log_error(USE_ERRNO|NO_EXIT, "can't open %s", sudoers);
-    else {
-       /*
-        * Make sure we can actually read sudoers so we can present the
-        * user with a reasonable error message (unlike the lexer).
-        */
-       if (statbuf.st_size != 0 && fgetc(fp) == EOF) {
-           log_error(USE_ERRNO|NO_EXIT, "can't read %s", sudoers);
-           fclose(fp);
-           fp = NULL;
-       }
-    }
-
-    if (fp != NULL) {
-       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()
-{
-    int miss[3], devnull = -1;
-    sigset_t mask;
-#if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL))
-    struct rlimit rl;
-#endif
-
-    /* Reset signal mask. */
-    (void) sigemptyset(&mask);
-    (void) sigprocmask(SIG_SETMASK, &mask, NULL);
-
-#if defined(__linux__)
-    /*
-     * Unlimit the number of processes since Linux's setuid() will
-     * apply resource limits when changing uid and return EAGAIN if
-     * nproc would be violated by the uid switch.
-     */
-    (void) getrlimit(RLIMIT_NPROC, &nproclimit);
-    rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
-    if (setrlimit(RLIMIT_NPROC, &rl)) {
-       memcpy(&rl, &nproclimit, sizeof(struct rlimit));
-       rl.rlim_cur = rl.rlim_max;
-       (void)setrlimit(RLIMIT_NPROC, &rl);
-    }
-#endif /* __linux__ */
-#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
-    /*
-     * Turn off core dumps.
-     */
-    (void) getrlimit(RLIMIT_CORE, &corelimit);
-    memcpy(&rl, &corelimit, sizeof(struct rlimit));
-    rl.rlim_cur = 0;
-    (void) setrlimit(RLIMIT_CORE, &rl);
-#endif /* RLIMIT_CORE && !SUDO_DEVEL */
-
-    /*
-     * stdin, stdout and stderr must be open; set them to /dev/null
-     * if they are closed and close all other fds.
-     */
-    miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1;
-    miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1;
-    miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1;
-    if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) {
-       if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) == -1)
-           error(1, "unable to open %s", _PATH_DEVNULL);
-       if (miss[STDIN_FILENO] && dup2(devnull, STDIN_FILENO) == -1)
-           error(1, "dup2");
-       if (miss[STDOUT_FILENO] && dup2(devnull, STDOUT_FILENO) == -1)
-           error(1, "dup2");
-       if (miss[STDERR_FILENO] && dup2(devnull, STDERR_FILENO) == -1)
-           error(1, "dup2");
-       if (devnull > STDERR_FILENO)
-           close(devnull);
-    }
-}
-
-#ifdef HAVE_LOGIN_CAP_H
-static void
-set_loginclass(pw)
-    struct passwd *pw;
-{
-    int errflags;
-
-    /*
-     * Don't make it a fatal error if the user didn't specify the login
-     * class themselves.  We do this because if login.conf gets
-     * corrupted we want the admin to be able to use sudo to fix it.
-     */
-    if (login_class)
-       errflags = NO_MAIL|MSG_ONLY;
-    else
-       errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
-
-    if (login_class && strcmp(login_class, "-") != 0) {
-       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)
-           login_class =
-               (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
-    }
-
-    lc = login_getclass(login_class);
-    if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
-       log_error(errflags, "unknown login class: %s", login_class);
-       if (!lc)
-           lc = login_getclass(NULL);  /* needed for login_getstyle() later */
-    }
-}
-#else
-static void
-set_loginclass(pw)
-    struct passwd *pw;
-{
-}
-#endif /* HAVE_LOGIN_CAP_H */
-
-/*
- * Look up the fully qualified domain name and set user_host and user_shost.
- */
-void
-set_fqdn()
-{
-#ifdef HAVE_GETADDRINFO
-    struct addrinfo *res0, hint;
-#else
-    struct hostent *hp;
-#endif
-    char *p;
-
-#ifdef HAVE_GETADDRINFO
-    zero_bytes(&hint, sizeof(hint));
-    hint.ai_family = PF_UNSPEC;
-    hint.ai_flags = AI_CANONNAME;
-    if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
-#else
-    if (!(hp = gethostbyname(user_host))) {
-#endif
-       log_error(MSG_ONLY|NO_EXIT,
-           "unable to resolve host %s", user_host);
-    } else {
-       if (user_shost != user_host)
-           efree(user_shost);
-       efree(user_host);
-#ifdef HAVE_GETADDRINFO
-       user_host = estrdup(res0->ai_canonname);
-       freeaddrinfo(res0);
-#else
-       user_host = estrdup(hp->h_name);
-#endif
-    }
-    if ((p = strchr(user_host, '.'))) {
-       *p = '\0';
-       user_shost = estrdup(user_host);
-       *p = '.';
-    } else {
-       user_shost = user_host;
-    }
-}
-
-/*
- * Get passwd entry for the user we are going to run commands as
- * and store it in runas_pw.  By default, commands run as "root".
- */
-static void
-set_runaspw(user)
-    char *user;
-{
-    if (runas_pw != NULL)
-       pw_delref(runas_pw);
-    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) {
-           audit_failure(NewArgv, "unknown user: %s", user);
-           log_error(NO_MAIL|MSG_ONLY, "unknown user: %s", user);
-       }
-    }
-}
-
-/*
- * Get group entry for the group we are going to run commands as
- * and store it in runas_gr.
- */
-static void
-set_runasgr(group)
-    char *group;
-{
-    if (runas_gr != NULL)
-       gr_delref(runas_gr);
-    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);
-    }
-}
-
-/*
- * 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);
-       }
-#ifdef USING_NONUNIX_GROUPS
-       sudo_nonunix_groupcheck_cleanup();
-#endif
-       sudo_endpwent();
-       sudo_endgrent();
-#ifdef _PATH_SUDO_IO_LOGDIR
-       io_log_close();
-#endif
-    }
-    term_restore(STDIN_FILENO, 0);
-#ifdef HAVE_SELINUX
-    selinux_restore_tty();
-#endif
-}
-
-static void
-show_version()
-{
-    (void) printf("Sudo version %s\n", PACKAGE_VERSION);
-    if (getuid() == 0) {
-       putchar('\n');
-       (void) printf("Configure args: %s\n", CONFIGURE_ARGS);
-       (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);
-}
-
-#ifdef USE_ADMIN_FLAG
-static void
-create_admin_success_flag()
-{
-    struct stat statbuf;
-    char flagfile[PATH_MAX];
-    int fd, n;
-
-    /* Check whether the user is in the admin group. */
-    if (!user_in_group(sudo_user.pw, "admin"))
-       return;
-
-    /* Build path to flag file. */
-    n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful",
-       user_dir);
-    if (n <= 0 || n >= sizeof(flagfile))
-       return;
-
-    /* Create admin flag file if it doesn't already exist. */
-    set_perms(PERM_USER);
-    if (stat(flagfile, &statbuf) == 0) {
-       set_perms(PERM_ROOT);
-       return;
-    }
-
-    fd = open(flagfile, O_CREAT|O_WRONLY|O_EXCL, 0644);
-    close(fd);
-    set_perms(PERM_ROOT);
-}
-#else /* !USE_ADMIN_FLAG */
-static void
-create_admin_success_flag()
-{
-    /* STUB */
-}
-#endif /* USE_ADMIN_FLAG */
diff --git a/sudo.cat b/sudo.cat
deleted file mode 100644 (file)
index 4cee486..0000000
--- a/sudo.cat
+++ /dev/null
@@ -1,660 +0,0 @@
-
-
-
-SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
-
-
-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\bo -\b-h\bh | -\b-K\bK | -\b-k\bk | -\b-L\bL | -\b-V\bV
-
-       s\bsu\bud\bdo\bo -\b-v\bv [-\b-A\bAk\bkn\bnS\bS] [-\b-a\ba _\ba_\bu_\bt_\bh_\b__\bt_\by_\bp_\be] [-\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]
-
-       s\bsu\bud\bdo\bo -\b-l\bl[\b[l\bl]\b] [-\b-A\bAk\bkn\bnS\bS] [-\b-a\ba _\ba_\bu_\bt_\bh_\b__\bt_\by_\bp_\be] [-\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-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\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-r\br _\br_\bo_\bl_\be] [-\b-t\bt _\bt_\by_\bp_\be]
-       [-\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 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 time stamp 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.
-
-       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.  If a password is required,
-       s\bsu\bud\bdo\bo will exit if the user's password is not entered within a
-       configurable time limit.  The default password prompt timeout is 5
-       minutes.
-
-       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 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
-
-
-
-1.7.6                     April  9, 2011                        1
-
-
-
-
-
-SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
-
-
-       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
-       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          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 (possibly graphical) 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.
-
-       -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.
-
-       -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.
-
-       -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).
-
-       -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.
-
-       -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
-
-
-
-1.7.6                     April  9, 2011                        2
-
-
-
-
-
-SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
-
-
-                   _\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
-                   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:
-
-                   1.  Temporary copies are made of the files to be edited
-                       with the owner set to the invoking user.
-
-                   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.
-
-                   3.  If they have been modified, the temporary files are
-                       copied back to their original location and the
-                       temporary versions are removed.
-
-                   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.
-
-       -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.
-
-       -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).  The default handling of the HOME
-                   environment variable depends on _\bs_\bu_\bd_\bo_\be_\br_\bs(4) settings.  By
-                   default, s\bsu\bud\bdo\bo will set HOME if _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt or _\ba_\bl_\bw_\ba_\by_\bs_\b__\bs_\be_\bt_\b__\bh_\bo_\bm_\be
-                   are set, or if _\bs_\be_\bt_\b__\bh_\bo_\bm_\be is set and the -\b-s\bs option is
-                   specified on the command line.
-
-       -h          The -\b-h\bh (_\bh_\be_\bl_\bp) option causes s\bsu\bud\bdo\bo to print a short help
-                   message to the standard output and exit.
-
-       -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
-
-
-
-1.7.6                     April  9, 2011                        3
-
-
-
-
-
-SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
-
-
-                   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
-                   _\bH_\bO_\bM_\bE, _\bM_\bA_\bI_\bL, _\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.
-
-       -K          The -\b-K\bK (sure _\bk_\bi_\bl_\bl) option is like -\b-k\bk except that it removes
-                   the user's time stamp entirely and may not be used in
-                   conjunction with a command or other option.  This option
-                   does not require a password.
-
-       -k          When used by itself, the -\b-k\bk (_\bk_\bi_\bl_\bl) option to s\bsu\bud\bdo\bo
-                   invalidates the user's time stamp 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.
-
-                   When used in conjunction with a command or an option that
-                   may require a password, the -\b-k\bk option will cause s\bsu\bud\bdo\bo to
-                   ignore the user's time stamp file.  As a result, s\bsu\bud\bdo\bo will
-                   prompt for a password (if one is required by _\bs_\bu_\bd_\bo_\be_\br_\bs) and
-                   will not update the user's time stamp file.
-
-       -L          The -\b-L\bL (_\bl_\bi_\bs_\bt defaults) option will list 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 will be removed from a
-                   future version of s\bsu\bud\bdo\bo.
-
-       -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.
-
-       -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.
-
-       -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
-
-
-
-1.7.6                     April  9, 2011                        4
-
-
-
-
-
-SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
-
-
-                   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.
-
-       -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:
-
-                   %H  expanded to the local host name including the domain
-                       name (on if the machine's host name is fully qualified
-                       or the _\bf_\bq_\bd_\bn _\bs_\bu_\bd_\bo_\be_\br_\bs option is set)
-
-                   %h  expanded to the local host name 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 collapsed into a
-                       single % character
-
-                   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 _\br_\bo_\bl_\be     The -\b-r\br (_\br_\bo_\bl_\be) option causes the new (SELinux) security
-                   context to have the role specified by _\br_\bo_\bl_\be.
-
-       -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.  The
-                   password must be followed by a newline character.
-
-       -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.
-
-       -t _\bt_\by_\bp_\be     The -\b-t\bt (_\bt_\by_\bp_\be) option causes the new (SELinux) security
-                   context to have the type specified by _\bt_\by_\bp_\be.  If no type is
-                   specified, the default type is derived from the specified
-                   role.
-
-       -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.
-
-
-
-
-1.7.6                     April  9, 2011                        5
-
-
-
-
-
-SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
-
-
-       -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.
-
-       -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 time stamp, 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.
-
-       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_\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
-
-
-
-1.7.6                     April  9, 2011                        6
-
-
-
-
-
-SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
-
-
-       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.
-
-       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
-       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 time stamp directory
-       (_\b/_\bv_\ba_\br_\b/_\ba_\bd_\bm_\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 time stamp directory is located in a directory writable by anyone
-       (e.g., _\b/_\bt_\bm_\bp), it is possible for a user to create the time stamp
-       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 time stamp
-       dir.  This is unlikely to happen since once the time stamp 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 time stamps
-       (_\b/_\bv_\ba_\br_\b/_\ba_\bd_\bm_\b/_\bs_\bu_\bd_\bo for instance) or create _\b/_\bv_\ba_\br_\b/_\ba_\bd_\bm_\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 time stamps 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 time stamp with a bogus date on systems that allow users to
-       give away files.
-
-       On systems where the boot time is available, s\bsu\bud\bdo\bo will also not honor
-       time stamps from before the machine booted.
-
-
-
-1.7.6                     April  9, 2011                        7
-
-
-
-
-
-SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
-
-
-       Since time stamp files live in the file system, they can outlive a
-       user's login session.  As a result, a user may be able to login, run a
-       command with s\bsu\bud\bdo\bo after authenticating, logout, login again, and run
-       s\bsu\bud\bdo\bo without authenticating so long as the time stamp file's
-       modification time is within 5 minutes (or whatever the timeout is set
-       to in _\bs_\bu_\bd_\bo_\be_\br_\bs).  When the _\bt_\bt_\by_\b__\bt_\bi_\bc_\bk_\be_\bt_\bs option is enabled in _\bs_\bu_\bd_\bo_\be_\br_\bs, the
-       time stamp has per-tty granularity but still may outlive the user's
-       session.  On Linux systems where the devpts filesystem is used, Solaris
-       systems with the devices filesystem, as well as other systems that
-       utilize a devfs filesystem that monotonically increase the inode number
-       of devices as they are created (such as Mac OS X), s\bsu\bud\bdo\bo is able to
-       determine when a tty-based time stamp file is stale and will ignore it.
-       Administrators should not rely on this feature as it is not universally
-       available.
-
-       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 neither
-                       SUDO_EDITOR nor VISUAL is set
-
-       MAIL            In -\b-i\bi mode or when _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt is enabled in _\bs_\bu_\bd_\bo_\be_\br_\bs, set
-                       to the mail spool of the target user
-
-       HOME            Set to the home directory of the target user if -\b-i\bi or
-                       -\b-H\bH are specified, _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt or _\ba_\bl_\bw_\ba_\by_\bs_\b__\bs_\be_\bt_\b__\bh_\bo_\bm_\be are set
-                       in _\bs_\bu_\bd_\bo_\be_\br_\bs, or when the -\b-s\bs option is specified and
-                       _\bs_\be_\bt_\b__\bh_\bo_\bm_\be is set in _\bs_\bu_\bd_\bo_\be_\br_\bs
-
-       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
-
-       SUDO_ASKPASS    Specifies the path to a helper program used to read the
-                       password if no terminal is available or if the -A
-                       option is specified.
-
-       SUDO_COMMAND    Set to the command run by sudo
-
-       SUDO_EDITOR     Default editor to use in -\b-e\be (sudoedit) mode
-
-       SUDO_GID        Set to the group ID of the user who invoked sudo
-
-
-
-
-1.7.6                     April  9, 2011                        8
-
-
-
-
-
-SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
-
-
-       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
-
-       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/_\ba_\bd_\bm_\b/_\bs_\bu_\bd_\bo           Directory containing time stamps
-
-       _\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.
-
-       To get a file listing of an unreadable directory:
-
-        $ sudo ls /usr/local/protected
-
-       To list the home directory of user yaz on a machine where the file
-       system holding ~yaz is not exported as root:
-
-        $ sudo -u yaz ls ~yaz
-
-       To edit the _\bi_\bn_\bd_\be_\bx_\b._\bh_\bt_\bm_\bl file as user www:
-
-        $ sudo -u www vi ~www/htdocs/index.html
-
-       To view system logs only accessible to root and users in the adm group:
-
-        $ sudo -g adm view /var/log/syslog
-
-       To run an editor as jim with a different primary group:
-
-        $ sudo -u jim -g audio vi ~jim/sound.txt
-
-       To shutdown a machine:
-
-        $ 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.
-
-
-
-1.7.6                     April  9, 2011                        9
-
-
-
-
-
-SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
-
-
-        $ 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.
-
-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.
-
-       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 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/
-
-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.
-
-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.6                     April  9, 2011                       10
-
-
diff --git a/sudo.h b/sudo.h
deleted file mode 100644 (file)
index a59677b..0000000
--- a/sudo.h
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright (c) 1993-1996, 1998-2005, 2007-2010
- *     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.
- */
-
-#ifndef _SUDO_SUDO_H
-#define _SUDO_SUDO_H
-
-#include <pathnames.h>
-#include <limits.h>
-#include "missing.h"
-#include "alloc.h"
-#include "defaults.h"
-#include "error.h"
-#include "list.h"
-#include "logging.h"
-#include "missing.h"
-#include "sudo_nss.h"
-
-#ifdef HAVE_MBR_CHECK_MEMBERSHIP
-# include <membership.h>
-#endif
-
-/*
- * 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 *host;
-    char *shost;
-    char *prompt;
-    char *cmnd;
-    char *cmnd_args;
-    char *cmnd_base;
-    char *cmnd_safe;
-    char *class_name;
-    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];
-    char  sessid[7];
-#ifdef HAVE_MBR_CHECK_MEMBERSHIP
-    uuid_t uuid;
-#endif
-};
-
-/* Status passed between parent and child via socketpair */
-struct command_status {
-#define CMD_INVALID 0
-#define CMD_ERRNO 1
-#define CMD_WSTATUS 2
-#define CMD_SIGNO 3
-    int type;
-    int val;
-};
-
-/*
- * Return values for sudoers_lookup(), also used as arguments for log_auth()
- * Note: cannot use '0' as a value here.
- */
-/* XXX - VALIDATE_SUCCESS and VALIDATE_FAILURE instead? */
-#define VALIDATE_ERROR          0x001
-#define VALIDATE_OK            0x002
-#define VALIDATE_NOT_OK                0x004
-#define FLAG_CHECK_USER                0x010
-#define FLAG_NO_USER           0x020
-#define FLAG_NO_HOST           0x040
-#define FLAG_NO_CHECK          0x080
-
-/*
- * Pseudo-boolean values
- */
-#undef TRUE
-#define TRUE                     1
-#undef FALSE
-#define FALSE                    0
-
-/*
- * find_path()/load_cmnd() return values
- */
-#define FOUND                    1
-#define NOT_FOUND                0
-#define NOT_FOUND_DOT          -1
-
-/*
- * Various modes sudo can be in (based on arguments) in hex
- */
-#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()
- */
-#define PERM_ROOT                0x00
-#define PERM_USER                0x01
-#define PERM_FULL_USER           0x02
-#define PERM_SUDOERS             0x03
-#define PERM_RUNAS               0x04
-#define PERM_FULL_RUNAS          0x05
-#define PERM_TIMESTAMP           0x06
-#define PERM_NOEXIT              0x10 /* flag */
-#define PERM_MASK                0xf0
-
-/*
- * Shortcuts for sudo_user contents.
- */
-#define user_name              (sudo_user.pw->pw_name)
-#define user_passwd            (sudo_user.pw->pw_passwd)
-#define user_uid               (sudo_user.pw->pw_uid)
-#define user_uuid              (sudo_user.uuid)
-#define user_gid               (sudo_user.pw->pw_gid)
-#define user_dir               (sudo_user.pw->pw_dir)
-#define user_shell             (sudo_user.shell)
-#define user_ngroups           (sudo_user.ngroups)
-#define user_groups            (sudo_user.groups)
-#define user_tty               (sudo_user.tty)
-#define user_ttypath           (sudo_user.ttypath)
-#define user_cwd               (sudo_user.cwd)
-#define user_cmnd              (sudo_user.cmnd)
-#define user_args              (sudo_user.cmnd_args)
-#define user_base              (sudo_user.cmnd_base)
-#define user_stat              (sudo_user.cmnd_stat)
-#define user_path              (sudo_user.path)
-#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)
-
-/*
- * We used to use the system definition of PASS_MAX or _PASSWD_LEN,
- * but that caused problems with various alternate authentication
- * methods.  So, we just define our own and assume that it is >= the
- * system max.
- */
-#define SUDO_PASS_MAX  256
-
-/*
- * Flags for lock_file()
- */
-#define SUDO_LOCK      1               /* lock a file */
-#define SUDO_TLOCK     2               /* test & lock a file (non-blocking) */
-#define SUDO_UNLOCK    4               /* unlock a file */
-
-/*
- * Flags for tgetpass()
- */
-#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 stat;
-struct timeval;
-
-/* aix.c */
-void aix_prep_user __P((char *, char *));
-void aix_setauthdb __P((char *user));
-void aix_restoreauthdb __P((void));
-
-/* boottime.c */
-int get_boottime __P((struct timeval *));
-
-/* check.c */
-int user_is_exempt     __P((void));
-void check_user                __P((int, int));
-void remove_timestamp  __P((int));
-
-/* env.c */
-char **env_get         __P((void));
-void env_init          __P((int lazy));
-void init_envtables    __P((void));
-void insert_env_vars   __P((struct list_member *));
-void read_env_file     __P((const char *, int));
-void rebuild_env       __P((int));
-void validate_env_vars __P((struct list_member *));
-
-/* exec.c */
-int sudo_execve __P((const char *path, char *argv[], char *envp[], uid_t uid,
-    struct command_status *cstat, int dowait, int bgmode));
-void save_signals __P((void));
-void restore_signals __P((void));
-
-/* fileops.c */
-char *sudo_parseln     __P((FILE *));
-int lock_file          __P((int, int));
-int touch              __P((int, char *, struct timeval *));
-
-/* find_path.c */
-int find_path          __P((char *, char **, struct stat *, char *, int));
-
-/* getspwuid.c */
-char *sudo_getepw      __P((const struct passwd *));
-
-/* gettime.c */
-int gettime            __P((struct timeval *));
-
-/* goodpath.c */
-char *sudo_goodpath    __P((const char *, struct stat *));
-
-/* gram.y */
-int yyparse            __P((void));
-
-/* iolog.c */
-int io_log_open __P((void));
-int log_stderr __P((const char *buf, unsigned int len));
-int log_stdin __P((const char *buf, unsigned int len));
-int log_stdout __P((const char *buf, unsigned int len));
-int log_ttyin __P((const char *buf, unsigned int len));
-int log_ttyout __P((const char *buf, unsigned int len));
-void io_log_close __P((void));
-void io_nextid __P((void));
-
-/* pam.c */
-int pam_begin_session  __P((struct passwd *));
-int pam_end_session    __P((void));
-
-/* parse.c */
-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 *));
-
-/* parse_args.c */
-int parse_args __P((int, char **));
-
-/* get_pty.c */
-int get_pty __P((int *master, int *slave, char *name, size_t namesz, uid_t uid));
-
-/* pwutil.c */
-int user_in_group      __P((struct passwd *, const char *));
-struct group *sudo_fakegrnam __P((const char *));
-struct group *sudo_getgrgid __P((gid_t));
-struct group *sudo_getgrnam __P((const char *));
-struct passwd *sudo_fakepwnam __P((const char *, gid_t));
-struct passwd *sudo_getpwnam __P((const char *));
-struct passwd *sudo_getpwuid __P((uid_t));
-void sudo_endgrent     __P((void));
-void sudo_endpwent     __P((void));
-void sudo_endspent     __P((void));
-void sudo_setgrent     __P((void));
-void sudo_setpwent     __P((void));
-void sudo_setspent     __P((void));
-void gr_addref         __P((struct group *));
-void gr_delref         __P((struct group *));
-void pw_addref         __P((struct passwd *));
-void pw_delref         __P((struct passwd *));
-
-/* selinux.c */
-int selinux_restore_tty __P((void));
-int selinux_setup __P((const char *role, const char *type, const char *ttyn,
-    int ttyfd));
-void selinux_execve __P((const char *path, char *argv[], char *envp[]));
-
-/* set_perms.c */
-int set_perms          __P((int));
-
-/* sudo.c */
-FILE *open_sudoers     __P((const char *, int, int *));
-int exec_setup         __P((int, const char *, int));
-RETSIGTYPE cleanup     __P((int));
-void set_fqdn          __P((void));
-
-/* sudo_auth.c */
-void verify_user       __P((struct passwd *, char *));
-void pass_warn         __P((FILE *));
-void dump_auth_methods __P((void));
-
-/* sudo_nss.c */
-void display_privs     __P((struct sudo_nss_list *, struct passwd *));
-int display_cmnd       __P((struct sudo_nss_list *, struct passwd *));
-
-/* term.c */
-int term_cbreak __P((int));
-int term_copy __P((int, int));
-int term_noecho __P((int));
-int term_raw __P((int, int));
-int term_restore __P((int, int));
-
-/* tgetpass.c */
-char *tgetpass         __P((const char *, int, int));
-int tty_present                __P((void));
-
-/* timestr.c */
-char *get_timestr __P((time_t, int));
-
-/* toke.l */
-#define YY_DECL int yylex __P((void))
-YY_DECL;
-
-/* zero_bytes.c */
-void zero_bytes                __P((volatile void *, size_t));
-
-/* Only provide extern declarations outside of sudo.c. */
-#ifndef _SUDO_MAIN
-extern struct sudo_user sudo_user;
-extern struct passwd *list_pw;
-
-extern int tgetpass_flags;
-extern int long_list;
-extern int sudo_mode;
-extern uid_t timestamp_uid;
-/* XXX - conflicts with the one in visudo */
-int run_command __P((const char *path, char *argv[], char *envp[], uid_t uid, int dowait));
-#endif
-#ifndef errno
-extern int errno;
-#endif
-
-#endif /* _SUDO_SUDO_H */
diff --git a/sudo.man.in b/sudo.man.in
deleted file mode 100644 (file)
index 09f1508..0000000
+++ /dev/null
@@ -1,803 +0,0 @@
-.\" Copyright (c) 1994-1996, 1998-2005, 2007-2010
-.\"    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.
-.\" 
-.\" 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.
-.\" 
-.nr SL @SEMAN@
-.nr BA @BAMAN@
-.nr LC @LCMAN@
-.nr PT @password_timeout@
-.\"
-.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.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 (.SS), 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 "SUDO @mansectsu@"
-.TH SUDO @mansectsu@ "April  9, 2011" "1.7.6" "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\-V\fR
-.PP
-\&\fBsudo\fR \fB\-v\fR [\fB\-AknS\fR]
-.if \n(BA [\fB\-a\fR\ \fIauth_type\fR]
-[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR]
-[\fB\-u\fR\ \fIusername\fR|\fI#uid\fR]
-.PP
-\&\fBsudo\fR \fB\-l[l]\fR [\fB\-AknS\fR]
-.if \n(BA [\fB\-a\fR\ \fIauth_type\fR]
-[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR]
-[\fB\-U\fR\ \fIuser\ name\fR] [\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR] [\fIcommand\fR]
-.PP
-\&\fBsudo\fR [\fB\-AbEHnPS\fR]
-.if \n(BA [\fB\-a\fR\ \fIauth_type\fR]
-[\fB\-C\fR\ \fIfd\fR]
-.if \n(LC [\fB\-c\fR\ \fIclass\fR|\fI\-\fR]
-[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR]
-.if \n(SL [\fB\-r\fR\ \fIrole\fR] [\fB\-t\fR\ \fItype\fR]
-[\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR]
-[\fB\s-1VAR\s0\fR=\fIvalue\fR] [\fB\-i\fR\ |\ \fB\-s\fR] [\fIcommand\fR]
-.PP
-\&\fBsudoedit\fR [\fB\-AnS\fR]
-.if \n(BA [\fB\-a\fR\ \fIauth_type\fR]
-[\fB\-C\fR\ \fIfd\fR]
-.if \n(LC [\fB\-c\fR\ \fIclass\fR|\fI\-\fR]
-[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR]
-[\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR] file ...
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBsudo\fR allows a permitted user to execute a \fIcommand\fR as the
-superuser or another user, as specified in the \fIsudoers\fR 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 \fB\-P\fR 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,
-\&\fBsudo\fR requires that users authenticate themselves with a password
-by default (\s-1NOTE:\s0 in the default configuration this is the user's
-password, not the root password).  Once a user has been authenticated,
-a time stamp is updated and the user may then use sudo without a
-password for a short period of time (\f(CW\*(C`@timeout@\*(C'\fR minutes unless
-overridden in \fIsudoers\fR).
-.PP
-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 running \fBsudo\fR with the \fB\-v\fR option,
-a user can update the time stamp without running a \fIcommand\fR.  If
-a password is required, \fBsudo\fR will exit if the user's password
-is not entered within a configurable time limit.  The default
-password prompt timeout is 
-.ie \n(PT \f(CW\*(C`@password_timeout@\*(C'\fR minutes.
-.el unlimited.
-.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 option.  This allows
-users to determine for themselves whether or not they are allowed
-to use \fBsudo\fR.
-.PP
-If \fBsudo\fR is run by root and the \f(CW\*(C`SUDO_USER\*(C'\fR environment variable
-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
-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
-\&\fBsudo\fR can log both successful and unsuccessful attempts (as well
-as errors) to \fIsyslog\fR\|(3), a log file, or both.  By default \fBsudo\fR
-will log via \fIsyslog\fR\|(3) but this is changeable at configure time
-or via the \fIsudoers\fR file.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-\&\fBsudo\fR accepts the following command line options:
-.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 (possibly graphical) 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.
-.if \n(BA \{\
-.IP "\-a \fItype\fR" 12
-.IX Item "-a type"
-The \fB\-a\fR (\fIauthentication type\fR) option causes \fBsudo\fR to use the
-specified authentication type when validating the user, as allowed
-by \fI/etc/login.conf\fR.  The system administrator may specify a list
-of sudo-specific authentication methods by adding an \*(L"auth-sudo\*(R"
-entry in \fI/etc/login.conf\fR.  This option is only available on systems
-that support \s-1BSD\s0 authentication.
-\}
-.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.
-.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@).
-.if \n(LC \{\
-.IP "\-c \fIclass\fR" 12
-.IX Item "-c class"
-The \fB\-c\fR (\fIclass\fR) option causes \fBsudo\fR to run the specified command
-with resources limited by the specified login class.  The \fIclass\fR
-argument can be either a class name as defined in \fI/etc/login.conf\fR,
-or a single '\-' character.  Specifying a \fIclass\fR of \f(CW\*(C`\-\*(C'\fR indicates
-that the command should be run restricted by the default login
-capabilities for the user the command is run as.  If the \fIclass\fR
-argument specifies an existing user class, the command must be run
-as root, or the \fBsudo\fR command must be run from a shell that is already
-root.  This option is only available on systems with \s-1BSD\s0 login classes.
-\}
-.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" 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 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`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 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
-the invoking user's environment unmodified.  If, for some reason,
-\&\fBsudo\fR 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.
-.RE
-.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@).  The default handling of the \f(CW\*(C`HOME\*(C'\fR environment
-variable depends on \fIsudoers\fR\|(@mansectform@) settings.  By default, \fBsudo\fR
-will set \f(CW\*(C`HOME\*(C'\fR if \fIenv_reset\fR or \fIalways_set_home\fR are set, or
-if \fIset_home\fR is set and the \fB\-s\fR option is specified on the
-command line.
-.IP "\-h" 12
-.IX Item "-h"
-The \fB\-h\fR (\fIhelp\fR) option causes \fBsudo\fR to print a short help message
-to the standard output and exit.
-.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 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-1MAIL\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 time stamp entirely and may not be used in conjunction
-with a command or other option.  This option does not require a
-password.
-.IP "\-k" 12
-.IX Item "-k"
-When used by itself, the \fB\-k\fR (\fIkill\fR) option to \fBsudo\fR invalidates
-the user's time stamp 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.
-.Sp
-When used in conjunction with a command or an option that may require
-a password, the \fB\-k\fR option will cause \fBsudo\fR to ignore the user's
-time stamp file.  As a result, \fBsudo\fR will prompt for a password
-(if one is required by \fIsudoers\fR) and will not update the user's
-time stamp file.
-.IP "\-L" 12
-.IX Item "-L"
-The \fB\-L\fR (\fIlist\fR defaults) option will list the parameters that
-may be set in a \fIDefaults\fR line along with a short description for
-each.  This option will be removed from a future version of \fBsudo\fR.
-.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 \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 12
-.ie n .IP "%H" 4
-.el .IP "\f(CW%H\fR" 4
-.IX Item "%H"
-expanded to the local host name including the domain name
-(on if the machine's host name is fully qualified or the \fIfqdn\fR
-\&\fIsudoers\fR option is set)
-.ie n .IP "%h" 4
-.el .IP "\f(CW%h\fR" 4
-.IX Item "%h"
-expanded to the local host name without the domain name
-.ie n .IP "%p" 4
-.el .IP "\f(CW%p\fR" 4
-.IX Item "%p"
-expanded to the user whose password is being asked for (respects the
-\&\fIrootpw\fR, \fItargetpw\fR and \fIrunaspw\fR flags in \fIsudoers\fR)
-.ie n .IP "%U" 4
-.el .IP "\f(CW%U\fR" 4
-.IX Item "%U"
-expanded to the login name of the user the command will
-be run as (defaults to root)
-.ie n .IP "%u" 4
-.el .IP "\f(CW%u\fR" 4
-.IX Item "%u"
-expanded to the invoking user's login name
-.ie n .IP "\*(C`%%\*(C'" 4
-.el .IP "\f(CW\*(C`%%\*(C'\fR" 4
-.IX Item "%%"
-two consecutive \f(CW\*(C`%\*(C'\fR characters are collapsed into a single \f(CW\*(C`%\*(C'\fR character
-.RE
-.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
-.if \n(SL \{\
-.IP "\-r \fIrole\fR" 12
-.IX Item "-r role"
-The \fB\-r\fR (\fIrole\fR) option causes the new (SELinux) security context to
-have the role specified by \fIrole\fR.
-\}
-.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.  The password must
-be followed by a newline character.
-.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@).  If a command is specified, it is passed to the shell
-for execution.  Otherwise, an interactive shell is executed.
-.if \n(SL \{\
-.IP "\-t \fItype\fR" 12
-.IX Item "-t type"
-The \fB\-t\fR (\fItype\fR) option causes the new (SELinux) security context to
-have the type specified by \fItype\fR.  If no type is specified, the default
-type is derived from the specified role.
-\}
-.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 \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" 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" 12
-.IX Item "-v"
-If given the \fB\-v\fR (\fIvalidate\fR) option, \fBsudo\fR will update the
-user's time stamp, 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 "\-\-" 12
-The \fB\-\-\fR option indicates that \fBsudo\fR should stop processing command
-line arguments.
-.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.
-\&\fB\s-1LD_LIBRARY_PATH\s0\fR=\fI/usr/local/pkg/lib\fR.  Variables passed on the
-command line are subject to the same restrictions as normal environment
-variables with one important exception.  If the \fIsetenv\fR option
-is set in \fIsudoers\fR, the command to be run has the \f(CW\*(C`SETENV\*(C'\fR tag
-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 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
-given command.  In the latter case the error string is printed to
-stderr.  If \fBsudo\fR cannot \fIstat\fR\|(2) one or more entries in the user's
-\&\f(CW\*(C`PATH\*(C'\fR 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 \fIstat\fR\|(2) to return
-\&\*(L"permission denied\*(R" is if you are running an automounter and one
-of the directories in your \f(CW\*(C`PATH\*(C'\fR is on a machine that is currently
-unreachable.
-.SH "SECURITY NOTES"
-.IX Header "SECURITY NOTES"
-\&\fBsudo\fR tries to be safe when executing external commands.
-.PP
-There are two distinct ways to deal with environment variables.
-By default, the \fIenv_reset\fR \fIsudoers\fR option is enabled.
-This causes commands to be executed with a minimal environment
-containing \f(CW\*(C`TERM\*(C'\fR, \f(CW\*(C`PATH\*(C'\fR, \f(CW\*(C`HOME\*(C'\fR, \f(CW\*(C`SHELL\*(C'\fR, \f(CW\*(C`LOGNAME\*(C'\fR, \f(CW\*(C`USER\*(C'\fR
-and \f(CW\*(C`USERNAME\*(C'\fR in addition to variables from the invoking process
-permitted by the \fIenv_check\fR and \fIenv_keep\fR \fIsudoers\fR options.
-There is effectively a whitelist for environment variables.
-.PP
-If, however, the \fIenv_reset\fR option is disabled in \fIsudoers\fR, any
-variables not explicitly denied by the \fIenv_check\fR and \fIenv_delete\fR
-options are inherited from the invoking process.  In this case,
-\&\fIenv_check\fR and \fIenv_delete\fR behave like a blacklist.  Since it
-is not possible to blacklist all potentially dangerous environment
-variables, use of the default \fIenv_reset\fR behavior is encouraged.
-.PP
-In all cases, environment variables with a value beginning with
-\&\f(CW\*(C`()\*(C'\fR are removed as they could be interpreted as \fBbash\fR functions.
-The list of environment variables that \fBsudo\fR allows or denies is
-contained in the output of \f(CW\*(C`sudo \-V\*(C'\fR when run as root.
-.PP
-Note that the dynamic linker on most operating systems will remove
-variables that can control dynamic linking from the environment of
-setuid executables, including \fBsudo\fR.  Depending on the operating
-system this may include \f(CW\*(C`_RLD*\*(C'\fR, \f(CW\*(C`DYLD_*\*(C'\fR, \f(CW\*(C`LD_*\*(C'\fR, \f(CW\*(C`LDR_*\*(C'\fR,
-\&\f(CW\*(C`LIBPATH\*(C'\fR, \f(CW\*(C`SHLIB_PATH\*(C'\fR, and others.  These type of variables are
-removed from the environment before \fBsudo\fR even begins execution
-and, as such, it is not possible for \fBsudo\fR to preserve them.
-.PP
-To prevent command spoofing, \fBsudo\fR checks \*(L".\*(R" and "" (both denoting
-current directory) last when searching for a command in the user's
-\&\s-1PATH\s0 (if one or both are in the \s-1PATH\s0).  Note, however, that the
-actual \f(CW\*(C`PATH\*(C'\fR environment variable is \fInot\fR modified and is passed
-unchanged to the program that \fBsudo\fR executes.
-.PP
-\&\fBsudo\fR will check the ownership of its time stamp directory
-(\fI@timedir@\fR 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
-\&\fIchown\fR\|(2), if the time stamp directory is located in a directory
-writable by anyone (e.g., \fI/tmp\fR), it is possible for a user to
-create the time stamp directory before \fBsudo\fR is run.  However,
-because \fBsudo\fR checks the ownership and mode of the directory and
-its contents, the only damage that can be done is to \*(L"hide\*(R" files
-by putting them in the time stamp dir.  This is unlikely to happen
-since once the time stamp 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 time stamps (\fI/var/adm/sudo\fR for
-instance) or create \fI@timedir@\fR with the appropriate owner (root)
-and permissions (0700) in the system startup files.
-.PP
-\&\fBsudo\fR will not honor time stamps set far in the future.
-Timestamps with a date greater than current_time + 2 * \f(CW\*(C`TIMEOUT\*(C'\fR
-will be ignored and sudo will log and complain.  This is done to
-keep a user from creating his/her own time stamp with a bogus
-date on systems that allow users to give away files.
-.PP
-On systems where the boot time is available, \fBsudo\fR will also not
-honor time stamps from before the machine booted.
-.PP
-Since time stamp files live in the file system, they can outlive a
-user's login session.  As a result, a user may be able to login,
-run a command with \fBsudo\fR after authenticating, logout, login
-again, and run \fBsudo\fR without authenticating so long as the time
-stamp file's modification time is within \f(CW\*(C`@timeout@\*(C'\fR minutes (or
-whatever the timeout is set to in \fIsudoers\fR).  When the \fItty_tickets\fR
-option is enabled in \fIsudoers\fR, the time stamp has per-tty granularity
-but still may outlive the user's session.  On Linux systems where
-the devpts filesystem is used, Solaris systems with the devices
-filesystem, as well as other systems that utilize a devfs filesystem
-that monotonically increase the inode number of devices as they are
-created (such as Mac \s-1OS\s0 X), \fBsudo\fR is able to determine when a
-tty-based time stamp file is stale and will ignore it.  Administrators
-should not rely on this feature as it is not universally available.
-.PP
-Please note that \fBsudo\fR will normally only log the command it
-explicitly runs.  If a user runs a command such as \f(CW\*(C`sudo su\*(C'\fR or
-\&\f(CW\*(C`sudo sh\*(C'\fR, subsequent commands run from that shell will \fInot\fR be
-logged, nor will \fBsudo\fR'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 \fBsudo\fR to verify that the command does not
-inadvertently give the user an effective root shell.  For more
-information, please see the \f(CW\*(C`PREVENTING SHELL ESCAPES\*(C'\fR section in
-\&\fIsudoers\fR\|(@mansectform@).
-.SH "ENVIRONMENT"
-.IX Header "ENVIRONMENT"
-\&\fBsudo\fR utilizes the following environment variables:
-.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 neither \f(CW\*(C`SUDO_EDITOR\*(C'\fR
-nor \f(CW\*(C`VISUAL\*(C'\fR is set
-.ie n .IP "\*(C`MAIL\*(C'" 16
-.el .IP "\f(CW\*(C`MAIL\*(C'\fR" 16
-.IX Item "MAIL"
-In \fB\-i\fR mode or when \fIenv_reset\fR is enabled in \fIsudoers\fR, set
-to the mail spool of the target user
-.ie n .IP "\*(C`HOME\*(C'" 16
-.el .IP "\f(CW\*(C`HOME\*(C'\fR" 16
-.IX Item "HOME"
-Set to the home directory of the target user if \fB\-i\fR or \fB\-H\fR are
-specified, \fIenv_reset\fR or \fIalways_set_home\fR are set in \fIsudoers\fR,
-or when the \fB\-s\fR option is specified and \fIset_home\fR is set in
-\&\fIsudoers\fR
-.ie n .IP "\*(C`PATH\*(C'" 16
-.el .IP "\f(CW\*(C`PATH\*(C'\fR" 16
-.IX Item "PATH"
-Set to a sane value if the \fIsecure_path\fR sudoers option is set.
-.ie n .IP "\*(C`SHELL\*(C'" 16
-.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_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_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 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 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"
-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 if \f(CW\*(C`SUDO_EDITOR\*(C'\fR
-is not set
-.SH "FILES"
-.IX Header "FILES"
-.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
-.ie n .IP "\fI@timedir@\fR" 24
-.el .IP "\fI@timedir@\fR" 24
-.IX Item "@timedir@"
-Directory containing time stamps
-.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.
-.PP
-To get a file listing of an unreadable directory:
-.PP
-.Vb 1
-\& $ sudo ls /usr/local/protected
-.Ve
-.PP
-To list the home directory of user yaz on a machine where the
-file system holding ~yaz is not exported as root:
-.PP
-.Vb 1
-\& $ sudo \-u yaz ls ~yaz
-.Ve
-.PP
-To edit the \fIindex.html\fR file as user www:
-.PP
-.Vb 1
-\& $ sudo \-u www vi ~www/htdocs/index.html
-.Ve
-.PP
-To view system logs only accessible to root and users in the adm group:
-.PP
-.Vb 1
-\& $ sudo \-g adm view /var/log/syslog
-.Ve
-.PP
-To run an editor as jim with a different primary group:
-.PP
-.Vb 1
-\& $ sudo \-u jim \-g audio vi ~jim/sound.txt
-.Ve
-.PP
-To shutdown a machine:
-.PP
-.Vb 1
-\& $ sudo shutdown \-r +15 "quick reboot"
-.Ve
-.PP
-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 \f(CW\*(C`cd\*(C'\fR and file redirection work.
-.PP
-.Vb 1
-\& $ sudo sh \-c "cd /home ; du \-s * | sort \-rn > USAGE"
-.Ve
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIgrep\fR\|(1), \fIsu\fR\|(1), \fIstat\fR\|(2),
-.if \n(LC \&\fIlogin_cap\fR\|(3),
-\&\fIpasswd\fR\|(@mansectform@), \fIsudoers\fR\|(5), \fIvisudo\fR\|(@mansectsu@)
-.SH "AUTHORS"
-.IX Header "AUTHORS"
-Many people have worked on \fBsudo\fR over the years; this
-version consists of code written primarily by:
-.PP
-.Vb 1
-\&        Todd C. Miller
-.Ve
-.PP
-See the \s-1HISTORY\s0 file in the \fBsudo\fR distribution or visit
-http://www.sudo.ws/sudo/history.html for a short history
-of \fBsudo\fR.
-.SH "CAVEATS"
-.IX Header "CAVEATS"
-There is no easy way to prevent a user from gaining a root shell
-if that user is allowed to run arbitrary commands via \fBsudo\fR.
-Also, many programs (such as editors) allow the user to run commands
-via shell escapes, thus avoiding \fBsudo\fR's checks.  However, on
-most systems it is possible to prevent shell escapes with \fBsudo\fR's
-\&\fInoexec\fR functionality.  See the \fIsudoers\fR\|(@mansectform@) manual
-for details.
-.PP
-It is not meaningful to run the \f(CW\*(C`cd\*(C'\fR command directly via sudo, e.g.,
-.PP
-.Vb 1
-\& $ sudo cd /usr/local/protected
-.Ve
-.PP
-since when the command exits the parent process (your shell) will
-still be the same.  Please see the \s-1EXAMPLES\s0 section for more information.
-.PP
-If users have sudo \f(CW\*(C`ALL\*(C'\fR 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.
-.PP
-Running shell scripts via \fBsudo\fR can expose the same kernel bugs that
-make setuid shell scripts unsafe on some operating systems (if your \s-1OS\s0
-has a /dev/fd/ directory, setuid shell scripts are generally safe).
-.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/sudo.man.pl b/sudo.man.pl
deleted file mode 100644 (file)
index e8e6125..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/perl -p
-
-BEGIN {
-    %tags = ( 'a', 'BA', 'c', 'LC', 'r', 'SL', 't', 'SL');
-    $cond = -1;
-}
-
-# Initialize the numeric register we use for conditionals
-if ($cond == -1) {
-    $_ = ".nr SL \@SEMAN\@\n.nr BA \@BAMAN\@\n.nr LC \@LCMAN\@\n.nr PT \@password_timeout\@\n.\\\"\n$_";
-    $cond = 0;
-}
-
-# Add conditionals
-if (/^\.IP.*-([acrt])/) {
-    $_ = ".if \\n($tags{$1} \\{\\\n$_";
-    $cond = 1;
-} elsif ($cond && /^\.(Sh|SS|IP|PP)/) {
-    $_ = "\\}\n$_";
-    $cond = 0;
-}
-
-if (/-a.*auth_type/) {
-    $_ = ".if \\n($tags{'a'} $_";
-} elsif (/(-c.*class.*\||login_cap)/) {
-    $_ = ".if \\n($tags{'c'} $_";
-} elsif (/-r.*role.*-t.*type/) {
-    $_ = ".if \\n($tags{'r'} $_";
-}
-
-# Fix up broken pod2man formatting of F<@foo@/bar>
-s/\\fI\\f(\(C)?I\@([^\@]*)\\fI\@/\\fI\@$2\@/g;
-
-# Try to deal sensibly with password_timeout being set to 0 by default
-s/([^ ]*\@password_timeout\@[^ ]* minutes.$)/\n.ie \\n(PT $1\n.el unlimited./;
diff --git a/sudo.pod b/sudo.pod
deleted file mode 100644 (file)
index 555274c..0000000
--- a/sudo.pod
+++ /dev/null
@@ -1,702 +0,0 @@
-Copyright (c) 1994-1996, 1998-2005, 2007-2010
-       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.
-
-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.
-
-=pod
-
-=head1 NAME
-
-sudo, sudoedit - execute a command as another user
-
-=head1 SYNOPSIS
-
-B<sudo> B<-h> | B<-K> | B<-k> | B<-L> | B<-V>
-
-B<sudo> B<-v> [B<-AknS>]
-S<[B<-a> I<auth_type>]>
-S<[B<-g> I<group name>|I<#gid>]> S<[B<-p> I<prompt>]>
-S<[B<-u> I<username>|I<#uid>]>
-
-B<sudo> B<-l[l]> [B<-AknS>]
-S<[B<-a> I<auth_type>]>
-S<[B<-g> I<group name>|I<#gid>]> S<[B<-p> I<prompt>]>
-S<[B<-U> I<user name>]> S<[B<-u> I<user name>|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<-g> I<group name>|I<#gid>]> S<[B<-p> I<prompt>]>
-S<[B<-r> I<role>]> S<[B<-t> I<type>]>
-S<[B<-u> I<user name>|I<#uid>]>
-S<[B<VAR>=I<value>]> S<[B<-i> | B<-s>]> [I<command>]
-
-B<sudoedit> [B<-AnS>]
-S<[B<-a> I<auth_type>]>
-S<[B<-C> I<fd>]>
-S<[B<-c> I<class>|I<->]>
-S<[B<-g> I<group name>|I<#gid>]> S<[B<-p> I<prompt>]>
-S<[B<-u> I<user name>|I<#uid>]> file ...
-
-=head1 DESCRIPTION
-
-B<sudo> allows a permitted user to execute a I<command> as the
-superuser or another user, as specified in the I<sudoers> file.
-The real and effective uid and gid are set to match those of the
-target user as specified in the passwd file and the group vector
-is initialized based on the group file (unless the B<-P> option was
-specified).  If the invoking user is root or if the target user is
-the same as the invoking user, no password is required.  Otherwise,
-B<sudo> 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 time stamp is updated and the user may then use sudo without a
-password for a short period of time (C<@timeout@> minutes unless
-overridden in I<sudoers>).
-
-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 running B<sudo> with the B<-v> option,
-a user can update the time stamp without running a I<command>.  If
-a password is required, B<sudo> will exit if the user's password
-is not entered within a configurable time limit.  The default
-password prompt timeout is C<@password_timeout@> minutes.
-
-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> option.  This allows
-users to determine for themselves whether or not they are allowed
-to use B<sudo>.
-
-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>
-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>.
-
-B<sudo> can log both successful and unsuccessful attempts (as well
-as errors) to syslog(3), a log file, or both.  By default B<sudo>
-will log via syslog(3) but this is changeable at configure time
-or via the I<sudoers> file.
-
-=head1 OPTIONS
-
-B<sudo> accepts the following command line options:
-
-=over 12
-
-=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 (possibly graphical) 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
-by F</etc/login.conf>.  The system administrator may specify a list
-of sudo-specific authentication methods by adding an "auth-sudo"
-entry in F</etc/login.conf>.  This option is only available on systems
-that support BSD authentication.
-
-=item -b
-
-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 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 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>
-argument specifies an existing user class, the command must be run
-as root, or the B<sudo> command must be run from a shell that is already
-root.  This option is only available on systems with BSD login classes.
-
-=item -E
-
-The B<-E> (I<preserve> I<environment>) option will override the
-I<env_reset> option in L<sudoers(5)>).  It is only
-available when either the matching command has the C<SETENV> tag
-or the I<setenv> option is set in L<sudoers(5)>.
-
-=item -e
-
-The B<-e> (I<edit>) option indicates that, instead of running
-a command, the user wishes to edit one or more files.  In lieu
-of a command, the string "sudoedit" is used when consulting
-the I<sudoers> file.  If the user is authorized by I<sudoers>
-the following steps are taken:
-
-=over 4
-
-=item 1.
-
-Temporary copies are made of the files to be edited with the owner
-set to the invoking user.
-
-=item 2.
-
-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.
-
-If they have been modified, the temporary files are copied back to
-their original location and the temporary versions are removed.
-
-=back
-
-If the specified file does not exist, it will be created.  Note
-that unlike most commands run by B<sudo>, the editor is run with
-the invoking user's environment unmodified.  If, for some reason,
-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
-to the homedir of the target user (root by default) as specified
-in passwd(5).  The default handling of the C<HOME> environment
-variable depends on L<sudoers(5)> settings.  By default, B<sudo>
-will set C<HOME> if I<env_reset> or I<always_set_home> are set, or
-if I<set_home> is set and the B<-s> option is specified on the
-command line.
-
-=item -h
-
-The B<-h> (I<help>) option causes B<sudo> to print a short help message
-to the standard output and exit.
-
-=item -i [command]
-
-The B<-i> (I<simulate initial login>) option runs the shell specified
-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<MAIL>, 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
-
-The B<-K> (sure I<kill>) option is like B<-k> except that it removes
-the user's time stamp entirely and may not be used in conjunction
-with a command or other option.  This option does not require a
-password.
-
-=item -k
-
-When used by itself, the B<-k> (I<kill>) option to B<sudo> invalidates
-the user's time stamp by setting the time on it to the Epoch.  The
-next time B<sudo> is run a password will be required.  This option
-does not require a password and was added to allow a user to revoke
-B<sudo> permissions from a .logout file.
-
-When used in conjunction with a command or an option that may require
-a password, the B<-k> option will cause B<sudo> to ignore the user's
-time stamp file.  As a result, B<sudo> will prompt for a password
-(if one is required by I<sudoers>) and will not update the user's
-time stamp file.
-
-=item -L
-
-The B<-L> (I<list> defaults) option will list the parameters that
-may be set in a I<Defaults> line along with a short description for
-each.  This option will be removed from a future version of B<sudo>.
-
-=item -l[l] [I<command>]
-
-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
-
-The B<-P> (I<preserve> I<group vector>) option causes B<sudo> to
-preserve the invoking user's group vector unaltered.  By default,
-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 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<%>')
-escapes are supported:
-
-=over 4
-
-=item C<%H>
-
-expanded to the local host name including the domain name
-(on if the machine's host name is fully qualified or the I<fqdn>
-I<sudoers> option is set)
-
-=item C<%h>
-
-expanded to the local host name without the domain name
-
-=item C<%p>
-
-expanded to the user whose password is being asked for (respects the
-I<rootpw>, I<targetpw> and I<runaspw> flags in I<sudoers>)
-
-=item C<%U>
-
-expanded to the login name of the user the command will
-be run as (defaults to root)
-
-=item C<%u>
-
-expanded to the invoking user's login name
-
-=item C<%%>
-
-two consecutive C<%> characters are collapsed into a single C<%> character
-
-=back
-
-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>.
-
-=item -S
-
-The B<-S> (I<stdin>) option causes B<sudo> to read the password from
-the standard input instead of the terminal device.  The password must
-be followed by a newline character.
-
-=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)>.  If a command is specified, it is passed to the shell
-for execution.  Otherwise, an interactive shell is executed.
-
-=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 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<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
-password database.
-
-=item -V
-
-The B<-V> (I<version>) option causes B<sudo> to print the version
-number and exit.  If the invoking user is already root the B<-V>
-option will print out a list of the defaults B<sudo> was compiled
-with as well as the machine's local network addresses.
-
-=item -v
-
-If given the B<-v> (I<validate>) option, B<sudo> will update the
-user's time stamp, prompting for the user's password if necessary.
-This extends the B<sudo> timeout for another C<@timeout@> minutes
-(or whatever the timeout is set to in I<sudoers>) but does not run
-a command.
-
-=item --
-
-The B<--> option indicates that B<sudo> should stop processing command
-line arguments.
-
-=back
-
-Environment variables to be set for the command may also be passed
-on the command line in the form of B<VAR>=I<value>, e.g.
-B<LD_LIBRARY_PATH>=I</usr/local/pkg/lib>.  Variables passed on the
-command line are subject to the same restrictions as normal environment
-variables with one important exception.  If the I<setenv> option
-is set in I<sudoers>, the command to be run has the C<SETENV> tag
-set or the command matched is C<ALL>, the user may set variables
-that would overwise be forbidden.  See L<sudoers(5)> for more information.
-
-=head1 RETURN VALUES
-
-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
-given command.  In the latter case the error string is printed to
-stderr.  If B<sudo> cannot L<stat(2)> one or more entries in the user's
-C<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 L<stat(2)> to return
-"permission denied" is if you are running an automounter and one
-of the directories in your C<PATH> is on a machine that is currently
-unreachable.
-
-=head1 SECURITY NOTES
-
-B<sudo> tries to be safe when executing external commands.
-
-There are two distinct ways to deal with environment variables.
-By default, the I<env_reset> I<sudoers> option is enabled.
-This causes commands to be executed with a minimal environment
-containing C<TERM>, C<PATH>, C<HOME>, C<SHELL>, C<LOGNAME>, C<USER>
-and C<USERNAME> in addition to variables from the invoking process
-permitted by the I<env_check> and I<env_keep> I<sudoers> options.
-There is effectively a whitelist for environment variables.
-
-If, however, the I<env_reset> option is disabled in I<sudoers>, any
-variables not explicitly denied by the I<env_check> and I<env_delete>
-options are inherited from the invoking process.  In this case,
-I<env_check> and I<env_delete> behave like a blacklist.  Since it
-is not possible to blacklist all potentially dangerous environment
-variables, use of the default I<env_reset> behavior is encouraged.
-
-In all cases, environment variables with a value beginning with
-C<()> are removed as they could be interpreted as B<bash> functions.
-The list of environment variables that B<sudo> allows or denies is
-contained in the output of C<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 B<sudo>.  Depending on the operating
-system this may include C<_RLD*>, C<DYLD_*>, C<LD_*>, C<LDR_*>,
-C<LIBPATH>, C<SHLIB_PATH>, and others.  These type of variables are
-removed from the environment before B<sudo> even begins execution
-and, as such, it is not possible for B<sudo> to preserve them.
-
-To prevent command spoofing, B<sudo> checks "." and "" (both denoting
-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 C<PATH> environment variable is I<not> modified and is passed
-unchanged to the program that B<sudo> executes.
-
-B<sudo> will check the ownership of its time stamp directory
-(F<@timedir@> 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
-L<chown(2)>, if the time stamp directory is located in a directory
-writable by anyone (e.g., F</tmp>), it is possible for a user to
-create the time stamp directory before B<sudo> is run.  However,
-because B<sudo> 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 time stamp dir.  This is unlikely to happen
-since once the time stamp 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 time stamps (F</var/adm/sudo> for
-instance) or create F<@timedir@> with the appropriate owner (root)
-and permissions (0700) in the system startup files.
-
-B<sudo> will not honor time stamps set far in the future.
-Timestamps with a date greater than current_time + 2 * C<TIMEOUT>
-will be ignored and sudo will log and complain.  This is done to
-keep a user from creating his/her own time stamp with a bogus
-date on systems that allow users to give away files.
-
-On systems where the boot time is available, B<sudo> will also not
-honor time stamps from before the machine booted.
-
-Since time stamp files live in the file system, they can outlive a
-user's login session.  As a result, a user may be able to login,
-run a command with B<sudo> after authenticating, logout, login
-again, and run B<sudo> without authenticating so long as the time
-stamp file's modification time is within C<@timeout@> minutes (or
-whatever the timeout is set to in I<sudoers>).  When the I<tty_tickets>
-option is enabled in I<sudoers>, the time stamp has per-tty granularity
-but still may outlive the user's session.  On Linux systems where
-the devpts filesystem is used, Solaris systems with the devices
-filesystem, as well as other systems that utilize a devfs filesystem
-that monotonically increase the inode number of devices as they are
-created (such as Mac OS X), B<sudo> is able to determine when a
-tty-based time stamp file is stale and will ignore it.  Administrators
-should not rely on this feature as it is not universally available.
-
-Please note that B<sudo> will normally only log the command it
-explicitly runs.  If a user runs a command such as C<sudo su> or
-C<sudo sh>, subsequent commands run from that shell will I<not> be
-logged, nor will B<sudo>'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 B<sudo> to verify that the command does not
-inadvertently give the user an effective root shell.  For more
-information, please see the C<PREVENTING SHELL ESCAPES> section in
-L<sudoers(5)>.
-
-=head1 ENVIRONMENT
-
-B<sudo> utilizes the following environment variables:
-
-=over 16
-
-=item C<EDITOR>
-
-Default editor to use in B<-e> (sudoedit) mode if neither C<SUDO_EDITOR>
-nor C<VISUAL> is set
-
-=item C<MAIL>
-
-In B<-i> mode or when I<env_reset> is enabled in I<sudoers>, set
-to the mail spool of the target user
-
-=item C<HOME>
-
-Set to the home directory of the target user if B<-i> or B<-H> are
-specified, I<env_reset> or I<always_set_home> are set in I<sudoers>,
-or when the B<-s> option is specified and I<set_home> is set in
-I<sudoers>
-
-=item C<PATH>
-
-Set to a sane value if the I<secure_path> sudoers option is set.
-
-=item C<SHELL>
-
-Used to determine shell to run with C<-s> option
-
-=item C<SUDO_ASKPASS>
-
-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_EDITOR>
-
-Default editor to use in B<-e> (sudoedit) mode
-
-=item C<SUDO_GID>
-
-Set to the group ID of the user who invoked sudo
-
-=item C<SUDO_PROMPT>
-
-Used as the default password prompt
-
-=item C<SUDO_PS1>
-
-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>
-
-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 if C<SUDO_EDITOR>
-is not set
-
-=back
-
-=head1 FILES
-
-=over 24
-
-=item F<@sysconfdir@/sudoers>
-
-List of who can run what
-
-=item F<@timedir@>
-
-Directory containing time stamps
-
-=item F</etc/environment>
-
-Initial environment for B<-i> mode on Linux and AIX
-
-=back
-
-=head1 EXAMPLES
-
-Note: the following examples assume suitable L<sudoers(5)> entries.
-
-To get a file listing of an unreadable directory:
-
- $ sudo ls /usr/local/protected
-
-To list the home directory of user yaz on a machine where the
-file system holding ~yaz is not exported as root:
-
- $ sudo -u yaz ls ~yaz
-
-To edit the F<index.html> file as user www:
-
- $ sudo -u www vi ~www/htdocs/index.html
-
-To view system logs only accessible to root and users in the adm group:
-
- $ sudo -g adm view /var/log/syslog
-
-To run an editor as jim with a different primary group:
-
- $ sudo -u jim -g audio vi ~jim/sound.txt
-
-To shutdown a machine:
-
- $ 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 C<cd> and file redirection work.
-
- $ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE"
-
-=head1 SEE ALSO
-
-L<grep(1)>, L<su(1)>, L<stat(2)>,
-L<login_cap(3)>,
-L<passwd(5)>, L<sudoers(5)>, L<visudo(8)>
-
-=head1 AUTHORS
-
-Many people have worked on B<sudo> over the years; this
-version consists of code written primarily by:
-
-       Todd C. Miller
-
-See the HISTORY file in the B<sudo> distribution or visit
-http://www.sudo.ws/sudo/history.html for a short history
-of B<sudo>.
-
-=head1 CAVEATS
-
-There is no easy way to prevent a user from gaining a root shell
-if that user is allowed to run arbitrary commands via B<sudo>.
-Also, many programs (such as editors) allow the user to run commands
-via shell escapes, thus avoiding B<sudo>'s checks.  However, on
-most systems it is possible to prevent shell escapes with B<sudo>'s
-I<noexec> functionality.  See the L<sudoers(5)> manual
-for details.
-
-It is not meaningful to run the C<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.
-
-If users have sudo C<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 B<sudo> 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).
-
-=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.
diff --git a/sudo.pp b/sudo.pp
index 35c18b7b80e3148efd0ac48c551c8e67e19799f9..6b9cd926807a4201e72e4c86d9a80853c1919cd2 100644 (file)
--- a/sudo.pp
+++ b/sudo.pp
@@ -181,6 +181,7 @@ still allow people to get their work done."
        $bindir/sudoedit    4111 root:
        $sbindir/visudo     0111
        $bindir/sudoreplay  0111
+       $includedir/sudo_plugin.h
        $libexecdir/*
        $sudoersdir/sudoers.d/  0750 $sudoers_uid:$sudoers_gid
        $timedir/               0700 root:
diff --git a/sudo_edit.c b/sudo_edit.c
deleted file mode 100644 (file)
index f8666d9..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * Copyright (c) 2004-2008, 2010 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>
-
-#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID)
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#include <sys/socket.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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <ctype.h>
-#include <grp.h>
-#include <pwd.h>
-#include <signal.h>
-#include <errno.h>
-#include <fcntl.h>
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-
-#include "sudo.h"
-
-static char *find_editor __P((int *argc_out, char ***argv_out));
-
-extern char **NewArgv; /* XXX */
-
-/*
- * Wrapper to allow users to edit privileged files with their own uid.
- */
-int
-sudo_edit(argc, argv, envp)
-    int argc;
-    char *argv[];
-    char *envp[];
-{
-    ssize_t nread, nwritten;
-    const char *tmpdir;
-    char *cp, *suff, **nargv, *editor, **files;
-    char **editor_argv = NULL;
-    char buf[BUFSIZ];
-    int rc, i, j, ac, ofd, tfd, nargc, rval, nfiles, tmplen;
-    int editor_argc = 0;
-    struct stat sb;
-    struct timeval tv, tv1, tv2;
-    struct tempfile {
-       char *tfile;
-       char *ofile;
-       struct timeval omtim;
-       off_t osize;
-    } *tf;
-
-    /* Determine user's editor. */
-    editor = find_editor(&editor_argc, &editor_argv);
-    if (editor == NULL)
-       return 1;
-
-    /*
-     * Find our temporary directory, one of /var/tmp, /usr/tmp, or /tmp
-     */
-    if (stat(_PATH_VARTMP, &sb) == 0 && S_ISDIR(sb.st_mode))
-       tmpdir = _PATH_VARTMP;
-#ifdef _PATH_USRTMP
-    else if (stat(_PATH_USRTMP, &sb) == 0 && S_ISDIR(sb.st_mode))
-       tmpdir = _PATH_USRTMP;
-#endif
-    else
-       tmpdir = _PATH_TMP;
-    tmplen = strlen(tmpdir);
-    while (tmplen > 0 && tmpdir[tmplen - 1] == '/')
-       tmplen--;
-
-    /*
-     * For each file specified by the user, make a temporary version
-     * and copy the contents of the original to it.
-     */
-    files = argv + 1;
-    nfiles = argc - 1;
-    tf = emalloc2(nfiles, sizeof(*tf));
-    zero_bytes(tf, nfiles * sizeof(*tf));
-    for (i = 0, j = 0; i < nfiles; i++) {
-       rc = -1;
-       set_perms(PERM_RUNAS);
-       if ((ofd = open(files[i], O_RDONLY, 0644)) != -1 || errno == ENOENT) {
-           if (ofd == -1) {
-               zero_bytes(&sb, sizeof(sb));            /* new file */
-               rc = 0;
-           } else {
-#ifdef HAVE_FSTAT
-               rc = fstat(ofd, &sb);
-#else
-               rc = stat(tf[j].ofile, &sb);
-#endif
-           }
-       }
-       set_perms(PERM_ROOT);
-       if (rc || (ofd != -1 && !S_ISREG(sb.st_mode))) {
-           if (rc)
-               warning("%s", files[i]);
-           else
-               warningx("%s: not a regular file", files[i]);
-           if (ofd != -1)
-               close(ofd);
-           continue;
-       }
-       tf[j].ofile = files[i];
-       tf[j].osize = sb.st_size;
-       mtim_get(&sb, &tf[j].omtim);
-       if ((cp = strrchr(tf[j].ofile, '/')) != NULL)
-           cp++;
-       else
-           cp = tf[j].ofile;
-       suff = strrchr(cp, '.');
-       if (suff != NULL) {
-           easprintf(&tf[j].tfile, "%.*s/%.*sXXXXXXXX%s", tmplen, tmpdir, (int)(size_t)(suff - cp), cp, suff);
-       } else {
-           easprintf(&tf[j].tfile, "%.*s/%s.XXXXXXXX", tmplen, tmpdir, cp);
-       }
-       set_perms(PERM_USER);
-       tfd = mkstemps(tf[j].tfile, suff ? strlen(suff) : 0);
-       set_perms(PERM_ROOT);
-       if (tfd == -1) {
-           warning("mkstemps");
-           goto cleanup;
-       }
-       if (ofd != -1) {
-           while ((nread = read(ofd, buf, sizeof(buf))) != 0) {
-               if ((nwritten = write(tfd, buf, nread)) != nread) {
-                   if (nwritten == -1)
-                       warning("%s", tf[j].tfile);
-                   else
-                       warningx("%s: short write", tf[j].tfile);
-                   goto cleanup;
-               }
-           }
-           close(ofd);
-       }
-       /*
-        * We always update the stashed mtime because the time
-        * resolution of the filesystem the temporary file is on may
-        * not match that of the filesystem where the file to be edited
-        * resides.  It is OK if touch() fails since we only use the info
-        * to determine whether or not a file has been modified.
-        */
-       (void) touch(tfd, NULL, &tf[j].omtim);
-#ifdef HAVE_FSTAT
-       rc = fstat(tfd, &sb);
-#else
-       rc = stat(tf[j].tfile, &sb);
-#endif
-       if (!rc)
-           mtim_get(&sb, &tf[j].omtim);
-       close(tfd);
-       j++;
-    }
-    if ((nfiles = j) == 0)
-       return 1;                       /* no files readable, you lose */
-
-    /*
-     * Allocate space for the new argument vector and fill it in.
-     * We concatenate the editor with its args and the file list
-     * to create a new argv.
-     * We allocate an extra slot to be used if execve() fails.
-     */
-    nargc = editor_argc + nfiles;
-    nargv = (char **) emalloc2(1 + nargc + 1, sizeof(char *));
-    nargv++;
-    for (ac = 0; ac < editor_argc; ac++)
-       nargv[ac] = editor_argv[ac];
-    for (i = 0; i < nfiles && ac < nargc; )
-       nargv[ac++] = tf[i++].tfile;
-    nargv[ac] = NULL;
-
-    /*
-     * Run the editor with the invoking user's creds,
-     * keeping track of the time spent in the editor.
-     */
-    gettime(&tv1);
-    rval = run_command(editor, nargv, envp, user_uid, TRUE);
-    gettime(&tv2);
-
-    /* Copy contents of temp files to real ones */
-    for (i = 0; i < nfiles; i++) {
-       rc = -1;
-       set_perms(PERM_USER);
-       if ((tfd = open(tf[i].tfile, O_RDONLY, 0644)) != -1) {
-#ifdef HAVE_FSTAT
-           rc = fstat(tfd, &sb);
-#else
-           rc = stat(tf[i].tfile, &sb);
-#endif
-       }
-       set_perms(PERM_ROOT);
-       if (rc || !S_ISREG(sb.st_mode)) {
-           if (rc)
-               warning("%s", tf[i].tfile);
-           else
-               warningx("%s: not a regular file", tf[i].tfile);
-           warningx("%s left unmodified", tf[i].ofile);
-           if (tfd != -1)
-               close(tfd);
-           continue;
-       }
-       mtim_get(&sb, &tv);
-       if (tf[i].osize == sb.st_size && timevalcmp(&tf[i].omtim, &tv, ==)) {
-           /*
-            * If mtime and size match but the user spent no measurable
-            * time in the editor we can't tell if the file was changed.
-            */
-           timevalsub(&tv1, &tv2);
-           if (timevalisset(&tv2)) {
-               warningx("%s unchanged", tf[i].ofile);
-               unlink(tf[i].tfile);
-               close(tfd);
-               continue;
-           }
-       }
-       set_perms(PERM_RUNAS);
-       ofd = open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT, 0644);
-       set_perms(PERM_ROOT);
-       if (ofd == -1) {
-           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)
-                   warning("%s", tf[i].ofile);
-               else
-                   warningx("%s: short write", tf[i].ofile);
-               break;
-           }
-       }
-       if (nread == 0) {
-           /* success, got EOF */
-           unlink(tf[i].tfile);
-       } else if (nread < 0) {
-           warning("unable to read temporary file");
-           warningx("contents of edit session left in %s", tf[i].tfile);
-       } else {
-           warning("unable to write to %s", tf[i].ofile);
-           warningx("contents of edit session left in %s", tf[i].tfile);
-       }
-       close(ofd);
-    }
-
-    return rval;
-cleanup:
-    /* Clean up temp files and return. */
-    for (i = 0; i < nfiles; i++) {
-       if (tf[i].tfile != NULL)
-           unlink(tf[i].tfile);
-    }
-    return 1;
-}
-
-static char *
-resolve_editor(editor, argc_out, argv_out)
-    char *editor;
-    int *argc_out;
-    char ***argv_out;
-{
-    char *cp, **nargv, *editor_path = NULL;
-    int ac, nargc, wasblank;
-
-    editor = estrdup(editor); /* becomes part of argv_out */
-
-    /*
-     * Split editor into an argument vector; editor is reused (do not free).
-     * The EDITOR and VISUAL environment variables may contain command
-     * line args so look for those and alloc space for them too.
-     */
-    nargc = 1;
-    for (wasblank = FALSE, cp = editor; *cp != '\0'; cp++) {
-       if (isblank((unsigned char) *cp))
-           wasblank = TRUE;
-       else if (wasblank) {
-           wasblank = FALSE;
-           nargc++;
-       }
-    }
-    /* If we can't find the editor in the user's PATH, give up. */
-    cp = strtok(editor, " \t");
-    if (cp == NULL ||
-       find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) {
-       efree(editor);
-       return NULL;
-    }
-    nargv = (char **) emalloc2(nargc + 1, sizeof(char *));
-    for (ac = 0; cp != NULL && ac < nargc; ac++) {
-       nargv[ac] = cp;
-       cp = strtok(NULL, " \t");
-    }
-    nargv[ac] = NULL;
-
-    *argc_out = nargc;
-    *argv_out = nargv;
-    return editor_path;
-}
-
-/*
- * Determine which editor to use.  We don't need to worry about restricting
- * this to a "safe" editor since it runs with the uid of the invoking user,
- * not the runas (privileged) user.
- * Fills in argv_out with an argument vector suitable for execve() that
- * includes the editor with the specified files.
- */
-static char *
-find_editor(argc_out, argv_out)
-    int *argc_out;
-    char ***argv_out;
-{
-    char *cp, *editor, *editor_path = NULL, **ev, *ev0[4];
-
-    /*
-     * If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one.
-     */
-    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') {
-           editor_path = resolve_editor(editor, argc_out, argv_out);
-           if (editor_path != NULL)
-               break;
-       }
-    }
-    if (editor_path == NULL) {
-       /* def_editor could be a path, split it up */
-       editor = estrdup(def_editor);
-       cp = strtok(editor, ":");
-       while (cp != NULL && editor_path == NULL) {
-           editor_path = resolve_editor(cp, argc_out, argv_out);
-           cp = strtok(NULL, ":");
-       }
-       if (editor_path)
-           efree(editor);
-    }
-    if (!editor_path) {
-       audit_failure(NewArgv, "%s: command not found", editor);
-       warningx("%s: command not found", editor);
-    }
-    return editor_path;
-}
-
-#else /* HAVE_SETRESUID || HAVE_SETREUID || HAVE_SETEUID */
-
-/*
- * Must have the ability to change the effective uid to use sudoedit.
- */
-int
-sudo_edit(argc, argv, envp)
-    int argc;
-    char *argv[];
-    char *envp[];
-{
-    return 1;
-}
-
-#endif /* HAVE_SETRESUID || HAVE_SETREUID || HAVE_SETEUID */
diff --git a/sudo_exec.h b/sudo_exec.h
deleted file mode 100644 (file)
index ea43d55..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2010 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.
- */
-
-#ifndef _SUDO_EXEC_H
-#define _SUDO_EXEC_H
-
-/*
- * Special values to indicate whether continuing in foreground or background.
- */
-#define SIGCONT_FG     -2
-#define SIGCONT_BG     -3
-
-/*
- * Symbols shared between exec.c and exec_pty.c
- */
-
-/* exec.c */
-int my_execve __P((const char *path, char *argv[], char *envp[]));
-int pipe_nonblock __P((int fds[2]));
-
-/* exec_pty.c */
-int fork_pty __P((const char *path, char *argv[], char *envp[], int sv[],
-    int rbac_enabled, int *maxfd));
-int perform_io __P((fd_set *fdsr, fd_set *fdsw, struct command_status *cstat));
-int suspend_parent __P((int signo));
-void fd_set_iobs __P((fd_set *fdsr, fd_set *fdsw));
-RETSIGTYPE handler __P((int s));
-void pty_close __P((struct command_status *cstat));
-void pty_setup __P((uid_t uid));
-extern int signal_pipe[2];
-
-#endif /* _SUDO_EXEC_H */
diff --git a/sudo_noexec.c b/sudo_noexec.c
deleted file mode 100644 (file)
index ba180b5..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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 <config.h>
-
-#include <sys/types.h>
-
-#include <errno.h>
-#ifndef HAVE_TIMESPEC
-# include <time.h>
-#endif
-#ifdef __STDC__
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
-
-#include "missing.h"
-
-/*
- * Dummy versions of the execve() family of syscalls.  We don't need
- * to stub out all of them, just the ones that correspond to actual
- * system calls (which varies by OS).  Note that it is still possible
- * to access the real syscalls via the syscall() interface but very
- * few programs actually do that.
- */
-
-#ifndef errno
-extern int errno;
-#endif
-
-#define DUMMY_BODY                             \
-{                                              \
-    errno = EACCES;                            \
-    return -1;                                 \
-}
-
-#ifdef __STDC__
-
-#define DUMMY2(fn, t1, t2)                     \
-int                                            \
-fn(t1 a1, t2 a2)                               \
-DUMMY_BODY
-
-#define DUMMY3(fn, t1, t2, t3)                 \
-int                                            \
-fn(t1 a1, t2 a2, t3 a3)                                \
-DUMMY_BODY
-
-#define DUMMY_VA(fn, t1, t2)                   \
-int                                            \
-fn(t1 a1, t2 a2, ...)                          \
-DUMMY_BODY
-
-#else /* !__STDC__ */
-
-#define DUMMY2(fn, t1, t2)                     \
-int                                            \
-fn(a1, a2)                                     \
-t1 a1; t2 a2;                                  \
-DUMMY_BODY
-
-#define DUMMY3(fn, t1, t2, t3)                 \
-int                                            \
-fn(a1, a2, a3)                                 \
-t1 a1; t2 a2; t3 a3;                           \
-DUMMY_BODY
-
-#define DUMMY_VA(fn, t1, t2)                   \
-int                                            \
-fn(a1, a2, va_alist)                           \
-t1 a1; t2 a2; va_dcl                           \
-DUMMY_BODY
-
-#endif /* !__STDC__ */
-
-DUMMY_VA(execl, const char *, const char *)
-DUMMY_VA(_execl, const char *, const char *)
-DUMMY_VA(__execl, const char *, const char *)
-DUMMY_VA(execle, const char *, const char *)
-DUMMY_VA(_execle, const char *, const char *)
-DUMMY_VA(__execle, const char *, const char *)
-DUMMY_VA(execlp, const char *, const char *)
-DUMMY_VA(_execlp, const char *, const char *)
-DUMMY_VA(__execlp, const char *, const char *)
-DUMMY2(execv, const char *, char * const *)
-DUMMY2(_execv, const char *, char * const *)
-DUMMY2(__execv, const char *, char * const *)
-DUMMY2(execvp, const char *, char * const *)
-DUMMY2(_execvp, const char *, char * const *)
-DUMMY2(__execvp, const char *, char * const *)
-DUMMY3(execvP, const char *, const char *, char * const *)
-DUMMY3(_execvP, const char *, const char *, char * const *)
-DUMMY3(__execvP, const char *, const char *, char * const *)
-DUMMY3(execve, const char *, char * const *, char * const *)
-DUMMY3(_execve, const char *, char * const *, char * const *)
-DUMMY3(__execve, const char *, char * const *, char * const *)
-DUMMY3(fexecve, int , char * const *, char * const *)
-DUMMY3(_fexecve, int , char * const *, char * const *)
-DUMMY3(__fexecve, int , char * const *, char * const *)
diff --git a/sudo_nss.c b/sudo_nss.c
deleted file mode 100644 (file)
index 9630320..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * Copyright (c) 2007-2011 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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <grp.h>
-#include <ctype.h>
-
-#include "sudo.h"
-#include "lbuf.h"
-
-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_if_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 */
-
-# if defined(HAVE_LDAP) && defined(_PATH_NETSVC_CONF)
-
-/*
- * Read in /etc/netsvc.conf (like nsswitch.conf on AIX)
- * Returns a tail queue of matches.
- */
-struct sudo_nss_list *
-sudo_read_nss()
-{
-    FILE *fp;
-    char *cp, *ep;
-    int saw_files = FALSE;
-    int saw_ldap = FALSE;
-    int got_match = FALSE;
-    static struct sudo_nss_list snl;
-
-    if ((fp = fopen(_PATH_NETSVC_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", 7) != 0)
-           continue;
-       cp += 7;
-       while (isspace((unsigned char)*cp))
-           cp++;
-       if (*cp++ != '=')
-           continue;
-
-       /* Parse line */
-       for ((cp = strtok(cp, ",")); cp != NULL; (cp = strtok(NULL, ","))) {
-           /* Trim leading whitespace. */
-           while (isspace((unsigned char)*cp))
-               cp++;
-
-           if (!saw_files && strncasecmp(cp, "files", 5) == 0 &&
-               (isspace((unsigned char)cp[5]) || cp[5] == '\0')) {
-               tq_append(&snl, &sudo_nss_file);
-               got_match = TRUE;
-               ep = &cp[5];
-           } else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 &&
-               (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
-               tq_append(&snl, &sudo_nss_ldap);
-               got_match = TRUE;
-               ep = &cp[4];
-           } else {
-               got_match = FALSE;
-           }
-
-           /* check for = auth qualifier */
-           if (got_match && *ep) {
-               cp = ep;
-               while (isspace((unsigned char)*cp) || *cp == '=')
-                   cp++;
-               if (strncasecmp(cp, "auth", 4) == 0 &&
-                   (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
-                   tq_last(&snl)->ret_if_found = TRUE;
-               }
-           }
-       }
-       /* 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 /* !_PATH_NETSVC_CONF && !_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_NETSVC_CONF */
-
-#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) {
-# ifdef HAVE_SETAUTHDB
-       aix_setauthdb(pw->pw_name);
-# endif
-       if (initgroups(pw->pw_name, pw->pw_gid) == -1)
-           log_error(USE_ERRNO|MSG_ONLY, "can't reset group vector");
-       efree(user_groups);
-       user_groups = NULL;
-       if ((user_ngroups = getgroups(0, NULL)) > 0) {
-           user_groups = emalloc2(user_ngroups, sizeof(GETGROUPS_T));
-           if (getgroups(user_ngroups, user_groups) < 0)
-               log_error(USE_ERRNO|MSG_ONLY, "can't get group vector");
-       }
-# ifdef HAVE_SETAUTHDB
-       aix_restoreauthdb();
-# endif
-    }
-#endif /* HAVE_INITGROUPS && HAVE_GETGROUPS */
-}
-
-static int
-output(buf)
-    const char *buf;
-{
-    return fputs(buf, stdout);
-}
-
-/*
- * 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 defs, privs;
-    int count, olen;
-
-    /* Reset group vector so group matching works correctly. */
-    reset_groups(pw);
-
-    lbuf_init(&defs, output, 4, NULL);
-    lbuf_init(&privs, output, 4, NULL);
-
-    /* Display defaults from all sources. */
-    lbuf_append(&defs, "Matching Defaults entries for ", pw->pw_name,
-       " on this host:\n", NULL);
-    count = 0;
-    tq_foreach_fwd(snl, nss) {
-       count += nss->display_defaults(nss, pw, &defs);
-    }
-    if (count)
-       lbuf_append(&defs, "\n\n", NULL);
-    else
-       defs.len = 0;
-
-    /* Display Runas and Cmnd-specific defaults from all sources. */
-    olen = defs.len;
-    lbuf_append(&defs, "Runas and Command-specific defaults for ", pw->pw_name,
-       ":\n", NULL);
-    count = 0;
-    tq_foreach_fwd(snl, nss) {
-       count += nss->display_bound_defaults(nss, pw, &defs);
-    }
-    if (count)
-       lbuf_append(&defs, "\n\n", NULL);
-    else
-       defs.len = olen;
-
-    /* Display privileges from all sources. */
-    lbuf_append(&privs, "User ", pw->pw_name,
-       " may run the following commands on this host:\n", NULL);
-    count = 0;
-    tq_foreach_fwd(snl, nss) {
-       count += nss->display_privs(nss, pw, &privs);
-    }
-    if (count) {
-       lbuf_print(&defs);
-       lbuf_print(&privs);
-    } else {
-       printf("User %s is not allowed to run sudo on %s.\n", pw->pw_name,
-           user_shost);
-    }
-
-    lbuf_destroy(&defs);
-    lbuf_destroy(&privs);
-}
-
-/*
- * 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
deleted file mode 100644 (file)
index f036add..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2007-2009 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.
- */
-
-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;
-    short ret_if_found;
-    short ret_if_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
deleted file mode 100644 (file)
index b26e3ec..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2007-2009 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.
- */
-
-#ifndef _SUDO_USAGE_H
-#define _SUDO_USAGE_H
-
-void help __P((void)) __attribute__((__noreturn__));
-void usage __P((int));
-
-/*
- * Usage strings for sudo.  These are here because we
- * need to be able to substitute values from configure.
- */
-#define SUDO_USAGE1 " -h | -K | -k | -L | -V"
-#define SUDO_USAGE2 " -v [-AknS] @BSDAUTH_USAGE@[-g groupname|#gid] [-p prompt] [-u user name|#uid]"
-#define SUDO_USAGE3 " -l[l] [-AknS] @BSDAUTH_USAGE@[-g groupname|#gid] [-p prompt] [-U user name] [-u user name|#uid] [-g groupname|#gid] [command]"
-#define SUDO_USAGE4 " [-AbEHknPS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u user name|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] [<command>]"
-#define SUDO_USAGE5 " -e [-AknS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u user name|#uid] file ..."
-
-/*
- * Configure script arguments used to build sudo.
- */
-#define CONFIGURE_ARGS "@CONFIGURE_ARGS@"
-
-#endif /* _SUDO_USAGE_H */
diff --git a/sudoers.cat b/sudoers.cat
deleted file mode 100644 (file)
index 2a7a521..0000000
+++ /dev/null
@@ -1,1782 +0,0 @@
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-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).
-
-       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.
-
-   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_\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 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) may appear
-           zero 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).
-
-   A\bAl\bli\bia\bas\bse\bes\bs
-       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
-
-        Host_Alias ::= NAME '=' Host_List
-
-
-
-1.7.6                     April  9, 2011                        1
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-
-        Cmnd_Alias ::= NAME '=' Cmnd_List
-
-        NAME ::= [A-Z]([A-Z][0-9]_)*
-
-       Each _\ba_\bl_\bi_\ba_\bs definition is of the form
-
-        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 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.
-
-        User_List ::= User |
-                      User ',' User_List
-
-        User ::= '!'* user name |
-                 '!'* #uid |
-                 '!'* %group |
-                 '!'* %#gid |
-                 '!'* +netgroup |
-                 '!'* %:nonunix_group |
-                 '!'* %:#nonunix_gid |
-                 '!'* User_Alias
-
-       A User_List is made up of one or more user names, user ids (prefixed
-       with '#'), system group names and ids (prefixed with '%' and '%#'
-       respectively), netgroups (prefixed with '+'), non-Unix group names and
-       IDs (prefixed with '%:' and '%:#' respectively) 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.
-
-       A user name, uid, group, gid, netgroup, nonunix_group or nonunix_gid
-       may be enclosed in double quotes to avoid the need for escaping special
-       characters.  Alternately, special characters may be specified in
-       escaped hex mode, e.g. \x20 for space.  When using double quotes, any
-       prefix characters must be included inside the quotes.
-
-       The nonunix_group and nonunix_gid syntax depends on the underlying
-       implementation.  For instance, the QAS AD backend supports the
-       following formats:
-
-       +\bo   Group in the same domain: "Group Name"
-
-       +\bo   Group in any domain: "Group Name@FULLY.QUALIFIED.DOMAIN"
-
-       +\bo   Group SID: "S-1-2-34-5678901234-5678901234-5678901234-567"
-
-
-
-1.7.6                     April  9, 2011                        2
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-       Note that quotes around group names are optional.  Unquoted strings
-       must use a backslash (\) to escape spaces and special characters.  See
-       "Other special characters and reserved words" for a list of characters
-       that need to be escaped.
-
-        Runas_List ::= Runas_Member |
-                       Runas_Member ',' Runas_List
-
-        Runas_Member ::= '!'* user name |
-                         '!'* #uid |
-                         '!'* %group |
-                         '!'* %#gid |
-                         '!'* %:nonunix_group |
-                         '!'* %:#nonunix_gid |
-                         '!'* +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 user names 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 user names 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
-
-        Host ::= '!'* host name |
-                 '!'* ip_addr |
-                 '!'* network(/netmask)? |
-                 '!'* +netgroup |
-                 '!'* Host_Alias
-
-       A Host_List is made up of one or more host names, 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 host name may include
-       shell-style wildcards (see the Wildcards section below), but unless the
-       host name command on your machine returns the fully qualified host
-       name, you'll need to use the _\bf_\bq_\bd_\bn option for wildcards to be useful.
-       Note s\bsu\bud\bdo\bo only inspects actual network interfaces; this means that IP
-       address 127.0.0.1 (localhost) will never match.  Also, the host name
-       "localhost" will only match if that is the actual host name, which is
-       usually only the case for non-networked systems.
-
-        Cmnd_List ::= Cmnd |
-                      Cmnd ',' Cmnd_List
-
-        commandname ::= file name |
-
-
-
-1.7.6                     April  9, 2011                        3
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-                        file name args |
-                        file name '""'
-
-        Cmnd ::= '!'* commandname |
-                 '!'* directory |
-                 '!'* "sudoedit" |
-                 '!'* Cmnd_Alias
-
-       A Cmnd_List is a list of one or more commandnames, directories, and
-       other aliases.  A commandname is a fully qualified file name which may
-       include shell-style wildcards (see the Wildcards section below).  A
-       simple file name 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 path name 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.
-
-   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, 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
-
-        Parameter_List ::= Parameter |
-                           Parameter ',' Parameter_List
-
-        Parameter ::= Parameter '=' Value |
-                      Parameter '+=' Value |
-                      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
-
-
-
-1.7.6                     April  9, 2011                        4
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-       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.
-
-       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
-        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? SELinux_Spec? Tag_Spec* Cmnd
-
-        Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
-
-        SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
-
-        Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' |
-                      'SETENV:' | 'NOSETENV:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' |
-                      'LOG_OUTPUT:' | 'NOLOG_OUTPUT:')
-
-       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.
-
-       The basic structure of a user specification is `who where = (as_whom)
-       what'.  Let's break that down into its constituent parts:
-
-   R\bRu\bun\bna\bas\bs_\b_S\bSp\bpe\bec\bc
-       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.
-
-
-
-
-1.7.6                     April  9, 2011                        5
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-       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.,
-
-        $ 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:
-
-        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_\bl
-       and _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bl_\bp_\br_\bm as r\bro\boo\bot\bt.
-
-       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
-
-       Note that while the group portion of the Runas_Spec permits the user to
-       run as command with that group, it does not force the user to do so.
-       If no group is specified on the command line, the command will run with
-       the group listed in the target user's password database entry.  The
-       following would all be permitted by the sudoers entry above:
-
-        $ sudo -u operator /bin/ls
-        $ sudo -u operator -g operator /bin/ls
-        $ sudo -g operator /bin/ls
-
-       In the following example, user t\btc\bcm\bm may run commands that access a modem
-       device file with the dialer group.
-
-        tcm    boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \
-               /usr/local/bin/minicom
-
-       Note that in this example only the group will be set, the command still
-       runs as user t\btc\bcm\bm.  E.g.
-
-        $ sudo -g dialer /usr/bin/cu
-
-       Multiple users and groups may be present in a Runas_Spec, in which case
-       the user may select any combination of users and groups via the -\b-u\bu and
-       -\b-g\bg options.  In this example:
-
-        alan   ALL = (root, bin : operator, system) ALL
-
-       user a\bal\bla\ban\bn may run any command as either user root or bin, optionally
-       setting the group to operator or system.
-
-
-
-
-1.7.6                     April  9, 2011                        6
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-   S\bSE\bEL\bLi\bin\bnu\bux\bx_\b_S\bSp\bpe\bec\bc
-       On systems with SELinux support, _\bs_\bu_\bd_\bo_\be_\br_\bs entries may optionally have an
-       SELinux role and/or type associated with a command.  If a role or type
-       is specified with the command it will override any default values
-       specified in _\bs_\bu_\bd_\bo_\be_\br_\bs.  A role or type specified on the command line,
-       however, will supercede the values in _\bs_\bu_\bd_\bo_\be_\br_\bs.
-
-   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,
-       NOSETENV, LOG_INPUT, NOLOG_INPUT, LOG_OUTPUT and NOLOG_OUTPUT.  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:
-
-        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 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.
-
-       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.
-
-       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
-
-
-
-1.7.6                     April  9, 2011                        7
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-       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, the user may
-       disable the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option from the command line via the -\b-E\bE option.
-       Additionally, environment variables set on 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.  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 NOSETENV tag.
-
-       _\bL_\bO_\bG_\b__\bI_\bN_\bP_\bU_\bT _\ba_\bn_\bd _\bN_\bO_\bL_\bO_\bG_\b__\bI_\bN_\bP_\bU_\bT
-
-       These tags override the value of the _\bl_\bo_\bg_\b__\bi_\bn_\bp_\bu_\bt option on a per-command
-       basis.  For more information, see the description of _\bl_\bo_\bg_\b__\bi_\bn_\bp_\bu_\bt in the
-       "SUDOERS OPTIONS" section below.
-
-       _\bL_\bO_\bG_\b__\bO_\bU_\bT_\bP_\bU_\bT _\ba_\bn_\bd _\bN_\bO_\bL_\bO_\bG_\b__\bO_\bU_\bT_\bP_\bU_\bT
-
-       These tags override the value of the _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt option on a per-command
-       basis.  For more information, see the description of _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt in the
-       "SUDOERS OPTIONS" section below.
-
-   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 characters) to be
-       used in host names, path names 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 _\bg_\bl_\bo_\bb(3) and
-       _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3) routines.  Note that these are _\bn_\bo_\bt regular expressions.
-
-       *       Matches any set of zero or more characters.
-
-       ?       Matches any single character.
-
-       [...]   Matches any character in the specified range.
-
-       [!...]  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 "}".
-
-       POSIX character classes may also be used if your system's _\bg_\bl_\bo_\bb(3) and
-       _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3) functions support 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\:]]*
-
-       Would match any file name beginning with a letter.
-
-       Note that a forward slash ('/') will n\bno\bot\bt be matched by wildcards used
-       in the path name.  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:
-
-
-
-1.7.6                     April  9, 2011                        8
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-           /usr/bin/*
-
-       match _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bw_\bh_\bo but not _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn_\b/_\bX_\b1_\b1_\b/_\bx_\bt_\be_\br_\bm.
-
-   E\bEx\bxc\bce\bep\bpt\bti\bio\bon\bns\bs t\bto\bo w\bwi\bil\bld\bdc\bca\bar\brd\bd r\bru\bul\ble\bes\bs
-       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 command is not allowed to be run
-               with a\ban\bny\by arguments.
-
-   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
-       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 and #includedir
-       directives.
-
-       This can be used, for example, to keep a site-wide _\bs_\bu_\bd_\bo_\be_\br_\bs file in
-       addition to a local, per-machine file.  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 within
-       _\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:
-
-           #include /etc/sudoers.local
-
-       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.
-
-       The file name may include the %h escape, signifying the short form of
-       the host name.  I.e., if the machine's host name is "xerxes", then
-
-       #include /etc/sudoers.%h
-
-       will cause s\bsu\bud\bdo\bo to include the file _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bx_\be_\br_\bx_\be_\bs.
-
-       The #includedir directive can be used to create a _\bs_\bu_\bd_\bo_\b._\bd directory that
-       the system package manager can drop _\bs_\bu_\bd_\bo_\be_\br_\bs rules into as part of
-       package installation.  For example, given:
-
-       #includedir /etc/sudoers.d
-
-       s\bsu\bud\bdo\bo will read each file in _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bd, skipping file names that
-       end in ~ or contain a . character to avoid causing problems with
-       package manager or editor temporary/backup files.  Files are parsed in
-       sorted lexical order.  That is, _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bd_\b/_\b0_\b1_\b__\bf_\bi_\br_\bs_\bt will be parsed
-       before _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bd_\b/_\b1_\b0_\b__\bs_\be_\bc_\bo_\bn_\bd.  Be aware that because the sorting is
-       lexical, not numeric, _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bd_\b/_\b1_\b__\bw_\bh_\bo_\bo_\bp_\bs would be loaded a\baf\bft\bte\ber\br
-       _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs_\b._\bd_\b/_\b1_\b0_\b__\bs_\be_\bc_\bo_\bn_\bd.  Using a consistent number of leading zeroes
-       in the file names can be used to avoid such problems.
-
-       Note that unlike files included via #include, v\bvi\bis\bsu\bud\bdo\bo will not edit the
-
-
-
-1.7.6                     April  9, 2011                        9
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-       files in a #includedir directory unless one of them contains a syntax
-       error.  It is still possible to run v\bvi\bis\bsu\bud\bdo\bo with the -f flag to edit the
-       files directly.
-
-   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 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).
-
-       Long lines can be continued with a backslash ('\') as the last
-       character on the line.
-
-       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.
-
-       The following characters must be escaped with a backslash ('\') when
-       used as part of a word (e.g. a user name or host name): '!', '=', ':',
-       ',', '(', ')', '\'.
-
-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.
-
-       B\bBo\boo\bol\ble\bea\ban\bn F\bFl\bla\bag\bgs\bs:
-
-       always_set_home If enabled, 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.  Note that HOME
-                       is already set when the the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is
-                       enabled, so _\ba_\bl_\bw_\ba_\by_\bs_\b__\bs_\be_\bt_\b__\bh_\bo_\bm_\be is only effective for
-                       configurations where either _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt is disabled or
-                       HOME is present in the _\be_\bn_\bv_\b__\bk_\be_\be_\bp list.  This flag is _\bo_\bf_\bf
-                       by default.
-
-       authenticate    If set, users must authenticate themselves via a
-                       password (or other means of authentication) before they
-
-
-
-1.7.6                     April  9, 2011                       10
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-                       may run commands.  This default may be overridden via
-                       the PASSWD and NOPASSWD tags.  This flag is _\bo_\bn 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.
-
-       compress_io     If set, and s\bsu\bud\bdo\bo is configured to log a command's input
-                       or output, the I/O logs will be compressed using z\bzl\bli\bib\bb.
-                       This flag is _\bo_\bn by default when s\bsu\bud\bdo\bo is compiled with
-                       z\bzl\bli\bib\bb support.
-
-       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, MAIL, 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.
-
-       fast_glob       Normally, s\bsu\bud\bdo\bo uses the _\bg_\bl_\bo_\bb(3) function to do shell-
-                       style globbing when matching path names.  However,
-                       since it accesses the file system, _\bg_\bl_\bo_\bb(3) can take a
-                       long time to complete for some patterns, especially
-                       when the pattern references a network file system that
-                       is mounted on demand (automounted).  The _\bf_\ba_\bs_\bt_\b__\bg_\bl_\bo_\bb
-                       option causes s\bsu\bud\bdo\bo to use the _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3) function,
-                       which does not access the file system to do its
-                       matching.  The disadvantage of _\bf_\ba_\bs_\bt_\b__\bg_\bl_\bo_\bb is that it is
-                       unable to match relative path names such as _\b._\b/_\bl_\bs or
-                       _\b._\b._\b/_\bb_\bi_\bn_\b/_\bl_\bs.  This has security implications when path
-                       names that include globbing characters are used with
-                       the negation operator, '!', as such rules can be
-                       trivially bypassed.  As such, this option should not be
-                       used when _\bs_\bu_\bd_\bo_\be_\br_\bs contains rules that contain negated
-                       path names which include globbing characters.  This
-                       flag is _\bo_\bf_\bf by default.
-
-       fqdn            Set this flag if you want to put fully qualified host
-
-
-
-1.7.6                     April  9, 2011                       11
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-                       names 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 host name (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_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.
-
-       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.
-
-       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 host name will be logged in the (non-
-                       syslog) s\bsu\bud\bdo\bo log file.  This flag is _\bo_\bf_\bf by default.
-
-       log_input       If set, s\bsu\bud\bdo\bo will run the command in a _\bp_\bs_\be_\bu_\bd_\bo _\bt_\bt_\by and
-                       log all user input.  If the standard input is not
-                       connected to the user's tty, due to I/O redirection or
-                       because the command is part of a pipeline, that input
-                       is also captured and stored in a separate log file.
-
-                       Input is logged to the directory specified by the
-                       _\bi_\bo_\bl_\bo_\bg_\b__\bd_\bi_\br option (_\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo by default) using a
-                       unique session ID that is included in the normal s\bsu\bud\bdo\bo
-                       log line, prefixed with _\bT_\bS_\bI_\bD_\b=.
-
-                       Note that user input may contain sensitive information
-                       such as passwords (even if they are not echoed to the
-                       screen), which will be stored in the log file
-                       unencrypted.  In most cases, logging the command output
-                       via _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt is all that is required.
-
-
-
-1.7.6                     April  9, 2011                       12
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-       log_output      If set, s\bsu\bud\bdo\bo will run the command in a _\bp_\bs_\be_\bu_\bd_\bo _\bt_\bt_\by and
-                       log all output that is sent to the screen, similar to
-                       the _\bs_\bc_\br_\bi_\bp_\bt(1) command.  If the standard output or
-                       standard error is not connected to the user's tty, due
-                       to I/O redirection or because the command is part of a
-                       pipeline, that output is also captured and stored in
-                       separate log files.
-
-                       Output is logged to the directory specified by the
-                       _\bi_\bo_\bl_\bo_\bg_\b__\bd_\bi_\br option (_\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo by default) using a
-                       unique session ID that is included in the normal s\bsu\bud\bdo\bo
-                       log line, prefixed with _\bT_\bS_\bI_\bD_\b=.
-
-                       Output logs may be viewed with the _\bs_\bu_\bd_\bo_\br_\be_\bp_\bl_\ba_\by(1m)
-                       utility, which can also be used to list or search the
-                       available logs.
-
-       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.
-
-       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_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_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_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_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.
-
-       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.
-
-
-
-1.7.6                     April  9, 2011                       13
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-       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 password 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.
-
-       pwfeedback      By default, s\bsu\bud\bdo\bo reads the password like most other
-                       Unix programs, by turning off echo until the user hits
-                       the return (or enter) key.  Some users become confused
-                       by this as it appears to them that s\bsu\bud\bdo\bo has hung at
-                       this point.  When _\bp_\bw_\bf_\be_\be_\bd_\bb_\ba_\bc_\bk is set, s\bsu\bud\bdo\bo will provide
-                       visual feedback when the user presses a key.  Note that
-                       this does have a security impact as an onlooker may be
-                       able to determine the length of the password being
-                       entered.  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.  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 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.
-
-       runaspw         If set, s\bsu\bud\bdo\bo will prompt for the password of the user
-
-
-
-1.7.6                     April  9, 2011                       14
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-                       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.
-
-       set_home        If enabled 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.  Note that HOME is already set when
-                       the the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is enabled, so _\bs_\be_\bt_\b__\bh_\bo_\bm_\be is
-                       only effective for configurations where either
-                       _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt is disabled or HOME is present in the
-                       _\be_\bn_\bv_\b__\bk_\be_\be_\bp list.  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_\bn 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.
-
-       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.  In addition, the
-
-
-
-1.7.6                     April  9, 2011                       15
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-                       timestamp file name will include the target user's
-                       name.  Note that this flag 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.
-
-       tty_tickets     If set, users must authenticate on a per-tty basis.
-                       With this flag enabled, s\bsu\bud\bdo\bo will use a file named for
-                       the tty the user is logged in on in the user's time
-                       stamp directory.  If disabled, the time stamp of the
-                       directory is used instead.  This flag is _\bo_\bn by default.
-
-       umask_override  If set, s\bsu\bud\bdo\bo will set the umask as specified by _\bs_\bu_\bd_\bo_\be_\br_\bs
-                       without modification.  This makes it possible to
-                       specify a more permissive umask in _\bs_\bu_\bd_\bo_\be_\br_\bs than the
-                       user's own umask and matches historical behavior.  If
-                       _\bu_\bm_\ba_\bs_\bk_\b__\bo_\bv_\be_\br_\br_\bi_\bd_\be is not set, s\bsu\bud\bdo\bo will set the umask to
-                       be the union of the user's umask and what is specified
-                       in _\bs_\bu_\bd_\bo_\be_\br_\bs.  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.
-
-       use_pty         If set, s\bsu\bud\bdo\bo will run the command in a pseudo-pty even
-                       if no I/O logging is being gone.  A malicious program
-                       run under s\bsu\bud\bdo\bo could conceivably fork a background
-                       process that retains to the user's terminal device
-                       after the main program has finished executing.  Use of
-                       this option will make that impossible.
-
-       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:
-
-       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:
-
-
-
-
-1.7.6                     April  9, 2011                       16
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-       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, or 0 for no timeout.  The timeout may include a
-                       fractional component if minute granularity is
-                       insufficient, for example 2.5.  The default is 5.
-
-       timestamp_timeout
-                       Number of minutes that can elapse before s\bsu\bud\bdo\bo will ask
-                       for a passwd again.  The timeout may include a
-                       fractional component if minute granularity is
-                       insufficient, for example 2.5.  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 the value of the _\bu_\bm_\ba_\bs_\bk option, which
-                       defaults to 0022.  This guarantees that s\bsu\bud\bdo\bo 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 _\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
-                       possible, or the first editor in the list that exists
-                       and is executable.  The default is "vi".
-
-       iolog_dir       The directory in which to store input/output logs when
-                       the _\bl_\bo_\bg_\b__\bi_\bn_\bp_\bu_\bt or _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt options are enabled or when
-                       the LOG_INPUT or LOG_OUTPUT tags are present for a
-                       command.  The default is "/var/log/sudo-io".
-
-       mailsub         Subject of the mail sent to the _\bm_\ba_\bi_\bl_\bt_\bo user. The escape
-                       %h will expand to the host name of the machine.
-                       Default is *** SECURITY information for %h ***.
-
-       noexec_file     Path to a shared library containing dummy versions of
-
-
-
-1.7.6                     April  9, 2011                       17
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-                       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 (`%')
-                       escapes are supported:
-
-                       %H  expanded to the local host name including the
-                           domain name (on if the machine's host name is fully
-                           qualified or the _\bf_\bq_\bd_\bn option is set)
-
-                       %h  expanded to the local host name 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 collapsed into a
-                           single % character
-
-                       The default value is Password:.
-
-       role            The default SELinux role to use when constructing a new
-                       security context to run the command.  The default role
-                       may be overridden on a per-command basis in _\bs_\bu_\bd_\bo_\be_\br_\bs or
-                       via command line options.  This option is only
-                       available whe s\bsu\bud\bdo\bo is built with SELinux support.
-
-       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 authenticates
-                       unsuccessfully.  Defaults to alert.
-
-       syslog_goodpri  Syslog priority to use when user authenticates
-                       successfully.  Defaults to notice.
-
-       sudoers_locale  Locale to use when parsing the sudoers file, logging
-                       commands, and sending email.  Note that changing the
-                       locale may affect how sudoers is interpreted.  Defaults
-                       to "C".
-
-
-
-
-1.7.6                     April  9, 2011                       18
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-       timestampdir    The directory in which s\bsu\bud\bdo\bo stores its timestamp files.
-                       The default is _\b/_\bv_\ba_\br_\b/_\ba_\bd_\bm_\b/_\bs_\bu_\bd_\bo.
-
-       timestampowner  The owner of the timestamp directory and the timestamps
-                       stored therein.  The default is root.
-
-       type            The default SELinux type to use when constructing a new
-                       security context to run the command.  The default type
-                       may be overridden on a per-command basis in _\bs_\bu_\bd_\bo_\be_\br_\bs or
-                       via command line options.  This option is only
-                       available whe s\bsu\bud\bdo\bo is built with SELinux support.
-
-       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 either
-                   be of the form VARIABLE=value or export VARIABLE=value.
-                   The value may optionally be surrounded by single or double
-                   quotes.  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.
-
-       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.
-
-                   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.
-
-
-
-1.7.6                     April  9, 2011                       19
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-       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:
-
-                   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.
-
-                   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-l\bl
-                           option.
-
-                   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.
-
-       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.
-
-       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 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
-                   _\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
-                   option is not set by default.
-
-       syslog      Syslog facility if syslog is being used for logging (negate
-                   to disable syslog logging).  Defaults to auth.
-
-       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:
-
-
-
-1.7.6                     April  9, 2011                       20
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-                   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
-                           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 entering a password.
-
-                   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.
-
-       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 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 when the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is not in effect.
-                       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 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 =, +=,
-
-
-
-1.7.6                     April  9, 2011                       21
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-                       -=, 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
-
-       _\b/_\be_\bt_\bc_\b/_\bg_\br_\bo_\bu_\bp              Local groups file
-
-       _\b/_\be_\bt_\bc_\b/_\bn_\be_\bt_\bg_\br_\bo_\bu_\bp           List of network groups
-
-       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo        I/O log files
-
-E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
-       Below are example _\bs_\bu_\bd_\bo_\be_\br_\bs entries.  Admittedly, some of these are a bit
-       contrived.  First, we allow a few environment variables to pass and
-       then define our _\ba_\bl_\bi_\ba_\bs_\be_\bs:
-
-        # Run X applications through sudo; HOME is used to find the
-        # .Xauthority file.  Note that other programs use HOME to find
-        # configuration files and this may lead to privilege escalation!
-        Defaults env_keep += "DISPLAY HOME"
-
-        # User alias specification
-        User_Alias     FULLTIMERS = millert, mikef, dowdy
-        User_Alias     PARTTIMERS = bostley, jwfox, crawl
-        User_Alias     WEBMASTERS = will, wendy, wim
-
-        # Runas alias specification
-        Runas_Alias    OP = root, operator
-        Runas_Alias    DB = oracle, sybase
-        Runas_Alias    ADMINGRP = adm, oper
-
-        # Host alias specification
-        Host_Alias     SPARC = bigtime, eclipse, moet, anchor :\
-                       SGI = grolsch, dandelion, black :\
-                       ALPHA = widget, thalamus, foobar :\
-                       HPPA = boa, nag, python
-        Host_Alias     CUNETS = 128.138.0.0/255.255.0.0
-        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
-
-        # Cmnd alias specification
-        Cmnd_Alias     DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\
-                               /usr/sbin/restore, /usr/sbin/rrestore
-        Cmnd_Alias     KILL = /usr/bin/kill
-
-
-
-1.7.6                     April  9, 2011                       22
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-        Cmnd_Alias     PRINTING = /usr/sbin/lpc, /usr/bin/lprm
-        Cmnd_Alias     SHUTDOWN = /usr/sbin/shutdown
-        Cmnd_Alias     HALT = /usr/sbin/halt
-        Cmnd_Alias     REBOOT = /usr/sbin/reboot
-        Cmnd_Alias     SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \
-                                /usr/local/bin/tcsh, /usr/bin/rsh, \
-                                /usr/local/bin/zsh
-        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
-       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
-        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
-
-       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.
-
-        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
-
-       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
-
-
-
-1.7.6                     April  9, 2011                       23
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-       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).
-
-        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 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-Za-z]*, !/usr/bin/passwd root
-
-        %opers         ALL = (: ADMINGRP) /usr/sbin/
-
-       Users in the o\bop\bpe\ber\brs\bs group may run commands in _\b/_\bu_\bs_\br_\b/_\bs_\bb_\bi_\bn_\b/ as themselves
-       with any group in the _\bA_\bD_\bM_\bI_\bN_\bG_\bR_\bP Runas_Alias (the a\bad\bdm\bm and o\bop\bpe\ber\br groups).
-
-       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 user names 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
-
-       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.
-
-        john           ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
-
-
-
-
-1.7.6                     April  9, 2011                       24
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-       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.
-
-        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).
-
-        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_\bU
-       and _\bS_\bH_\bE_\bL_\bL_\bS Cmnd_Aliases.
-
-        steve          CSNETS = (operator) /usr/local/op_commands/
-
-       The user s\bst\bte\bev\bve\be may run any command in the directory
-       /usr/local/op_commands/ but only as user operator.
-
-        matt           valkyrie = KILL
-
-       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.
-
-        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.
-
-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 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 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).
-
-       Furthermore, if the _\bf_\ba_\bs_\bt_\b__\bg_\bl_\bo_\bb option is in use, it is not possible to
-       reliably negate commands where the path name includes globbing (aka
-
-
-
-1.7.6                     April  9, 2011                       25
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-       wildcard) characters.  This is because the C library's _\bf_\bn_\bm_\ba_\bt_\bc_\bh(3)
-       function cannot resolve relative paths.  While this is typically only
-       an inconvenience for rules that grant privileges, it can result in a
-       security issue for rules that subtract or revoke privileges.
-
-       For example, given the following _\bs_\bu_\bd_\bo_\be_\br_\bs entry:
-
-        john   ALL = /usr/bin/passwd [a-zA-Z0-9]*, /usr/bin/chsh [a-zA-Z0-9]*,
-             /usr/bin/chfn [a-zA-Z0-9]*, !/usr/bin/* root
-
-       User j\bjo\boh\bhn\bn can still run /usr/bin/passwd root if _\bf_\ba_\bs_\bt_\b__\bg_\bl_\bo_\bb is enabled by
-       changing to _\b/_\bu_\bs_\br_\b/_\bb_\bi_\bn and running ./passwd root instead.
-
-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,
-       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 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 is 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:
-
-                     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,
-
-
-
-1.7.6                     April  9, 2011                       26
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
-                 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 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.
-
-       Note that restricting shell escapes is not a panacea.  Programs running
-       as root are still capable of many potentially hazardous operations
-       (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), _\bg_\bl_\bo_\bb(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 host name in the netgroup (as is usually the case), you
-       either need to have the machine's host name 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/
-
-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.
-
-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.6                     April  9, 2011                       27
-
-
diff --git a/sudoers.in b/sudoers.in
deleted file mode 100644 (file)
index 42e639e..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-## sudoers file.
-##
-## This file MUST be edited with the 'visudo' command as root.
-## Failure to use 'visudo' may result in syntax or file permission errors
-## that prevent sudo from running.
-##
-## See the sudoers man page for the details on how to write a sudoers file.
-##
-
-##
-## Host alias specification
-##
-## Groups of machines. These may include host names (optionally with wildcards),
-## IP addresses, network numbers or netgroups.
-# Host_Alias   WEBSERVERS = www1, www2, www3
-
-##
-## User alias specification
-##
-## Groups of users.  These may consist of user names, uids, Unix groups,
-## or netgroups.
-# User_Alias   ADMINS = millert, dowdy, mikef
-
-##
-## Cmnd alias specification
-##
-## Groups of commands.  Often used to group related commands together.
-# Cmnd_Alias   PROCESSES = /usr/bin/nice, /bin/kill, /usr/bin/renice, \
-#                          /usr/bin/pkill, /usr/bin/top
-
-##
-## Defaults specification
-##
-## You may wish to keep some of the following environment variables
-## when running commands via sudo.
-##
-## Locale settings
-# Defaults env_keep += "LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET"
-##
-## Run X applications through sudo; HOME is used to find the
-## .Xauthority file.  Note that other programs use HOME to find   
-## configuration files and this may lead to privilege escalation!
-# Defaults env_keep += "HOME"
-##
-## X11 resource path settings
-# Defaults env_keep += "XAPPLRESDIR XFILESEARCHPATH XUSERFILESEARCHPATH"
-##
-## Desktop path settings
-# Defaults env_keep += "QTDIR KDEDIR"
-##
-## Allow sudo-run commands to inherit the callers' ConsoleKit session
-# Defaults env_keep += "XDG_SESSION_COOKIE"
-##
-## Uncomment to enable special input methods.  Care should be taken as
-## this may allow users to subvert the command being run via sudo.
-# Defaults env_keep += "XMODIFIERS GTK_IM_MODULE QT_IM_MODULE QT_IM_SWITCHER"
-##
-## Uncomment to enable logging of a command's output, except for
-## sudoreplay and reboot.  Use sudoreplay to play back logged sessions.
-# Defaults log_output
-# Defaults!/usr/bin/sudoreplay !log_output
-# Defaults!/usr/local/bin/sudoreplay !log_output
-# Defaults!/sbin/reboot !log_output
-
-##
-## Runas alias specification
-##
-
-##
-## User privilege specification
-##
-root ALL=(ALL) ALL
-
-## Uncomment to allow members of group wheel to execute any command
-# %wheel ALL=(ALL) ALL
-
-## Same thing without a password
-# %wheel ALL=(ALL) NOPASSWD: ALL
-
-## Uncomment to allow members of group sudo to execute any command
-# %sudo        ALL=(ALL) ALL
-
-## Uncomment to allow any user to run sudo if they know the password
-## of the user they are running the command as (root by default).
-# Defaults targetpw  # Ask for the password of the target user
-# ALL ALL=(ALL) ALL  # WARNING: only use this together with 'Defaults targetpw'
-
-## Read drop-in files from @sysconfdir@/sudoers.d
-## (the '#' here does not indicate a comment)
-#includedir @sysconfdir@/sudoers.d
diff --git a/sudoers.ldap.cat b/sudoers.ldap.cat
deleted file mode 100644 (file)
index 8b14333..0000000
+++ /dev/null
@@ -1,924 +0,0 @@
-
-
-
-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
-       LDAP.  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/_\be_\bt_\bc_\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/_\be_\bt_\bc_\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
-       Runas_Aliases.  Host netgroups can be used in place of Host_Aliases.
-       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
-       found, the multi-valued sudoOption attribute is parsed in the same
-
-
-
-1.7.6                     April  9, 2011                        1
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-       manner as a global Defaults line in _\b/_\be_\bt_\bc_\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 attributes:
-
-       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.
-
-           The sudoRunAsUser attribute is only available in s\bsu\bud\bdo\bo versions
-           1.7.0 and higher.  Older versions of s\bsu\bud\bdo\bo use the sudoRunAs
-           attribute instead.
-
-       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.
-
-           The sudoRunAsGroup attribute is only available in s\bsu\bud\bdo\bo versions
-           1.7.0 and higher.
-
-       s\bsu\bud\bdo\boN\bNo\bot\btB\bBe\bef\bfo\bor\bre\be
-           A timestamp in the form yyyymmddHHMMZ that can be used to provide a
-           start date/time for when the sudoRole will be valid.  If multiple
-           sudoNotBefore entries are present, the earliest is used.  Note that
-
-
-
-1.7.6                     April  9, 2011                        2
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-           timestamps must be in Coordinated Universal Time (UTC), not the
-           local timezone.
-
-           The sudoNotBefore attribute is only available in s\bsu\bud\bdo\bo versions
-           1.7.5 and higher and must be explicitly enabled via the
-           S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_T\bTI\bIM\bME\bED\bD option in _\b/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf.
-
-       s\bsu\bud\bdo\boN\bNo\bot\btA\bAf\bft\bte\ber\br
-           A timestamp in the form yyyymmddHHMMZ that indicates an expiration
-           date/time, after which the sudoRole will no longer be valid.  If
-           multiple sudoNotBefore entries are present, the last one is used.
-           Note that timestamps must be in Coordinated Universal Time (UTC),
-           not the local timezone.
-
-           The sudoNotAfter attribute is only available in s\bsu\bud\bdo\bo versions 1.7.5
-           and higher and must be explicitly enabled via the S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_T\bTI\bIM\bME\bED\bD
-           option in _\b/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf.
-
-       s\bsu\bud\bdo\boO\bOr\brd\bde\ber\br
-           The sudoRole entries retrieved from the LDAP directory have no
-           inherent order.  The sudoOrder attribute is an integer (or floating
-           point value for LDAP servers that support it) that is used to sort
-           the matching entries.  This allows LDAP-based sudoers entries to
-           more closely mimic the behaviour of the sudoers file, where the of
-           the entries influences the result.  If multiple entries match, the
-           entry with the highest sudoOrder attribute is chosen.  This
-           corresponds to the "last match" behavior of the sudoers file.  If
-           the sudoOrder attribute is not present, a value of 0 is assumed.
-
-           The sudoOrder attribute is only available in s\bsu\bud\bdo\bo versions 1.7.5
-           and higher.
-
-       Each attribute listed above should contain a single value, but there
-       may be multiple instances of each attribute 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:
-
-           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
-
-
-
-1.7.6                     April  9, 2011                        3
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-       see if the user belongs to any of them.
-
-       If timed entries are enabled with the S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_T\bTI\bIM\bME\bED\bD configuration
-       directive, the LDAP queries include a subfilter that limits retrieval
-       to entries that satisfy the time constraints, if any.
-
-   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.
-
-       The order in which different entries are applied can be controlled
-       using the sudoOrder attribute, but there is no way to guarantee the
-       order of attributes within a specific entry.  If there are conflicting
-       command rules in 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 ignored.  For example, the following attributes do not behave
-       the way one might expect.
-
-
-
-
-
-1.7.6                     April  9, 2011                        4
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-           # 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/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf 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/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf 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/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf as being
-       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
-           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.  Multiple U\bUR\bRI\bI lines are treated
-           identically to a U\bUR\bRI\bI line containing multiple entries.  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.
-
-
-
-1.7.6                     April  9, 2011                        5
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-       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.
-
-       N\bNE\bET\bTW\bWO\bOR\bRK\bK_\b_T\bTI\bIM\bME\bEO\bOU\bUT\bT seconds
-           An alias for B\bBI\bIN\bND\bD_\b_T\bTI\bIM\bME\bEL\bLI\bIM\bMI\bIT\bT for OpenLDAP compatibility.
-
-       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.
-
-       T\bTI\bIM\bME\bEO\bOU\bUT\bT seconds
-           The T\bTI\bIM\bME\bEO\bOU\bUT\bT parameter specifies the amount of time, in seconds, to
-           wait for a response from the various LDAP APIs.
-
-       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.  Multiple S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_B\bBA\bAS\bSE\bE lines may be specified, in
-           which case they are queried in the order specified.
-
-       S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_S\bSE\bEA\bAR\bRC\bCH\bH_\b_F\bFI\bIL\bLT\bTE\bER\bR ldap_filter
-           An LDAP filter which is used to restrict the set of records
-           returned when performing a s\bsu\bud\bdo\bo LDAP query.  Typically, this is of
-           the form attribute=value or
-           (&(attribute=value)(attribute2=value2)).
-
-       S\bSU\bUD\bDO\bOE\bER\bRS\bS_\b_T\bTI\bIM\bME\bED\bD on/true/yes/off/false/no
-           Whether or not to evaluate the sudoNotBefore and sudoNotAfter
-           attributes that implement time-dependent sudoers entries.
-
-       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
-
-
-
-1.7.6                     April  9, 2011                        6
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-           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.
-
-       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/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bs_\be_\bc_\br_\be_\bt.  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.  Note that disabling
-           the check creates an opportunity for man-in-the-middle attacks
-           since the server's identity will not be authenticated.  If
-           possible, the CA's certificate should be installed locally so it
-           can be verified.
-
-       T\bTL\bLS\bS_\b_C\bCA\bAC\bCE\bER\bRT\bT file name
-           An alias for T\bTL\bLS\bS_\b_C\bCA\bAC\bCE\bER\bRT\bTF\bFI\bIL\bLE\bE for OpenLDAP compatibility.
-
-
-
-
-
-1.7.6                     April  9, 2011                        7
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-       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.  Netscape-derived LDAP
-           libraries use the same certificate database for CA and client
-           certificates (see T\bTL\bLS\bS_\b_C\bCE\bER\bRT\bT).
-
-       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.
-
-           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.
-
-
-
-
-
-1.7.6                     April  9, 2011                        8
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-       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.
-
-       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/_\be_\bt_\bc_\b/_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b._\bc_\bo_\bn_\bf, 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/_\be_\bt_\bc_\b/_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b._\bc_\bo_\bn_\bf file is not present or there is no sudoers
-       line, the following default is assumed:
-
-           sudoers: files
-
-
-
-
-1.7.6                     April  9, 2011                        9
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-       Note that _\b/_\be_\bt_\bc_\b/_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b._\bc_\bo_\bn_\bf is supported even when the underlying
-       operating system does not use an nsswitch.conf file.
-
-   C\bCo\bon\bnf\bfi\big\bgu\bur\bri\bin\bng\bg n\bne\bet\bts\bsv\bvc\bc.\b.c\bco\bon\bnf\bf
-       On AIX systems, the _\b/_\be_\bt_\bc_\b/_\bn_\be_\bt_\bs_\bv_\bc_\b._\bc_\bo_\bn_\bf file is consulted instead of
-       _\b/_\be_\bt_\bc_\b/_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b._\bc_\bo_\bn_\bf.  s\bsu\bud\bdo\bo simply treats _\bn_\be_\bt_\bs_\bv_\bc_\b._\bc_\bo_\bn_\bf as a variant of
-       _\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b._\bc_\bo_\bn_\bf; information in the previous section unrelated to the
-       file format itself still applies.
-
-       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
-
-       To treat LDAP as authoratative and only use the local sudoers file if
-       the user is not present in LDAP, use:
-
-           sudoers = ldap = auth, files
-
-       Note that in the above example, the auth qualfier only affects user
-       lookups; both LDAP and _\bs_\bu_\bd_\bo_\be_\br_\bs will be queried for Defaults entries.
-
-       If the _\b/_\be_\bt_\bc_\b/_\bn_\be_\bt_\bs_\bv_\bc_\b._\bc_\bo_\bn_\bf file is not present or there is no sudoers
-       line, the following default is assumed:
-
-           sudoers = files
-
-F\bFI\bIL\bLE\bES\bS
-       _\b/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bf          LDAP configuration file
-
-       _\b/_\be_\bt_\bc_\b/_\bn_\bs_\bs_\bw_\bi_\bt_\bc_\bh_\b._\bc_\bo_\bn_\bf      determines sudoers source order
-
-       _\b/_\be_\bt_\bc_\b/_\bn_\be_\bt_\bs_\bv_\bc_\b._\bc_\bo_\bn_\bf        determines sudoers source order on AIX
-
-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.
-         uri            ldap://ldapserver
-         #uri            ldaps://secureldapserver
-         #uri            ldaps://secureldapserver ldap://ldapserver
-         #
-
-
-
-1.7.6                     April  9, 2011                       10
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-         # 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; may be specified multiple times.
-         sudoers_base   ou=SUDOers,dc=example,dc=com
-         #
-         # verbose sudoers matching from ldap
-         #sudoers_debug 2
-         #
-         # Enable support for time-based entries in sudoers.
-         #sudoers_timed yes
-         #
-         # 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
-
-
-
-1.7.6                     April  9, 2011                       11
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-         # 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, tls_cert and tls_key may specify either
-         # a directory, in which case the files in the directory must have the
-         # default names (e.g. cert8.db and key4.db), or the path to the cert
-         # and key files themselves.  However, a bug in version 5.0 of the LDAP
-         # SDK will prevent specific file names from working.  For this reason
-         # it is suggested that tls_cert and tls_key be set to a directory,
-         # not a file name.
-         #
-         # The certificate database 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
-         #tls_key /var/ldap
-         #
-         # If using SASL authentication for LDAP (OpenSSL)
-         # use_sasl yes
-         # sasl_auth_id <SASL user name>
-         # rootuse_sasl yes
-         # rootsasl_auth_id <SASL user name 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, in OpenLDAP format, is included with s\bsu\bud\bdo\bo source
-       and binary distributions as _\bs_\bc_\bh_\be_\bm_\ba_\b._\bO_\bp_\be_\bn_\bL_\bD_\bA_\bP.  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'
-
-
-
-1.7.6                     April  9, 2011                       12
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-           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 )
-
-        attributetype ( 1.3.6.1.4.1.15953.9.1.8
-           NAME 'sudoNotBefore'
-           DESC 'Start of time interval for which the entry is valid'
-           EQUALITY generalizedTimeMatch
-           ORDERING generalizedTimeOrderingMatch
-           SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
-
-        attributetype ( 1.3.6.1.4.1.15953.9.1.9
-           NAME 'sudoNotAfter'
-           DESC 'End of time interval for which the entry is valid'
-           EQUALITY generalizedTimeMatch
-           ORDERING generalizedTimeOrderingMatch
-           SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
-
-        attributeTypes ( 1.3.6.1.4.1.15953.9.1.10
-            NAME 'sudoOrder'
-            DESC 'an integer to order the sudoRole entries'
-            EQUALITY integerMatch
-            ORDERING integerOrderingMatch
-
-
-
-1.7.6                     April  9, 2011                       13
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-            SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
-
-        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 $ sudoNotBefore $ sudoNotAfter $
-                 sudoOrder $ description )
-           )
-
-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
-       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.
-
-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.6                     April  9, 2011                       14
-
-
diff --git a/sudoers.ldap.man.in b/sudoers.ldap.man.in
deleted file mode 100644 (file)
index 74cafec..0000000
+++ /dev/null
@@ -1,918 +0,0 @@
-.\" Copyright (c) 2003-2011
-.\"    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.
-.\" 
-.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.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 (.SS), 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@ "April  9, 2011" "1.7.6" "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-1LDAP\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@sysconfdir@/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@sysconfdir@/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 Runas_Aliases.  Host netgroups can be used in place
-of Host_Aliases.  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 \f(CW\*(C`sudoRole\*(C'\fR.  Instead of defining
-a Cmnd_Alias that is referenced by multiple users, one can create
-a \f(CW\*(C`sudoRole\*(C'\fR that contains the commands and assign multiple users
-to it.
-.SS "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@sysconfdir@/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 attributes:
-.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.
-.Sp
-The \f(CW\*(C`sudoRunAsUser\*(C'\fR attribute is only available in \fBsudo\fR versions
-1.7.0 and higher.  Older versions of \fBsudo\fR use the \f(CW\*(C`sudoRunAs\*(C'\fR
-attribute instead.
-.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.
-.Sp
-The \f(CW\*(C`sudoRunAsGroup\*(C'\fR attribute is only available in \fBsudo\fR versions
-1.7.0 and higher.
-.IP "\fBsudoNotBefore\fR" 4
-.IX Item "sudoNotBefore"
-A timestamp in the form \f(CW\*(C`yyyymmddHHMMZ\*(C'\fR that can be used to provide
-a start date/time for when the \f(CW\*(C`sudoRole\*(C'\fR will be valid.  If
-multiple \f(CW\*(C`sudoNotBefore\*(C'\fR entries are present, the earliest is used.
-Note that timestamps must be in Coordinated Universal Time (\s-1UTC\s0),
-not the local timezone.
-.Sp
-The \f(CW\*(C`sudoNotBefore\*(C'\fR attribute is only available in \fBsudo\fR versions
-1.7.5 and higher and must be explicitly enabled via the \fB\s-1SUDOERS_TIMED\s0\fR
-option in \fI@ldap_conf@\fR.
-.IP "\fBsudoNotAfter\fR" 4
-.IX Item "sudoNotAfter"
-A timestamp in the form \f(CW\*(C`yyyymmddHHMMZ\*(C'\fR that indicates an expiration
-date/time, after which the \f(CW\*(C`sudoRole\*(C'\fR will no longer be valid.  If
-multiple \f(CW\*(C`sudoNotBefore\*(C'\fR entries are present, the last one is used.
-Note that timestamps must be in Coordinated Universal Time (\s-1UTC\s0),
-not the local timezone.
-.Sp
-The \f(CW\*(C`sudoNotAfter\*(C'\fR attribute is only available in \fBsudo\fR versions
-1.7.5 and higher and must be explicitly enabled via the \fB\s-1SUDOERS_TIMED\s0\fR
-option in \fI@ldap_conf@\fR.
-.IP "\fBsudoOrder\fR" 4
-.IX Item "sudoOrder"
-The \f(CW\*(C`sudoRole\*(C'\fR entries retrieved from the \s-1LDAP\s0 directory have no
-inherent order.  The \f(CW\*(C`sudoOrder\*(C'\fR attribute is an integer (or
-floating point value for \s-1LDAP\s0 servers that support it) that is used
-to sort the matching entries.  This allows LDAP-based sudoers entries
-to more closely mimic the behaviour of the sudoers file, where the
-of the entries influences the result.  If multiple entries match,
-the entry with the highest \f(CW\*(C`sudoOrder\*(C'\fR attribute is chosen.  This
-corresponds to the \*(L"last match\*(R" behavior of the sudoers file.  If
-the \f(CW\*(C`sudoOrder\*(C'\fR attribute is not present, a value of 0 is assumed.
-.Sp
-The \f(CW\*(C`sudoOrder\*(C'\fR attribute is only available in \fBsudo\fR versions
-1.7.5 and higher.
-.PP
-Each attribute listed above should contain a single value, but there
-may be multiple instances of each attribute type.  A \f(CW\*(C`sudoRole\*(C'\fR 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
-.SS "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.
-.PP
-If timed entries are enabled with the \fB\s-1SUDOERS_TIMED\s0\fR configuration
-directive, the \s-1LDAP\s0 queries include a subfilter that limits retrieval
-to entries that satisfy the time constraints, if any.
-.SS "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.
-.PP
-The order in which different entries are applied can be controlled
-using the \f(CW\*(C`sudoOrder\*(C'\fR attribute, but there is no way to guarantee
-the order of attributes within a specific entry.  If there are
-conflicting command rules in 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 ignored.  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
-.SS "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.
-.SS "Configuring ldap.conf"
-.IX Subsection "Configuring ldap.conf"
-Sudo reads the \fI@ldap_conf@\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@ldap_conf@\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@ldap_conf@\fR as being
-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.  Multiple \fB\s-1URI\s0\fR
-lines are treated identically to a \fB\s-1URI\s0\fR line containing multiple
-entries.  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-1NETWORK_TIMEOUT\s0\fR seconds" 4
-.IX Item "NETWORK_TIMEOUT seconds"
-An alias for \fB\s-1BIND_TIMELIMIT\s0\fR for OpenLDAP compatibility.
-.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-1TIMEOUT\s0\fR seconds" 4
-.IX Item "TIMEOUT seconds"
-The \fB\s-1TIMEOUT\s0\fR parameter specifies the amount of time, in seconds,
-to wait for a response from the various \s-1LDAP\s0 APIs.
-.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.  Multiple \fB\s-1SUDOERS_BASE\s0\fR lines may be specified,
-in which case they are queried in the order specified.
-.IP "\fB\s-1SUDOERS_SEARCH_FILTER\s0\fR ldap_filter" 4
-.IX Item "SUDOERS_SEARCH_FILTER ldap_filter"
-An \s-1LDAP\s0 filter which is used to restrict the set of records returned
-when performing a \fBsudo\fR \s-1LDAP\s0 query.  Typically, this is of the
-form \f(CW\*(C`attribute=value\*(C'\fR or \f(CW\*(C`(&(attribute=value)(attribute2=value2))\*(C'\fR.
-.IP "\fB\s-1SUDOERS_TIMED\s0\fR on/true/yes/off/false/no" 4
-.IX Item "SUDOERS_TIMED on/true/yes/off/false/no"
-Whether or not to evaluate the \f(CW\*(C`sudoNotBefore\*(C'\fR and \f(CW\*(C`sudoNotAfter\*(C'\fR
-attributes that implement time-dependent sudoers entries.
-.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@ldap_secret@\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.  Note that disabling the check creates
-an opportunity for man-in-the-middle attacks since the server's
-identity will not be authenticated.  If possible, the \s-1CA\s0's certificate
-should be installed locally so it can be verified.
-.IP "\fB\s-1TLS_CACERT\s0\fR file name" 4
-.IX Item "TLS_CACERT file name"
-An alias for \fB\s-1TLS_CACERTFILE\s0\fR for OpenLDAP compatibility.
-.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.
-Netscape-derived \s-1LDAP\s0 libraries use the same certificate
-database for \s-1CA\s0 and client certificates (see \fB\s-1TLS_CERT\s0\fR).
-.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.
-.SS "Configuring nsswitch.conf"
-.IX Subsection "Configuring nsswitch.conf"
-Unless it is disabled at build time, \fBsudo\fR consults the Name
-Service Switch file, \fI@nsswitch_conf@\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@nsswitch_conf@\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@nsswitch_conf@\fR is supported even when the underlying
-operating system does not use an nsswitch.conf file.
-.SS "Configuring netsvc.conf"
-.IX Subsection "Configuring netsvc.conf"
-On \s-1AIX\s0 systems, the \fI@netsvc_conf@\fR file is consulted instead of
-\&\fI@nsswitch_conf@\fR.  \fBsudo\fR simply treats \fInetsvc.conf\fR as a
-variant of \fInsswitch.conf\fR; information in the previous section
-unrelated to the file format itself still applies.
-.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
-To treat \s-1LDAP\s0 as authoratative and only use the local sudoers file
-if the user is not present in \s-1LDAP\s0, use:
-.PP
-.Vb 1
-\&    sudoers = ldap = auth, files
-.Ve
-.PP
-Note that in the above example, the \f(CW\*(C`auth\*(C'\fR qualfier only affects
-user lookups; both \s-1LDAP\s0 and \fIsudoers\fR will be queried for \f(CW\*(C`Defaults\*(C'\fR
-entries.
-.PP
-If the \fI@netsvc_conf@\fR file is not present or there is no
-sudoers line, the following default is assumed:
-.PP
-.Vb 1
-\&    sudoers = files
-.Ve
-.SH "FILES"
-.IX Header "FILES"
-.ie n .IP "\fI@ldap_conf@\fR" 24
-.el .IP "\fI@ldap_conf@\fR" 24
-.IX Item "@ldap_conf@"
-\&\s-1LDAP\s0 configuration file
-.ie n .IP "\fI@nsswitch_conf@\fR" 24
-.el .IP "\fI@nsswitch_conf@\fR" 24
-.IX Item "@nsswitch_conf@"
-determines sudoers source order
-.ie n .IP "\fI@netsvc_conf@\fR" 24
-.el .IP "\fI@netsvc_conf@\fR" 24
-.IX Item "@netsvc_conf@"
-determines sudoers source order on \s-1AIX\s0
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-.SS "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; may be specified multiple times.
-\&  sudoers_base   ou=SUDOers,dc=example,dc=com
-\&  #
-\&  # verbose sudoers matching from ldap
-\&  #sudoers_debug 2
-\&  #
-\&  # Enable support for time\-based entries in sudoers.
-\&  #sudoers_timed yes
-\&  #
-\&  # 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, tls_cert and tls_key may specify either
-\&  # a directory, in which case the files in the directory must have the
-\&  # default names (e.g. cert8.db and key4.db), or the path to the cert
-\&  # and key files themselves.  However, a bug in version 5.0 of the LDAP
-\&  # SDK will prevent specific file names from working.  For this reason
-\&  # it is suggested that tls_cert and tls_key be set to a directory,
-\&  # not a file name.
-\&  #
-\&  # The certificate database 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
-\&  #tls_key /var/ldap
-\&  #
-\&  # If using SASL authentication for LDAP (OpenSSL)
-\&  # use_sasl yes
-\&  # sasl_auth_id <SASL user name>
-\&  # rootuse_sasl yes
-\&  # rootsasl_auth_id <SASL user name for root access>
-\&  # sasl_secprops none
-\&  # krb5_ccname /etc/.ldapcache
-.Ve
-.SS "Sudo schema for OpenLDAP"
-.IX Subsection "Sudo schema for OpenLDAP"
-The following schema, in OpenLDAP format, is included with \fBsudo\fR
-source and binary distributions as \fIschema.OpenLDAP\fR.  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 )
-\&
-\& attributetype ( 1.3.6.1.4.1.15953.9.1.8
-\&    NAME \*(AqsudoNotBefore\*(Aq
-\&    DESC \*(AqStart of time interval for which the entry is valid\*(Aq
-\&    EQUALITY generalizedTimeMatch
-\&    ORDERING generalizedTimeOrderingMatch
-\&    SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
-\&
-\& attributetype ( 1.3.6.1.4.1.15953.9.1.9
-\&    NAME \*(AqsudoNotAfter\*(Aq
-\&    DESC \*(AqEnd of time interval for which the entry is valid\*(Aq
-\&    EQUALITY generalizedTimeMatch
-\&    ORDERING generalizedTimeOrderingMatch
-\&    SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
-\&
-\& attributeTypes ( 1.3.6.1.4.1.15953.9.1.10
-\&     NAME \*(AqsudoOrder\*(Aq
-\&     DESC \*(Aqan integer to order the sudoRole entries\*(Aq
-\&     EQUALITY integerMatch
-\&     ORDERING integerOrderingMatch
-\&     SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
-\&
-\& 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 $ sudoNotBefore $ sudoNotAfter $
-\&          sudoOrder $ description )
-\&    )
-.Ve
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIldap.conf\fR\|(@mansectform@), \fIsudoers\fR\|(5)
-.SH "CAVEATS"
-.IX Header "CAVEATS"
-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
deleted file mode 100644 (file)
index a981654..0000000
+++ /dev/null
@@ -1,841 +0,0 @@
-Copyright (c) 2003-2011
-       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.
-
-=pod
-
-=head1 NAME
-
-sudoers.ldap - sudo LDAP configuration
-
-=head1 DESCRIPTION
-
-In addition to the standard I<sudoers> file, B<sudo> may be configured
-via LDAP.  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 Runas_Aliases.  Host netgroups can be used in place
-of Host_Aliases.  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 C<sudoRole>.  Instead of defining
-a Cmnd_Alias that is referenced by multiple users, one can create
-a C<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 attributes:
-
-=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.
-
-The C<sudoRunAsUser> attribute is only available in B<sudo> versions
-1.7.0 and higher.  Older versions of B<sudo> use the C<sudoRunAs>
-attribute instead.
-
-=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.
-
-The C<sudoRunAsGroup> attribute is only available in B<sudo> versions
-1.7.0 and higher.
-
-=item B<sudoNotBefore>
-
-A timestamp in the form C<yyyymmddHHMMZ> that can be used to provide
-a start date/time for when the C<sudoRole> will be valid.  If
-multiple C<sudoNotBefore> entries are present, the earliest is used.
-Note that timestamps must be in Coordinated Universal Time (UTC),
-not the local timezone.
-
-The C<sudoNotBefore> attribute is only available in B<sudo> versions
-1.7.5 and higher and must be explicitly enabled via the B<SUDOERS_TIMED>
-option in F<@ldap_conf@>.
-
-=item B<sudoNotAfter>
-
-A timestamp in the form C<yyyymmddHHMMZ> that indicates an expiration
-date/time, after which the C<sudoRole> will no longer be valid.  If
-multiple C<sudoNotBefore> entries are present, the last one is used.
-Note that timestamps must be in Coordinated Universal Time (UTC),
-not the local timezone.
-
-The C<sudoNotAfter> attribute is only available in B<sudo> versions
-1.7.5 and higher and must be explicitly enabled via the B<SUDOERS_TIMED>
-option in F<@ldap_conf@>.
-
-=item B<sudoOrder>
-
-The C<sudoRole> entries retrieved from the LDAP directory have no
-inherent order.  The C<sudoOrder> attribute is an integer (or
-floating point value for LDAP servers that support it) that is used
-to sort the matching entries.  This allows LDAP-based sudoers entries
-to more closely mimic the behaviour of the sudoers file, where the
-of the entries influences the result.  If multiple entries match,
-the entry with the highest C<sudoOrder> attribute is chosen.  This
-corresponds to the "last match" behavior of the sudoers file.  If
-the C<sudoOrder> attribute is not present, a value of 0 is assumed.
-
-The C<sudoOrder> attribute is only available in B<sudo> versions
-1.7.5 and higher.
-
-=back
-
-Each attribute listed above should contain a single value, but there
-may be multiple instances of each attribute type.  A C<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.
-
-If timed entries are enabled with the B<SUDOERS_TIMED> configuration
-directive, the LDAP queries include a subfilter that limits retrieval
-to entries that satisfy the time constraints, if any.
-
-=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.
-
-The order in which different entries are applied can be controlled
-using the C<sudoOrder> attribute, but there is no way to guarantee
-the order of attributes within a specific entry.  If there are
-conflicting command rules in 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 ignored.  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@> as being
-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>.  Multiple B<URI>
-lines are treated identically to a B<URI> line containing multiple
-entries.  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<NETWORK_TIMEOUT> seconds
-
-An alias for B<BIND_TIMELIMIT> for OpenLDAP compatibility.
-
-=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<TIMEOUT> seconds
-
-The B<TIMEOUT> parameter specifies the amount of time, in seconds,
-to wait for a response from the various LDAP APIs.
-
-=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>.  Multiple B<SUDOERS_BASE> lines may be specified,
-in which case they are queried in the order specified.
-
-=item B<SUDOERS_SEARCH_FILTER> ldap_filter
-
-An LDAP filter which is used to restrict the set of records returned
-when performing a B<sudo> LDAP query.  Typically, this is of the
-form C<attribute=value> or C<(&(attribute=value)(attribute2=value2))>.
-
-=item B<SUDOERS_TIMED> on/true/yes/off/false/no
-
-Whether or not to evaluate the C<sudoNotBefore> and C<sudoNotAfter>
-attributes that implement time-dependent sudoers entries.
-
-=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.  Note that disabling the check creates
-an opportunity for man-in-the-middle attacks since the server's
-identity will not be authenticated.  If possible, the CA's certificate
-should be installed locally so it can be verified.
-
-=item B<TLS_CACERT> file name
-
-An alias for B<TLS_CACERTFILE> for OpenLDAP compatibility.
-
-=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.
-Netscape-derived LDAP libraries use the same certificate
-database for CA and client certificates (see B<TLS_CERT>).
-
-=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.
-
-=head2 Configuring netsvc.conf
-
-On AIX systems, the F<@netsvc_conf@> file is consulted instead of
-F<@nsswitch_conf@>.  B<sudo> simply treats I<netsvc.conf> as a
-variant of I<nsswitch.conf>; information in the previous section
-unrelated to the file format itself still applies.
-
-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
-
-To treat LDAP as authoratative and only use the local sudoers file
-if the user is not present in LDAP, use:
-
-    sudoers = ldap = auth, files
-
-Note that in the above example, the C<auth> qualfier only affects
-user lookups; both LDAP and I<sudoers> will be queried for C<Defaults>
-entries.
-
-If the F<@netsvc_conf@> file is not present or there is no
-sudoers line, the following default is assumed:
-
-    sudoers = files
-
-=head1 FILES
-
-=over 24
-
-=item F<@ldap_conf@>
-
-LDAP configuration file
-
-=item F<@nsswitch_conf@>
-
-determines sudoers source order
-
-=item F<@netsvc_conf@>
-
-determines sudoers source order on AIX
-
-=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; may be specified multiple times.
-  sudoers_base   ou=SUDOers,dc=example,dc=com
-  #
-  # verbose sudoers matching from ldap
-  #sudoers_debug 2
-  #
-  # Enable support for time-based entries in sudoers.
-  #sudoers_timed yes
-  #
-  # 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, tls_cert and tls_key may specify either
-  # a directory, in which case the files in the directory must have the
-  # default names (e.g. cert8.db and key4.db), or the path to the cert
-  # and key files themselves.  However, a bug in version 5.0 of the LDAP
-  # SDK will prevent specific file names from working.  For this reason
-  # it is suggested that tls_cert and tls_key be set to a directory,
-  # not a file name.
-  #
-  # The certificate database 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
-  #tls_key /var/ldap
-  #
-  # If using SASL authentication for LDAP (OpenSSL)
-  # use_sasl yes
-  # sasl_auth_id <SASL user name>
-  # rootuse_sasl yes
-  # rootsasl_auth_id <SASL user name for root access>
-  # sasl_secprops none
-  # krb5_ccname /etc/.ldapcache
-
-=head2 Sudo schema for OpenLDAP 
-
-The following schema, in OpenLDAP format, is included with B<sudo>
-source and binary distributions as F<schema.OpenLDAP>.  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 )
-
- attributetype ( 1.3.6.1.4.1.15953.9.1.8
-    NAME 'sudoNotBefore'
-    DESC 'Start of time interval for which the entry is valid'
-    EQUALITY generalizedTimeMatch
-    ORDERING generalizedTimeOrderingMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
-
- attributetype ( 1.3.6.1.4.1.15953.9.1.9
-    NAME 'sudoNotAfter'
-    DESC 'End of time interval for which the entry is valid'
-    EQUALITY generalizedTimeMatch
-    ORDERING generalizedTimeOrderingMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
-
- attributeTypes ( 1.3.6.1.4.1.15953.9.1.10
-     NAME 'sudoOrder'
-     DESC 'an integer to order the sudoRole entries'
-     EQUALITY integerMatch
-     ORDERING integerOrderingMatch
-     SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
-
- 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 $ sudoNotBefore $ sudoNotAfter $
-         sudoOrder $ description )
-    )
-
-=head1 SEE ALSO
-
-L<ldap.conf(5)>, L<sudoers(5)>
-
-=head1 CAVEATS
-
-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.
diff --git a/sudoers.man.in b/sudoers.man.in
deleted file mode 100644 (file)
index 531ead6..0000000
+++ /dev/null
@@ -1,1814 +0,0 @@
-.\" Copyright (c) 1994-1996, 1998-2005, 2007-2011
-.\"    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.
-.\" 
-.\" 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.
-.\" 
-.nr SL @SEMAN@
-.nr BA @BAMAN@
-.nr LC @LCMAN@
-.\"
-.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.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 (.SS), 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 @mansectform@"
-.TH SUDOERS @mansectform@ "April  9, 2011" "1.7.6" "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"
-.IX Header "DESCRIPTION"
-The \fIsudoers\fR file is composed of two types of entries: aliases
-(basically variables) and user specifications (which specify who
-may run what).
-.PP
-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).
-.PP
-The \fIsudoers\fR grammar will be described below in Extended Backus-Naur
-Form (\s-1EBNF\s0).  Don't despair if you don't know what \s-1EBNF\s0 is; it is
-fairly simple, and the definitions below are annotated.
-.SS "Quick guide to \s-1EBNF\s0"
-.IX Subsection "Quick guide to EBNF"
-\&\s-1EBNF\s0 is a concise and exact way of describing the grammar of a language.
-Each \s-1EBNF\s0 definition is made up of \fIproduction rules\fR.  E.g.,
-.PP
-.Vb 1
-\& symbol ::= definition | alternate1 | alternate2 ...
-.Ve
-.PP
-Each \fIproduction rule\fR references others and thus makes up a
-grammar for the language.  \s-1EBNF\s0 also contains the following
-operators, which many readers will recognize from regular
-expressions.  Do not, however, confuse them with \*(L"wildcard\*(R"
-characters, which have different meanings.
-.ie n .IP "\*(C`?\*(C'" 4
-.el .IP "\f(CW\*(C`?\*(C'\fR" 4
-.IX Item "?"
-Means that the preceding symbol (or group of symbols) is optional.
-That is, it may appear once or not at all.
-.ie n .IP "\*(C`*\*(C'" 4
-.el .IP "\f(CW\*(C`*\*(C'\fR" 4
-.IX Item "*"
-Means that the preceding symbol (or group of symbols) may appear
-zero or more times.
-.ie n .IP "\*(C`+\*(C'" 4
-.el .IP "\f(CW\*(C`+\*(C'\fR" 4
-.IX Item "+"
-Means that the preceding symbol (or group of symbols) may appear
-one or more times.
-.PP
-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).
-.SS "Aliases"
-.IX Subsection "Aliases"
-There are four kinds of aliases: \f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_Alias\*(C'\fR,
-\&\f(CW\*(C`Host_Alias\*(C'\fR and \f(CW\*(C`Cmnd_Alias\*(C'\fR.
-.PP
-.Vb 4
-\& 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
-.PP
-.Vb 1
-\& Alias_Type NAME = item1, item2, ...
-.Ve
-.PP
-where \fIAlias_Type\fR is one of \f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_Alias\*(C'\fR, \f(CW\*(C`Host_Alias\*(C'\fR,
-or \f(CW\*(C`Cmnd_Alias\*(C'\fR.  A \f(CW\*(C`NAME\*(C'\fR is a string of uppercase letters, numbers,
-and underscore characters ('_').  A \f(CW\*(C`NAME\*(C'\fR \fBmust\fR 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.,
-.PP
-.Vb 1
-\& Alias_Type NAME = item1, item2, item3 : NAME = item4, item5
-.Ve
-.PP
-The definitions of what constitutes a valid \fIalias\fR member follow.
-.PP
-.Vb 2
-\& User_List ::= User |
-\&               User \*(Aq,\*(Aq User_List
-\&
-\& User ::= \*(Aq!\*(Aq* user name |
-\&          \*(Aq!\*(Aq* #uid |
-\&          \*(Aq!\*(Aq* %group |
-\&          \*(Aq!\*(Aq* %#gid |
-\&          \*(Aq!\*(Aq* +netgroup |
-\&          \*(Aq!\*(Aq* %:nonunix_group |
-\&          \*(Aq!\*(Aq* %:#nonunix_gid |
-\&          \*(Aq!\*(Aq* User_Alias
-.Ve
-.PP
-A \f(CW\*(C`User_List\*(C'\fR is made up of one or more user names, user ids
-(prefixed with '#'), system group names and ids (prefixed with '%'
-and '%#' respectively), netgroups (prefixed with '+'), non-Unix
-group names and IDs (prefixed with '%:' and '%:#' respectively) 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
-A \f(CW\*(C`user name\*(C'\fR, \f(CW\*(C`uid\*(C'\fR, \f(CW\*(C`group\*(C'\fR, \f(CW\*(C`gid\*(C'\fR, \f(CW\*(C`netgroup\*(C'\fR, \f(CW\*(C`nonunix_group\*(C'\fR
-or \f(CW\*(C`nonunix_gid\*(C'\fR may be enclosed in double quotes to avoid the
-need for escaping special characters.  Alternately, special characters
-may be specified in escaped hex mode, e.g. \ex20 for space.  When
-using double quotes, any prefix characters must be included inside
-the quotes.
-.PP
-The \f(CW\*(C`nonunix_group\*(C'\fR and \f(CW\*(C`nonunix_gid\*(C'\fR syntax depends on the
-underlying implementation.  For instance, the \s-1QAS\s0 \s-1AD\s0 backend supports
-the following formats:
-.IP "\(bu" 4
-Group in the same domain: \*(L"Group Name\*(R"
-.IP "\(bu" 4
-Group in any domain: \*(L"Group Name@FULLY.QUALIFIED.DOMAIN\*(R"
-.IP "\(bu" 4
-Group \s-1SID:\s0 \*(L"S\-1\-2\-34\-5678901234\-5678901234\-5678901234\-567\*(R"
-.PP
-Note that quotes around group names are optional.  Unquoted strings
-must use a backslash (\e) to escape spaces and special characters.
-See \*(L"Other special characters and reserved words\*(R" for a list of
-characters that need to be escaped.
-.PP
-.Vb 2
-\& Runas_List ::= Runas_Member |
-\&                Runas_Member \*(Aq,\*(Aq Runas_List
-\&
-\& Runas_Member ::= \*(Aq!\*(Aq* user name |
-\&                  \*(Aq!\*(Aq* #uid |
-\&                  \*(Aq!\*(Aq* %group |
-\&                  \*(Aq!\*(Aq* %#gid |
-\&                  \*(Aq!\*(Aq* %:nonunix_group |
-\&                  \*(Aq!\*(Aq* %:#nonunix_gid |
-\&                  \*(Aq!\*(Aq* +netgroup |
-\&                  \*(Aq!\*(Aq* 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 instead
-of \f(CW\*(C`User_Alias\*(C'\fRes it can contain \f(CW\*(C`Runas_Alias\*(C'\fRes.  Note that
-user names 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 user names 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 \*(Aq,\*(Aq Host_List
-\&
-\& Host ::= \*(Aq!\*(Aq* host name |
-\&          \*(Aq!\*(Aq* ip_addr |
-\&          \*(Aq!\*(Aq* network(/netmask)? |
-\&          \*(Aq!\*(Aq* +netgroup |
-\&          \*(Aq!\*(Aq* Host_Alias
-.Ve
-.PP
-A \f(CW\*(C`Host_List\*(C'\fR is made up of one or more host names, \s-1IP\s0 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,
-\&\fBsudo\fR 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 \s-1IP\s0 address notation
-(e.g.\ 255.255.255.0 or ffff:ffff:ffff:ffff::),
-or \s-1CIDR\s0 notation (number of bits, e.g.\ 24 or 64).  A host name may
-include shell-style wildcards (see the Wildcards section below),
-but unless the \f(CW\*(C`host name\*(C'\fR command on your machine returns the fully
-qualified host name, you'll need to use the \fIfqdn\fR option for
-wildcards to be useful.  Note \fBsudo\fR only inspects actual network
-interfaces; this means that \s-1IP\s0 address 127.0.0.1 (localhost) will
-never match.  Also, the host name \*(L"localhost\*(R" will only match if
-that is the actual host name, which is usually only the case for
-non-networked systems.
-.PP
-.Vb 2
-\& Cmnd_List ::= Cmnd |
-\&               Cmnd \*(Aq,\*(Aq Cmnd_List
-\&
-\& commandname ::= file name |
-\&                 file name args |
-\&                 file name \*(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
-aliases.  A commandname is a fully qualified file name which may include
-shell-style wildcards (see the Wildcards section below).  A simple
-file name 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 \f(CW""\fR to indicate that the command
-may only be run \fBwithout\fR command line arguments.  A directory is a
-fully qualified path name ending in a '/'.  When you specify a directory
-in a \f(CW\*(C`Cmnd_List\*(C'\fR, the user will be able to run any file within that directory
-(but not in any subdirectories therein).
-.PP
-If a \f(CW\*(C`Cmnd\*(C'\fR has associated command line arguments, then the arguments
-in the \f(CW\*(C`Cmnd\*(C'\fR 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 '\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 option (or
-as \fBsudoedit\fR).  It may take command line arguments just as
-a normal command does.
-.SS "Defaults"
-.IX Subsection "Defaults"
-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, 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 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
-\&
-\& Parameter_List ::= 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.
-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 (\f(CW\*(C`"\*(C'\fR) when they contain multiple words.  Special
-characters may be escaped with a backslash (\f(CW\*(C`\e\*(C'\fR).
-.PP
-Lists have two additional assignment operators, \f(CW\*(C`+=\*(C'\fR and \f(CW\*(C`\-=\*(C'\fR.
-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.
-.SS "User Specification"
-.IX Subsection "User Specification"
-.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 \*(Aq,\*(Aq Cmnd_Spec_List
-\&
-.ie \n(SL \& Cmnd_Spec ::= Runas_Spec? SELinux_Spec? Tag_Spec* Cmnd
-.el \& Cmnd_Spec ::= Runas_Spec? Tag_Spec* Cmnd
-\&
-\& Runas_Spec ::= \*(Aq(\*(Aq Runas_List? (\*(Aq:\*(Aq Runas_List)? \*(Aq)\*(Aq
-\&
-.if \n(SL \{\
-\& SELinux_Spec ::= (\*(AqROLE=role\*(Aq | \*(AqTYPE=type\*(Aq)
-\&
-\}
-\& Tag_Spec ::= (\*(AqNOPASSWD:\*(Aq | \*(AqPASSWD:\*(Aq | \*(AqNOEXEC:\*(Aq | \*(AqEXEC:\*(Aq |
-\&               \*(AqSETENV:\*(Aq | \*(AqNOSETENV:\*(Aq | \*(AqLOG_INPUT:\*(Aq | \*(AqNOLOG_INPUT:\*(Aq |
-\&               \*(AqLOG_OUTPUT:\*(Aq | \*(AqNOLOG_OUTPUT:\*(Aq)
-.Ve
-.PP
-A \fBuser specification\fR determines which commands a user may run
-(and as what user) on specified hosts.  By default, commands are
-run as \fBroot\fR, but this can be changed on a per-command basis.
-.PP
-The basic structure of a user specification is `who where = (as_whom)
-what'.  Let's break that down into its constituent parts:
-.SS "Runas_Spec"
-.IX Subsection "Runas_Spec"
-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
-.Ve
-.PP
-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
-.Ve
-.PP
-It is also possible to override a \f(CW\*(C`Runas_Spec\*(C'\fR later on in an
-entry.  If we modify the entry like so:
-.PP
-.Vb 1
-\& dgb    boulder = (operator) /bin/ls, (root) /bin/kill, /usr/bin/lprm
-.Ve
-.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
-Note that while the group portion of the \f(CW\*(C`Runas_Spec\*(C'\fR permits the
-user to run as command with that group, it does not force the user
-to do so.  If no group is specified on the command line, the command
-will run with the group listed in the target user's password database
-entry.  The following would all be permitted by the sudoers entry above:
-.PP
-.Vb 3
-\& $ sudo \-u operator /bin/ls
-\& $ sudo \-u operator \-g operator /bin/ls
-\& $ sudo \-g operator /bin/ls
-.Ve
-.PP
-In the following example, user \fBtcm\fR may run commands that access
-a modem device file with the dialer group.
-.PP
-.Vb 2
-\& tcm    boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \e
-\&        /usr/local/bin/minicom
-.Ve
-.PP
-Note that in this example only the group will be set, the command
-still runs as user \fBtcm\fR.  E.g.
-.PP
-.Vb 1
-\& $ sudo \-g dialer /usr/bin/cu
-.Ve
-.PP
-Multiple users and groups may be present in a \f(CW\*(C`Runas_Spec\*(C'\fR, in
-which case the user may select any combination of users and groups
-via the \fB\-u\fR and \fB\-g\fR options.  In this example:
-.PP
-.Vb 1
-\& alan   ALL = (root, bin : operator, system) ALL
-.Ve
-.PP
-user \fBalan\fR may run any command as either user root or bin,
-optionally setting the group to operator or system.
-.if \n(SL \{\
-.SS "SELinux_Spec"
-.IX Subsection "SELinux_Spec"
-On systems with SELinux support, \fIsudoers\fR entries may optionally have
-an SELinux role and/or type associated with a command.  If a role or
-type is specified with the command it will override any default values
-specified in \fIsudoers\fR.  A role or type specified on the command line,
-however, will supercede the values in \fIsudoers\fR.
-\}
-.SS "Tag_Spec"
-.IX Subsection "Tag_Spec"
-A command may have zero or more tags associated with it.  There are
-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, \f(CW\*(C`NOSETENV\*(C'\fR, \f(CW\*(C`LOG_INPUT\*(C'\fR, \f(CW\*(C`NOLOG_INPUT\*(C'\fR,
-\&\f(CW\*(C`LOG_OUTPUT\*(C'\fR and \f(CW\*(C`NOLOG_OUTPUT\*(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 opposite tag (i.e.: \f(CW\*(C`PASSWD\*(C'\fR overrides
-\&\f(CW\*(C`NOPASSWD\*(C'\fR and \f(CW\*(C`NOEXEC\*(C'\fR overrides \f(CW\*(C`EXEC\*(C'\fR).
-.PP
-\fI\s-1NOPASSWD\s0 and \s-1PASSWD\s0\fR
-.IX Subsection "NOPASSWD and PASSWD"
-.PP
-By default, \fBsudo\fR requires that a user authenticate him or herself
-before running a command.  This behavior can be modified via the
-\&\f(CW\*(C`NOPASSWD\*(C'\fR tag.  Like a \f(CW\*(C`Runas_Spec\*(C'\fR, the \f(CW\*(C`NOPASSWD\*(C'\fR tag sets
-a default for the commands that follow it in the \f(CW\*(C`Cmnd_Spec_List\*(C'\fR.
-Conversely, the \f(CW\*(C`PASSWD\*(C'\fR tag can be used to reverse things.
-For example:
-.PP
-.Vb 1
-\& ray    rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm
-.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 \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
-.Vb 1
-\& ray    rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm
-.Ve
-.PP
-Note, however, that the \f(CW\*(C`PASSWD\*(C'\fR tag has no effect on users who are
-in the group specified by the \fIexempt_group\fR option.
-.PP
-By default, if the \f(CW\*(C`NOPASSWD\*(C'\fR tag is applied to any of the entries
-for a user on the current host, he or she will be able to run
-\&\f(CW\*(C`sudo \-l\*(C'\fR without a password.  Additionally, a user may only run
-\&\f(CW\*(C`sudo \-v\*(C'\fR without a password if the \f(CW\*(C`NOPASSWD\*(C'\fR 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.
-.PP
-\fI\s-1NOEXEC\s0 and \s-1EXEC\s0\fR
-.IX Subsection "NOEXEC and EXEC"
-.PP
-If \fBsudo\fR has been compiled with \fInoexec\fR support and the underlying
-operating system supports it, the \f(CW\*(C`NOEXEC\*(C'\fR tag can be used to prevent
-a dynamically-linked executable from running further commands itself.
-.PP
-In the following example, user \fBaaron\fR may run \fI/usr/bin/more\fR
-and \fI/usr/bin/vi\fR but shell escapes will be disabled.
-.PP
-.Vb 1
-\& aaron  shanty = NOEXEC: /usr/bin/more, /usr/bin/vi
-.Ve
-.PP
-See the \*(L"\s-1PREVENTING\s0 \s-1SHELL\s0 \s-1ESCAPES\s0\*(R" section below for more details
-on how \f(CW\*(C`NOEXEC\*(C'\fR works and whether or not it will work on your system.
-.PP
-\fI\s-1SETENV\s0 and \s-1NOSETENV\s0\fR
-.IX Subsection "SETENV and NOSETENV"
-.PP
-These tags override the value of the \fIsetenv\fR option on a per-command
-basis.  Note that if \f(CW\*(C`SETENV\*(C'\fR has been set for a command, the user
-may disable the \fIenv_reset\fR option from the command line via the
-\&\fB\-E\fR option.  Additionally, environment variables set on the command
-line are not subject to the restrictions imposed by \fIenv_check\fR,
-\&\fIenv_delete\fR, or \fIenv_keep\fR.  As such, only trusted users should
-be allowed to set variables in this manner.  If the command matched
-is \fB\s-1ALL\s0\fR, the \f(CW\*(C`SETENV\*(C'\fR tag is implied for that command; this
-default may be overridden by use of the \f(CW\*(C`NOSETENV\*(C'\fR tag.
-.PP
-\fI\s-1LOG_INPUT\s0 and \s-1NOLOG_INPUT\s0\fR
-.IX Subsection "LOG_INPUT and NOLOG_INPUT"
-.PP
-These tags override the value of the \fIlog_input\fR option on a
-per-command basis.  For more information, see the description of
-\&\fIlog_input\fR in the \*(L"\s-1SUDOERS\s0 \s-1OPTIONS\s0\*(R" section below.
-.PP
-\fI\s-1LOG_OUTPUT\s0 and \s-1NOLOG_OUTPUT\s0\fR
-.IX Subsection "LOG_OUTPUT and NOLOG_OUTPUT"
-.PP
-These tags override the value of the \fIlog_output\fR option on a
-per-command basis.  For more information, see the description of
-\&\fIlog_output\fR in the \*(L"\s-1SUDOERS\s0 \s-1OPTIONS\s0\*(R" section below.
-.SS "Wildcards"
-.IX Subsection "Wildcards"
-\&\fBsudo\fR allows shell-style \fIwildcards\fR (aka meta or glob characters)
-to be used in host names, path names and command line arguments in
-the \fIsudoers\fR file.  Wildcard matching is done via the \fB\s-1POSIX\s0\fR
-\&\fIglob\fR\|(3) and \fIfnmatch\fR\|(3) routines.  Note that these are \fInot\fR
-regular expressions.
-.ie n .IP "\*(C`*\*(C'" 8
-.el .IP "\f(CW\*(C`*\*(C'\fR" 8
-.IX Item "*"
-Matches any set of zero or more characters.
-.ie n .IP "\*(C`?\*(C'" 8
-.el .IP "\f(CW\*(C`?\*(C'\fR" 8
-.IX Item "?"
-Matches any single character.
-.ie n .IP "\*(C`[...]\*(C'" 8
-.el .IP "\f(CW\*(C`[...]\*(C'\fR" 8
-.IX Item "[...]"
-Matches any character in the specified range.
-.ie n .IP "\*(C`[!...]\*(C'" 8
-.el .IP "\f(CW\*(C`[!...]\*(C'\fR" 8
-.IX Item "[!...]"
-Matches any character \fBnot\fR in the specified range.
-.ie n .IP "\*(C`\ex\*(C'" 8
-.el .IP "\f(CW\*(C`\ex\*(C'\fR" 8
-.IX Item "x"
-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 \fIglob\fR\|(3)
-and \fIfnmatch\fR\|(3) functions support 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 file name beginning with a letter.
-.PP
-Note that a forward slash ('/') will \fBnot\fR be matched by
-wildcards used in the path name.  When matching the command
-line arguments, however, a slash \fBdoes\fR get matched by
-wildcards.  This is to make a path like:
-.PP
-.Vb 1
-\&    /usr/bin/*
-.Ve
-.PP
-match \fI/usr/bin/who\fR but not \fI/usr/bin/X11/xterm\fR.
-.SS "Exceptions to wildcard rules"
-.IX Subsection "Exceptions to wildcard rules"
-The following exceptions apply to the above rules:
-.ie n .IP """""" 8
-.el .IP "\f(CW``''\fR" 8
-.IX Item """"""
-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.
-.SS "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 and
-\&\f(CW\*(C`#includedir\*(C'\fR directives.
-.PP
-This can be used, for example, to keep a site-wide \fIsudoers\fR file
-in addition to a local, per-machine file.  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 within \fI/etc/sudoers\fR we would use the
-following line in \fI/etc/sudoers\fR:
-.Sp
-.RS 4
-\&\f(CW\*(C`#include /etc/sudoers.local\*(C'\fR
-.RE
-.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.
-.PP
-The file name may include the \f(CW%h\fR escape, signifying the short form
-of the host name.  I.e., if the machine's host name is \*(L"xerxes\*(R", then
-.PP
-\&\f(CW\*(C`#include /etc/sudoers.%h\*(C'\fR
-.PP
-will cause \fBsudo\fR to include the file \fI/etc/sudoers.xerxes\fR.
-.PP
-The \f(CW\*(C`#includedir\*(C'\fR directive can be used to create a \fIsudo.d\fR
-directory that the system package manager can drop \fIsudoers\fR rules
-into as part of package installation.  For example, given:
-.PP
-\&\f(CW\*(C`#includedir /etc/sudoers.d\*(C'\fR
-.PP
-\&\fBsudo\fR will read each file in \fI/etc/sudoers.d\fR, skipping file
-names that end in \f(CW\*(C`~\*(C'\fR or contain a \f(CW\*(C`.\*(C'\fR character to avoid causing
-problems with package manager or editor temporary/backup files.
-Files are parsed in sorted lexical order.  That is,
-\&\fI/etc/sudoers.d/01_first\fR will be parsed before
-\&\fI/etc/sudoers.d/10_second\fR.  Be aware that because the sorting is
-lexical, not numeric, \fI/etc/sudoers.d/1_whoops\fR would be loaded
-\&\fBafter\fR \fI/etc/sudoers.d/10_second\fR.  Using a consistent number
-of leading zeroes in the file names can be used to avoid such
-problems.
-.PP
-Note that unlike files included via \f(CW\*(C`#include\*(C'\fR, \fBvisudo\fR will not
-edit the files in a \f(CW\*(C`#includedir\*(C'\fR directory unless one of them
-contains a syntax error.  It is still possible to run \fBvisudo\fR
-with the \f(CW\*(C`\-f\*(C'\fR flag to edit the files directly.
-.SS "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
-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.
-.PP
-The reserved word \fB\s-1ALL\s0\fR is a built-in \fIalias\fR that always causes
-a match to succeed.  It can be used wherever one might otherwise
-use a \f(CW\*(C`Cmnd_Alias\*(C'\fR, \f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_Alias\*(C'\fR, or \f(CW\*(C`Host_Alias\*(C'\fR.
-You should not try to define your own \fIalias\fR called \fB\s-1ALL\s0\fR as the
-built-in alias will be used in preference to your own.  Please note
-that using \fB\s-1ALL\s0\fR can be dangerous since in a command context, it
-allows the user to run \fBany\fR command on the system.
-.PP
-An exclamation point ('!') can be used as a logical \fInot\fR operator
-both in an \fIalias\fR and in front of a \f(CW\*(C`Cmnd\*(C'\fR.  This allows one to
-exclude certain values.  Note, however, that using a \f(CW\*(C`!\*(C'\fR in
-conjunction with the built-in \f(CW\*(C`ALL\*(C'\fR alias to allow a user to
-run \*(L"all but a few\*(R" commands rarely works as intended (see \s-1SECURITY\s0
-\&\s-1NOTES\s0 below).
-.PP
-Long lines can be continued with a backslash ('\e') as the last
-character on the line.
-.PP
-Whitespace between elements in a list as well as special syntactic
-characters in a \fIUser Specification\fR ('=', ':', '(', ')') is optional.
-.PP
-The following characters must be escaped with a backslash ('\e') when
-used as part of a word (e.g.\ a user name or host name):
-\&'!', '=', ':', ',', '(', ')', '\e'.
-.SH "SUDOERS OPTIONS"
-.IX Header "SUDOERS OPTIONS"
-\&\fBsudo\fR's behavior can be modified by \f(CW\*(C`Default_Entry\*(C'\fR lines, as
-explained earlier.  A list of all supported Defaults parameters,
-grouped by type, are listed below.
-.PP
-\&\fBBoolean Flags\fR:
-.IP "always_set_home" 16
-.IX Item "always_set_home"
-If enabled, \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 option is
-always implied.  Note that \f(CW\*(C`HOME\*(C'\fR is already set when the the
-\&\fIenv_reset\fR option is enabled, so \fIalways_set_home\fR is only
-effective for configurations where either \fIenv_reset\fR is disabled
-or \f(CW\*(C`HOME\*(C'\fR is present in the \fIenv_keep\fR list.
-This flag is \fIoff\fR by default.
-.IP "authenticate" 16
-.IX Item "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 \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 "compress_io" 16
-.IX Item "compress_io"
-If set, and \fBsudo\fR is configured to log a command's input or output,
-the I/O logs will be compressed using \fBzlib\fR.  This flag is \fIon\fR
-by default when \fBsudo\fR is compiled with \fBzlib\fR support.
-.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
-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 \f(CW\*(C`editor\*(C'\fR
-variable.  \fBvisudo\fR will then only use the \s-1EDITOR\s0 or \s-1VISUAL\s0 if
-they match a value specified in \f(CW\*(C`editor\*(C'\fR.  This flag is \fI@env_editor@\fR by
-default.
-.IP "env_reset" 16
-.IX Item "env_reset"
-If set, \fBsudo\fR will reset the environment to only contain the
-\&\s-1LOGNAME\s0, \s-1MAIL\s0, \s-1SHELL\s0, \s-1USER\s0, \s-1USERNAME\s0 and the \f(CW\*(C`SUDO_*\*(C'\fR variables.  Any
-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 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 \fI@env_reset@\fR by default.
-.IP "fast_glob" 16
-.IX Item "fast_glob"
-Normally, \fBsudo\fR uses the \fIglob\fR\|(3) function to do shell-style
-globbing when matching path names.  However, since it accesses the
-file system, \fIglob\fR\|(3) can take a long time to complete for some
-patterns, especially when the pattern references a network file
-system that is mounted on demand (automounted).  The \fIfast_glob\fR
-option causes \fBsudo\fR to use the \fIfnmatch\fR\|(3) function, which does
-not access the file system to do its matching.  The disadvantage
-of \fIfast_glob\fR is that it is unable to match relative path names
-such as \fI./ls\fR or \fI../bin/ls\fR.  This has security implications
-when path names that include globbing characters are used with the
-negation operator, \f(CW\*(Aq!\*(Aq\fR, as such rules can be trivially bypassed.
-As such, this option should not be used when \fIsudoers\fR contains rules 
-that contain negated path names which include globbing characters.
-This flag is \fIoff\fR by default.
-.IP "fqdn" 16
-.IX Item "fqdn"
-Set this flag if you want to put fully qualified host names in the
-\&\fIsudoers\fR 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 \fIfqdn\fR requires \fBsudo\fR to make \s-1DNS\s0 lookups
-which may make \fBsudo\fR unusable if \s-1DNS\s0 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 \s-1DNS\s0 knows it.  That is,
-you may not use a host alias (\f(CW\*(C`CNAME\*(C'\fR entry) due to performance
-issues and the fact that there is no way to get all aliases from
-\&\s-1DNS\s0.  If your machine's host name (as returned by the \f(CW\*(C`hostname\*(C'\fR
-command) is already fully qualified you shouldn't need to set
-\&\fIfqdn\fR.  This flag is \fI@fqdn@\fR by default.
-.IP "ignore_dot" 16
-.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.
-.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.
-This is intended for Enterprises that wish to prevent the usage of local
-sudoers files so that only \s-1LDAP\s0 is used.  This thwarts the efforts of
-rogue operators who would attempt to add roles to \fI@sysconfdir@/sudoers\fR.
-When this option is present, \fI@sysconfdir@/sudoers\fR does not even need to
-exist. Since this option tells \fBsudo\fR how to behave when no specific \s-1LDAP\s0
-entries have been matched, this sudoOption is only meaningful for the
-\&\f(CW\*(C`cn=defaults\*(C'\fR section.  This flag is \fIoff\fR by default.
-.IP "insults" 16
-.IX Item "insults"
-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 host name will be logged in the (non-syslog) \fBsudo\fR log file.
-This flag is \fIoff\fR by default.
-.IP "log_input" 16
-.IX Item "log_input"
-If set, \fBsudo\fR will run the command in a \fIpseudo tty\fR and log all
-user input.
-If the standard input is not connected to the user's tty, due to
-I/O redirection or because the command is part of a pipeline, that
-input is also captured and stored in a separate log file.
-.Sp
-Input is logged to the directory specified by the \fIiolog_dir\fR
-option (\fI@iolog_dir@\fR by default) using a unique session \s-1ID\s0 that
-is included in the normal \fBsudo\fR log line, prefixed with \fITSID=\fR.
-.Sp
-Note that user input may contain sensitive information such as
-passwords (even if they are not echoed to the screen), which will
-be stored in the log file unencrypted.  In most cases, logging the
-command output via \fIlog_output\fR is all that is required.
-.IP "log_output" 16
-.IX Item "log_output"
-If set, \fBsudo\fR will run the command in a \fIpseudo tty\fR and log all
-output that is sent to the screen, similar to the \fIscript\fR\|(1) command.
-If the standard output or standard error is not connected to the
-user's tty, due to I/O redirection or because the command is part
-of a pipeline, that output is also captured and stored in separate
-log files.
-.Sp
-Output is logged to the directory specified by the \fIiolog_dir\fR
-option (\fI@iolog_dir@\fR by default) using a unique session \s-1ID\s0 that
-is included in the normal \fBsudo\fR log line, prefixed with \fITSID=\fR.
-.Sp
-Output logs may be viewed with the \fIsudoreplay\fR\|(@mansectsu@) utility, which
-can also be used to list or search the available logs.
-.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.
-This flag is \fIoff\fR by default.
-.IP "long_otp_prompt" 16
-.IX Item "long_otp_prompt"
-When validating with a One Time Password (\s-1OPT\s0) scheme such as
-\&\fBS/Key\fR or \fB\s-1OPIE\s0\fR, 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 \fI@long_otp_prompt@\fR by default.
-.IP "mail_always" 16
-.IX Item "mail_always"
-Send mail to the \fImailto\fR user every time a users runs \fBsudo\fR.
-This flag is \fIoff\fR by default.
-.IP "mail_badpass" 16
-.IX Item "mail_badpass"
-Send mail to the \fImailto\fR user if the user running \fBsudo\fR does not
-enter the correct password.  This flag is \fIoff\fR by default.
-.IP "mail_no_host" 16
-.IX Item "mail_no_host"
-If set, mail will be sent to the \fImailto\fR user if the invoking
-user exists in the \fIsudoers\fR file, but is not allowed to run
-commands on the current host.  This flag is \fI@mail_no_host@\fR by default.
-.IP "mail_no_perms" 16
-.IX Item "mail_no_perms"
-If set, mail will be sent to the \fImailto\fR user if the invoking
-user is allowed to use \fBsudo\fR but the command they are trying is not
-listed in their \fIsudoers\fR file entry or is explicitly denied.
-This flag is \fI@mail_no_perms@\fR by default.
-.IP "mail_no_user" 16
-.IX Item "mail_no_user"
-If set, mail will be sent to the \fImailto\fR user if the invoking
-user is not in the \fIsudoers\fR file.  This flag is \fI@mail_no_user@\fR
-by default.
-.IP "noexec" 16
-.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.
-.IP "path_info" 16
-.IX Item "path_info"
-Normally, \fBsudo\fR will tell the user when a command could not be
-found in their \f(CW\*(C`PATH\*(C'\fR 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 \f(CW\*(C`PATH\*(C'\fR, \fBsudo\fR will tell the user that they are not
-allowed to run it, which can be confusing.  This flag is \fI@path_info@\fR
-by default.
-.IP "passprompt_override" 16
-.IX Item "passprompt_override"
-The password prompt specified by \fIpassprompt\fR will normally only
-be used if the password prompt provided by systems such as \s-1PAM\s0 matches
-the string \*(L"Password:\*(R".  If \fIpassprompt_override\fR is set, \fIpassprompt\fR
-will always be used.  This flag is \fIoff\fR by default.
-.IP "preserve_groups" 16
-.IX Item "preserve_groups"
-By default, \fBsudo\fR will initialize the group vector to the list of
-groups the target user is in.  When \fIpreserve_groups\fR 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 \fIoff\fR by default.
-.IP "pwfeedback" 16
-.IX Item "pwfeedback"
-By default, \fBsudo\fR reads the password like most other Unix programs,
-by turning off echo until the user hits the return (or enter) key.
-Some users become confused by this as it appears to them that \fBsudo\fR
-has hung at this point.  When \fIpwfeedback\fR is set, \fBsudo\fR will
-provide visual feedback when the user presses a key.  Note that
-this does have a security impact as an onlooker may be able to
-determine the length of the password being entered.
-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.  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
-from \*(L"chaining\*(R" \fBsudo\fR commands to get a root shell by doing something
-like \f(CW"sudo sudo /bin/sh"\fR.  Note, however, that turning off \fIroot_sudo\fR
-will also prevent root from running \fBsudoedit\fR.
-Disabling \fIroot_sudo\fR provides no real additional security; it
-exists purely for historical reasons.
-This flag is \fI@root_sudo@\fR by default.
-.IP "rootpw" 16
-.IX Item "rootpw"
-If set, \fBsudo\fR will prompt for the root password instead of the password
-of the invoking user.  This flag is \fIoff\fR by default.
-.IP "runaspw" 16
-.IX Item "runaspw"
-If set, \fBsudo\fR will prompt for the password of the user defined by the
-\&\fIrunas_default\fR option (defaults to \f(CW\*(C`@runas_default@\*(C'\fR) instead of the
-password of the invoking user.  This flag is \fIoff\fR by default.
-.IP "set_home" 16
-.IX Item "set_home"
-If enabled 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 option imply \fB\-H\fR.  Note that \f(CW\*(C`HOME\*(C'\fR is already
-set when the the \fIenv_reset\fR option is enabled, so \fIset_home\fR is
-only effective for configurations where either \fIenv_reset\fR is disabled
-or \f(CW\*(C`HOME\*(C'\fR is present in the \fIenv_keep\fR list.
-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 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
-option.  Note that if the \fIenv_reset\fR option has not been disabled,
-entries in the \fIenv_keep\fR list will override the value of
-\&\fIset_logname\fR.  This flag is \fIon\fR by default.
-.IP "setenv" 16
-.IX Item "setenv"
-Allow the user to disable the \fIenv_reset\fR option from the command
-line.  Additionally, environment variables set via the command line
-are not subject to the restrictions imposed by \fIenv_check\fR,
-\&\fIenv_delete\fR, or \fIenv_keep\fR.  As such, only trusted users should
-be allowed to set variables in this manner.  This flag is \fIoff\fR
-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 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.
-.IP "stay_setuid" 16
-.IX Item "stay_setuid"
-Normally, when \fBsudo\fR 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 \s-1UID\s0 is left as the invoking
-user's \s-1UID\s0.  In other words, this makes \fBsudo\fR 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 \fIsetreuid()\fR or \fIsetresuid()\fR
-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 option (defaults to \f(CW\*(C`root\*(C'\fR) instead of the password
-of the invoking user.  In addition, the timestamp file name will
-include the target user's name.  Note that this flag precludes the
-use of a uid not listed 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"
-If set, users must authenticate on a per-tty basis.  With this flag
-enabled, \fBsudo\fR will use a file named for the tty the user is
-logged in on in the user's time stamp directory.  If disabled, the
-time stamp of the directory is used instead.  This flag is
-\&\fI@tty_tickets@\fR by default.
-.IP "umask_override" 16
-.IX Item "umask_override"
-If set, \fBsudo\fR will set the umask as specified by \fIsudoers\fR without
-modification.  This makes it possible to specify a more permissive
-umask in \fIsudoers\fR than the user's own umask and matches historical
-behavior.  If \fIumask_override\fR is not set, \fBsudo\fR will set the
-umask to be the union of the user's umask and what is specified in
-\&\fIsudoers\fR.  This flag is \fI@umask_override@\fR by default.
-.if \n(LC \{\
-.IP "use_loginclass" 16
-.IX Item "use_loginclass"
-If set, \fBsudo\fR will apply the defaults specified for the target user's
-login class if one exists.  Only available if \fBsudo\fR is configured with
-the \-\-with\-logincap option.  This flag is \fIoff\fR by default.
-\}
-.IP "use_pty" 16
-.IX Item "use_pty"
-If set, \fBsudo\fR will run the command in a pseudo-pty even if no I/O
-logging is being gone.  A malicious program run under \fBsudo\fR could
-conceivably fork a background process that retains to the user's
-terminal device after the main program has finished executing.  Use
-of this option will make that impossible.
-.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
-\&\fBsudo\fR logs the failure and exits.  The default is \f(CW\*(C`@passwd_tries@\*(C'\fR.
-.PP
-\&\fBIntegers that can be used in a boolean context\fR:
-.IP "loglinelen" 16
-.IX Item "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
-\&\f(CW\*(C`@loglen@\*(C'\fR (use 0 or negate the option to disable word wrap).
-.IP "passwd_timeout" 16
-.IX Item "passwd_timeout"
-Number of minutes before the \fBsudo\fR password prompt times out, or
-\&\f(CW0\fR for no timeout.  The timeout may include a fractional component
-if minute granularity is insufficient, for example \f(CW2.5\fR.  The
-default is \f(CW\*(C`@password_timeout@\*(C'\fR.
-.IP "timestamp_timeout" 16
-.IX Item "timestamp_timeout"
-Number of minutes that can elapse before \fBsudo\fR will ask for a
-passwd again.  The timeout may include a fractional component if
-minute granularity is insufficient, for example \f(CW2.5\fR.  The default
-is \f(CW\*(C`@timeout@\*(C'\fR.  Set this to \f(CW0\fR to always prompt for a password.
-If set to a value less than \f(CW0\fR the user's timestamp will never
-expire.  This can be used to allow users to create or delete their
-own timestamps via \f(CW\*(C`sudo \-v\*(C'\fR and \f(CW\*(C`sudo \-k\*(C'\fR respectively.
-.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 actual umask that is
-used will be the union of the user's umask and the value of the
-\&\fIumask\fR option, which defaults to \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
-.IX Item "badpass_message"
-Message that is displayed if a user enters an incorrect password.
-The default is \f(CW\*(C`@badpass_message@\*(C'\fR unless insults are enabled.
-.IP "editor" 16
-.IX Item "editor"
-A colon (':') separated list of editors allowed to be used with
-\&\fBvisudo\fR.  \fBvisudo\fR will choose the editor that matches the user's
-\&\s-1EDITOR\s0 environment variable if possible, or the first editor in the
-list that exists and is executable.  The default is \f(CW"@editor@"\fR.
-.IP "iolog_dir" 16
-.IX Item "iolog_dir"
-The directory in which to store input/output logs when the \fIlog_input\fR
-or \fIlog_output\fR options are enabled or when the \f(CW\*(C`LOG_INPUT\*(C'\fR or
-\&\f(CW\*(C`LOG_OUTPUT\*(C'\fR tags are present for a command.
-The default is \f(CW"@iolog_dir@"\fR.
-.IP "mailsub" 16
-.IX Item "mailsub"
-Subject of the mail sent to the \fImailto\fR user. The escape \f(CW%h\fR
-will expand to the host name of the machine.
-Default is \f(CW\*(C`@mailsub@\*(C'\fR.
-.IP "noexec_file" 16
-.IX Item "noexec_file"
-Path to a shared library containing dummy versions of the \fIexecv()\fR,
-\&\fIexecve()\fR and \fIfexecve()\fR library functions that just return an error.
-This is used to implement the \fInoexec\fR functionality on systems that
-support \f(CW\*(C`LD_PRELOAD\*(C'\fR or its equivalent.  Defaults to \fI@noexec_file@\fR.
-.IP "passprompt" 16
-.IX Item "passprompt"
-The default prompt to use when asking for a password; can be overridden
-via the \fB\-p\fR option or the \f(CW\*(C`SUDO_PROMPT\*(C'\fR environment variable.
-The following percent (`\f(CW\*(C`%\*(C'\fR') escapes are supported:
-.RS 16
-.ie n .IP "%H" 4
-.el .IP "\f(CW%H\fR" 4
-.IX Item "%H"
-expanded to the local host name including the domain name
-(on if the machine's host name is fully qualified or the \fIfqdn\fR
-option is set)
-.ie n .IP "%h" 4
-.el .IP "\f(CW%h\fR" 4
-.IX Item "%h"
-expanded to the local host name without the domain name
-.ie n .IP "%p" 4
-.el .IP "\f(CW%p\fR" 4
-.IX Item "%p"
-expanded to the user whose password is being asked for (respects the 
-\&\fIrootpw\fR, \fItargetpw\fR and \fIrunaspw\fR flags in \fIsudoers\fR)
-.ie n .IP "%U" 4
-.el .IP "\f(CW%U\fR" 4
-.IX Item "%U"
-expanded to the login name of the user the command will
-be run as (defaults to root)
-.ie n .IP "%u" 4
-.el .IP "\f(CW%u\fR" 4
-.IX Item "%u"
-expanded to the invoking user's login name
-.ie n .IP "\*(C`%%\*(C'" 4
-.el .IP "\f(CW\*(C`%%\*(C'\fR" 4
-.IX Item "%%"
-two consecutive \f(CW\*(C`%\*(C'\fR characters are collapsed into a single \f(CW\*(C`%\*(C'\fR character
-.RE
-.RS 16
-.Sp
-The default value is \f(CW\*(C`@passprompt@\*(C'\fR.
-.RE
-.if \n(SL \{\
-.IP "role" 16
-.IX Item "role"
-The default SELinux role to use when constructing a new security
-context to run the command.  The default role may be overridden on
-a per-command basis in \fIsudoers\fR or via command line options.
-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 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.
-.IP "syslog_badpri" 16
-.IX Item "syslog_badpri"
-Syslog priority to use when user authenticates unsuccessfully.
-Defaults to \f(CW\*(C`@badpri@\*(C'\fR.
-.IP "syslog_goodpri" 16
-.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, logging commands, and
-sending email.  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.
-The default is \fI@timedir@\fR.
-.IP "timestampowner" 16
-.IX Item "timestampowner"
-The owner of the timestamp directory and the timestamps stored therein.
-The default is \f(CW\*(C`root\*(C'\fR.
-.if \n(SL \{\
-.IP "type" 16
-.IX Item "type"
-The default SELinux type to use when constructing a new security
-context to run the command.  The default type may be overridden on
-a per-command basis in \fIsudoers\fR or via command line options.
-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 either be of the form
-\&\f(CW\*(C`VARIABLE=value\*(C'\fR or \f(CW\*(C`export VARIABLE=value\*(C'\fR.  The value may
-optionally be surrounded by single or double quotes.  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.
-This is not set by default.
-.IP "lecture" 12
-.IX Item "lecture"
-This option controls when a short lecture will be printed along with
-the password prompt.  It has the following possible values:
-.RS 12
-.IP "always" 8
-.IX Item "always"
-Always lecture the user.
-.IP "never" 8
-.IX Item "never"
-Never lecture the user.
-.IP "once" 8
-.IX Item "once"
-Only lecture the user the first time they run \fBsudo\fR.
-.RE
-.RS 12
-.Sp
-If no value is specified, a value of \fIonce\fR is implied.
-Negating the option results in a value of \fInever\fR being used.
-The default value is \fI@lecture@\fR.
-.RE
-.IP "lecture_file" 12
-.IX Item "lecture_file"
-Path to a file containing an alternate \fBsudo\fR lecture that will
-be used in place of the standard lecture if the named file exists.
-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 option.  It has the following possible values:
-.RS 12
-.IP "all" 8
-.IX Item "all"
-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 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 option.
-.RE
-.RS 12
-.Sp
-If no value is specified, a value of \fIany\fR is implied.
-Negating the option results in a value of \fInever\fR being used.
-The default value is \fIany\fR.
-.RE
-.IP "logfile" 12
-.IX Item "logfile"
-Path to the \fBsudo\fR log file (not the syslog log file).  Setting a path
-turns on logging to a file; negating this option turns it off.
-By default, \fBsudo\fR logs via syslog.
-.IP "mailerflags" 12
-.IX Item "mailerflags"
-Flags to use when invoking mailer. Defaults to \fB\-t\fR.
-.IP "mailerpath" 12
-.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 option is @secure_path@ by default.
-.IP "syslog" 12
-.IX Item "syslog"
-Syslog facility if syslog is being used for logging (negate to
-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 option.  It has the following possible values:
-.RS 12
-.IP "all" 8
-.IX Item "all"
-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 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 option.
-.RE
-.RS 12
-.Sp
-If no value is specified, a value of \fIall\fR is implied.
-Negating the option results in a value of \fInever\fR being used.
-The default value is \fIall\fR.
-.RE
-.PP
-\&\fBLists that can be used in a boolean context\fR:
-.IP "env_check" 16
-.IX Item "env_check"
-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
-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
-specified by \f(CW\*(C`env_check\*(C'\fR will be preserved in the environment if
-they pass the aforementioned check.  The default list of environment
-variables to check is displayed when \fBsudo\fR is run by root with
-the \fI\-V\fR option.
-.IP "env_delete" 16
-.IX Item "env_delete"
-Environment variables to be removed from the user's environment
-when the \fIenv_reset\fR option is not in effect.  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 \fI\-V\fR option.
-Note that many operating systems will remove potentially dangerous
-variables from the environment of any setuid process (such as
-\&\fBsudo\fR).
-.IP "env_keep" 16
-.IX Item "env_keep"
-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
-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.
-.PP
-When logging via \fIsyslog\fR\|(3), \fBsudo\fR accepts the following values
-for the syslog facility (the value of the \fBsyslog\fR Parameter):
-\&\fBauthpriv\fR (if your \s-1OS\s0 supports it), \fBauth\fR, \fBdaemon\fR, \fBuser\fR,
-\&\fBlocal0\fR, \fBlocal1\fR, \fBlocal2\fR, \fBlocal3\fR, \fBlocal4\fR, \fBlocal5\fR,
-\&\fBlocal6\fR, and \fBlocal7\fR.  The following syslog priorities are
-supported: \fBalert\fR, \fBcrit\fR, \fBdebug\fR, \fBemerg\fR, \fBerr\fR, \fBinfo\fR,
-\&\fBnotice\fR, and \fBwarning\fR.
-.SH "FILES"
-.IX Header "FILES"
-.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
-.IX Item "/etc/group"
-Local groups file
-.IP "\fI/etc/netgroup\fR" 24
-.IX Item "/etc/netgroup"
-List of network groups
-.ie n .IP "\fI@iolog_dir@\fR" 24
-.el .IP "\fI@iolog_dir@\fR" 24
-.IX Item "@iolog_dir@"
-I/O log files
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-Below are example \fIsudoers\fR entries.  Admittedly, some of
-these are a bit contrived.  First, we allow a few environment
-variables to pass and then define our \fIaliases\fR:
-.PP
-.Vb 4
-\& # Run X applications through sudo; HOME is used to find the
-\& # .Xauthority file.  Note that other programs use HOME to find
-\& # configuration files and this may lead to privilege escalation!
-\& Defaults env_keep += "DISPLAY HOME"
-\&
-\& # User alias specification
-\& User_Alias     FULLTIMERS = millert, mikef, dowdy
-\& User_Alias     PARTTIMERS = bostley, jwfox, crawl
-\& User_Alias     WEBMASTERS = will, wendy, wim
-\&
-\& # Runas alias specification
-\& Runas_Alias    OP = root, operator
-\& Runas_Alias    DB = oracle, sybase
-\& Runas_Alias    ADMINGRP = adm, oper
-\&
-\& # Host alias specification
-\& Host_Alias     SPARC = bigtime, eclipse, moet, anchor :\e
-\&                SGI = grolsch, dandelion, black :\e
-\&                ALPHA = widget, thalamus, foobar :\e
-\&                HPPA = boa, nag, python
-\& Host_Alias     CUNETS = 128.138.0.0/255.255.0.0
-\& 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
-\&
-\& # Cmnd alias specification
-\& Cmnd_Alias     DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\e
-\&                        /usr/sbin/restore, /usr/sbin/rrestore
-\& Cmnd_Alias     KILL = /usr/bin/kill
-\& Cmnd_Alias     PRINTING = /usr/sbin/lpc, /usr/bin/lprm
-\& Cmnd_Alias     SHUTDOWN = /usr/sbin/shutdown
-\& Cmnd_Alias     HALT = /usr/sbin/halt
-\& Cmnd_Alias     REBOOT = /usr/sbin/reboot
-\& Cmnd_Alias     SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \e
-\&                         /usr/local/bin/tcsh, /usr/bin/rsh, \e
-\&                         /usr/local/bin/zsh
-\& Cmnd_Alias     SU = /usr/bin/su
-\& Cmnd_Alias     PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less
-.Ve
-.PP
-Here we override some of the compiled in default values.  We want
-\&\fBsudo\fR to log via \fIsyslog\fR\|(3) using the \fIauth\fR facility in all
-cases.  We don't want to subject the full time staff to the \fBsudo\fR
-lecture, user \fBmillert\fR need not give a password, and we don't
-want to reset the \f(CW\*(C`LOGNAME\*(C'\fR, \f(CW\*(C`USER\*(C'\fR or \f(CW\*(C`USERNAME\*(C'\fR environment
-variables when running commands as root.  Additionally, on the
-machines in the \fI\s-1SERVERS\s0\fR \f(CW\*(C`Host_Alias\*(C'\fR, 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 \s-1PAGERS\s0 \f(CW\*(C`Cmnd_Alias\*(C'\fR
-(\fI/usr/bin/more\fR, \fI/usr/bin/pg\fR and \fI/usr/bin/less\fR).
-.PP
-.Vb 7
-\& # 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
-.Ve
-.PP
-The \fIUser specification\fR is the part that actually determines who may
-run what.
-.PP
-.Vb 2
-\& root           ALL = (ALL) ALL
-\& %wheel         ALL = (ALL) ALL
-.Ve
-.PP
-We let \fBroot\fR and any user in group \fBwheel\fR run any command on any
-host as any user.
-.PP
-.Vb 1
-\& FULLTIMERS     ALL = NOPASSWD: ALL
-.Ve
-.PP
-Full time sysadmins (\fBmillert\fR, \fBmikef\fR, and \fBdowdy\fR) may run any
-command on any host without authenticating themselves.
-.PP
-.Vb 1
-\& PARTTIMERS     ALL = ALL
-.Ve
-.PP
-Part time sysadmins (\fBbostley\fR, \fBjwfox\fR, and \fBcrawl\fR) may run any
-command on any host but they must authenticate themselves first
-(since the entry lacks the \f(CW\*(C`NOPASSWD\*(C'\fR tag).
-.PP
-.Vb 1
-\& jack           CSNETS = ALL
-.Ve
-.PP
-The user \fBjack\fR may run any command on the machines in the \fI\s-1CSNETS\s0\fR alias
-(the networks \f(CW128.138.243.0\fR, \f(CW128.138.204.0\fR, and \f(CW128.138.242.0\fR).
-Of those networks, only \f(CW128.138.204.0\fR has an explicit netmask (in
-\&\s-1CIDR\s0 notation) indicating it is a class C network.  For the other
-networks in \fI\s-1CSNETS\s0\fR, the local machine's netmask will be used
-during matching.
-.PP
-.Vb 1
-\& lisa           CUNETS = ALL
-.Ve
-.PP
-The user \fBlisa\fR may run any command on any host in the \fI\s-1CUNETS\s0\fR alias
-(the class B network \f(CW128.138.0.0\fR).
-.PP
-.Vb 2
-\& operator       ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\e
-\&                sudoedit /etc/printcap, /usr/oper/bin/
-.Ve
-.PP
-The \fBoperator\fR 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 \fI/usr/oper/bin/\fR.
-.PP
-.Vb 1
-\& joe            ALL = /usr/bin/su operator
-.Ve
-.PP
-The user \fBjoe\fR may only \fIsu\fR\|(1) to operator.
-.PP
-.Vb 1
-\& pete           HPPA = /usr/bin/passwd [A\-Za\-z]*, !/usr/bin/passwd root
-\&
-\& %opers         ALL = (: ADMINGRP) /usr/sbin/
-.Ve
-.PP
-Users in the \fBopers\fR group may run commands in \fI/usr/sbin/\fR as themselves
-with any group in the \fI\s-1ADMINGRP\s0\fR \f(CW\*(C`Runas_Alias\*(C'\fR (the \fBadm\fR and \fBoper\fR
-groups).
-.PP
-The user \fBpete\fR is allowed to change anyone's password except for
-root on the \fI\s-1HPPA\s0\fR machines.  Note that this assumes \fIpasswd\fR\|(1)
-does not take multiple user names on the command line.
-.PP
-.Vb 1
-\& bob            SPARC = (OP) ALL : SGI = (OP) ALL
-.Ve
-.PP
-The user \fBbob\fR may run anything on the \fI\s-1SPARC\s0\fR and \fI\s-1SGI\s0\fR machines
-as any user listed in the \fI\s-1OP\s0\fR \f(CW\*(C`Runas_Alias\*(C'\fR (\fBroot\fR and \fBoperator\fR).
-.PP
-.Vb 1
-\& jim            +biglab = ALL
-.Ve
-.PP
-The user \fBjim\fR may run any command on machines in the \fIbiglab\fR netgroup.
-\&\fBsudo\fR knows that \*(L"biglab\*(R" is a netgroup due to the '+' prefix.
-.PP
-.Vb 1
-\& +secretaries   ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser
-.Ve
-.PP
-Users in the \fBsecretaries\fR 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.
-.PP
-.Vb 1
-\& fred           ALL = (DB) NOPASSWD: ALL
-.Ve
-.PP
-The user \fBfred\fR can run commands as any user in the \fI\s-1DB\s0\fR \f(CW\*(C`Runas_Alias\*(C'\fR
-(\fBoracle\fR or \fBsybase\fR) without giving a password.
-.PP
-.Vb 1
-\& 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 specify any options to the \fIsu\fR\|(1) command.
-.PP
-.Vb 1
-\& jen            ALL, !SERVERS = ALL
-.Ve
-.PP
-The user \fBjen\fR may run any command on any machine except for those
-in the \fI\s-1SERVERS\s0\fR \f(CW\*(C`Host_Alias\*(C'\fR (master, mail, www and ns).
-.PP
-.Vb 1
-\& jill           SERVERS = /usr/bin/, !SU, !SHELLS
-.Ve
-.PP
-For any machine in the \fI\s-1SERVERS\s0\fR \f(CW\*(C`Host_Alias\*(C'\fR, \fBjill\fR may run
-any commands in the directory \fI/usr/bin/\fR except for those commands
-belonging to the \fI\s-1SU\s0\fR and \fI\s-1SHELLS\s0\fR \f(CW\*(C`Cmnd_Aliases\*(C'\fR.
-.PP
-.Vb 1
-\& steve          CSNETS = (operator) /usr/local/op_commands/
-.Ve
-.PP
-The user \fBsteve\fR may run any command in the directory /usr/local/op_commands/
-but only as user operator.
-.PP
-.Vb 1
-\& matt           valkyrie = KILL
-.Ve
-.PP
-On his personal workstation, valkyrie, \fBmatt\fR needs to be able to
-kill hung processes.
-.PP
-.Vb 1
-\& WEBMASTERS     www = (www) ALL, (root) /usr/bin/su www
-.Ve
-.PP
-On the host www, any user in the \fI\s-1WEBMASTERS\s0\fR \f(CW\*(C`User_Alias\*(C'\fR (will,
-wendy, and wim), may run any command as user www (which owns the
-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
-.Ve
-.PP
-Any user may mount or unmount a CD-ROM on the machines in the \s-1CDROM\s0
-\&\f(CW\*(C`Host_Alias\*(C'\fR (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.
-.SH "SECURITY NOTES"
-.IX Header "SECURITY NOTES"
-It is generally not effective to \*(L"subtract\*(R" commands from \f(CW\*(C`ALL\*(C'\fR
-using the '!' operator.  A user can trivially circumvent this
-by copying the desired command to a different name and then
-executing that.  For example:
-.PP
-.Vb 1
-\&    bill        ALL = ALL, !SU, !SHELLS
-.Ve
-.PP
-Doesn't really prevent \fBbill\fR from running the commands listed in
-\&\fI\s-1SU\s0\fR or \fI\s-1SHELLS\s0\fR 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).
-.PP
-Furthermore, if the \fIfast_glob\fR option is in use, it is not possible
-to reliably negate commands where the path name includes globbing
-(aka wildcard) characters.  This is because the C library's
-\&\fIfnmatch\fR\|(3) function cannot resolve relative paths.  While this
-is typically only an inconvenience for rules that grant privileges,
-it can result in a security issue for rules that subtract or revoke
-privileges.
-.PP
-For example, given the following \fIsudoers\fR entry:
-.PP
-.Vb 2
-\& john   ALL = /usr/bin/passwd [a\-zA\-Z0\-9]*, /usr/bin/chsh [a\-zA\-Z0\-9]*,
-\&      /usr/bin/chfn [a\-zA\-Z0\-9]*, !/usr/bin/* root
-.Ve
-.PP
-User \fBjohn\fR can still run \f(CW\*(C`/usr/bin/passwd root\*(C'\fR if \fIfast_glob\fR is
-enabled by changing to \fI/usr/bin\fR and running \f(CW\*(C`./passwd root\*(C'\fR instead.
-.SH "PREVENTING SHELL ESCAPES"
-.IX Header "PREVENTING SHELL ESCAPES"
-Once \fBsudo\fR 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 \fBsudo\fR's access control and logging.
-Common programs that permit shell escapes include shells (obviously),
-editors, paginators, mail and terminal programs.
-.PP
-There are two basic approaches to this problem:
-.IP "restrict" 10
-.IX Item "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 \fBsudoedit\fR is a better solution to
-running editors via \fBsudo\fR.  Due to the large number of programs that
-offer shell escapes, restricting users to the set of programs that
-do not is often unworkable.
-.IP "noexec" 10
-.IX Item "noexec"
-Many systems that support shared libraries have the ability to
-override default library functions by pointing an environment
-variable (usually \f(CW\*(C`LD_PRELOAD\*(C'\fR) to an alternate shared library.
-On such systems, \fBsudo\fR's \fInoexec\fR functionality can be used to
-prevent a program run by \fBsudo\fR 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.
-.Sp
-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"
-.Ve
-.Sp
-If the resulting output contains a line that begins with:
-.Sp
-.Vb 1
-\&    File containing dummy exec functions:
-.Ve
-.Sp
-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
-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
-\&\f(CW\*(C`LD_PRELOAD\*(C'\fR 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 \f(CW\*(C`LD_PRELOAD\*(C'\fR is supported.
-.Sp
-To enable \fInoexec\fR for a command, use the \f(CW\*(C`NOEXEC\*(C'\fR tag as documented
-in the User Specification section above.  Here is that example again:
-.Sp
-.Vb 1
-\& aaron  shanty = NOEXEC: /usr/bin/more, /usr/bin/vi
-.Ve
-.Sp
-This allows user \fBaaron\fR to run \fI/usr/bin/more\fR and \fI/usr/bin/vi\fR
-with \fInoexec\fR 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 \fInoexec\fR you
-can always just try it out and see if it works.
-.PP
-Note that restricting shell escapes is not a panacea.  Programs
-running as root are still capable of many potentially hazardous
-operations (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
-\&\fBsudoedit\fR.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIrsh\fR\|(1), \fIsu\fR\|(1), \fIfnmatch\fR\|(3), \fIglob\fR\|(3), \fIsudo\fR\|(@mansectsu@), \fIvisudo\fR\|(8)
-.SH "CAVEATS"
-.IX Header "CAVEATS"
-The \fIsudoers\fR file should \fBalways\fR be edited by the \fBvisudo\fR
-command which locks the file and does grammatical checking. It is
-imperative that \fIsudoers\fR be free of syntax errors since \fBsudo\fR
-will not run with a syntactically incorrect \fIsudoers\fR file.
-.PP
-When using netgroups of machines (as opposed to users), if you
-store fully qualified host name in the netgroup (as is usually the
-case), you either need to have the machine's host name be fully qualified
-as returned by the \f(CW\*(C`hostname\*(C'\fR command or use the \fIfqdn\fR option in
-\&\fIsudoers\fR.
-.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.man.pl b/sudoers.man.pl
deleted file mode 100644 (file)
index 6e5da2c..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/perl -p
-
-BEGIN {
-    $cond = -1;
-}
-
-# Initialize the numeric register we use for conditionals
-if ($cond == -1) {
-    $_ = ".nr SL \@SEMAN\@\n.nr BA \@BAMAN\@\n.nr LC \@LCMAN\@\n.\\\"\n$_";
-    $cond = 0;
-}
-
-# Make SELinux_Spec conditional
-if (/(.*)SELinux_Spec\? (.*)$/) {
-    $_ = ".ie \\n(SL $_.el $1$2\n";
-} elsif (/^(.*SELinux_Spec ::=)/) {
-    $_ = ".if \\n(SL \\{\\\n$_";
-} elsif (/^(.*Tag_Spec ::=)/) {
-    $_ = "\\}\n$_";
-}
-
-if (/^\.S[Sh] "SELinux_Spec"/) {
-    $_ = ".if \\n(SL \\{\\\n$_";
-    $cond = 1;
-} elsif (/^\.IP "(role|type)"/) {
-    $_ = ".if \\n(SL \\{\\\n$_";
-    $cond = 1;
-} elsif (/^\.IP "use_loginclass"/) {
-    $_ = ".if \\n(LC \\{\\\n$_";
-    $cond = 1;
-} elsif ($cond && /^\.(Sh|SS|IP|PP)/) {
-    $_ = "\\}\n$_";
-    $cond = 0;
-}
-
-# Fix up broken pod2man formatting of F<@foo@/bar>
-s/\\fI\\f(\(C)?I\@([^\@]*)\\fI\@/\\fI\@$2\@/g;
-s/\\f\(\CW\@([^\@]*)\\fR\@/\@$1\@/g;
-#\f(CW@secure_path\fR@
diff --git a/sudoers.pod b/sudoers.pod
deleted file mode 100644 (file)
index ef250cd..0000000
+++ /dev/null
@@ -1,1738 +0,0 @@
-Copyright (c) 1994-1996, 1998-2005, 2007-2011
-       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.
-
-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.
-
-=pod
-
-=head1 NAME
-
-sudoers - list of which users may execute what
-
-=head1 DESCRIPTION
-
-The I<sudoers> 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).
-
-The I<sudoers> 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.
-
-=head2 Quick guide to EBNF
-
-EBNF is a concise and exact way of describing the grammar of a language.
-Each EBNF definition is made up of I<production rules>.  E.g.,
-
- symbol ::= definition | alternate1 | alternate2 ...
-
-Each I<production rule> 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.
-
-=over 4
-
-=item C<?>
-
-Means that the preceding symbol (or group of symbols) is optional.
-That is, it may appear once or not at all.
-
-=item C<*>
-
-Means that the preceding symbol (or group of symbols) may appear
-zero or more times.
-
-=item C<+>
-
-Means that the preceding symbol (or group of symbols) may appear
-one or more times.
-
-=back
-
-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).
-
-=head2 Aliases
-
-There are four kinds of aliases: C<User_Alias>, C<Runas_Alias>,
-C<Host_Alias> and C<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
-
- Host_Alias ::= NAME '=' Host_List
-
- Cmnd_Alias ::= NAME '=' Cmnd_List
-
- NAME ::= [A-Z]([A-Z][0-9]_)*
-
-Each I<alias> definition is of the form
-
- Alias_Type NAME = item1, item2, ...
-
-where I<Alias_Type> is one of C<User_Alias>, C<Runas_Alias>, C<Host_Alias>,
-or C<Cmnd_Alias>.  A C<NAME> is a string of uppercase letters, numbers,
-and underscore characters ('_').  A C<NAME> B<must> 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 I<alias> member follow.
-
- User_List ::= User |
-              User ',' User_List
-
- User ::= '!'* user name |
-         '!'* #uid |
-         '!'* %group |
-         '!'* %#gid |
-         '!'* +netgroup |
-         '!'* %:nonunix_group |
-         '!'* %:#nonunix_gid |
-         '!'* User_Alias
-
-A C<User_List> is made up of one or more user names, user ids
-(prefixed with '#'), system group names and ids (prefixed with '%'
-and '%#' respectively), netgroups (prefixed with '+'), non-Unix
-group names and IDs (prefixed with '%:' and '%:#' respectively) 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.
-
-A C<user name>, C<uid>, C<group>, C<gid>, C<netgroup>, C<nonunix_group>
-or C<nonunix_gid> may be enclosed in double quotes to avoid the
-need for escaping special characters.  Alternately, special characters
-may be specified in escaped hex mode, e.g. \x20 for space.  When
-using double quotes, any prefix characters must be included inside
-the quotes.
-
-The C<nonunix_group> and C<nonunix_gid> syntax depends on the
-underlying implementation.  For instance, the QAS AD backend supports
-the following formats:
-
-=over 4
-
-=item *
-
-Group in the same domain: "Group Name"
-
-=item *
-
-Group in any domain: "Group Name@FULLY.QUALIFIED.DOMAIN"
-
-=item *
-
-Group SID: "S-1-2-34-5678901234-5678901234-5678901234-567"
-
-=back
-
-Note that quotes around group names are optional.  Unquoted strings
-must use a backslash (\) to escape spaces and special characters.
-See L<"Other special characters and reserved words"> for a list of
-characters that need to be escaped.
-
- Runas_List ::= Runas_Member |
-               Runas_Member ',' Runas_List
-
- Runas_Member ::= '!'* user name |
-                 '!'* #uid |
-                 '!'* %group |
-                 '!'* %#gid |
-                 '!'* %:nonunix_group |
-                 '!'* %:#nonunix_gid |
-                 '!'* +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
-user names 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 user names 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
-
- Host ::= '!'* host name |
-         '!'* ip_addr |
-         '!'* network(/netmask)? |
-         '!'* +netgroup |
-         '!'* Host_Alias
-
-A C<Host_List> is made up of one or more host names, 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,
-B<sudo> 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.E<nbsp>255.255.255.0 or ffff:ffff:ffff:ffff::),
-or CIDR notation (number of bits, e.g.E<nbsp>24 or 64).  A host name may
-include shell-style wildcards (see the L<Wildcards> section below),
-but unless the C<host name> command on your machine returns the fully
-qualified host name, you'll need to use the I<fqdn> option for
-wildcards to be useful.  Note B<sudo> only inspects actual network
-interfaces; this means that IP address 127.0.0.1 (localhost) will
-never match.  Also, the host name "localhost" will only match if
-that is the actual host name, which is usually only the case for
-non-networked systems.
-
- Cmnd_List ::= Cmnd |
-              Cmnd ',' Cmnd_List
-
- commandname ::= file name |
-                file name args |
-                file name '""'
-
- Cmnd ::= '!'* commandname |
-         '!'* directory |
-         '!'* "sudoedit" |
-         '!'* Cmnd_Alias
-
-A C<Cmnd_List> is a list of one or more commandnames, directories, and other
-aliases.  A commandname is a fully qualified file name which may include
-shell-style wildcards (see the L<Wildcards> section below).  A simple
-file name 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 C<""> to indicate that the command
-may only be run B<without> command line arguments.  A directory is a
-fully qualified path name ending in a '/'.  When you specify a directory
-in a C<Cmnd_List>, the user will be able to run any file within that directory
-(but not in any subdirectories therein).
-
-If a C<Cmnd> has associated command line arguments, then the arguments
-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> option (or
-as B<sudoedit>).  It may take command line arguments just as
-a normal command does.
-
-=head2 Defaults
-
-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, 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
-
- Parameter_List ::= Parameter |
-                   Parameter ',' Parameter_List
-
- Parameter ::= Parameter '=' Value |
-              Parameter '+=' Value |
-              Parameter '-=' Value |
-              '!'* Parameter
-
-Parameters may be B<flags>, B<integer> values, B<strings>, or B<lists>.
-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 (C<">) when they contain multiple words.  Special
-characters may be escaped with a backslash (C<\>).
-
-Lists have two additional assignment operators, C<+=> and C<-=>.
-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
-
- 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? SELinux_Spec? Tag_Spec* Cmnd
-
- Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
-
- SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
-
- Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' |
-              'SETENV:' | 'NOSETENV:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' |
-               'LOG_OUTPUT:' | 'NOLOG_OUTPUT:')
-
-A B<user specification> determines which commands a user may run
-(and as what user) on specified hosts.  By default, commands are
-run as B<root>, but this can be changed on a per-command basis.
-
-The basic structure of a user specification is `who where = (as_whom)
-what'.  Let's break that down into its constituent parts:
-
-=head2 Runas_Spec
-
-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
-
-The user B<dgb> may run F</bin/ls>, F</bin/kill>, and
-F</usr/bin/lprm> -- but only as B<operator>.  E.g.,
-
- $ sudo -u operator /bin/ls
-
-It is also possible to override a C<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 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
-
-Note that while the group portion of the C<Runas_Spec> permits the
-user to run as command with that group, it does not force the user
-to do so.  If no group is specified on the command line, the command
-will run with the group listed in the target user's password database
-entry.  The following would all be permitted by the sudoers entry above:
-
- $ sudo -u operator /bin/ls
- $ sudo -u operator -g operator /bin/ls
- $ sudo -g operator /bin/ls
-
-In the following example, user B<tcm> may run commands that access
-a modem device file with the dialer group.
-
- tcm   boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \
-       /usr/local/bin/minicom
-
-Note that in this example only the group will be set, the command
-still runs as user B<tcm>.  E.g.
-
- $ sudo -g dialer /usr/bin/cu
-
-Multiple users and groups may be present in a C<Runas_Spec>, in
-which case the user may select any combination of users and groups
-via the B<-u> and B<-g> options.  In this example:
-
- alan  ALL = (root, bin : operator, system) ALL
-
-user B<alan> may run any command as either user root or bin,
-optionally setting the group to operator or system.
-
-=head2 SELinux_Spec
-
-On systems with SELinux support, I<sudoers> entries may optionally have
-an SELinux role and/or type associated with a command.  If a role or
-type is specified with the command it will override any default values
-specified in I<sudoers>.  A role or type specified on the command line,
-however, will supercede the values in I<sudoers>.
-
-=head2 Tag_Spec
-
-A command may have zero or more tags associated with it.  There are
-eight possible tag values, C<NOPASSWD>, C<PASSWD>, C<NOEXEC>,
-C<EXEC>, C<SETENV>, C<NOSETENV>, C<LOG_INPUT>, C<NOLOG_INPUT>,
-C<LOG_OUTPUT> and C<NOLOG_OUTPUT>.  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 opposite tag (i.e.: C<PASSWD> overrides
-C<NOPASSWD> and C<NOEXEC> overrides C<EXEC>).
-
-=head3 NOPASSWD and PASSWD
-
-By default, B<sudo> requires that a user authenticate him or herself
-before running a command.  This behavior can be modified via the
-C<NOPASSWD> tag.  Like a C<Runas_Spec>, the C<NOPASSWD> tag sets
-a default for the commands that follow it in the C<Cmnd_Spec_List>.
-Conversely, the C<PASSWD> tag can be used to reverse things.
-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 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:
-
- ray   rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm
-
-Note, however, that the C<PASSWD> tag has no effect on users who are
-in the group specified by the I<exempt_group> option.
-
-By default, if the C<NOPASSWD> tag is applied to any of the entries
-for a user on the current host, he or she will be able to run
-C<sudo -l> without a password.  Additionally, a user may only run
-C<sudo -v> without a password if the C<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.
-
-=head3 NOEXEC and EXEC
-
-If B<sudo> has been compiled with I<noexec> support and the underlying
-operating system supports it, the C<NOEXEC> tag can be used to prevent
-a dynamically-linked executable from running further commands itself.
-
-In the following example, user B<aaron> may run F</usr/bin/more>
-and F</usr/bin/vi> but shell escapes will be disabled.
-
- aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi
-
-See the L<PREVENTING SHELL ESCAPES> section below for more details
-on how C<NOEXEC> works and whether or not it will work on your system.
-
-=head3 SETENV and NOSETENV
-
-These tags override the value of the I<setenv> option on a per-command
-basis.  Note that if C<SETENV> has been set for a command, the user
-may disable the I<env_reset> option from the command line via the
-B<-E> option.  Additionally, environment variables set on the command
-line are not subject to the restrictions imposed by I<env_check>,
-I<env_delete>, or I<env_keep>.  As such, only trusted users should
-be allowed to set variables in this manner.  If the command matched
-is B<ALL>, the C<SETENV> tag is implied for that command; this
-default may be overridden by use of the C<NOSETENV> tag.
-
-=head3 LOG_INPUT and NOLOG_INPUT
-
-These tags override the value of the I<log_input> option on a
-per-command basis.  For more information, see the description of
-I<log_input> in the L<"SUDOERS OPTIONS"> section below.
-
-=head3 LOG_OUTPUT and NOLOG_OUTPUT
-
-These tags override the value of the I<log_output> option on a
-per-command basis.  For more information, see the description of
-I<log_output> in the L<"SUDOERS OPTIONS"> section below.
-
-=head2 Wildcards
-
-B<sudo> allows shell-style I<wildcards> (aka meta or glob characters)
-to be used in host names, path names and command line arguments in
-the I<sudoers> file.  Wildcard matching is done via the B<POSIX>
-L<glob(3)> and L<fnmatch(3)> routines.  Note that these are I<not>
-regular expressions.
-
-=over 8
-
-=item C<*>
-
-Matches any set of zero or more characters.
-
-=item C<?>
-
-Matches any single character.
-
-=item C<[...]>
-
-Matches any character in the specified range.
-
-=item C<[!...]>
-
-Matches any character B<not> in the specified range.
-
-=item C<\x>
-
-For any character "x", evaluates to "x".  This is used to
-escape special characters such as: "*", "?", "[", and "}".
-
-=back
-
-POSIX character classes may also be used if your system's L<glob(3)>
-and L<fnmatch(3)> functions support them.  However, because the
-C<':'> character has special meaning in I<sudoers>, it must be
-escaped.  For example:
-
-    /bin/ls [[\:alpha\:]]*
-
-Would match any file name beginning with a letter.
-
-Note that a forward slash ('/') will B<not> be matched by
-wildcards used in the path name.  When matching the command
-line arguments, however, a slash B<does> get matched by
-wildcards.  This is to make a path like:
-
-    /usr/bin/*
-
-match F</usr/bin/who> but not F</usr/bin/X11/xterm>.
-
-=head2 Exceptions to wildcard rules
-
-The following exceptions apply to the above rules:
-
-=over 8
-
-=item C<"">
-
-If the empty string C<""> is the only command line argument in the
-I<sudoers> entry it means that command is not allowed to be run
-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> and
-C<#includedir> directives.
-
-This can be used, for example, to keep a site-wide I<sudoers> file
-in addition to a local, per-machine file.  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 within F</etc/sudoers> we would use the
-following line in F</etc/sudoers>:
-
-=over 4
-
-C<#include /etc/sudoers.local>
-
-=back
-
-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.
-
-The file name may include the C<%h> escape, signifying the short form
-of the host name.  I.e., if the machine's host name is "xerxes", then
-
-C<#include /etc/sudoers.%h>
-
-will cause B<sudo> to include the file F</etc/sudoers.xerxes>.
-
-The C<#includedir> directive can be used to create a F<sudo.d>
-directory that the system package manager can drop I<sudoers> rules
-into as part of package installation.  For example, given:
-
-C<#includedir /etc/sudoers.d>
-
-B<sudo> will read each file in F</etc/sudoers.d>, skipping file
-names that end in C<~> or contain a C<.> character to avoid causing
-problems with package manager or editor temporary/backup files.
-Files are parsed in sorted lexical order.  That is,
-F</etc/sudoers.d/01_first> will be parsed before
-F</etc/sudoers.d/10_second>.  Be aware that because the sorting is
-lexical, not numeric, F</etc/sudoers.d/1_whoops> would be loaded
-B<after> F</etc/sudoers.d/10_second>.  Using a consistent number
-of leading zeroes in the file names can be used to avoid such
-problems.
-
-Note that unlike files included via C<#include>, B<visudo> will not
-edit the files in a C<#includedir> directory unless one of them
-contains a syntax error.  It is still possible to run B<visudo>
-with the C<-f> flag to edit the files directly.
-
-=head2 Other special characters and reserved words
-
-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 B<ALL> is a built-in I<alias> that always causes
-a match to succeed.  It can be used wherever one might otherwise
-use a C<Cmnd_Alias>, C<User_Alias>, C<Runas_Alias>, or C<Host_Alias>.
-You should not try to define your own I<alias> called B<ALL> as the
-built-in alias will be used in preference to your own.  Please note
-that using B<ALL> can be dangerous since in a command context, it
-allows the user to run B<any> command on the system.
-
-An exclamation point ('!') can be used as a logical I<not> operator
-both in an I<alias> and in front of a C<Cmnd>.  This allows one to
-exclude certain values.  Note, however, that using a C<!> in
-conjunction with the built-in C<ALL> alias to allow a user to
-run "all but a few" commands rarely works as intended (see SECURITY
-NOTES below).
-
-Long lines can be continued with a backslash ('\') as the last
-character on the line.
-
-Whitespace between elements in a list as well as special syntactic
-characters in a I<User Specification> ('=', ':', '(', ')') is optional.
-
-The following characters must be escaped with a backslash ('\') when
-used as part of a word (e.g.E<nbsp>a user name or host name):
-'!', '=', ':', ',', '(', ')', '\'.
-
-=head1 SUDOERS OPTIONS
-
-B<sudo>'s behavior can be modified by C<Default_Entry> lines, as
-explained earlier.  A list of all supported Defaults parameters,
-grouped by type, are listed below.
-
-B<Boolean Flags>:
-
-=over 16
-
-=item always_set_home
-
-If enabled, 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> option is
-always implied.  Note that C<HOME> is already set when the the
-I<env_reset> option is enabled, so I<always_set_home> is only
-effective for configurations where either I<env_reset> is disabled
-or C<HOME> is present in the I<env_keep> list.
-This flag is I<off> by default.
-
-=item 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 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 compress_io
-
-If set, and B<sudo> is configured to log a command's input or output,
-the I/O logs will be compressed using B<zlib>.  This flag is I<on>
-by default when B<sudo> is compiled with B<zlib> support.
-
-=item env_editor
-
-If set, B<visudo> 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 C<editor>
-variable.  B<visudo> will then only use the EDITOR or VISUAL if
-they match a value specified in C<editor>.  This flag is I<@env_editor@> by
-default.
-
-=item env_reset
-
-If set, B<sudo> will reset the environment to only contain the
-LOGNAME, MAIL, 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 the I<secure_path> option
-is set, its value will be used for the C<PATH> environment variable.
-This flag is I<@env_reset@> by default.
-
-=item fast_glob
-
-Normally, B<sudo> uses the L<glob(3)> function to do shell-style
-globbing when matching path names.  However, since it accesses the
-file system, L<glob(3)> can take a long time to complete for some
-patterns, especially when the pattern references a network file
-system that is mounted on demand (automounted).  The I<fast_glob>
-option causes B<sudo> to use the L<fnmatch(3)> function, which does
-not access the file system to do its matching.  The disadvantage
-of I<fast_glob> is that it is unable to match relative path names
-such as F<./ls> or F<../bin/ls>.  This has security implications
-when path names that include globbing characters are used with the
-negation operator, C<'!'>, as such rules can be trivially bypassed.
-As such, this option should not be used when I<sudoers> contains rules 
-that contain negated path names which include globbing characters.
-This flag is I<off> by default.
-
-=item fqdn
-
-Set this flag if you want to put fully qualified host names in the
-I<sudoers> 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 I<fqdn> requires B<sudo> to make DNS lookups
-which may make B<sudo> 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 (C<CNAME> entry) due to performance
-issues and the fact that there is no way to get all aliases from
-DNS.  If your machine's host name (as returned by the C<hostname>
-command) is already fully qualified you shouldn't need to set
-I<fqdn>.  This flag is I<@fqdn@> by default.
-
-=item ignore_dot
-
-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.
-
-=item ignore_local_sudoers
-
-If set via LDAP, parsing of F<@sysconfdir@/sudoers> 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 F<@sysconfdir@/sudoers>.
-When this option is present, F<@sysconfdir@/sudoers> does not even need to
-exist. Since this option tells B<sudo> how to behave when no specific LDAP
-entries have been matched, this sudoOption is only meaningful for the
-C<cn=defaults> section.  This flag is I<off> by default.
-
-=item insults
-
-If set, B<sudo> will insult users when they enter an incorrect
-password.  This flag is I<@insults@> by default.
-
-=item log_host
-
-If set, the host name will be logged in the (non-syslog) B<sudo> log file.
-This flag is I<off> by default.
-
-=item log_input
-
-If set, B<sudo> will run the command in a I<pseudo tty> and log all
-user input.
-If the standard input is not connected to the user's tty, due to
-I/O redirection or because the command is part of a pipeline, that
-input is also captured and stored in a separate log file.
-
-Input is logged to the directory specified by the I<iolog_dir>
-option (F<@iolog_dir@> by default) using a unique session ID that
-is included in the normal B<sudo> log line, prefixed with I<TSID=>.
-
-Note that user input may contain sensitive information such as
-passwords (even if they are not echoed to the screen), which will
-be stored in the log file unencrypted.  In most cases, logging the
-command output via I<log_output> is all that is required.
-
-=item log_output
-
-If set, B<sudo> will run the command in a I<pseudo tty> and log all
-output that is sent to the screen, similar to the script(1) command.
-If the standard output or standard error is not connected to the
-user's tty, due to I/O redirection or because the command is part
-of a pipeline, that output is also captured and stored in separate
-log files.
-
-Output is logged to the directory specified by the I<iolog_dir>
-option (F<@iolog_dir@> by default) using a unique session ID that
-is included in the normal B<sudo> log line, prefixed with I<TSID=>.
-
-Output logs may be viewed with the L<sudoreplay(8)> utility, which
-can also be used to list or search the available logs.
-
-=item log_year
-
-If set, the four-digit year will be logged in the (non-syslog) B<sudo> log file.
-This flag is I<off> by default.
-
-=item long_otp_prompt
-
-When validating with a One Time Password (OPT) scheme such as
-B<S/Key> or B<OPIE>, 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 I<@long_otp_prompt@> by default.
-
-=item mail_always
-
-Send mail to the I<mailto> user every time a users runs B<sudo>.
-This flag is I<off> by default.
-
-=item mail_badpass
-
-Send mail to the I<mailto> user if the user running B<sudo> does not
-enter the correct password.  This flag is I<off> by default.
-
-=item mail_no_host
-
-If set, mail will be sent to the I<mailto> user if the invoking
-user exists in the I<sudoers> file, but is not allowed to run
-commands on the current host.  This flag is I<@mail_no_host@> by default.
-
-=item mail_no_perms
-
-If set, mail will be sent to the I<mailto> user if the invoking
-user is allowed to use B<sudo> but the command they are trying is not
-listed in their I<sudoers> file entry or is explicitly denied.
-This flag is I<@mail_no_perms@> by default.
-
-=item mail_no_user
-
-If set, mail will be sent to the I<mailto> user if the invoking
-user is not in the I<sudoers> file.  This flag is I<@mail_no_user@>
-by default.
-
-=item noexec
-
-If set, all commands run via B<sudo> will behave as if the C<NOEXEC>
-tag has been set, unless overridden by a C<EXEC> tag.  See the
-description of I<NOEXEC and EXEC> below as well as the L<PREVENTING SHELL
-ESCAPES> section at the end of this manual.  This flag is I<off> by default.
-
-=item path_info
-
-Normally, B<sudo> will tell the user when a command could not be
-found in their C<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 C<PATH>, B<sudo> will tell the user that they are not
-allowed to run it, which can be confusing.  This flag is I<@path_info@>
-by default.
-
-=item passprompt_override
-
-The password prompt specified by I<passprompt> will normally only
-be used if the password prompt provided by systems such as PAM matches
-the string "Password:".  If I<passprompt_override> is set, I<passprompt>
-will always be used.  This flag is I<off> by default.
-
-=item preserve_groups
-
-By default, B<sudo> will initialize the group vector to the list of
-groups the target user is in.  When I<preserve_groups> 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 I<off> by default.
-
-=item pwfeedback
-
-By default, B<sudo> reads the password like most other Unix programs,
-by turning off echo until the user hits the return (or enter) key.
-Some users become confused by this as it appears to them that B<sudo>
-has hung at this point.  When I<pwfeedback> is set, B<sudo> will
-provide visual feedback when the user presses a key.  Note that
-this does have a security impact as an onlooker may be able to
-determine the length of the password being entered.
-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.  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
-
-If set, root is allowed to run B<sudo> too.  Disabling this prevents users
-from "chaining" B<sudo> commands to get a root shell by doing something
-like C<"sudo sudo /bin/sh">.  Note, however, that turning off I<root_sudo>
-will also prevent root from running B<sudoedit>.
-Disabling I<root_sudo> provides no real additional security; it
-exists purely for historical reasons.
-This flag is I<@root_sudo@> by default.
-
-=item rootpw
-
-If set, B<sudo> will prompt for the root password instead of the password
-of the invoking user.  This flag is I<off> by default.
-
-=item runaspw
-
-If set, B<sudo> will prompt for the password of the user defined by the
-I<runas_default> option (defaults to C<@runas_default@>) instead of the
-password of the invoking user.  This flag is I<off> by default.
-
-=item set_home
-
-If enabled 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> option imply B<-H>.  Note that C<HOME> is already
-set when the the I<env_reset> option is enabled, so I<set_home> is
-only effective for configurations where either I<env_reset> is disabled
-or C<HOME> is present in the I<env_keep> list.
-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> 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
-option.  Note that if the I<env_reset> option has not been disabled,
-entries in the I<env_keep> list will override the value of
-I<set_logname>.  This flag is I<on> by default.
-
-=item setenv
-
-Allow the user to disable the I<env_reset> option from the command
-line.  Additionally, environment variables set via the command line
-are not subject to the restrictions imposed by I<env_check>,
-I<env_delete>, or I<env_keep>.  As such, only trusted users should
-be allowed to set variables in this manner.  This flag is I<off>
-by default.
-
-=item shell_noargs
-
-If set and B<sudo> is invoked with no arguments it acts as if 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.
-
-=item stay_setuid
-
-Normally, when B<sudo> 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 B<sudo> 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 setreuid() or setresuid()
-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> option (defaults to C<root>) instead of the password
-of the invoking user.  In addition, the timestamp file name will
-include the target user's name.  Note that this flag precludes the
-use of a uid not listed in the passwd database as an argument to
-the B<-u> option.  This flag is I<off> by default.
-
-=item tty_tickets
-
-If set, users must authenticate on a per-tty basis.  With this flag
-enabled, B<sudo> will use a file named for the tty the user is
-logged in on in the user's time stamp directory.  If disabled, the
-time stamp of the directory is used instead.  This flag is
-I<@tty_tickets@> by default.
-
-=item umask_override
-
-If set, B<sudo> will set the umask as specified by I<sudoers> without
-modification.  This makes it possible to specify a more permissive
-umask in I<sudoers> than the user's own umask and matches historical
-behavior.  If I<umask_override> is not set, B<sudo> will set the
-umask to be the union of the user's umask and what is specified in
-I<sudoers>.  This flag is I<@umask_override@> by default.
-
-=item use_loginclass
-
-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 use_pty
-
-If set, B<sudo> will run the command in a pseudo-pty even if no I/O
-logging is being gone.  A malicious program run under B<sudo> could
-conceivably fork a background process that retains to the user's
-terminal device after the main program has finished executing.  Use
-of this option will make that impossible.
-
-=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
-B<sudo> logs the failure and exits.  The default is C<@passwd_tries@>.
-
-=back
-
-B<Integers that can be used in a boolean context>:
-
-=over 16
-
-=item 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
-C<@loglen@> (use 0 or negate the option to disable word wrap).
-
-=item passwd_timeout
-
-Number of minutes before the B<sudo> password prompt times out, or
-C<0> for no timeout.  The timeout may include a fractional component
-if minute granularity is insufficient, for example C<2.5>.  The
-default is C<@password_timeout@>.
-
-=item timestamp_timeout
-
-Number of minutes that can elapse before B<sudo> will ask for a
-passwd again.  The timeout may include a fractional component if
-minute granularity is insufficient, for example C<2.5>.  The default
-is C<@timeout@>.  Set this to C<0> to always prompt for a password.
-If set to a value less than C<0> the user's timestamp will never
-expire.  This can be used to allow users to create or delete their
-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 actual umask that is
-used will be the union of the user's umask and the value of the
-I<umask> option, which defaults to 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
-
-B<Strings>:
-
-=over 16
-
-=item badpass_message
-
-Message that is displayed if a user enters an incorrect password.
-The default is C<@badpass_message@> unless insults are enabled.
-
-=item editor
-
-A colon (':') separated list of editors allowed to be used with
-B<visudo>.  B<visudo> 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 C<"@editor@">.
-
-=item iolog_dir
-
-The directory in which to store input/output logs when the I<log_input>
-or I<log_output> options are enabled or when the C<LOG_INPUT> or
-C<LOG_OUTPUT> tags are present for a command.
-The default is C<"@iolog_dir@">.
-
-=item mailsub
-
-Subject of the mail sent to the I<mailto> user. The escape C<%h>
-will expand to the host name of the machine.
-Default is C<@mailsub@>.
-
-=item noexec_file
-
-Path to a shared library containing dummy versions of the execv(),
-execve() and fexecve() library functions that just return an error.
-This is used to implement the I<noexec> functionality on systems that
-support C<LD_PRELOAD> or its equivalent.  Defaults to F<@noexec_file@>.
-
-=item passprompt
-
-The default prompt to use when asking for a password; can be overridden
-via the B<-p> option or the C<SUDO_PROMPT> environment variable.
-The following percent (`C<%>') escapes are supported:
-
-=over 4
-
-=item C<%H>
-
-expanded to the local host name including the domain name
-(on if the machine's host name is fully qualified or the I<fqdn>
-option is set)
-
-=item C<%h>
-
-expanded to the local host name without the domain name
-
-=item C<%p>
-
-expanded to the user whose password is being asked for (respects the 
-I<rootpw>, I<targetpw> and I<runaspw> flags in I<sudoers>)
-
-=item C<%U>
-
-expanded to the login name of the user the command will
-be run as (defaults to root)
-
-=item C<%u>
-
-expanded to the invoking user's login name
-
-=item C<%%>
-
-two consecutive C<%> characters are collapsed into a single C<%> character
-
-=back
-
-The default value is C<@passprompt@>.
-
-=item role
-
-The default SELinux role to use when constructing a new security
-context to run the command.  The default role may be overridden on
-a per-command basis in I<sudoers> or via command line options.
-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> 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.
-
-=item syslog_badpri
-
-Syslog priority to use when user authenticates unsuccessfully.
-Defaults to C<@badpri@>.
-
-=item syslog_goodpri
-
-Syslog priority to use when user authenticates successfully.
-Defaults to C<@goodpri@>.
-
-=item sudoers_locale
-
-Locale to use when parsing the sudoers file, logging commands, and
-sending email.  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.
-The default is F<@timedir@>.
-
-=item timestampowner
-
-The owner of the timestamp directory and the timestamps stored therein.
-The default is C<root>.
-
-=item type
-
-The default SELinux type to use when constructing a new security
-context to run the command.  The default type may be overridden on
-a per-command basis in I<sudoers> or via command line options.
-This option is only available whe B<sudo> is built with SELinux support.
-
-=back
-
-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 either be of the form
-C<VARIABLE=value> or C<export VARIABLE=value>.  The value may
-optionally be surrounded by single or double quotes.  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.
-This is not set by default.
-
-=item lecture
-
-This option controls when a short lecture will be printed along with
-the password prompt.  It has the following possible values:
-
-=over 8
-
-=item always
-
-Always lecture the user.
-
-=item never
-
-Never lecture the user.
-
-=item once
-
-Only lecture the user the first time they run B<sudo>.
-
-=back
-
-If no value is specified, a value of I<once> is implied.
-Negating the option results in a value of I<never> being used.
-The default value is I<@lecture@>.
-
-=item lecture_file
-
-Path to a file containing an alternate B<sudo> lecture that will
-be used in place of the standard lecture if the named file exists.
-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> option.  It has the following possible values:
-
-=over 8
-
-=item all
-
-All the user's I<sudoers> entries for the current host must have
-the C<NOPASSWD> flag set to avoid entering a password.
-
-=item always
-
-The user must always enter a password to use the B<-l> option.
-
-=item any
-
-At least one of the user's I<sudoers> entries for the current host
-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> option.
-
-=back
-
-If no value is specified, a value of I<any> is implied.
-Negating the option results in a value of I<never> being used.
-The default value is I<any>.
-
-=item logfile
-
-Path to the B<sudo> log file (not the syslog log file).  Setting a path
-turns on logging to a file; negating this option turns it off.
-By default, B<sudo> logs via syslog.
-
-=item mailerflags
-
-Flags to use when invoking mailer. Defaults to B<-t>.
-
-=item mailerpath
-
-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 option is @secure_path@ by default.
-
-=item syslog
-
-Syslog facility if syslog is being used for logging (negate to
-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> option.  It has the following possible values:
-
-=over 8
-
-=item all
-
-All the user's I<sudoers> entries for the current host must have
-the C<NOPASSWD> flag set to avoid entering a password.
-
-=item always
-
-The user must always enter a password to use the B<-v> option.
-
-=item any
-
-At least one of the user's I<sudoers> entries for the current host
-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> option.
-
-=back
-
-If no value is specified, a value of I<all> is implied.
-Negating the option results in a value of I<never> being used.
-The default value is I<all>.
-
-=back
-
-B<Lists that can be used in a boolean context>:
-
-=over 16
-
-=item env_check
-
-Environment variables to be removed from the user's environment if
-the variable's value contains C<%> or C</> 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 C<=>, C<+=>, C<-=>, and C<!> operators respectively.  Regardless
-of whether the C<env_reset> option is enabled or disabled, variables
-specified by C<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 B<sudo> is run by root with
-the I<-V> option.
-
-=item env_delete
-
-Environment variables to be removed from the user's environment
-when the I<env_reset> option is not in effect.  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 C<=>, C<+=>, C<-=>, and C<!> operators
-respectively.  The default list of environment variables to remove
-is displayed when B<sudo> is run by root with the I<-V> option.
-Note that many operating systems will remove potentially dangerous
-variables from the environment of any setuid process (such as
-B<sudo>).
-
-=item env_keep
-
-Environment variables to be preserved in the user's environment
-when the I<env_reset> option is in effect.  This allows fine-grained
-control over the environment B<sudo>-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 C<=>, C<+=>, C<-=>, and
-C<!> operators respectively.  The default list of variables to keep
-is displayed when B<sudo> is run by root with the I<-V> option.
-
-=back
-
-When logging via L<syslog(3)>, B<sudo> accepts the following values
-for the syslog facility (the value of the B<syslog> Parameter):
-B<authpriv> (if your OS supports it), B<auth>, B<daemon>, B<user>,
-B<local0>, B<local1>, B<local2>, B<local3>, B<local4>, B<local5>,
-B<local6>, and B<local7>.  The following syslog priorities are
-supported: B<alert>, B<crit>, B<debug>, B<emerg>, B<err>, B<info>,
-B<notice>, and B<warning>.
-
-=head1 FILES
-
-=over 24
-
-=item F<@sysconfdir@/sudoers>
-
-List of who can run what
-
-=item F</etc/group>
-
-Local groups file
-
-=item F</etc/netgroup>
-
-List of network groups
-
-=item F<@iolog_dir@>
-
-I/O log files
-
-=back
-
-=head1 EXAMPLES
-
-Below are example I<sudoers> entries.  Admittedly, some of
-these are a bit contrived.  First, we allow a few environment
-variables to pass and then define our I<aliases>:
-
- # Run X applications through sudo; HOME is used to find the
- # .Xauthority file.  Note that other programs use HOME to find
- # configuration files and this may lead to privilege escalation!
- Defaults env_keep += "DISPLAY HOME"
-
- # User alias specification
- User_Alias    FULLTIMERS = millert, mikef, dowdy
- User_Alias    PARTTIMERS = bostley, jwfox, crawl
- User_Alias    WEBMASTERS = will, wendy, wim
-
- # Runas alias specification
- Runas_Alias   OP = root, operator
- Runas_Alias   DB = oracle, sybase
- Runas_Alias   ADMINGRP = adm, oper
-
- # Host alias specification
- Host_Alias    SPARC = bigtime, eclipse, moet, anchor :\
-               SGI = grolsch, dandelion, black :\
-               ALPHA = widget, thalamus, foobar :\
-               HPPA = boa, nag, python
- Host_Alias    CUNETS = 128.138.0.0/255.255.0.0
- 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
-
- # Cmnd alias specification
- Cmnd_Alias    DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\
-                       /usr/sbin/restore, /usr/sbin/rrestore
- Cmnd_Alias    KILL = /usr/bin/kill
- Cmnd_Alias    PRINTING = /usr/sbin/lpc, /usr/bin/lprm
- Cmnd_Alias    SHUTDOWN = /usr/sbin/shutdown
- Cmnd_Alias    HALT = /usr/sbin/halt
- Cmnd_Alias    REBOOT = /usr/sbin/reboot
- Cmnd_Alias    SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \
-                        /usr/local/bin/tcsh, /usr/bin/rsh, \
-                        /usr/local/bin/zsh
- 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
-B<sudo> to log via L<syslog(3)> using the I<auth> facility in all
-cases.  We don't want to subject the full time staff to the B<sudo>
-lecture, user B<millert> need not give a password, and we don't
-want to reset the C<LOGNAME>, C<USER> or C<USERNAME> environment
-variables when running commands as root.  Additionally, on the
-machines in the I<SERVERS> C<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 C<Cmnd_Alias>
-(F</usr/bin/more>, F</usr/bin/pg> and F</usr/bin/less>).
-
- # 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
-
-The I<User specification> is the part that actually determines who may
-run what.
-
- root          ALL = (ALL) ALL
- %wheel                ALL = (ALL) ALL
-
-We let B<root> and any user in group B<wheel> run any command on any
-host as any user.
-
- FULLTIMERS    ALL = NOPASSWD: ALL
-
-Full time sysadmins (B<millert>, B<mikef>, and B<dowdy>) may run any
-command on any host without authenticating themselves.
-
- PARTTIMERS    ALL = ALL
-
-Part time sysadmins (B<bostley>, B<jwfox>, and B<crawl>) may run any
-command on any host but they must authenticate themselves first
-(since the entry lacks the C<NOPASSWD> tag).
-
- jack          CSNETS = ALL
-
-The user B<jack> may run any command on the machines in the I<CSNETS> alias
-(the networks C<128.138.243.0>, C<128.138.204.0>, and C<128.138.242.0>).
-Of those networks, only C<128.138.204.0> has an explicit netmask (in
-CIDR notation) indicating it is a class C network.  For the other
-networks in I<CSNETS>, the local machine's netmask will be used
-during matching.
-
- lisa          CUNETS = ALL
-
-The user B<lisa> may run any command on any host in the I<CUNETS> alias
-(the class B network C<128.138.0.0>).
-
- operator      ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\
-               sudoedit /etc/printcap, /usr/oper/bin/
-
-The B<operator> 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 F</usr/oper/bin/>.
-
- joe           ALL = /usr/bin/su operator
-
-The user B<joe> may only L<su(1)> to operator.
-
- pete          HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root
-
- %opers                ALL = (: ADMINGRP) /usr/sbin/
-
-Users in the B<opers> group may run commands in F</usr/sbin/> as themselves
-with any group in the I<ADMINGRP> C<Runas_Alias> (the B<adm> and B<oper>
-groups).
-
-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)>
-does not take multiple user names on the command line.
-
- bob           SPARC = (OP) ALL : SGI = (OP) ALL
-
-The user B<bob> may run anything on the I<SPARC> and I<SGI> machines
-as any user listed in the I<OP> C<Runas_Alias> (B<root> and B<operator>).
-
- jim           +biglab = ALL
-
-The user B<jim> may run any command on machines in the I<biglab> netgroup.
-B<sudo> knows that "biglab" is a netgroup due to the '+' prefix.
-
- +secretaries  ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser
-
-Users in the B<secretaries> 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 B<fred> can run commands as any user in the I<DB> C<Runas_Alias>
-(B<oracle> or B<sybase>) without giving a password.
-
- 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 specify any options to the L<su(1)> command.
-
- jen           ALL, !SERVERS = ALL
-
-The user B<jen> may run any command on any machine except for those
-in the I<SERVERS> C<Host_Alias> (master, mail, www and ns).
-
- jill          SERVERS = /usr/bin/, !SU, !SHELLS
-
-For any machine in the I<SERVERS> C<Host_Alias>, B<jill> may run
-any commands in the directory F</usr/bin/> except for those commands
-belonging to the I<SU> and I<SHELLS> C<Cmnd_Aliases>.
-
- steve         CSNETS = (operator) /usr/local/op_commands/
-
-The user B<steve> may run any command in the directory /usr/local/op_commands/
-but only as user operator.
-
- matt          valkyrie = KILL
-
-On his personal workstation, valkyrie, B<matt> 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 I<WEBMASTERS> C<User_Alias> (will,
-wendy, and wim), may run any command as user www (which owns the
-web pages) or simply L<su(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
-C<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.
-
-=head1 SECURITY NOTES
-
-It is generally not effective to "subtract" commands from C<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<bill> from running the commands listed in
-I<SU> or I<SHELLS> 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).
-
-Furthermore, if the I<fast_glob> option is in use, it is not possible
-to reliably negate commands where the path name includes globbing
-(aka wildcard) characters.  This is because the C library's
-L<fnmatch(3)> function cannot resolve relative paths.  While this
-is typically only an inconvenience for rules that grant privileges,
-it can result in a security issue for rules that subtract or revoke
-privileges.
-
-For example, given the following I<sudoers> entry:
-
- john  ALL = /usr/bin/passwd [a-zA-Z0-9]*, /usr/bin/chsh [a-zA-Z0-9]*,
-      /usr/bin/chfn [a-zA-Z0-9]*, !/usr/bin/* root
-
-User B<john> can still run C</usr/bin/passwd root> if I<fast_glob> is
-enabled by changing to F</usr/bin> and running C<./passwd root> instead.
-
-=head1 PREVENTING SHELL ESCAPES
-
-Once B<sudo> 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 B<sudo>'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:
-
-=over 10
-
-=item 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 B<sudoedit> is a better solution to
-running editors via B<sudo>.  Due to the large number of programs that
-offer shell escapes, restricting users to the set of programs that
-do not is often unworkable.
-
-=item noexec
-
-Many systems that support shared libraries have the ability to
-override default library functions by pointing an environment
-variable (usually C<LD_PRELOAD>) to an alternate shared library.
-On such systems, B<sudo>'s I<noexec> functionality can be used to
-prevent a program run by B<sudo> 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 B<sudo> supports I<noexec>, you can run
-the following as root:
-
-    sudo -V | grep "dummy exec"
-
-If the resulting output contains a line that begins with:
-
-    File containing dummy exec functions:
-
-then B<sudo> 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
-I<noexec> will work at compile-time.  I<noexec> should work on
-SunOS, Solaris, *BSD, Linux, IRIX, Tru64 UNIX, MacOS X, and HP-UX
-11.x.  It is known B<not> to work on AIX and UnixWare.  I<noexec>
-is expected to work on most operating systems that support the
-C<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 C<LD_PRELOAD> is supported.
-
-To enable I<noexec> for a command, use the C<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 B<aaron> to run F</usr/bin/more> and F</usr/bin/vi>
-with I<noexec> 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 I<noexec> you
-can always just try it out and see if it works.
-
-=back
-
-Note that restricting shell escapes is not a panacea.  Programs
-running as root are still capable of many potentially hazardous
-operations (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
-B<sudoedit>.
-
-=head1 SEE ALSO
-
-L<rsh(1)>, L<su(1)>, L<fnmatch(3)>, L<glob(3)>, L<sudo(8)>, L<visudo(8)>
-
-=head1 CAVEATS
-
-The I<sudoers> file should B<always> be edited by the B<visudo>
-command which locks the file and does grammatical checking. It is
-imperative that I<sudoers> be free of syntax errors since B<sudo>
-will not run with a syntactically incorrect I<sudoers> file.
-
-When using netgroups of machines (as opposed to users), if you
-store fully qualified host name in the netgroup (as is usually the
-case), you either need to have the machine's host name be fully qualified
-as returned by the C<hostname> command or use the I<fqdn> option in
-I<sudoers>.
-
-=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.
diff --git a/sudoers2ldif b/sudoers2ldif
deleted file mode 100755 (executable)
index 442155e..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-#!/usr/bin/env perl
-use strict;
-
-#
-# Converts a sudoers file to LDIF format in prepration for loading into
-# the LDAP server.
-#
-
-# BUGS:
-#   Does not yet handle multiple lines with : in them
-#   Does not yet remove quotation marks from options
-#   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)
-#
-# 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;
-my $base=$ENV{SUDOERS_BASE} or die "$0: Container SUDOERS_BASE undefined\n";
-my @options=();
-
-my $did_defaults=0;
-my $order = 0;
-
-# parse sudoers one line at a time
-while (<>){
-
-  # remove comment
-  s/#.*//;
-
-  # line continuation
-  $_.=<> while s/\\\s*$//s;
-
-  # cleanup newline
-  chomp;
-
-  # ignore blank lines
-  next if /^\s*$/;
-
-  if (/^Defaults\s+/i) {
-    my $opt=$';
-    $opt=~s/\s+$//; # remove trailing whitespace
-    push @options,$opt;
-  } elsif (/^(\S+)\s+(.+)=\s*(.*)/) {
-
-    # Aliases or Definitions
-    my ($p1,$p2,$p3)=($1,$2,$3);
-    $p2=~s/\s+$//; # remove trailing whitespace
-    $p3=~s/\s+$//; # remove trailing whitespace
-
-    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") {
-      $CA{$p2}=$p3;
-    } else {
-      if (!$did_defaults++){
-        # do this once
-        print "dn: cn=defaults,$base\n";
-        print "objectClass: top\n";
-        print "objectClass: sudoRole\n";
-        print "cn: defaults\n";
-        print "description: Default sudoOption's go here\n";
-        print "sudoOption: $_\n" foreach @options;
-        printf "sudoOrder: %d\n", ++$order;
-        print "\n";
-      }
-      # Definition
-      my @users=split /\s*,\s*/,$p1;
-      my @hosts=split /\s*,\s*/,$p2;
-      my @cmds= split /\s*,\s*/,$p3;
-      @options=();
-      print "dn: cn=$users[0],$base\n";
-      print "objectClass: top\n";
-      print "objectClass: sudoRole\n";
-      print "cn: $users[0]\n";
-      # will clobber options
-      print "sudoUser: $_\n"   foreach expand(\%UA,@users);
-      print "sudoHost: $_\n"   foreach expand(\%HA,@hosts);
-      foreach (@cmds) {
-       if (s/^\(([^\)]+)\)\s*//) {
-         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);
-      print "sudoOption: $_\n" foreach @options;
-      printf "sudoOrder: %d\n", ++$order;
-      print "\n";
-    }
-
-  } else {
-    print "parse error: $_\n";
-  }
-
-}
-
-#
-# recursively expand hash elements
-sub expand{
-  my $ref=shift;
-  my @a=();
-
-  # preen the line a little
-  foreach (@_){
-    # if NOPASSWD: directive found, mark entire entry as not requiring
-    s/NOPASSWD:\s*// && push @options,"!authenticate";
-    s/PASSWD:\s*// && push @options,"authenticate";
-    s/NOEXEC:\s*// && push @options,"noexec";
-    s/EXEC:\s*// && push @options,"!noexec";
-    s/SETENV:\s*// && push @options,"setenv";
-    s/NOSETENV:\s*// && push @options,"!setenv";
-    s/LOG_INPUT:\s*// && push @options,"log_input";
-    s/NOLOG_INPUT:\s*// && push @options,"!log_input";
-    s/LOG_OUTPUT:\s*// && push @options,"log_output";
-    s/NOLOG_OUTPUT:\s*// && push @options,"!log_output";
-    s/\w+://; # silently remove other directives
-    s/\s+$//; # right trim
-  }
-
-  # do the expanding
-  push @a,$ref->{$_} ? expand($ref,split /\s*,\s*/,$ref->{$_}):$_ foreach @_;
-  @a;
-}
-
-
diff --git a/sudoreplay.c b/sudoreplay.c
deleted file mode 100644 (file)
index 9fdb5bb..0000000
+++ /dev/null
@@ -1,985 +0,0 @@
-/*
- * Copyright (c) 2009-2010 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>
-#ifdef HAVE_SYS_SYSMACROS_H
-# include <sys/sysmacros.h>
-#endif
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#include <sys/ioctl.h>
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif /* HAVE_SYS_SELECT_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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-#ifndef HAVE_TIMESPEC
-# include "emul/timespec.h"
-#endif
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <fcntl.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
-#ifdef HAVE_REGCOMP
-# include <regex.h>
-#endif
-#ifdef HAVE_ZLIB_H
-# include <zlib.h>
-#endif
-#ifdef HAVE_SETLOCALE
-# include <locale.h>
-#endif
-#include <signal.h>
-
-#include <pathnames.h>
-
-#include "missing.h"
-#include "alloc.h"
-#include "error.h"
-
-#ifndef LINE_MAX
-# define LINE_MAX 2048
-#endif
-
-/* Must match the defines in iolog.c */
-#define IOFD_STDIN      0
-#define IOFD_STDOUT     1
-#define IOFD_STDERR     2
-#define IOFD_TTYIN      3
-#define IOFD_TTYOUT     4
-#define IOFD_TIMING     5
-#define IOFD_MAX        6
-
-/* Bitmap of iofds to be replayed */
-unsigned int replay_filter = (1 << IOFD_STDOUT) | (1 << IOFD_STDERR) |
-                            (1 << IOFD_TTYOUT);
-
-/* For getopt(3) */
-extern char *optarg;
-extern int optind;
-
-int Argc;
-char **Argv;
-
-union io_fd {
-    FILE *f;
-#ifdef HAVE_ZLIB_H
-    gzFile g;
-#endif
-    void *v;
-};
-
-/*
- * Info present in the I/O log file
- */
-struct log_info {
-    char *cwd;
-    char *user;
-    char *runas_user;
-    char *runas_group;
-    char *tty;
-    char *cmd;
-    time_t tstamp;
-};
-
-/*
- * Handle expressions like:
- * ( user millert or user root ) and tty console and command /bin/sh
- */
-struct search_node {
-    struct search_node *next;
-#define ST_EXPR                1
-#define ST_TTY         2
-#define ST_USER                3
-#define ST_PATTERN     4
-#define ST_RUNASUSER   5
-#define ST_RUNASGROUP  6
-#define ST_FROMDATE    7
-#define ST_TODATE      8
-#define ST_CWD         9
-    char type;
-    char negated;
-    char or;
-    char pad;
-    union {
-#ifdef HAVE_REGCOMP
-       regex_t cmdre;
-#endif
-       time_t tstamp;
-       char *cwd;
-       char *tty;
-       char *user;
-       char *pattern;
-       char *runas_group;
-       char *runas_user;
-       struct search_node *expr;
-       void *ptr;
-    } u;
-} *search_expr;
-
-#define STACK_NODE_SIZE        32
-static struct search_node *node_stack[32];
-static int stack_top;
-
-static const char *session_dir = _PATH_SUDO_IO_LOGDIR;
-
-static union io_fd io_fds[IOFD_MAX];
-static const char *io_fnames[IOFD_MAX] = {
-    "/stdin",
-    "/stdout",
-    "/stderr",
-    "/ttyin",
-    "/ttyout",
-    "/timing"
-};
-
-extern time_t get_date __P((char *));
-extern char *get_timestr __P((time_t, int));
-extern int term_raw __P((int, int));
-extern int term_restore __P((int, int));
-extern void zero_bytes __P((volatile void *, size_t));
-RETSIGTYPE cleanup __P((int));
-
-static int list_sessions __P((int, char **, const char *, const char *, const char *));
-static int parse_expr __P((struct search_node **, char **));
-static void check_input __P((int, double *));
-static void delay __P((double));
-static void help __P((void)) __attribute__((__noreturn__));
-static void usage __P((int));
-static void *open_io_fd __P((char *pathbuf, int len, const char *suffix));
-static int parse_timing __P((const char *buf, const char *decimal, int *idx, double *seconds, size_t *nbytes));
-
-#ifdef HAVE_REGCOMP
-# define REGEX_T       regex_t
-#else
-# define REGEX_T       char
-#endif
-
-#define VALID_ID(s) (isalnum((unsigned char)(s)[0]) && \
-    isalnum((unsigned char)(s)[1]) && isalnum((unsigned char)(s)[2]) && \
-    isalnum((unsigned char)(s)[3]) && isalnum((unsigned char)(s)[4]) && \
-    isalnum((unsigned char)(s)[5]) && (s)[6] == '\0')
-
-int
-main(argc, argv)
-    int argc;
-    char *argv[];
-{
-    int ch, idx, plen, nready, interactive = 0, listonly = 0;
-    const char *id, *user = NULL, *pattern = NULL, *tty = NULL, *decimal = ".";
-    char path[PATH_MAX], buf[LINE_MAX], *cp, *ep;
-    double seconds, to_wait, speed = 1.0, max_wait = 0;
-    FILE *lfile;
-    fd_set *fdsw;
-    sigaction_t sa;
-    size_t len, nbytes, nread, off;
-    ssize_t nwritten;
-
-    Argc = argc;
-    Argv = argv;
-
-#ifdef HAVE_SETLOCALE
-    setlocale(LC_ALL, "");
-    decimal = localeconv()->decimal_point;
-#endif
-
-    while ((ch = getopt(argc, argv, "d:f:hlm:s:V")) != -1) {
-       switch(ch) {
-       case 'd':
-           session_dir = optarg;
-           break;
-       case 'f':
-           /* Set the replay filter. */
-           replay_filter = 0;
-           for (cp = strtok(optarg, ","); cp; cp = strtok(NULL, ",")) {
-               if (strcmp(cp, "stdout") == 0)
-                   SET(replay_filter, 1 << IOFD_STDOUT);
-               else if (strcmp(cp, "stderr") == 0)
-                   SET(replay_filter, 1 << IOFD_STDERR);
-               else if (strcmp(cp, "ttyout") == 0)
-                   SET(replay_filter, 1 << IOFD_TTYOUT);
-               else
-                   errorx(1, "invalid filter option: %s", optarg);
-           }
-           break;
-       case 'h':
-           help();
-           /* NOTREACHED */
-       case 'l':
-           listonly = 1;
-           break;
-       case 'm':
-           errno = 0;
-           max_wait = strtod(optarg, &ep);
-           if (*ep != '\0' || errno != 0)
-               errorx(1, "invalid max wait: %s", optarg);
-           break;
-       case 's':
-           errno = 0;
-           speed = strtod(optarg, &ep);
-           if (*ep != '\0' || errno != 0)
-               errorx(1, "invalid speed factor: %s", optarg);
-           break;
-       case 'V':
-           (void) printf("%s version %s\n", getprogname(), PACKAGE_VERSION);
-           exit(0);
-       default:
-           usage(1);
-           /* NOTREACHED */
-       }
-
-    }
-    argc -= optind;
-    argv += optind;
-
-    if (listonly)
-       exit(list_sessions(argc, argv, pattern, user, tty));
-
-    if (argc != 1)
-       usage(1);
-
-    /* 6 digit ID in base 36, e.g. 01G712AB */
-    id = argv[0];
-    if (!VALID_ID(id))
-       errorx(1, "invalid ID %s", id);
-
-    plen = snprintf(path, sizeof(path), "%s/%.2s/%.2s/%.2s/timing",
-       session_dir, id, &id[2], &id[4]);
-    if (plen <= 0 || plen >= sizeof(path))
-       errorx(1, "%s/%.2s/%.2s/%.2s/%.2s/timing: %s", session_dir,
-           id, &id[2], &id[4], strerror(ENAMETOOLONG));
-    plen -= 7;
-
-    /* Open files for replay, applying replay filter for the -f flag. */
-    for (idx = 0; idx < IOFD_MAX; idx++) {
-       if (ISSET(replay_filter, 1 << idx) || idx == IOFD_TIMING) {
-           io_fds[idx].v = open_io_fd(path, plen, io_fnames[idx]);
-           if (io_fds[idx].v == NULL)
-               error(1, "unable to open %s", path);
-       }
-    }
-
-    /* Read log file. */
-    path[plen] = '\0';
-    strlcat(path, "/log", sizeof(path));
-    lfile = fopen(path, "r");
-    if (lfile == NULL)
-       error(1, "unable to open %s", path);
-    cp = NULL;
-    len = 0;
-    /* Pull out command (third line). */
-    if (getline(&cp, &len, lfile) == -1 ||
-       getline(&cp, &len, lfile) == -1 ||
-       getline(&cp, &len, lfile) == -1) {
-       errorx(1, "invalid log file %s", path);
-    }
-    printf("Replaying sudo session: %s", cp);
-    free(cp);
-    fclose(lfile);
-
-    fflush(stdout);
-    zero_bytes(&sa, sizeof(sa));
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = SA_RESETHAND;
-    sa.sa_handler = cleanup;
-    (void) sigaction(SIGINT, &sa, NULL);
-    (void) sigaction(SIGKILL, &sa, NULL);
-    (void) sigaction(SIGTERM, &sa, NULL);
-    (void) sigaction(SIGHUP, &sa, NULL);
-    sa.sa_flags = SA_RESTART;
-    sa.sa_handler = SIG_IGN;
-    (void) sigaction(SIGTSTP, &sa, NULL);
-    (void) sigaction(SIGQUIT, &sa, NULL);
-
-    /* XXX - read user input from /dev/tty and set STDOUT to raw if not a pipe */
-    /* Set stdin to raw mode if it is a tty */
-    interactive = isatty(STDIN_FILENO);
-    if (interactive) {
-       ch = fcntl(STDIN_FILENO, F_GETFL, 0);
-       if (ch != -1)
-           (void) fcntl(STDIN_FILENO, F_SETFL, ch | O_NONBLOCK);
-       if (!term_raw(STDIN_FILENO, 1))
-           error(1, "cannot set tty to raw mode");
-    }
-    fdsw = (fd_set *)emalloc2(howmany(STDOUT_FILENO + 1, NFDBITS),
-       sizeof(fd_mask));
-
-    /*
-     * Timing file consists of line of the format: "%f %d\n"
-     */
-#ifdef HAVE_ZLIB_H
-    while (gzgets(io_fds[IOFD_TIMING].g, buf, sizeof(buf)) != NULL) {
-#else
-    while (fgets(buf, sizeof(buf), io_fds[IOFD_TIMING].f) != NULL) {
-#endif
-       if (!parse_timing(buf, decimal, &idx, &seconds, &nbytes))
-           errorx(1, "invalid timing file line: %s", buf);
-
-       if (interactive)
-           check_input(STDIN_FILENO, &speed);
-
-       /* Adjust delay using speed factor and clamp to max_wait */
-       to_wait = seconds / speed;
-       if (max_wait && to_wait > max_wait)
-           to_wait = max_wait;
-       delay(to_wait);
-
-       /* Even if we are not relaying, we still have to delay. */
-       if (io_fds[idx].v == NULL)
-           continue;
-
-       /* All output is sent to stdout. */
-       while (nbytes != 0) {
-           if (nbytes > sizeof(buf))
-               len = sizeof(buf);
-           else
-               len = nbytes;
-#ifdef HAVE_ZLIB_H
-           nread = gzread(io_fds[idx].g, buf, len);
-#else
-           nread = fread(buf, 1, len, io_fds[idx].f);
-#endif
-           nbytes -= nread;
-           off = 0;
-           do {
-               /* no stdio, must be unbuffered */
-               nwritten = write(STDOUT_FILENO, buf + off, nread - off);
-               if (nwritten == -1) {
-                   if (errno == EINTR)
-                       continue;
-                   if (errno == EAGAIN) {
-                       FD_SET(STDOUT_FILENO, fdsw);
-                       do {
-                           nready = select(STDOUT_FILENO + 1, NULL, fdsw, NULL, NULL);
-                       } while (nready == -1 && errno == EINTR);
-                       if (nready == 1)
-                           continue;
-                   }
-                   error(1, "writing to standard output");
-               }
-               off += nwritten;
-           } while (nread > off);
-       }
-    }
-    term_restore(STDIN_FILENO, 1);
-    exit(0);
-}
-
-static void
-delay(secs)
-    double secs;
-{
-    struct timespec ts, rts;
-    int rval;
-
-    /*
-     * Typical max resolution is 1/HZ but we can't portably check that.
-     * If the interval is small enough, just ignore it.
-     */
-    if (secs < 0.0001)
-       return;
-
-    rts.tv_sec = secs;
-    rts.tv_nsec = (secs - (double) rts.tv_sec) * 1000000000.0;
-    do {
-      memcpy(&ts, &rts, sizeof(ts));
-      rval = nanosleep(&ts, &rts);
-    } while (rval == -1 && errno == EINTR);
-    if (rval == -1)
-       error(1, "nanosleep: tv_sec %ld, tv_nsec %ld", ts.tv_sec, ts.tv_nsec);
-}
-
-static void *
-open_io_fd(path, len, suffix)
-    char *path;
-    int len;
-    const char *suffix;
-{
-    path[len] = '\0';
-    strlcat(path, suffix, PATH_MAX);
-
-#ifdef HAVE_ZLIB_H
-    return gzopen(path, "r");
-#else
-    return fopen(path, "r");
-#endif
-}
-
-/*
- * Build expression list from search args
- */
-static int
-parse_expr(headp, argv)
-    struct search_node **headp;
-    char *argv[];
-{
-    struct search_node *sn, *newsn;
-    char or = 0, not = 0, type, **av;
-
-    sn = *headp;
-    for (av = argv; *av; av++) {
-       switch (av[0][0]) {
-       case 'a': /* and (ignore) */
-           if (strncmp(*av, "and", strlen(*av)) != 0)
-               goto bad;
-           continue;
-       case 'o': /* or */
-           if (strncmp(*av, "or", strlen(*av)) != 0)
-               goto bad;
-           or = 1;
-           continue;
-       case '!': /* negate */
-           if (av[0][1] != '\0')
-               goto bad;
-           not = 1;
-           continue;
-       case 'c': /* command */
-           if (av[0][1] == '\0')
-               errorx(1, "ambiguous expression \"%s\"", *av);
-           if (strncmp(*av, "cwd", strlen(*av)) == 0)
-               type = ST_CWD;
-           else if (strncmp(*av, "command", strlen(*av)) == 0)
-               type = ST_PATTERN;
-           else
-               goto bad;
-           break;
-       case 'f': /* from date */
-           if (strncmp(*av, "fromdate", strlen(*av)) != 0)
-               goto bad;
-           type = ST_FROMDATE;
-           break;
-       case 'g': /* runas group */
-           if (strncmp(*av, "group", strlen(*av)) != 0)
-               goto bad;
-           type = ST_RUNASGROUP;
-           break;
-       case 'r': /* runas user */
-           if (strncmp(*av, "runas", strlen(*av)) != 0)
-               goto bad;
-           type = ST_RUNASUSER;
-           break;
-       case 't': /* tty or to date */
-           if (av[0][1] == '\0')
-               errorx(1, "ambiguous expression \"%s\"", *av);
-           if (strncmp(*av, "todate", strlen(*av)) == 0)
-               type = ST_TODATE;
-           else if (strncmp(*av, "tty", strlen(*av)) == 0)
-               type = ST_TTY;
-           else
-               goto bad;
-           break;
-       case 'u': /* user */
-           if (strncmp(*av, "user", strlen(*av)) != 0)
-               goto bad;
-           type = ST_USER;
-           break;
-       case '(': /* start sub-expression */
-           if (av[0][1] != '\0')
-               goto bad;
-           if (stack_top + 1 == STACK_NODE_SIZE) {
-               errorx(1, "too many parenthesized expressions, max %d",
-                   STACK_NODE_SIZE);
-           }
-           node_stack[stack_top++] = sn;
-           type = ST_EXPR;
-           break;
-       case ')': /* end sub-expression */
-           if (av[0][1] != '\0')
-               goto bad;
-           /* pop */
-           if (--stack_top < 0)
-               errorx(1, "unmatched ')' in expression");
-           if (node_stack[stack_top])
-               sn->next = node_stack[stack_top]->next;
-           return av - argv + 1;
-       bad:
-       default:
-           errorx(1, "unknown search term \"%s\"", *av);
-           /* NOTREACHED */
-       }
-
-       /* Allocate new search node */
-       newsn = emalloc(sizeof(*newsn));
-       newsn->next = NULL;
-       newsn->type = type;
-       newsn->or = or;
-       newsn->negated = not;
-       if (type == ST_EXPR) {
-           av += parse_expr(&newsn->u.expr, av + 1);
-       } else {
-           if (*(++av) == NULL)
-               errorx(1, "%s requires an argument", av[-1]);
-#ifdef HAVE_REGCOMP
-           if (type == ST_PATTERN) {
-               if (regcomp(&newsn->u.cmdre, *av, REG_EXTENDED|REG_NOSUB) != 0)
-                   errorx(1, "invalid regex: %s", *av);
-           } else
-#endif
-           if (type == ST_TODATE || type == ST_FROMDATE) {
-               newsn->u.tstamp = get_date(*av);
-               if (newsn->u.tstamp == -1)
-                   errorx(1, "could not parse date \"%s\"", *av);
-           } else {
-               newsn->u.ptr = *av;
-           }
-       }
-       not = or = 0; /* reset state */
-       if (sn)
-           sn->next = newsn;
-       else
-           *headp = newsn;
-       sn = newsn;
-    }
-    if (stack_top)
-       errorx(1, "unmatched '(' in expression");
-    if (or)
-       errorx(1, "illegal trailing \"or\"");
-    if (not)
-       errorx(1, "illegal trailing \"!\"");
-
-    return av - argv;
-}
-
-static int
-match_expr(head, log)
-    struct search_node *head;
-    struct log_info *log;
-{
-    struct search_node *sn;
-    int matched = 1, rc;
-
-    for (sn = head; sn; sn = sn->next) {
-       /* If we have no match, skip ahead to the next OR entry. */
-       if (!matched && !sn->or)
-           continue;
-
-       switch (sn->type) {
-       case ST_EXPR:
-           matched = match_expr(sn->u.expr, log);
-           break;
-       case ST_CWD:
-           matched = strcmp(sn->u.cwd, log->cwd) == 0;
-           break;
-       case ST_TTY:
-           matched = strcmp(sn->u.tty, log->tty) == 0;
-           break;
-       case ST_RUNASGROUP:
-           matched = strcmp(sn->u.runas_group, log->runas_group) == 0;
-           break;
-       case ST_RUNASUSER:
-           matched = strcmp(sn->u.runas_user, log->runas_user) == 0;
-           break;
-       case ST_USER:
-           matched = strcmp(sn->u.user, log->user) == 0;
-           break;
-       case ST_PATTERN:
-#ifdef HAVE_REGCOMP
-           rc = regexec(&sn->u.cmdre, log->cmd, 0, NULL, 0);
-           if (rc && rc != REG_NOMATCH) {
-               char buf[BUFSIZ];
-               regerror(rc, &sn->u.cmdre, buf, sizeof(buf));
-               errorx(1, "%s", buf);
-           }
-           matched = rc == REG_NOMATCH ? 0 : 1;
-#else
-           matched = strstr(log.cmd, sn->u.pattern) != NULL;
-#endif
-           break;
-       case ST_FROMDATE:
-           matched = log->tstamp >= sn->u.tstamp;
-           break;
-       case ST_TODATE:
-           matched = log->tstamp <= sn->u.tstamp;
-           break;
-       }
-       if (sn->negated)
-           matched = !matched;
-    }
-    return matched;
-}
-
-static int
-list_session_dir(pathbuf, re, user, tty)
-    char *pathbuf;
-    REGEX_T *re;
-    const char *user;
-    const char *tty;
-{
-    FILE *fp;
-    DIR *d;
-    struct dirent *dp;
-    char *buf = NULL, *cmd = NULL, *cwd = NULL, idstr[7], *cp;
-    struct log_info li;
-    size_t bufsize = 0, cwdsize = 0, cmdsize = 0, plen;
-
-    plen = strlen(pathbuf);
-    d = opendir(pathbuf);
-    if (d == NULL && errno != ENOTDIR) {
-       warning("cannot opendir %s", pathbuf);
-       return -1;
-    }
-    while ((dp = readdir(d)) != NULL) {
-       if (NAMLEN(dp) != 2 || !isalnum((unsigned char)dp->d_name[0]) ||
-           !isalnum((unsigned char)dp->d_name[1]))
-           continue;
-
-       /* open log file, print id and command */
-       pathbuf[plen + 0] = '/';
-       pathbuf[plen + 1] = dp->d_name[0];
-       pathbuf[plen + 2] = dp->d_name[1];
-       pathbuf[plen + 3] = '/';
-       pathbuf[plen + 4] = 'l';
-       pathbuf[plen + 5] = 'o';
-       pathbuf[plen + 6] = 'g';
-       pathbuf[plen + 7] = '\0';
-       fp = fopen(pathbuf, "r");
-       if (fp == NULL) {
-           warning("unable to open %s", pathbuf);
-           continue;
-       }
-
-       /*
-        * ID file has three lines:
-        *  1) a log info line
-        *  2) cwd
-        *  3) command with args
-        */
-       if (getline(&buf, &bufsize, fp) == -1 ||
-           getline(&cwd, &cwdsize, fp) == -1 ||
-           getline(&cmd, &cmdsize, fp) == -1) {
-           fclose(fp);
-           continue;
-       }
-       fclose(fp);
-
-       /* crack the log line: timestamp:user:runas_user:runas_group:tty */
-       buf[strcspn(buf, "\n")] = '\0';
-       if ((li.tstamp = atoi(buf)) == 0)
-           continue;
-
-       if ((cp = strchr(buf, ':')) == NULL)
-           continue;
-       *cp++ = '\0';
-       li.user = cp;
-
-       if ((cp = strchr(cp, ':')) == NULL)
-           continue;
-       *cp++ = '\0';
-       li.runas_user = cp;
-
-       if ((cp = strchr(cp, ':')) == NULL)
-           continue;
-       *cp++ = '\0';
-       li.runas_group = cp;
-
-       if ((cp = strchr(cp, ':')) == NULL)
-           continue;
-       *cp++ = '\0';
-       li.tty = cp;
-
-       cwd[strcspn(cwd, "\n")] = '\0';
-       li.cwd = cwd;
-
-       cmd[strcspn(cmd, "\n")] = '\0';
-       li.cmd = cmd;
-
-       /* Match on search expression if there is one. */
-       if (search_expr && !match_expr(search_expr, &li))
-           continue;
-
-       /* Convert from /var/log/sudo-sessions/00/00/01 to 000001 */
-       idstr[0] = pathbuf[plen - 5];
-       idstr[1] = pathbuf[plen - 4];
-       idstr[2] = pathbuf[plen - 2];
-       idstr[3] = pathbuf[plen - 1];
-       idstr[4] = pathbuf[plen + 1];
-       idstr[5] = pathbuf[plen + 2];
-       idstr[6] = '\0';
-       printf("%s : %s : TTY=%s ; CWD=%s ; USER=%s ; ",
-           get_timestr(li.tstamp, 1), li.user, li.tty, li.cwd, li.runas_user);
-       if (*li.runas_group)
-           printf("GROUP=%s ; ", li.runas_group);
-       printf("TSID=%s ; COMMAND=%s\n", idstr, li.cmd);
-    }
-    return 0;
-}
-
-static int
-list_sessions(argc, argv, pattern, user, tty)
-    int argc;
-    char **argv;
-    const char *pattern;
-    const char *user;
-    const char *tty;
-{
-    DIR *d1, *d2;
-    struct dirent *dp1, *dp2;
-    REGEX_T rebuf, *re = NULL;
-    size_t sdlen;
-    char pathbuf[PATH_MAX];
-
-    /* Parse search expression if present */
-    parse_expr(&search_expr, argv);
-
-    d1 = opendir(session_dir);
-    if (d1 == NULL)
-       error(1, "unable to open %s", session_dir);
-
-#ifdef HAVE_REGCOMP
-    /* optional regex */
-    if (pattern) {
-       re = &rebuf;
-       if (regcomp(re, pattern, REG_EXTENDED|REG_NOSUB) != 0)
-           errorx(1, "invalid regex: %s", pattern);
-    }
-#else
-    re = (char *) pattern;
-#endif /* HAVE_REGCOMP */
-
-    sdlen = strlcpy(pathbuf, session_dir, sizeof(pathbuf));
-    if (sdlen + sizeof("/00/00/00/log") >= sizeof(pathbuf)) {
-       errno = ENAMETOOLONG;
-       error(1, "%s/00/00/00/log", session_dir);
-    }
-
-    /*
-     * Three levels of directory, e.g. 00/00/00 .. ZZ/ZZ/ZZ
-     * We do a depth-first traversal.
-     */
-    while ((dp1 = readdir(d1)) != NULL) {
-       if (NAMLEN(dp1) != 2 || !isalnum((unsigned char)dp1->d_name[0]) ||
-           !isalnum((unsigned char)dp1->d_name[1]))
-           continue;
-
-       pathbuf[sdlen + 0] = '/';
-       pathbuf[sdlen + 1] = dp1->d_name[0];
-       pathbuf[sdlen + 2] = dp1->d_name[1];
-       pathbuf[sdlen + 3] = '\0';
-       d2 = opendir(pathbuf);
-       if (d2 == NULL)
-           continue;
-
-       while ((dp2 = readdir(d2)) != NULL) {
-           if (NAMLEN(dp2) != 2 || !isalnum((unsigned char)dp2->d_name[0]) ||
-               !isalnum((unsigned char)dp2->d_name[1]))
-               continue;
-
-           pathbuf[sdlen + 3] = '/';
-           pathbuf[sdlen + 4] = dp2->d_name[0];
-           pathbuf[sdlen + 5] = dp2->d_name[1];
-           pathbuf[sdlen + 6] = '\0';
-           list_session_dir(pathbuf, re, user, tty);
-       }
-       closedir(d2);
-    }
-    closedir(d1);
-    return 0;
-}
-
-/*
- * Check input for ' ', '<', '>'
- * pause, slow, fast
- */
-static void
-check_input(ttyfd, speed)
-    int ttyfd;
-    double *speed;
-{
-    fd_set *fdsr;
-    int nready, paused = 0;
-    struct timeval tv;
-    char ch;
-    ssize_t n;
-
-    fdsr = (fd_set *)emalloc2(howmany(ttyfd + 1, NFDBITS), sizeof(fd_mask));
-
-    for (;;) {
-       FD_SET(ttyfd, fdsr);
-       tv.tv_sec = 0;
-       tv.tv_usec = 0;
-
-       nready = select(ttyfd + 1, fdsr, NULL, NULL, paused ? NULL : &tv);
-       if (nready != 1)
-           break;
-       n = read(ttyfd, &ch, 1);
-       if (n == 1) {
-           if (paused) {
-               paused = 0;
-               continue;
-           }
-           switch (ch) {
-           case ' ':
-               paused = 1;
-               break;
-           case '<':
-               *speed /= 2;
-               break;
-           case '>':
-               *speed *= 2;
-               break;
-           }
-       }
-    }
-    free(fdsr);
-}
-
-/*
- * Parse a timing line, which is formatted as:
- *     index sleep_time num_bytes
- * Where index is IOFD_*, sleep_time is the number of seconds to sleep
- * before writing the data and num_bytes is the number of bytes to output.
- * Returns 1 on success and 0 on failure.
- */
-static int
-parse_timing(buf, decimal, idx, seconds, nbytes)
-    const char *buf;
-    const char *decimal;
-    int *idx;
-    double *seconds;
-    size_t *nbytes;
-{
-    unsigned long ul;
-    long l;
-    double d, fract = 0;
-    char *cp, *ep;
-
-    /* Parse index */
-    ul = strtoul(buf, &ep, 10);
-    if (ul > IOFD_MAX)
-       goto bad;
-    *idx = (int)ul;
-    for (cp = ep + 1; isspace((unsigned char) *cp); cp++)
-       continue;
-
-    /*
-     * Parse number of seconds.  Sudo logs timing data in the C locale
-     * but this may not match the current locale so we cannot use strtod().
-     * Furthermore, sudo < 1.7.4 logged with the user's locale so we need
-     * to be able to parse those logs too.
-     */
-    errno = 0;
-    l = strtol(cp, &ep, 10);
-    if ((errno == ERANGE && (l == LONG_MAX || l == LONG_MIN)) ||
-       l < 0 || l > INT_MAX ||
-       (*ep != '.' && strncmp(ep, decimal, strlen(decimal)) != 0)) {
-       goto bad;
-    }
-    *seconds = (double)l;
-    cp = ep + (*ep == '.' ? 1 : strlen(decimal));
-    d = 10.0;
-    while (isdigit((unsigned char) *cp)) {
-       fract += (*cp - '0') / d;
-       d *= 10;
-       cp++;
-    }
-    *seconds += fract;
-    while (isspace((unsigned char) *cp))
-       cp++;
-
-    errno = 0;
-    ul = strtoul(cp, &ep, 10);
-    if (errno == ERANGE && ul == ULONG_MAX)
-       goto bad;
-    *nbytes = (size_t)ul;
-
-    return 1;
-bad:
-    return 0;
-}
-
-static void
-usage(fatal)
-    int fatal;
-{
-    fprintf(fatal ? stderr : stdout,
-       "usage: %s [-h] [-d directory] [-f filter] [-m max_wait] [-s speed_factor] ID\n",
-       getprogname());
-    fprintf(fatal ? stderr : stdout,
-       "usage: %s [-h] [-d directory] -l [search expression]\n",
-       getprogname());
-    if (fatal)
-       exit(1);
-}
-
-static void
-help()
-{
-    (void) printf("%s - replay sudo session logs\n\n", getprogname());
-    usage(0);
-    (void) puts("\nOptions:");
-    (void) puts("  -d directory     specify directory for session logs");
-    (void) puts("  -f filter        specify which I/O type to display");
-    (void) puts("  -h               display help message and exit");
-    (void) puts("  -l [expression]  list available session IDs that match expression");
-    (void) puts("  -m max_wait      max number of seconds to wait between events");
-    (void) puts("  -s speed_factor  speed up or slow down output");
-    (void) puts("  -V               display version information and exit");
-    exit(0);
-}
-
-/*
- * Cleanup hook for error()/errorx()
-  */
-RETSIGTYPE
-cleanup(signo)
-    int signo;
-{
-    term_restore(STDIN_FILENO, 0);
-    if (signo)
-       kill(getpid(), signo);
-}
diff --git a/sudoreplay.cat b/sudoreplay.cat
deleted file mode 100644 (file)
index aee5497..0000000
+++ /dev/null
@@ -1,330 +0,0 @@
-
-
-
-SUDOREPLAY(1m)         MAINTENANCE COMMANDS        SUDOREPLAY(1m)
-
-
-N\bNA\bAM\bME\bE
-       sudoreplay - replay sudo session logs
-
-S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS
-       s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by [-\b-h\bh] [-\b-d\bd _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by] [-\b-f\bf _\bf_\bi_\bl_\bt_\be_\br] [-\b-m\bm _\bm_\ba_\bx_\b__\bw_\ba_\bi_\bt] [-\b-s\bs
-       _\bs_\bp_\be_\be_\bd_\b__\bf_\ba_\bc_\bt_\bo_\br] ID
-
-       s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by [-\b-h\bh] [-\b-d\bd _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by] -l [search expression]
-
-D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
-       s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by plays back or lists the session logs created by s\bsu\bud\bdo\bo.  When
-       replaying, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by can play the session back in real-time, or the
-       playback speed may be adjusted (faster or slower) based on the command
-       line options.  The _\bI_\bD should be a six character sequence of digits and
-       upper case letters, e.g.  0100A5, which is logged by s\bsu\bud\bdo\bo when a
-       command is run with session logging enabled.
-
-       In list mode, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by can be used to find the ID of a session based
-       on a number of criteria such as the user, tty or command run.
-
-       In replay mode, if the standard output has not been redirected,
-       s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by will act on the following keys:
-
-       ' ' (space)
-               Pause output; press any key to resume.
-
-       '<'     Reduce the playback speed by one half.
-
-       '>'     Double the playback speed.
-
-O\bOP\bPT\bTI\bIO\bON\bNS\bS
-       s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by accepts the following command line options:
-
-       -d _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by
-                   Use _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by to for the session logs instead of the
-                   default, _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo.
-
-       -f _\bf_\bi_\bl_\bt_\be_\br   By default, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by will play back the command's
-                   standard output, standard error and tty output.  The _\b-_\bf
-                   option can be used to select which of these to output.  The
-                   _\bf_\bi_\bl_\bt_\be_\br argument is a comma-separated list, consisting of
-                   one or more of following: _\bs_\bt_\bd_\bo_\bu_\bt, _\bs_\bt_\bd_\be_\br_\br, and _\bt_\bt_\by_\bo_\bu_\bt.
-
-       -h          The -\b-h\bh (_\bh_\be_\bl_\bp) option causes s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by to print a short
-                   help message to the standard output and exit.
-
-       -l [_\bs_\be_\ba_\br_\bc_\bh _\be_\bx_\bp_\br_\be_\bs_\bs_\bi_\bo_\bn]
-                   Enable "list mode".  In this mode, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by will list
-                   available session IDs.  If a _\bs_\be_\ba_\br_\bc_\bh _\be_\bx_\bp_\br_\be_\bs_\bs_\bi_\bo_\bn is
-                   specified, it will be used to restrict the IDs that are
-                   displayed.  An expression is composed of the following
-                   predicates:
-
-
-
-
-
-1.7.6                     April  9, 2011                        1
-
-
-
-
-
-SUDOREPLAY(1m)         MAINTENANCE COMMANDS        SUDOREPLAY(1m)
-
-
-                   command _\bc_\bo_\bm_\bm_\ba_\bn_\bd _\bp_\ba_\bt_\bt_\be_\br_\bn
-                           Evaluates to true if the command run matches
-                           _\bc_\bo_\bm_\bm_\ba_\bn_\bd _\bp_\ba_\bt_\bt_\be_\br_\bn.  On systems with POSIX regular
-                           expression support, the pattern may be an extended
-                           regular expression.  On systems without POSIX
-                           regular expression support, a simple substring
-                           match is performed instead.
-
-                   cwd _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by
-                           Evaluates to true if the command was run with the
-                           specified current working directory.
-
-                   fromdate _\bd_\ba_\bt_\be
-                           Evaluates to true if the command was run on or
-                           after _\bd_\ba_\bt_\be.  See "Date and time format" for a
-                           description of supported date and time formats.
-
-                   group _\br_\bu_\bn_\ba_\bs_\b__\bg_\br_\bo_\bu_\bp
-                           Evaluates to true if the command was run with the
-                           specified _\br_\bu_\bn_\ba_\bs_\b__\bg_\br_\bo_\bu_\bp.  Note that unless a
-                           _\br_\bu_\bn_\ba_\bs_\b__\bg_\br_\bo_\bu_\bp was explicitly specified when s\bsu\bud\bdo\bo was
-                           run this field will be empty in the log.
-
-                   runas _\br_\bu_\bn_\ba_\bs_\b__\bu_\bs_\be_\br
-                           Evaluates to true if the command was run as the
-                           specified _\br_\bu_\bn_\ba_\bs_\b__\bu_\bs_\be_\br.  Note that s\bsu\bud\bdo\bo runs commands
-                           as user _\br_\bo_\bo_\bt by default.
-
-                   todate _\bd_\ba_\bt_\be
-                           Evaluates to true if the command was run on or
-                           prior to _\bd_\ba_\bt_\be.  See "Date and time format" for a
-                           description of supported date and time formats.
-
-                   tty _\bt_\bt_\by Evaluates to true if the command was run on the
-                           specified terminal device.  The _\bt_\bt_\by should be
-                           specified without the _\b/_\bd_\be_\bv_\b/ prefix, e.g.  _\bt_\bt_\by_\b0_\b1
-                           instead of _\b/_\bd_\be_\bv_\b/_\bt_\bt_\by_\b0_\b1.
-
-                   user _\bu_\bs_\be_\br _\bn_\ba_\bm_\be
-                           Evaluates to true if the ID matches a command run
-                           by _\bu_\bs_\be_\br _\bn_\ba_\bm_\be.
-
-                   Predicates may be abbreviated to the shortest unique string
-                   (currently all predicates may be shortened to a single
-                   character).
-
-                   Predicates may be combined using _\ba_\bn_\bd, _\bo_\br and _\b! operators as
-                   well as '(' and ')' for grouping (note that parentheses
-                   must generally be escaped from the shell).  The _\ba_\bn_\bd
-                   operator is optional, adjacent predicates have an implied
-                   _\ba_\bn_\bd unless separated by an _\bo_\br.
-
-       -m _\bm_\ba_\bx_\b__\bw_\ba_\bi_\bt Specify an upper bound on how long to wait between key
-                   presses or output data.  By default, s\bsu\bud\bdo\bo_\b_r\bre\bep\bpl\bla\bay\by will
-
-
-
-1.7.6                     April  9, 2011                        2
-
-
-
-
-
-SUDOREPLAY(1m)         MAINTENANCE COMMANDS        SUDOREPLAY(1m)
-
-
-                   accurately reproduce the delays between key presses or
-                   program output.  However, this can be tedious when the
-                   session includes long pauses.  When the _\b-_\bm option is
-                   specified, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by will limit these pauses to at most
-                   _\bm_\ba_\bx_\b__\bw_\ba_\bi_\bt seconds.  The value may be specified as a floating
-                   point number, .e.g. _\b2_\b._\b5.
-
-       -s _\bs_\bp_\be_\be_\bd_\b__\bf_\ba_\bc_\bt_\bo_\br
-                   This option causes s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by to adjust the number of
-                   seconds it will wait between key presses or program output.
-                   This can be used to slow down or speed up the display.  For
-                   example, a _\bs_\bp_\be_\be_\bd_\b__\bf_\ba_\bc_\bt_\bo_\br of _\b2 would make the output twice as
-                   fast whereas a _\bs_\bp_\be_\be_\bd_\b__\bf_\ba_\bc_\bt_\bo_\br of <.5> would make the output
-                   twice as slow.
-
-       -V          The -\b-V\bV (version) option causes s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by to print its
-                   version number and exit.
-
-   D\bDa\bat\bte\be a\ban\bnd\bd t\bti\bim\bme\be f\bfo\bor\brm\bma\bat\bt
-       The time and date may be specified multiple ways, common formats
-       include:
-
-       HH:MM:SS am MM/DD/CCYY timezone
-               24 hour time may be used in place of am/pm.
-
-       HH:MM:SS am Month, Day Year timezone
-               24 hour time may be used in place of am/pm, and month and day
-               names may be abbreviated.  Note that month and day of the week
-               names must be specified in English.
-
-       CCYY-MM-DD HH:MM:SS
-               ISO time format
-
-       DD Month CCYY HH:MM:SS
-               The month name may be abbreviated.
-
-       Either time or date may be omitted, the am/pm and timezone are
-       optional.  If no date is specified, the current day is assumed; if no
-       time is specified, the first second of the specified date is used.  The
-       less significant parts of both time and date may also be omitted, in
-       which case zero is assumed.  For example, the following are all valid:
-
-       The following are all valid time and date specifications:
-
-       now     The current time and date.
-
-       tomorrow
-               Exactly one day from now.
-
-       yesterday
-               24 hours ago.
-
-       2 hours ago
-               2 hours ago.
-
-
-
-1.7.6                     April  9, 2011                        3
-
-
-
-
-
-SUDOREPLAY(1m)         MAINTENANCE COMMANDS        SUDOREPLAY(1m)
-
-
-       next Friday
-               The first second of the next Friday.
-
-       this week
-               The current time but the first day of the coming week.
-
-       a fortnight ago
-               The current time but 14 days ago.
-
-       10:01 am 9/17/2009
-               10:01 am, September 17, 2009.
-
-       10:01 am
-               10:01 am on the current day.
-
-       10      10:00 am on the current day.
-
-       9/17/2009
-               00:00 am, September 17, 2009.
-
-       10:01 am Sep 17, 2009
-               10:01 am, September 17, 2009.
-
-F\bFI\bIL\bLE\bES\bS
-       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo        The default I/O log directory.
-
-       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bl_\bo_\bg
-                               Example session log info.
-
-       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bs_\bt_\bd_\bi_\bn
-                               Example session standard input log.
-
-       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bs_\bt_\bd_\bo_\bu_\bt
-                               Example session standard output log.
-
-       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bs_\bt_\bd_\be_\br_\br
-                               Example session standard error log.
-
-       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bt_\bt_\by_\bi_\bn
-                               Example session tty input file.
-
-       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bt_\bt_\by_\bo_\bu_\bt
-                               Example session tty output file.
-
-       _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo_\b/_\b0_\b0_\b/_\b0_\b0_\b/_\b0_\b1_\b/_\bt_\bi_\bm_\bi_\bn_\bg
-                               Example session timing file.
-
-       Note that the _\bs_\bt_\bd_\bi_\bn, _\bs_\bt_\bd_\bo_\bu_\bt and _\bs_\bt_\bd_\be_\br_\br files will be empty unless s\bsu\bud\bdo\bo
-       was used as part of a pipeline for a particular command.
-
-E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
-       List sessions run by user _\bm_\bi_\bl_\bl_\be_\br_\bt:
-
-        sudoreplay -l user millert
-
-
-
-1.7.6                     April  9, 2011                        4
-
-
-
-
-
-SUDOREPLAY(1m)         MAINTENANCE COMMANDS        SUDOREPLAY(1m)
-
-
-       List sessions run by user _\bb_\bo_\bb with a command containing the string vi:
-
-        sudoreplay -l user bob command vi
-
-       List sessions run by user _\bj_\be_\bf_\bf that match a regular expression:
-
-        sudoreplay -l user jeff command '/bin/[a-z]*sh'
-
-       List sessions run by jeff or bob on the console:
-
-        sudoreplay -l ( user jeff or user bob ) tty console
-
-S\bSE\bEE\bE A\bAL\bLS\bSO\bO
-       _\bs_\bu_\bd_\bo(1m), _\bs_\bc_\br_\bi_\bp_\bt(1)
-
-A\bAU\bUT\bTH\bHO\bOR\bR
-       Todd C. Miller
-
-B\bBU\bUG\bGS\bS
-       If you feel you have found a bug in s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by, 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.
-
-D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
-       s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by 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.6                     April  9, 2011                        5
-
-
diff --git a/sudoreplay.man.in b/sudoreplay.man.in
deleted file mode 100644 (file)
index 89418d8..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-.\" Copyright (c) 2009-2010 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.
-.\" 
-.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.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 (.SS), 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 "SUDOREPLAY @mansectsu@"
-.TH SUDOREPLAY @mansectsu@ "April  9, 2011" "1.7.6" "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"
-sudoreplay \- replay sudo session logs
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBsudoreplay\fR [\fB\-h\fR] [\fB\-d\fR \fIdirectory\fR] [\fB\-f\fR \fIfilter\fR] [\fB\-m\fR \fImax_wait\fR] [\fB\-s\fR \fIspeed_factor\fR] \s-1ID\s0
-.PP
-\&\fBsudoreplay\fR [\fB\-h\fR] [\fB\-d\fR \fIdirectory\fR] \-l [search expression]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBsudoreplay\fR plays back or lists the session logs created by
-\&\fBsudo\fR.  When replaying, \fBsudoreplay\fR can play the session back
-in real-time, or the playback speed may be adjusted (faster or
-slower) based on the command line options.  The \fI\s-1ID\s0\fR should be
-a six character sequence of digits and upper case letters, e.g.
-0100A5, which is logged by \fBsudo\fR when a command is run with
-session logging enabled.
-.PP
-In list mode, \fBsudoreplay\fR can be used to find the \s-1ID\s0 of a session
-based on a number of criteria such as the user, tty or command run.
-.PP
-In replay mode, if the standard output has not been redirected,
-\&\fBsudoreplay\fR will act on the following keys:
-.IP "' ' (space)" 8
-.IX Item "' ' (space)"
-Pause output; press any key to resume.
-.IP "'<'" 8
-Reduce the playback speed by one half.
-.IP "'>'" 8
-Double the playback speed.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-\&\fBsudoreplay\fR accepts the following command line options:
-.IP "\-d \fIdirectory\fR" 12
-.IX Item "-d directory"
-Use \fIdirectory\fR to for the session logs instead of the default,
-\&\fI/var/log/sudo\-io\fR.
-.IP "\-f \fIfilter\fR" 12
-.IX Item "-f filter"
-By default, \fBsudoreplay\fR will play back the command's standard
-output, standard error and tty output.  The \fI\-f\fR option can be
-used to select which of these to output.  The \fIfilter\fR argument
-is a comma-separated list, consisting of one or more of following:
-\&\fIstdout\fR, \fIstderr\fR, and \fIttyout\fR.
-.IP "\-h" 12
-.IX Item "-h"
-The \fB\-h\fR (\fIhelp\fR) option causes \fBsudoreplay\fR to print a short
-help message to the standard output and exit.
-.IP "\-l [\fIsearch expression\fR]" 12
-.IX Item "-l [search expression]"
-Enable \*(L"list mode\*(R".  In this mode, \fBsudoreplay\fR will list available
-session IDs.  If a \fIsearch expression\fR is specified, it will be
-used to restrict the IDs that are displayed.  An expression is
-composed of the following predicates:
-.RS 12
-.IP "command \fIcommand pattern\fR" 8
-.IX Item "command command pattern"
-Evaluates to true if the command run matches \fIcommand pattern\fR.
-On systems with \s-1POSIX\s0 regular expression support, the pattern may
-be an extended regular expression.  On systems without \s-1POSIX\s0 regular
-expression support, a simple substring match is performed instead.
-.IP "cwd \fIdirectory\fR" 8
-.IX Item "cwd directory"
-Evaluates to true if the command was run with the specified current
-working directory.
-.IP "fromdate \fIdate\fR" 8
-.IX Item "fromdate date"
-Evaluates to true if the command was run on or after \fIdate\fR.
-See \*(L"Date and time format\*(R" for a description of supported
-date and time formats.
-.IP "group \fIrunas_group\fR" 8
-.IX Item "group runas_group"
-Evaluates to true if the command was run with the specified
-\&\fIrunas_group\fR.  Note that unless a \fIrunas_group\fR was explicitly
-specified when \fBsudo\fR was run this field will be empty in the log.
-.IP "runas \fIrunas_user\fR" 8
-.IX Item "runas runas_user"
-Evaluates to true if the command was run as the specified \fIrunas_user\fR.
-Note that \fBsudo\fR runs commands as user \fIroot\fR by default.
-.IP "todate \fIdate\fR" 8
-.IX Item "todate date"
-Evaluates to true if the command was run on or prior to \fIdate\fR.
-See \*(L"Date and time format\*(R" for a description of supported
-date and time formats.
-.IP "tty \fItty\fR" 8
-.IX Item "tty tty"
-Evaluates to true if the command was run on the specified terminal
-device.  The \fItty\fR should be specified without the \fI/dev/\fR prefix,
-e.g.  \fItty01\fR instead of \fI/dev/tty01\fR.
-.IP "user \fIuser name\fR" 8
-.IX Item "user user name"
-Evaluates to true if the \s-1ID\s0 matches a command run by \fIuser name\fR.
-.RE
-.RS 12
-.Sp
-Predicates may be abbreviated to the shortest unique string (currently
-all predicates may be shortened to a single character).
-.Sp
-Predicates may be combined using \fIand\fR, \fIor\fR and \fI!\fR operators
-as well as \f(CW\*(Aq(\*(Aq\fR and \f(CW\*(Aq)\*(Aq\fR for grouping (note that parentheses
-must generally be escaped from the shell).  The \fIand\fR operator is
-optional, adjacent predicates have an implied \fIand\fR unless separated
-by an \fIor\fR.
-.RE
-.IP "\-m \fImax_wait\fR" 12
-.IX Item "-m max_wait"
-Specify an upper bound on how long to wait between key presses or
-output data.  By default, \fBsudo_replay\fR will accurately reproduce
-the delays between key presses or program output.  However, this
-can be tedious when the session includes long pauses.  When the
-\&\fI\-m\fR option is specified, \fBsudoreplay\fR will limit these pauses
-to at most \fImax_wait\fR seconds.  The value may be specified as a
-floating point number, .e.g. \fI2.5\fR.
-.IP "\-s \fIspeed_factor\fR" 12
-.IX Item "-s speed_factor"
-This option causes \fBsudoreplay\fR to adjust the number of seconds
-it will wait between key presses or program output.  This can be
-used to slow down or speed up the display.  For example, a
-\&\fIspeed_factor\fR of \fI2\fR would make the output twice as fast whereas
-a \fIspeed_factor\fR of <.5> would make the output twice as slow.
-.IP "\-V" 12
-.IX Item "-V"
-The \fB\-V\fR (version) option causes \fBsudoreplay\fR to print its version number
-and exit.
-.SS "Date and time format"
-.IX Subsection "Date and time format"
-The time and date may be specified multiple ways, common formats include:
-.IP "\s-1HH:MM:SS\s0 am \s-1MM/DD/CCYY\s0 timezone" 8
-.IX Item "HH:MM:SS am MM/DD/CCYY timezone"
-24 hour time may be used in place of am/pm.
-.IP "\s-1HH:MM:SS\s0 am Month, Day Year timezone" 8
-.IX Item "HH:MM:SS am Month, Day Year timezone"
-24 hour time may be used in place of am/pm, and month and day names
-may be abbreviated.  Note that month and day of the week names must
-be specified in English.
-.IP "CCYY-MM-DD \s-1HH:MM:SS\s0" 8
-.IX Item "CCYY-MM-DD HH:MM:SS"
-\&\s-1ISO\s0 time format
-.IP "\s-1DD\s0 Month \s-1CCYY\s0 \s-1HH:MM:SS\s0" 8
-.IX Item "DD Month CCYY HH:MM:SS"
-The month name may be abbreviated.
-.PP
-Either time or date may be omitted, the am/pm and timezone are
-optional.  If no date is specified, the current day is assumed; if
-no time is specified, the first second of the specified date is
-used.  The less significant parts of both time and date may also
-be omitted, in which case zero is assumed.  For example, the following
-are all valid:
-.PP
-The following are all valid time and date specifications:
-.IP "now" 8
-.IX Item "now"
-The current time and date.
-.IP "tomorrow" 8
-.IX Item "tomorrow"
-Exactly one day from now.
-.IP "yesterday" 8
-.IX Item "yesterday"
-24 hours ago.
-.IP "2 hours ago" 8
-.IX Item "2 hours ago"
-2 hours ago.
-.IP "next Friday" 8
-.IX Item "next Friday"
-The first second of the next Friday.
-.IP "this week" 8
-.IX Item "this week"
-The current time but the first day of the coming week.
-.IP "a fortnight ago" 8
-.IX Item "a fortnight ago"
-The current time but 14 days ago.
-.IP "10:01 am 9/17/2009" 8
-.IX Item "10:01 am 9/17/2009"
-10:01 am, September 17, 2009.
-.IP "10:01 am" 8
-.IX Item "10:01 am"
-10:01 am on the current day.
-.IP "10" 8
-.IX Item "10"
-10:00 am on the current day.
-.IP "9/17/2009" 8
-.IX Item "9/17/2009"
-00:00 am, September 17, 2009.
-.IP "10:01 am Sep 17, 2009" 8
-.IX Item "10:01 am Sep 17, 2009"
-10:01 am, September 17, 2009.
-.SH "FILES"
-.IX Header "FILES"
-.IP "\fI/var/log/sudo\-io\fR" 24
-.IX Item "/var/log/sudo-io"
-The default I/O log directory.
-.IP "\fI/var/log/sudo\-io/00/00/01/log\fR" 24
-.IX Item "/var/log/sudo-io/00/00/01/log"
-Example session log info.
-.IP "\fI/var/log/sudo\-io/00/00/01/stdin\fR" 24
-.IX Item "/var/log/sudo-io/00/00/01/stdin"
-Example session standard input log.
-.IP "\fI/var/log/sudo\-io/00/00/01/stdout\fR" 24
-.IX Item "/var/log/sudo-io/00/00/01/stdout"
-Example session standard output log.
-.IP "\fI/var/log/sudo\-io/00/00/01/stderr\fR" 24
-.IX Item "/var/log/sudo-io/00/00/01/stderr"
-Example session standard error log.
-.IP "\fI/var/log/sudo\-io/00/00/01/ttyin\fR" 24
-.IX Item "/var/log/sudo-io/00/00/01/ttyin"
-Example session tty input file.
-.IP "\fI/var/log/sudo\-io/00/00/01/ttyout\fR" 24
-.IX Item "/var/log/sudo-io/00/00/01/ttyout"
-Example session tty output file.
-.IP "\fI/var/log/sudo\-io/00/00/01/timing\fR" 24
-.IX Item "/var/log/sudo-io/00/00/01/timing"
-Example session timing file.
-.PP
-Note that the \fIstdin\fR, \fIstdout\fR and \fIstderr\fR files will be empty
-unless \fBsudo\fR was used as part of a pipeline for a particular
-command.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-List sessions run by user \fImillert\fR:
-.PP
-.Vb 1
-\& sudoreplay \-l user millert
-.Ve
-.PP
-List sessions run by user \fIbob\fR with a command containing the string vi:
-.PP
-.Vb 1
-\& sudoreplay \-l user bob command vi
-.Ve
-.PP
-List sessions run by user \fIjeff\fR that match a regular expression:
-.PP
-.Vb 1
-\& sudoreplay \-l user jeff command \*(Aq/bin/[a\-z]*sh\*(Aq
-.Ve
-.PP
-List sessions run by jeff or bob on the console:
-.PP
-.Vb 1
-\& sudoreplay \-l ( user jeff or user bob ) tty console
-.Ve
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIsudo\fR\|(@mansectsu@), \fIscript\fR\|(1)
-.SH "AUTHOR"
-.IX Header "AUTHOR"
-Todd C. Miller
-.SH "BUGS"
-.IX Header "BUGS"
-If you feel you have found a bug in \fBsudoreplay\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"
-\&\fBsudoreplay\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/sudoreplay.pod b/sudoreplay.pod
deleted file mode 100644 (file)
index 5eb6e1e..0000000
+++ /dev/null
@@ -1,346 +0,0 @@
-Copyright (c) 2009-2010 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.
-
-=pod
-
-=head1 NAME
-
-sudoreplay - replay sudo session logs
-
-=head1 SYNOPSIS
-
-B<sudoreplay> [B<-h>] [B<-d> I<directory>] [B<-f> I<filter>] [B<-m> I<max_wait>] [B<-s> I<speed_factor>] ID
-
-B<sudoreplay> [B<-h>] [B<-d> I<directory>] -l [search expression]
-
-=head1 DESCRIPTION
-
-B<sudoreplay> plays back or lists the session logs created by
-B<sudo>.  When replaying, B<sudoreplay> can play the session back
-in real-time, or the playback speed may be adjusted (faster or
-slower) based on the command line options.  The I<ID> should be
-a six character sequence of digits and upper case letters, e.g.
-0100A5, which is logged by B<sudo> when a command is run with
-session logging enabled.
-
-In list mode, B<sudoreplay> can be used to find the ID of a session
-based on a number of criteria such as the user, tty or command run.
-
-In replay mode, if the standard output has not been redirected,
-B<sudoreplay> will act on the following keys:
-
-=over 8
-
-=item ' ' (space)
-
-Pause output; press any key to resume.
-
-=item '<'
-
-Reduce the playback speed by one half.
-
-=item '>'
-
-Double the playback speed.
-
-=back
-
-=head1 OPTIONS
-
-B<sudoreplay> accepts the following command line options:
-
-=over 12
-
-=item -d I<directory>
-
-Use I<directory> to for the session logs instead of the default,
-F</var/log/sudo-io>.
-
-=item -f I<filter>
-
-By default, B<sudoreplay> will play back the command's standard
-output, standard error and tty output.  The I<-f> option can be
-used to select which of these to output.  The I<filter> argument
-is a comma-separated list, consisting of one or more of following:
-I<stdout>, I<stderr>, and I<ttyout>.
-
-=item -h
-
-The B<-h> (I<help>) option causes B<sudoreplay> to print a short
-help message to the standard output and exit.
-
-=item -l [I<search expression>]
-
-Enable "list mode".  In this mode, B<sudoreplay> will list available
-session IDs.  If a I<search expression> is specified, it will be
-used to restrict the IDs that are displayed.  An expression is
-composed of the following predicates:
-
-=over 8
-
-=item command I<command pattern>
-
-Evaluates to true if the command run matches I<command pattern>.
-On systems with POSIX regular expression support, the pattern may
-be an extended regular expression.  On systems without POSIX regular
-expression support, a simple substring match is performed instead.
-
-=item cwd I<directory>
-
-Evaluates to true if the command was run with the specified current
-working directory.
-
-=item fromdate I<date>
-
-Evaluates to true if the command was run on or after I<date>.
-See L<"Date and time format"> for a description of supported
-date and time formats.
-
-=item group I<runas_group>
-
-Evaluates to true if the command was run with the specified
-I<runas_group>.  Note that unless a I<runas_group> was explicitly
-specified when B<sudo> was run this field will be empty in the log.
-
-=item runas I<runas_user>
-
-Evaluates to true if the command was run as the specified I<runas_user>.
-Note that B<sudo> runs commands as user I<root> by default.
-
-=item todate I<date>
-
-Evaluates to true if the command was run on or prior to I<date>.
-See L<"Date and time format"> for a description of supported
-date and time formats.
-
-=item tty I<tty>
-
-Evaluates to true if the command was run on the specified terminal
-device.  The I<tty> should be specified without the F</dev/> prefix,
-e.g.  F<tty01> instead of F</dev/tty01>.
-
-=item user I<user name>
-
-Evaluates to true if the ID matches a command run by I<user name>.
-
-=back
-
-Predicates may be abbreviated to the shortest unique string (currently
-all predicates may be shortened to a single character).
-
-Predicates may be combined using I<and>, I<or> and I<!> operators
-as well as C<'('> and C<')'> for grouping (note that parentheses
-must generally be escaped from the shell).  The I<and> operator is
-optional, adjacent predicates have an implied I<and> unless separated
-by an I<or>.
-
-=item -m I<max_wait>
-
-Specify an upper bound on how long to wait between key presses or
-output data.  By default, B<sudo_replay> will accurately reproduce
-the delays between key presses or program output.  However, this
-can be tedious when the session includes long pauses.  When the
-I<-m> option is specified, B<sudoreplay> will limit these pauses
-to at most I<max_wait> seconds.  The value may be specified as a
-floating point number, .e.g. I<2.5>.
-
-=item -s I<speed_factor>
-
-This option causes B<sudoreplay> to adjust the number of seconds
-it will wait between key presses or program output.  This can be
-used to slow down or speed up the display.  For example, a
-I<speed_factor> of I<2> would make the output twice as fast whereas
-a I<speed_factor> of <.5> would make the output twice as slow.
-
-=item -V
-
-The B<-V> (version) option causes B<sudoreplay> to print its version number
-and exit.
-
-=back
-
-=head2 Date and time format
-
-The time and date may be specified multiple ways, common formats include:
-
-=over 8
-
-=item HH:MM:SS am MM/DD/CCYY timezone
-
-24 hour time may be used in place of am/pm.
-
-=item HH:MM:SS am Month, Day Year timezone
-
-24 hour time may be used in place of am/pm, and month and day names
-may be abbreviated.  Note that month and day of the week names must
-be specified in English.
-
-=item CCYY-MM-DD HH:MM:SS
-
-ISO time format
-
-=item DD Month CCYY HH:MM:SS
-
-The month name may be abbreviated.
-
-=back
-
-Either time or date may be omitted, the am/pm and timezone are
-optional.  If no date is specified, the current day is assumed; if
-no time is specified, the first second of the specified date is
-used.  The less significant parts of both time and date may also
-be omitted, in which case zero is assumed.  For example, the following
-are all valid:
-
-The following are all valid time and date specifications:
-
-=over 8
-
-=item now
-
-The current time and date.
-
-=item tomorrow
-
-Exactly one day from now.
-
-=item yesterday
-
-24 hours ago.
-
-=item 2 hours ago
-
-2 hours ago.
-
-=item next Friday
-
-The first second of the next Friday.
-
-=item this week
-
-The current time but the first day of the coming week.
-
-=item a fortnight ago
-
-The current time but 14 days ago.
-
-=item 10:01 am 9/17/2009
-
-10:01 am, September 17, 2009.
-
-=item 10:01 am
-
-10:01 am on the current day.
-
-=item 10
-
-10:00 am on the current day.
-
-=item 9/17/2009
-
-00:00 am, September 17, 2009.
-
-=item 10:01 am Sep 17, 2009
-
-10:01 am, September 17, 2009.
-
-=back
-
-=head1 FILES
-
-=over 24
-
-=item F</var/log/sudo-io>
-
-The default I/O log directory.
-
-=item F</var/log/sudo-io/00/00/01/log>
-
-Example session log info.
-
-=item F</var/log/sudo-io/00/00/01/stdin>
-
-Example session standard input log.
-
-=item F</var/log/sudo-io/00/00/01/stdout>
-
-Example session standard output log.
-
-=item F</var/log/sudo-io/00/00/01/stderr>
-
-Example session standard error log.
-
-=item F</var/log/sudo-io/00/00/01/ttyin>
-
-Example session tty input file.
-
-=item F</var/log/sudo-io/00/00/01/ttyout>
-
-Example session tty output file.
-
-=item F</var/log/sudo-io/00/00/01/timing>
-
-Example session timing file.
-
-=back
-
-Note that the I<stdin>, I<stdout> and I<stderr> files will be empty
-unless B<sudo> was used as part of a pipeline for a particular
-command.
-
-=head1 EXAMPLES
-
-List sessions run by user I<millert>:
-
- sudoreplay -l user millert
-
-List sessions run by user I<bob> with a command containing the string vi:
-
- sudoreplay -l user bob command vi
-
-List sessions run by user I<jeff> that match a regular expression:
-
- sudoreplay -l user jeff command '/bin/[a-z]*sh'
-
-List sessions run by jeff or bob on the console:
-
- sudoreplay -l ( user jeff or user bob ) tty console
-
-=head1 SEE ALSO
-
-L<sudo(8)>, L<script(1)>
-
-=head1 AUTHOR
-
-Todd C. Miller
-
-=head1 BUGS
-
-If you feel you have found a bug in B<sudoreplay>, 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<sudoreplay> 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.
diff --git a/term.c b/term.c
deleted file mode 100644 (file)
index 4aa7128..0000000
--- a/term.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (c) 2009-2011 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
-# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
-#  include <memory.h>
-# endif
-# include <string.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_TERMIOS_H
-# include <termios.h>
-#else
-# ifdef HAVE_TERMIO_H
-#  include <termio.h>
-# else
-#  include <sgtty.h>
-#  include <sys/ioctl.h>
-# endif /* HAVE_TERMIO_H */
-#endif /* HAVE_TERMIOS_H */
-
-#include "sudo.h"
-
-#ifndef TCSASOFT
-# define TCSASOFT      0
-#endif
-#ifndef ECHONL
-# define ECHONL                0
-#endif
-#ifndef IEXTEN
-# define IEXTEN                0
-#endif
-#ifndef IUCLC
-# define IUCLC         0
-#endif
-
-#ifndef _POSIX_VDISABLE
-# ifdef VDISABLE
-#  define _POSIX_VDISABLE      VDISABLE
-# else
-#  define _POSIX_VDISABLE      0
-# endif
-#endif
-
-/*
- * Compat macros for non-termios systems.
- */
-#ifndef HAVE_TERMIOS_H
-# ifdef HAVE_TERMIO_H
-#  undef termios
-#  define termios              termio
-#  define tcgetattr(f, t)      ioctl(f, TCGETA, t)
-#  define tcsetattr(f, a, t)   ioctl(f, a, t)
-#  undef TCSAFLUSH
-#  define TCSAFLUSH            TCSETAF
-#  undef TCSADRAIN
-#  define TCSADRAIN            TCSETAW
-# else /* SGTTY */
-#  undef termios
-#  define termios              sgttyb
-#  define c_lflag              sg_flags
-#  define tcgetattr(f, t)      ioctl(f, TIOCGETP, t)
-#  define tcsetattr(f, a, t)   ioctl(f, a, t)
-#  undef TCSAFLUSH
-#  define TCSAFLUSH            TIOCSETP
-#  undef TCSADRAIN
-#  define TCSADRAIN            TIOCSETN
-# endif /* HAVE_TERMIO_H */
-#endif /* HAVE_TERMIOS_H */
-
-typedef struct termios sudo_term_t;
-
-static sudo_term_t term, oterm;
-static int changed;
-int term_erase;
-int term_kill;
-
-int
-term_restore(fd, flush)
-    int fd;
-    int flush;
-{
-    if (changed) {
-       int flags = TCSASOFT;
-       flags |= flush ? TCSAFLUSH : TCSADRAIN;
-       if (tcsetattr(fd, flags, &oterm) != 0)
-           return 0;
-       changed = 0;
-    }
-    return 1;
-}
-
-int
-term_noecho(fd)
-    int fd;
-{
-    if (!changed && tcgetattr(fd, &oterm) != 0)
-       return 0;
-    (void) memcpy(&term, &oterm, sizeof(term));
-    CLR(term.c_lflag, ECHO|ECHONL);
-#ifdef VSTATUS
-    term.c_cc[VSTATUS] = _POSIX_VDISABLE;
-#endif
-    if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
-       changed = 1;
-       return 1;
-    }
-    return 0;
-}
-
-#if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H)
-
-int
-term_raw(fd, isig)
-    int fd;
-    int isig;
-{
-    struct termios term;
-
-    if (!changed && tcgetattr(fd, &oterm) != 0)
-       return 0;
-    (void) memcpy(&term, &oterm, sizeof(term));
-    /* Set terminal to raw mode */
-    term.c_cc[VMIN] = 1;
-    term.c_cc[VTIME] = 0;
-    CLR(term.c_iflag, ICRNL | IGNCR | INLCR | IUCLC | IXON);
-    CLR(term.c_oflag, OPOST);
-    CLR(term.c_lflag, ECHO | ICANON | ISIG | IEXTEN);
-    if (isig)
-       SET(term.c_lflag, ISIG);
-    if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
-       changed = 1;
-       return 1;
-    }
-    return 0;
-}
-
-int
-term_cbreak(fd)
-    int fd;
-{
-    if (!changed && tcgetattr(fd, &oterm) != 0)
-       return 0;
-    (void) memcpy(&term, &oterm, sizeof(term));
-    /* Set terminal to half-cooked mode */
-    term.c_cc[VMIN] = 1;
-    term.c_cc[VTIME] = 0;
-    CLR(term.c_lflag, ECHO | ECHONL | ICANON | IEXTEN);
-    SET(term.c_lflag, ISIG);
-#ifdef VSTATUS
-    term.c_cc[VSTATUS] = _POSIX_VDISABLE;
-#endif
-    if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
-       term_erase = term.c_cc[VERASE];
-       term_kill = term.c_cc[VKILL];
-       changed = 1;
-       return 1;
-    }
-    return 0;
-}
-
-int
-term_copy(src, dst)
-    int src;
-    int dst;
-{
-    struct termios tt;
-
-    if (tcgetattr(src, &tt) != 0)
-       return 0;
-    /* XXX - add TCSANOW compat define */
-    if (tcsetattr(dst, TCSANOW|TCSASOFT, &tt) != 0)
-       return 0;
-    return 1;
-}
-
-#else /* SGTTY */
-
-int
-term_raw(fd, isig)
-    int fd;
-    int isig;
-{
-    if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0)
-       return 0;
-    (void) memcpy(&term, &oterm, sizeof(term));
-    /* Set terminal to raw mode */
-    /* XXX - how to support isig? */
-    CLR(term.c_lflag, ECHO);
-    SET(term.sg_flags, RAW);
-    if (ioctl(fd, TIOCSETP, &term) == 0) {
-       changed = 1;
-       return 1;
-    }
-    return 0;
-}
-
-int
-term_cbreak(fd)
-    int fd;
-{
-    if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0)
-       return 0;
-    (void) memcpy(&term, &oterm, sizeof(term));
-    /* Set terminal to half-cooked mode */
-    CLR(term.c_lflag, ECHO);
-    SET(term.sg_flags, CBREAK);
-    if (ioctl(fd, TIOCSETP, &term) == 0) {
-       term_erase = term.sg_erase;
-       term_kill = term.sg_kill;
-       changed = 1;
-       return 1;
-    }
-    return 0;
-}
-
-int
-term_copy(src, dst)
-    int src;
-    int dst;
-{
-    struct sgttyb b;
-    struct tchars tc;
-    struct ltchars lc;
-    int l, lb;
-
-    if (ioctl(src, TIOCGETP, &b) != 0 || ioctl(src, TIOCGETC, &tc) != 0 ||
-       ioctl(src, TIOCGETD, &l) != 0 || ioctl(src, TIOCGLTC, &lc) != 0 ||
-       ioctl(src, TIOCLGET, &lb)) {
-       return 0;
-    }
-    if (ioctl(dst, TIOCSETP, &b) != 0 || ioctl(dst, TIOCSETC, &tc) != 0 ||
-       ioctl(dst, TIOCSLTC, &lc) != 0 || ioctl(dst, TIOCLSET, &lb) != 0 ||
-       ioctl(dst, TIOCSETD, &l) != 0) {
-       return 0;
-    }
-    return 1;
-}
-
-#endif
diff --git a/testsudoers.c b/testsudoers.c
deleted file mode 100644 (file)
index 139c7c7..0000000
+++ /dev/null
@@ -1,572 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-2005, 2007-2010
- *     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.
- */
-
-#define _SUDO_MAIN
-
-#include <config.h>
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#ifdef HAVE_FNMATCH
-# include <fnmatch.h>
-#endif /* HAVE_FNMATCH */
-#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>
-
-#include "tsgetgrpw.h"
-#include "sudo.h"
-#include "interfaces.h"
-#include "parse.h"
-#include <gram.h>
-
-#ifndef HAVE_FNMATCH
-# include "emul/fnmatch.h"
-#endif /* HAVE_FNMATCH */
-
-/*
- * Globals
- */
-int  Argc, NewArgc;
-char **Argv, **NewArgv;
-int num_interfaces;
-struct interface *interfaces;
-struct sudo_user sudo_user;
-struct passwd *list_pw;
-extern int parse_error;
-
-/* 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
-
-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 *));
-
-int
-main(argc, argv)
-    int argc;
-    char **argv;
-{
-    struct cmndspec *cs;
-    struct privilege *priv;
-    struct userspec *us;
-    char *p, *grfile, *pwfile, *runas_group, *runas_user;
-    char hbuf[MAXHOSTNAMELEN + 1];
-    int match, host_match, runas_match, cmnd_match;
-    int ch, dflag;
-
-#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
-    malloc_options = "AFGJPR";
-#endif
-#ifdef YYDEBUG
-    yydebug = 1;
-#endif
-
-    Argv = argv;
-    Argc = argc;
-
-    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)
-       setgrfile(grfile);
-    if (pwfile)
-       setpwfile(pwfile);
-    sudo_setpwent();
-    sudo_setgrent();
-
-    if (argc < 2) {
-       if (!dflag)
-           usage();
-       if ((sudo_user.pw = sudo_getpwnam("root")) == NULL)
-            errorx(1, "no passwd entry for root!");
-       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;
-    }
-
-    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;
-    }
-
-    /* Fill in user_args from NewArgv. */
-    if (NewArgc > 0) {
-       char *to, **from;
-       size_t size, n;
-
-       for (size = 0, from = NewArgv + 1; *from; from++)
-           size += strlen(*from) + 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))
-                   errorx(1, "internal error, init_vars() overflow");
-           to += n;
-           *to++ = ' ';
-       }
-       *--to = '\0';
-    }
-
-    /* Initialize default values. */
-    init_defaults();
-
-    /* Load ip addr/mask for each interface. */
-    load_interfaces();
-
-    /* Allocate space for data structures in the parser. */
-    init_parser("sudoers", 0);
-
-    if (yyparse() != 0 || parse_error) {
-       parse_error = TRUE;
-       (void) fputs("Does not parse", stdout);
-    } else {
-       (void) fputs("Parses OK", stdout);
-    }
-
-    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(parse_error ? 1 : 0);
-    }
-
-    /* This loop must match the one in sudo_file_lookup() */
-    printf("\nEntries for user %s:\n", user_name);
-    match = UNSPEC;
-    tq_foreach_rev(&userspecs, us) {
-       if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
-           continue;
-       tq_foreach_rev(&us->privileges, priv) {
-           putchar('\n');
-           print_privilege(priv); /* XXX */
-           putchar('\n');
-           host_match = hostlist_matches(&priv->hostlist);
-           if (host_match == ALLOW) {
-               puts("\thost  matched");
-               tq_foreach_rev(&priv->cmndlist, cs) {
-                   runas_match = runaslist_matches(&cs->runasuserlist,
-                       &cs->runasgrouplist);
-                   if (runas_match == ALLOW) {
-                       puts("\trunas matched");
-                       cmnd_match = cmnd_matches(cs->cmnd);
-                       if (cmnd_match != UNSPEC)
-                           match = cmnd_match;
-                       printf("\tcmnd  %s\n", match == ALLOW ? "allowed" :
-                           match == DENY ? "denied" : "unmatched");
-                   }
-               }
-           } else
-               puts("\thost  unmatched");
-       }
-    }
-    printf("\nCommand %s\n", match == ALLOW ? "allowed" :
-       match == DENY ? "denied" : "unmatched");
-
-    /*
-     * Exit codes:
-     * 0 - parsed OK and command matched.
-     * 1 - parse error
-     * 2 - command not matched
-     * 3 - command denied
-     */
-    if (parse_error)
-       exit(1);
-    exit(match == ALLOW ? 0 : match + 3);
-}
-
-void
-set_runaspw(user)
-    char *user;
-{
-    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);
-    }
-}
-
-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)
-           errorx(1, "unknown group: %s", group);
-    }
-}
-
-void
-sudo_setspent()
-{
-    return;
-}
-
-void
-sudo_endspent()
-{
-    return;
-}
-
-char *
-sudo_getepw(pw)
-    const struct passwd *pw;
-{
-    return pw->pw_passwd;
-}
-
-void
-set_fqdn()
-{
-    return;
-}
-
-FILE *
-open_sudoers(path, isdir, keepopen)
-    const char *path;
-    int isdir;
-    int *keepopen;
-{
-    return fopen(path, "r");
-}
-
-void
-init_envtables()
-{
-    return;
-}
-
-int
-set_perms(perm)
-    int perm;
-{
-    return 1;
-}
-
-void
-cleanup(gotsignal)
-    int gotsignal;
-{
-    if (!gotsignal) {
-       sudo_endpwent();
-       sudo_endgrent();
-    }
-}
-
-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 : "");
-    }
-}
-
-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;
-       }
-       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');
-    }
-}
-
-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 if (m->type == ALL) {
-           fputs("ALL", stdout);
-       } else {
-           fputs(m->name, stdout);
-       }
-    }
-    putchar('\n');
-    return 0;
-}
-
-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);
-           if (!tq_empty(&cs->runasuserlist) || !tq_empty(&cs->runasgrouplist)) {
-               fputs("(", stdout);
-               if (!tq_empty(&cs->runasuserlist)) {
-                   tq_foreach_fwd(&cs->runasuserlist, m) {
-                       if (m != tq_first(&cs->runasuserlist))
-                           fputs(", ", stdout);
-                       print_member(m);
-                   }  
-               } else if (tq_empty(&cs->runasgrouplist)) {
-                   fputs(def_runas_default, stdout);
-               } else {
-                   fputs(sudo_user.pw->pw_name, stdout);
-               }
-               if (!tq_empty(&cs->runasgrouplist)) {
-                   fputs(" : ", stdout);
-                   tq_foreach_fwd(&cs->runasgrouplist, m) {
-                       if (m != tq_first(&cs->runasgrouplist))
-                           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));
-       }
-    }
-}
-
-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');
-    }
-}
-
-void
-dump_sudoers()
-{
-    print_defaults();
-
-    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);
-}
diff --git a/tgetpass.c b/tgetpass.c
deleted file mode 100644 (file)
index b64bb8d..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-2005, 2007-2010
- *     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.
- */
-
-#ifdef __TANDEM
-# include <floss.h>
-#endif
-
-#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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <errno.h>
-#include <signal.h>
-#include <fcntl.h>
-
-#include "sudo.h"
-
-static volatile sig_atomic_t signo[NSIG];
-
-static RETSIGTYPE handler __P((int));
-static char *getln __P((int, char *, size_t, int));
-static char *sudo_askpass __P((const char *));
-
-/*
- * Like getpass(3) but with timeout and echo flags.
- */
-char *
-tgetpass(prompt, timeout, flags)
-    const char *prompt;
-    int timeout;
-    int flags;
-{
-    sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
-    sigaction_t savetstp, savettin, savettou, savepipe;
-    char *pass;
-    static char buf[SUDO_PASS_MAX + 1];
-    int i, input, output, save_errno, neednl = 0, need_restart;
-
-    (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:
-    for (i = 0; i < NSIG; i++)
-       signo[i] = 0;
-    pass = NULL;
-    save_errno = 0;
-    need_restart = 0;
-    /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
-    if (ISSET(flags, TGP_STDIN) ||
-       (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
-       input = STDIN_FILENO;
-       output = STDERR_FILENO;
-    }
-
-    /*
-     * If we are using a tty but are not the foreground pgrp this will
-     * generate SIGTTOU, so do it *before* installing the signal handlers.
-     */
-    if (!ISSET(flags, TGP_ECHO)) {
-       if (def_pwfeedback)
-           neednl = term_cbreak(input);
-       else
-           neednl = term_noecho(input);
-    }
-
-    /*
-     * 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;
-    (void) sigaction(SIGALRM, &sa, &savealrm);
-    (void) sigaction(SIGINT, &sa, &saveint);
-    (void) sigaction(SIGHUP, &sa, &savehup);
-    (void) sigaction(SIGQUIT, &sa, &savequit);
-    (void) sigaction(SIGTERM, &sa, &saveterm);
-    (void) sigaction(SIGTSTP, &sa, &savetstp);
-    (void) sigaction(SIGTTIN, &sa, &savettin);
-    (void) sigaction(SIGTTOU, &sa, &savettou);
-
-    /* Ignore SIGPIPE in case stdin is a pipe and TGP_STDIN is set */
-    sa.sa_handler = SIG_IGN;
-    (void) sigaction(SIGPIPE, &sa, &savepipe);
-
-    if (prompt) {
-       if (write(output, prompt, strlen(prompt)) == -1)
-           goto restore;
-    }
-
-    if (timeout > 0)
-       alarm(timeout);
-    pass = getln(input, buf, sizeof(buf), def_pwfeedback);
-    alarm(0);
-    save_errno = errno;
-
-    if (neednl || pass == NULL) {
-       if (write(output, "\n", 1) == -1)
-           goto restore;
-    }
-
-restore:
-    /* Restore old tty settings and signals. */
-    if (!ISSET(flags, TGP_ECHO))
-       term_restore(input, 1);
-    (void) sigaction(SIGALRM, &savealrm, NULL);
-    (void) sigaction(SIGINT, &saveint, NULL);
-    (void) sigaction(SIGHUP, &savehup, NULL);
-    (void) sigaction(SIGQUIT, &savequit, NULL);
-    (void) sigaction(SIGTERM, &saveterm, NULL);
-    (void) sigaction(SIGTSTP, &savetstp, NULL);
-    (void) sigaction(SIGTTIN, &savettin, NULL);
-    (void) sigaction(SIGTTOU, &savettou, NULL);
-    (void) sigaction(SIGTTOU, &savepipe, NULL);
-    if (input != STDIN_FILENO)
-       (void) close(input);
-
-    /*
-     * If we were interrupted by a signal, resend it to ourselves
-     * now that we have restored the signal handlers.
-     */
-    for (i = 0; i < NSIG; i++) {
-       if (signo[i]) {
-           kill(getpid(), i);
-           switch (i) {
-               case SIGTSTP:
-               case SIGTTIN:
-               case SIGTTOU:
-                   need_restart = 1;
-                   break;
-           }
-       }
-    }
-    if (need_restart)
-       goto restart;
-
-    if (save_errno)
-       errno = save_errno;
-    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 */
-       if (dup2(pfd[1], STDOUT_FILENO) == -1) {
-           warning("dup2");
-           _exit(255);
-       }
-       (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 = SA_INTERRUPT;
-    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), 0);
-    (void) close(pfd[0]);
-    (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
-
-    return pass;
-}
-
-extern int term_erase, term_kill;
-
-static char *
-getln(fd, buf, bufsiz, feedback)
-    int fd;
-    char *buf;
-    size_t bufsiz;
-    int feedback;
-{
-    size_t left = bufsiz;
-    ssize_t nr = -1;
-    char *cp = buf;
-    char c = '\0';
-
-    if (left == 0) {
-       errno = EINVAL;
-       return NULL;                    /* sanity */
-    }
-
-    while (--left) {
-       nr = read(fd, &c, 1);
-       if (nr != 1 || c == '\n' || c == '\r')
-           break;
-       if (feedback) {
-           if (c == term_kill) {
-               while (cp > buf) {
-                   if (write(fd, "\b \b", 3) == -1)
-                       break;
-                   --cp;
-               }
-               left = bufsiz;
-               continue;
-           } else if (c == term_erase) {
-               if (cp > buf) {
-                   if (write(fd, "\b \b", 3) == -1)
-                       break;
-                   --cp;
-                   left++;
-               }
-               continue;
-           }
-           if (write(fd, "*", 1) == -1)
-               /* shut up glibc */;
-       }
-       *cp++ = c;
-    }
-    *cp = '\0';
-    if (feedback) {
-       /* erase stars */
-       while (cp > buf) {
-           if (write(fd, "\b \b", 3) == -1)
-               break;
-           --cp;
-       }
-    }
-
-    return nr == 1 ? buf : NULL;
-}
-
-static RETSIGTYPE
-handler(s)
-    int s;
-{
-    if (s != SIGALRM)
-       signo[s] = 1;
-}
-
-int
-tty_present()
-{
-    int fd;
-
-    if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1)
-       close(fd);
-    return fd != -1;
-}
diff --git a/timestr.c b/timestr.c
deleted file mode 100644 (file)
index 9369e8c..0000000
--- a/timestr.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 1999, 2009 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 <stdio.h>
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif /* STDC_HEADERS */
-#include <time.h>
-
-#include "missing.h"
-
-char *get_timestr      __P((time_t, int));
-
-/*
- * Return an ascii string with the current date + time
- * Uses strftime() if available, else falls back to ctime().
- */
-char *
-get_timestr(tstamp, log_year)
-    time_t tstamp;
-    int log_year;
-{
-    char *s;
-#ifdef HAVE_STRFTIME
-    static char buf[128];
-    struct tm *timeptr;
-
-    timeptr = localtime(&tstamp);
-    if (log_year)
-       s = "%h %e %T %Y";
-    else
-       s = "%h %e %T";
-
-    /* strftime() does not guarantee to NUL-terminate so we must check. */
-    buf[sizeof(buf) - 1] = '\0';
-    if (strftime(buf, sizeof(buf), s, timeptr) && buf[sizeof(buf) - 1] == '\0')
-       return buf;
-
-#endif /* HAVE_STRFTIME */
-
-    s = ctime(&tstamp) + 4;            /* skip day of the week */
-    if (log_year)
-       s[20] = '\0';                   /* avoid the newline */
-    else
-       s[15] = '\0';                   /* don't care about year */
-
-    return s;
-}
diff --git a/toke.c b/toke.c
deleted file mode 100644 (file)
index 77b6ecb..0000000
--- a/toke.c
+++ /dev/null
@@ -1,3623 +0,0 @@
-#include <config.h>
-/*     $OpenBSD: flex.skl,v 1.11 2010/08/04 18:24:50 millert Exp $     */
-
-/* A lexical scanner generated by flex */
-
-/* Scanner skeleton version:
- * $Header: /home/cvs/openbsd/src/usr.bin/lex/flex.skl,v 1.11 2010/08/04 18:24:50 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 56
-#define YY_END_OF_BUFFER 57
-static yyconst short int yy_accept[599] =
-    {   0,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,   57,   44,   52,   51,   50,   43,   55,   32,
-       45,   46,   32,   47,   44,   44,   44,   44,   49,   48,
-       55,   39,   39,   39,   39,   39,   39,   39,   55,   44,
-       44,   52,   55,   39,   39,   39,   39,   39,    2,   55,
-        1,   44,   44,   17,   16,   17,   16,   16,   55,   55,
-       55,    3,    9,    8,    9,    4,    9,    5,   55,   13,
-       13,   13,   11,   12,   44,    0,   52,   50,    0,   54,
-        0,   44,   34,    0,   32,    0,   33,    0,   42,   42,
-        0,   44,   44,    0,   44,   44,   44,   44,    0,   37,
-
-       39,   39,   39,   39,   39,   39,   39,   44,   53,   44,
-       52,    0,    0,    0,    0,    0,    0,   44,   44,   44,
-       44,   44,    2,    1,    0,    1,   40,   40,    0,   44,
-       17,   17,   15,   14,   15,    0,    0,    3,    9,    0,
-        6,    7,    9,    9,   13,    0,   13,   13,    0,   10,
-        0,    0,    0,   34,   34,    0,    0,   44,   44,   44,
-       44,   44,    0,    0,   37,   37,   39,   39,   39,   39,
-       39,   39,   39,   39,   39,   44,    0,    0,    0,    0,
-        0,    0,   44,   44,   44,   44,   44,    0,   44,   10,
-        0,   44,   44,   44,   44,   44,   44,    0,   38,   38,
-
-       38,    0,    0,   37,   37,   37,   37,   37,   37,   37,
-       39,   39,   39,   39,   39,   39,   39,   39,   39,   44,
-        0,    0,    0,    0,    0,    0,   44,   44,   44,   44,
-       44,   44,   44,    0,    0,   38,   38,   38,    0,   37,
-       37,    0,   37,   37,   37,   37,   37,   37,   37,   37,
-       37,   37,   37,    0,   25,   39,   39,   39,   39,   39,
-       39,   39,   39,   44,    0,    0,    0,    0,   44,   44,
-       44,   44,   44,   44,   44,   44,    0,   38,    0,   37,
-       37,   37,    0,    0,    0,   37,   37,   37,   37,   37,
-       37,   37,   37,   37,   37,   37,   37,   37,   39,   39,
-
-       39,   39,   39,   39,   39,   39,   44,    0,    0,    0,
-       44,   44,   44,   35,   35,   35,    0,    0,   37,   37,
-       37,   37,   37,   37,   37,    0,    0,    0,    0,    0,
-       37,   37,   37,   37,   37,   37,   37,   37,   37,   37,
-       37,   37,   37,   37,   39,   39,    0,   24,   39,   39,
-       39,   39,    0,   23,    0,   26,   44,    0,    0,    0,
-       44,   44,   44,   44,   35,   35,   35,   35,    0,   37,
-        0,   37,   37,   37,   37,   37,   37,   37,   37,   37,
-       37,   37,    0,    0,    0,   37,   37,   37,   37,   37,
-       37,   37,   37,   37,   37,   37,   37,   37,   39,   39,
-
-       39,   39,   39,   39,   41,    0,    0,    0,   44,   20,
-       40,   44,   36,   36,   36,   37,    0,    0,    0,   37,
-       37,   37,   37,   37,   37,   37,   37,   37,   37,   37,
-       37,   37,    0,    0,    0,    0,    0,   37,   37,   37,
-       37,   37,   37,   37,   37,   39,   39,   39,   39,    0,
-       22,    0,   27,    0,   20,    0,    0,   44,    0,   44,
-       44,   44,   36,   36,   36,   36,   36,    0,    0,    0,
-        0,    0,   37,   37,   37,   37,   37,   37,   37,   37,
-       37,   37,   37,   37,   37,   37,   37,   37,   37,   37,
-       37,   37,    0,   30,   39,   39,   39,    0,    0,    0,
-
-       21,   20,    0,    0,    0,    0,    0,   20,    0,   44,
-       44,   44,   36,   36,    0,    0,    0,   37,   37,   37,
-       37,   37,   37,   37,   37,   37,   37,   37,   37,   37,
-       37,   37,   37,   37,   37,    0,   28,   39,   39,   21,
-        0,   18,    0,    0,   20,   44,   44,   44,   44,   44,
-        0,    0,    0,    0,    0,   37,   37,   37,   37,   37,
-       37,   37,   37,    0,   31,   39,    0,   44,   44,   44,
-       37,   37,   37,   37,   37,   37,    0,   29,    0,   44,
-       44,   44,   44,   44,   37,   37,   37,   37,   37,    0,
-       19,   35,   35,   35,   35,   35,   35,    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,   35,   36,   36,   37,   36,   38,   39,   40,
-       36,   41,   42,   43,   44,   45,   46,   47,   36,   36,
-       10,   48,   10,    1,   49,    1,   50,   51,   52,   53,
-
-       54,   55,   56,   56,   57,   56,   56,   58,   59,   60,
-       61,   56,   56,   62,   63,   64,   65,   56,   56,   56,
-       56,   56,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    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[66] =
-    {   0,
-        1,    2,    3,    4,    5,    6,    1,    7,    7,    1,
-        1,    8,    1,    9,   10,   11,   11,   11,   11,   11,
-       11,   11,   11,   12,   13,    7,    1,   11,   11,   11,
-       11,   11,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,   14,   15,   16,
-       16,   16,   16,   16,   16,   15,   15,   15,   15,   15,
-       15,   15,   15,   15,   15
-    } ;
-
-static yyconst short int yy_base[663] =
-    {   0,
-        0,   64,   65,   66,   85,  100,  147,  211,  275,  322,
-       71,  111, 2613, 2557, 2602, 3671, 2599, 3671,  368,   87,
-     3671, 3671, 2554, 3671,  113,  378,  124,  146, 2577, 3671,
-     3671,  433, 2553,  483, 2560, 2551, 2555, 2550,  537,  154,
-       21,  150,  561, 2522, 2526, 2482, 2477, 2478,   80,  203,
-     2529,  288,   31,    0, 3671, 2516, 3671,    0,  305,  616,
-       81,    0, 2469, 3671,   75, 3671,   82, 3671,  124, 2468,
-       83,   86, 3671,  152, 2467,  638, 2512, 2509, 2509, 3671,
-      211,  219,  289,  230,  130,  336, 2447,  663,  294, 2437,
-      688,  356,  699, 2458, 2467,  395,  500,  169, 2456,  145,
-
-      739,    0, 2439, 2428,  314, 2408, 2396,  135, 3671,  236,
-      524, 2379, 2383, 2375, 2370, 2352,   96,   72,  230,  242,
-      197,  256,  180, 2409,  569, 2408,  567, 2356,  793,  253,
-        0, 2399,  252, 3671, 3671,  578,  280,    0, 2354,  433,
-     3671, 3671, 2353,  316, 2352, 2394,  310,  312,  319, 2393,
-     2388, 2377,  586,  604,  357,  699,  545,  806,  841,  876,
-      911, 2339, 2328,  951,  328,  992, 1032, 2317, 2291, 2292,
-     2299, 2294, 2289, 2275, 2268,  307, 2239, 2243, 2225, 2217,
-     2220,  328,  371, 2220,  301,  208,  131,  649,  321, 2240,
-     2222,  661,  318, 1074, 1109,  511,  335, 2183, 2158,  716,
-
-      404, 2148, 2145,  412,  725, 1144,  756,  764, 1185,  790,
-     2138,  401,  402, 2118, 2116, 2106, 2103, 2069, 2075,  496,
-     2008, 2004, 1989, 2002, 1974,  553,  460,  593,  504,  512,
-     1227, 1262, 1297, 2011, 1990,  814, 1990, 1967, 1964, 1963,
-      630,  823,  642,  849,  671, 1332,    0,  859, 1343,  884,
-      831, 1384,  894,  628, 3671, 1948, 1941, 1924, 1900, 1871,
-     1859, 1843, 1823,  500, 1803, 1786, 1757,  611,  600,  309,
-      657,  928,  752, 1426, 1461,  938, 1795, 1794, 1793, 1791,
-     1494,  772,  971, 1011, 1051,  867, 1042, 1065, 1082, 1092,
-     1536,    0, 1094, 1547, 1117,  902, 1588, 1127, 1759, 1755,
-
-      629,  577, 1751, 1738,  762,  885,  878, 1719, 1686,  607,
-      601,  889,  969, 1629, 1663, 1697, 1719, 1718, 1717, 1161,
-     1732, 1169,  979, 1772, 1204, 1235, 1725, 1245, 1272, 1282,
-     1127, 1195, 1218, 1307, 1307, 1318, 1814,    0, 1320, 1825,
-     1360, 1019, 1866, 1403, 1666, 1669,  936, 3671, 1670, 1662,
-     1643, 1627, 1017, 3671, 1057, 3671, 1105, 1613, 1606,  456,
-     1212,  643, 1106, 1437,  773, 1907, 1941, 1370, 1645, 1630,
-     1445, 1263, 1470, 1283, 1976,    0,  676, 1987, 1478, 1411,
-     2027, 1513, 1566, 1607, 1639, 1426, 1504, 1649, 1651, 1671,
-     1681, 2069,    0, 1683, 2080, 1705, 1486, 1715, 1594, 1589,
-
-     1591, 1547, 1169, 1210, 1525, 1463, 1445,  883,  715, 1866,
-     1424, 2122, 2157, 2192, 2227, 1446, 1751, 1791, 1844, 1445,
-     1567, 1608, 1883, 1716, 2262,    0,  792, 2273, 1915, 1521,
-     2313, 1925, 1949, 1438, 1959, 2006, 2046, 1652, 1742, 2090,
-      963, 1061, 2355,    0, 1055, 1368, 1325, 1299, 1272, 1409,
-     3671, 1449, 3671, 1256, 1568, 2104,  336, 1321, 1773, 1867,
-     2104,  970, 2365, 2400, 2435, 2470, 1256, 2052, 1197, 2137,
-     2167, 2147, 1128, 1100, 1792, 1926, 2175, 1960, 2505,    0,
-     1097, 2516, 2200, 1891, 2556, 2210, 2236, 2245, 2291, 1835,
-     1106, 1141, 1519, 3671, 1572, 1074, 1014,  825,  881,  288,
-
-      833, 2028, 2267, 2314, 2344, 2338, 2381, 2392, 2400, 2598,
-     2633, 2668, 2411, 1935, 2446, 2456, 2480,  832,  829, 1988,
-     2007, 2488, 2104, 2703,    0, 1206, 2714, 2533, 2183, 2575,
-      801, 2542, 2607, 2426,  788, 1591, 3671, 1611,  683, 3671,
-      699, 3671, 1228, 2615, 2641, 2649, 1257, 2756, 2791, 2659,
-     2682,  656, 2692, 2733, 2766,  589,  549, 2123,  510,  428,
-     2774,    0, 1286, 1612, 3671, 1756, 2114, 2826, 2861, 2896,
-     2799, 2807, 2815,  399,    0,  280, 1757, 3671,  215, 2837,
-     1620, 2931, 2966, 2847, 3671, 2870, 2880, 2218, 3671,  155,
-     3671, 2907, 2915, 2948,   53, 2981, 2741, 3671, 3029, 3045,
-
-     3061, 3077, 3093, 3109, 3125, 3141, 3157, 3163, 3179, 3195,
-     1394, 3211, 3227, 3243, 3259, 3275, 3291, 3307, 3313, 3320,
-     3336, 3352, 3358, 3365, 3371, 3377, 3383, 3390, 3396, 3402,
-     3408, 3415, 3423, 3429, 3435, 3441, 3448, 3456, 3462, 3468,
-     3475, 3483, 3489, 3497, 3504, 3512, 3518, 3526, 3533, 3541,
-     3557, 3573, 3579, 3587, 3594, 3610, 3616, 3624, 3630, 3638,
-     1460, 3654
-    } ;
-
-static yyconst short int yy_def[663] =
-    {   0,
-      598,    1,    1,    1,  599,  599,  600,  600,  601,  601,
-      602,  602,  598,  603,  598,  598,  598,  598,  604,  605,
-      598,  598,  606,  598,  607,  603,   26,   26,  608,  598,
-      598,  598,   32,   32,   34,   34,   34,   34,  603,   26,
-      603,  598,  604,   32,   32,   34,   34,   34,  598,  598,
-      598,  609,  603,  610,  598,  610,  598,  610,  598,  604,
-      598,  611,  612,  598,  612,  598,  612,  598,  613,  614,
-      614,  614,  598,  598,  603,  603,  598,  598,  615,  598,
-      616,  598,  605,  598,  617,  605,  606,  606,  607,  618,
-      603,  603,   26,  608,   93,   93,   93,   93,  619,  620,
-
-       32,   34,   34,   34,   34,   34,   34,  603,  598,  603,
-      598,  598,  598,  598,  598,  598,  615,  603,   93,  603,
-      603,  603,  598,  598,  598,  598,  609,  621,  603,  603,
-      610,  610,  598,  598,  598,  616,  598,  611,  612,  612,
-      598,  598,  612,  612,  614,  598,  614,  614,  598,  598,
-      615,  622,  598,  598,  617,  617,  598,  603,  603,  603,
-       93,  161,  623,  598,  624,  598,   32,   34,   34,   34,
-       34,   34,   34,   34,   34,  603,  598,  598,  598,  598,
-      598,  615,  603,  161,  603,  603,  603,  598,  603,  598,
-      622,  603,  603,  603,  603,  603,  603,  625,  626,  626,
-
-      200,  627,  626,  628,  166,  598,  206,  206,  598,  206,
-       34,   34,   34,   34,   34,   34,   34,   34,   34,  603,
-      598,  598,  598,  598,  598,  615,  603,  603,  603,  603,
-      603,  603,  603,  598,  629,  629,  236,  629,  630,  631,
-      632,  598,  633,  209,  633,  633,  246,  633,  598,  249,
-      249,  598,  249,  598,  598,   34,   34,   34,   34,   34,
-       34,   34,   34,  603,  598,  598,  598,  615,  603,  603,
-      603,  603,  603,  603,  603,  603,  634,  634,  635,  636,
-      598,  598,  598,  598,  598,  637,  637,  638,  252,  638,
-      638,  291,  638,  598,  294,  294,  598,  294,   34,   34,
-
-       34,   34,   34,   34,   34,   34,  603,  598,  598,  615,
-      603,  603,  603,  603,  603,  603,  598,  639,  640,  281,
-      598,  321,  321,  598,  321,  598,  598,  598,  598,  598,
-      598,  641,  641,  642,  297,  642,  642,  337,  642,  598,
-      340,  340,  598,  340,   34,   34,  598,  598,   34,   34,
-       34,   34,  598,  598,  598,  598,  603,  598,  598,  615,
-      603,  603,  603,  603,  603,  603,  603,  603,  598,  643,
-      598,  644,  324,  644,  644,  375,  375,  598,  378,  378,
-      598,  378,  598,  598,  598,  598,  645,  645,  646,  343,
-      646,  646,  392,  646,  598,  395,  395,  395,   34,   34,
-
-       34,   34,   34,   34,  603,  598,  598,  615,  603,  603,
-      603,  603,  603,  603,  603,  598,  598,  598,  598,  647,
-      647,  648,  381,  648,  648,  425,  425,  598,  428,  428,
-      598,  428,  598,  598,  598,  598,  598,  598,  649,  649,
-      650,  650,  650,  443,  443,   34,   34,   34,   34,  598,
-      598,  598,  598,  598,  598,  615,  615,  603,  651,  652,
-      603,  603,  603,  603,  603,  603,  603,  598,  598,  598,
-      598,  598,  598,  653,  653,  654,  431,  654,  654,  479,
-      479,  598,  482,  482,  598,  482,  598,  598,  598,  598,
-      655,  655,  598,  598,   34,   34,   34,  598,  656,  615,
-
-      603,  651,  651,  651,  651,  598,  651,  652,  652,  603,
-      603,  603,  603,  603,  598,  598,  598,  598,  657,  657,
-      658,  485,  658,  658,  524,  524,  598,  527,  527,  527,
-      598,  598,  598,  598,  598,  598,  598,   34,   34,  598,
-      656,  598,  615,  598,  598,  603,  603,  603,  603,  603,
-      598,  598,  598,  598,  598,  598,  659,  659,  660,  660,
-      660,  561,  561,  598,  598,   34,  615,  603,  603,  603,
-      598,  598,  598,  598,  661,  661,  598,  598,  662,  603,
-      603,  603,  603,  603,  598,  598,  598,  598,  598,  662,
-      598,  603,  603,  603,  603,  603,  603,    0,  598,  598,
-
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598
-    } ;
-
-static yyconst short int yy_nxt[3737] =
-    {   0,
-       14,   15,   16,   17,   18,   19,   20,   21,   22,   14,
-       23,   24,   14,   14,   25,   26,   27,   28,   26,   26,
-       26,   26,   26,   29,   30,   31,   14,   32,   32,   32,
-       32,   33,   34,   34,   34,   34,   35,   36,   34,   37,
-       34,   38,   34,   34,   34,   34,   34,   39,   14,   40,
-       40,   40,   40,   40,   40,   14,   14,   14,   14,   14,
-       14,   14,   41,   14,   14,   42,   49,   49,   76,   43,
-       50,   50,   71,   16,   72,   73,   51,   51,   76,   52,
-       52,  123,  137,  109,  147,  110,   15,   55,   56,  148,
-       57,  124,   84,   44,   45,  130,   57,   46,   80,  141,
-
-       76,   15,   55,   56,   47,   57,  142,   48,   57,   58,
-       85,   57,   71,   16,   72,   73,   90,   90,   74,   76,
-       90,   90,  140,   57,   58,  144,  109,   53,   53,  140,
-      146,  183,   59,  146,   86,   84,  137,  109,   90,   96,
-       96,   96,   96,   96,   96,   96,   96,   59,   15,   16,
-       17,  111,   60,  149,  150,  182,  145,  591,   74,  164,
-       91,   97,   97,   97,   97,   97,   98,   75,  166,   95,
-       95,   95,   95,   95,   95,   95,   95,  156,   76,  112,
-      113,  123,   76,  114,  162,  162,  162,  162,  162,  162,
-      115,  124,  227,  116,   61,   62,   62,   62,   62,   62,
-
-       62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
-       62,   62,   15,   16,   17,  125,   60,  591,   82,   82,
-       82,   82,   82,   82,   82,   82,   82,   82,   82,   82,
-       82,   82,   82,   82,   82,   82,   82,   82,   82,   82,
-       82,   82,  153,   75,   76,  154,  154,  154,  154,  154,
-      154,  154,  154,  137,  109,   76,  186,  229,   61,   62,
-       62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
-       62,   62,   62,   62,   62,   62,   15,   16,   17,   64,
-       60,  137,  109,   76,  184,   65,   66,   67,  176,   76,
-       80,  128,  128,  371,  598,  128,  128,   90,   90,   68,
-
-       76,   90,   90,   76,  185,  189,  133,  109,  134,  187,
-      135,  147,  598,  128,  134,  148,  135,  137,  109,   90,
-      149,  150,   69,   15,   16,   17,   64,   60,  135,  135,
-       80,  192,   65,   66,   67,  129,   86,   83,   80,   83,
-       83,   91,  164,   83,   83,  170,   68,   83,   76,  543,
-      171,  205,  135,  172,   76,  173,   76,  146,   94,  146,
-       83,   83,  598,  140,  227,   76,  312,  220,   76,   69,
-       80,  158,  159,  160,  158,  158,  158,  158,  158,  226,
-       81,  230,   76,   82,   82,   82,   82,   82,   82,   82,
-       82,   92,  500,   93,   93,   93,   93,   93,   93,   93,
-
-       93,   94,  254,   76,  156,   95,   95,   95,   95,   95,
-      162,  162,  162,  162,  162,  162,  162,  162,   76,  238,
-      238,  238,  522,  227,  255,   76,  164,   95,   95,   95,
-       95,   95,   95,   75,  139,  205,  256,  139,  139,   75,
-      257,  598,   75,   75,  139,   75,   75,   75,  101,  101,
-      101,  101,  101,  101,  101,  101,   94,  139,   80,   75,
-      101,  101,  101,  101,  101,  102,  102,  102,  102,  102,
-      102,  102,  102,  102,  102,  102,  102,  102,  102,  102,
-       76,  102,   95,   95,   95,   95,   95,   95,   75,   75,
-       75,   75,   75,   75,   75,   75,   75,   75,  102,  102,
-
-      102,  102,  102,  102,  102,  102,  598,   76,  269,  408,
-      102,  102,  102,  102,  102,  162,  162,  162,  162,  162,
-      162,  162,  162,  371,  192,  111,  193,  193,  193,  193,
-      193,  193,   75,   75,   75,   75,   75,   75,  108,  109,
-       75,   75,   75,   76,   75,   75,   90,   76,   75,  264,
-       90,   76,  307,  112,  113,   80,   90,  114,   76,   76,
-       75,   75,   75,   80,  115,  271,  227,  116,   90,   90,
-      128,  128,  522,   81,  128,  128,   82,   82,   82,   82,
-       82,   82,   82,   82,   82,   82,   82,   82,   82,   82,
-       82,   82,  128,  598,  598,  598,  598,  598,  598,  598,
-
-      598,  154,  154,  154,  154,  154,  154,  154,  154,   80,
-      268,  349,  477,   80,  129,  350,   94,  117,   80,  154,
-      154,  154,  154,  154,  154,  154,  154,  311,  136,  254,
-      347,  598,  598,  598,  598,  598,  598,  598,  598,   75,
-       76,   75,   75,   75,  164,   75,   75,   76,   76,   75,
-      128,  255,  348,  205,  128,  242,  164,  270,  361,  360,
-      128,   75,   75,   75,   87,  244,   87,   87,   87,  551,
-       87,   87,  128,  128,   87,  310,  231,  232,  233,  231,
-      231,  231,  231,  231,  598,  164,   87,   87,   87,   89,
-       76,   75,   75,   89,  244,   75,   75,  420,  420,   89,
-
-      155,  542,  155,  155,   76,  410,  155,  155,   76,  313,
-      155,   89,   89,   75,  161,  161,  161,  161,  161,  161,
-      161,  161,  155,  155,  155,  566,  161,  161,  161,  161,
-      161,  236,  236,  237,  238,  238,  238,  238,  238,  202,
-      210,  210,  210,  210,  210,  210,  210,  210,  161,  161,
-      161,  161,  161,  161,  167,  167,  167,  167,  167,  167,
-      167,  167,   76,  353,  458,  272,  167,  167,  167,  167,
-      167,  246,  246,  246,  246,  246,  246,  246,  246,  247,
-      247,  247,  247,  247,  248,  354,  164,  364,  161,  161,
-      161,  161,  161,  161,  127,  205,   75,   75,  127,   76,
-
-       75,   75,  164,  598,  127,  245,  245,  245,  245,  245,
-      245,  245,  245,  474,  474,  164,  127,  127,   75,  192,
-       76,  193,  193,  193,  193,  193,  193,  193,  193,  278,
-      278,  278,  278,  278,  278,  278,  278,  202,  283,  284,
-      285,  283,  283,  283,  283,  283,  292,  292,  292,  292,
-      292,  293,  477,   76,  192,  423,  194,  194,  194,  194,
-      194,  194,  194,  194,  253,  253,  253,  253,  253,  253,
-      253,  253,  242,  164,  287,  287,  287,  287,  287,  287,
-       76,  164,  244,  542,  456,   80,  355,  540,   76,  192,
-      244,  195,  195,  195,  195,  195,  196,  193,  193,  291,
-
-      291,  291,  291,  291,  291,  291,  291,  598,  356,  290,
-      290,  290,  290,  290,  290,  290,  290,  338,  338,  338,
-      338,  338,  339,   76,   75,   76,  197,  197,  197,  197,
-      197,  197,  197,  197,  357,  457,   76,  347,  197,  197,
-      197,  197,  197,  314,  315,  316,  314,  314,  314,  314,
-      314,  272,  362,  273,  273,  273,  273,  273,  273,  348,
-      197,  197,  197,  197,  197,  197,  199,  200,  201,  201,
-      201,  201,  201,  201,  202,   76,  242,  164,  203,  203,
-      203,  203,  203,  461,  326,   76,  327,  327,  327,  327,
-      327,  327,  327,  327,  376,  376,  376,  376,  376,  377,
-
-      203,  203,  203,  203,  203,  203,  164,  206,  207,  208,
-      206,  206,  206,  206,  206,  209,   76,   76,  353,  210,
-      210,  210,  210,  210,  326,  363,  328,  328,  328,  328,
-      328,  328,  328,  328,  393,  393,  393,  393,  393,  394,
-      354,  210,  210,  210,  210,  210,  210,  211,  211,  211,
-      211,  211,  211,  211,  211,  242,  164,  539,  355,  211,
-      211,  211,  211,  211,  326,  244,  329,  329,  329,  329,
-      329,  330,  327,  327,  598,  164,  491,  491,  242,  164,
-      356,  197,  197,  197,  197,  197,  197,  192,  289,  193,
-      193,  193,  193,  193,  193,  193,  193,  298,  298,  298,
-
-      298,  298,  298,  298,  298,  598,  164,  242,  164,  333,
-      333,  333,  333,  333,  333,  289,  538,  289,  519,  519,
-      164,   76,  192,  423,  193,  193,  193,  193,  193,  193,
-      193,  193,  337,  337,  337,  337,  337,  337,  337,  337,
-      598,  164,  336,  336,  336,  336,  336,  336,  336,  336,
-      244,  373,   76,   76,  242,  164,   76,  242,  164,  243,
-      243,  243,  243,  243,  243,  243,  243,  244,  405,  411,
-      450,  245,  245,  245,  245,  245,  325,  325,  325,  325,
-      325,  325,  325,  325,  375,  375,  375,  375,  375,  375,
-      375,  375,  451,  245,  245,  245,  245,  245,  245,  164,
-
-      249,  250,  251,  249,  249,  249,  249,  249,  252,  164,
-      468,  452,  253,  253,  253,  253,  253,  598,  289,  374,
-      374,  374,  374,  374,  374,  374,  374,  557,  557,  567,
-       80,  242,  164,  453,  253,  253,  253,  253,  253,  253,
-      272,  289,  273,  273,  273,  273,  273,  273,  273,  273,
-      383,  384,  385,  383,  383,  383,  383,  383,  326,   76,
-      327,  327,  327,  327,  327,  327,  327,  327,  409,  461,
-      546,  514,  514,  514,   76,  272,  371,  274,  274,  274,
-      274,  274,  274,  274,  274,  326,  373,  327,  327,  327,
-      327,  327,  327,  327,  327,  326,  598,  327,  327,  327,
-
-      327,  327,  327,   76,   76,  498,  373,  575,  575,   76,
-      272,  497,  275,  275,  275,  275,  275,  276,  273,  273,
-      242,  164,  344,  344,  344,  344,  344,  344,  344,  344,
-      335,  598,  164,  242,  164,  388,  388,  388,  388,  388,
-      388,  335,  496,  335,   76,  242,  164,  287,  287,  287,
-      287,  287,  287,  287,  287,  244,  242,  164,  288,  288,
-      288,  288,  288,  288,  288,  288,  289,  495,   76,  493,
-      290,  290,  290,  290,  290,  392,  392,  392,  392,  392,
-      392,  392,  392,  501,  364,  365,  365,  365,  365,  365,
-      365,  494,  290,  290,  290,  290,  290,  290,  164,  294,
-
-      295,  296,  294,  294,  294,  294,  294,  297,  138,  138,
-      450,  298,  298,  298,  298,  298,  598,   76,  391,  391,
-      391,  391,  391,  391,  391,  391,  426,  426,  426,  426,
-      426,  427,  451,  298,  298,  298,  298,  298,  298,  272,
-      164,  273,  273,  273,  273,  273,  273,  273,  273,  289,
-      452,  433,  412,  413,  414,  415,  412,  412,  412,  412,
-      417,  418,  419,  417,  417,  417,  417,  417,  373,  320,
-      589,   76,  453,   76,  272,  589,  273,  273,  273,  273,
-      273,  273,  273,  273,   76,  382,  382,  382,  382,  382,
-      382,  382,  382,  425,  425,  425,  425,  425,  425,  425,
-
-      425,  444,  444,  444,  444,  444,  445,  455,   76,  321,
-      322,  323,  321,  321,  321,  321,  321,  324,  164,  454,
-      493,  325,  325,  325,  325,  325,  598,  335,  424,  424,
-      424,  424,  424,  424,  424,  424,  480,  480,  480,  480,
-      480,  481,  494,  325,  325,  325,  325,  325,  325,  242,
-      164,  333,  333,  333,  333,  333,  333,  333,  333,  289,
-      242,  164,  334,  334,  334,  334,  334,  334,  334,  334,
-      335,  459,   76,  536,  336,  336,  336,  336,  336,  433,
-      371,  434,  434,  434,  434,  434,  434,  434,  434,  449,
-      373,  459,  536,  459,  459,  537,  336,  336,  336,  336,
-
-      336,  336,  164,  340,  341,  342,  340,  340,  340,  340,
-      340,  343,  564,  564,  537,  344,  344,  344,  344,  344,
-      433,  371,  435,  435,  435,  435,  435,  435,  435,  435,
-      448,  423,  447,  580,  565,  565,  446,  344,  344,  344,
-      344,  344,  344,  364,  365,  365,  365,  365,  365,  365,
-      365,  365,  433,  320,  436,  436,  436,  436,  436,  437,
-      434,  434,  242,  164,  242,  164,  164,   76,  240,  407,
-      406,  404,  335,  403,  390,  335,   76,  364,  366,  366,
-      366,  366,  366,  366,  366,  366,  398,  398,  398,  398,
-      398,  398,  398,  398,  598,  164,  242,  164,  440,  440,
-
-      440,  440,  440,  440,  390,  402,  390,  401,  400,  399,
-       76,  364,  367,  367,  367,  367,  367,  368,  365,  365,
-      443,  443,  443,  443,  443,  443,  443,  443,  598,  598,
-      442,  442,  442,  442,  442,  442,  442,  442,  326,  423,
-      320,  240,  202,  359,   76,  371,  358,  372,  372,  372,
-      372,  372,  372,  372,  372,  373,  164,  577,  577,  374,
-      374,  374,  374,  374,  468,  390,  469,  469,  469,  469,
-      469,  469,  469,  469,  503,  352,  504,  505,  506,  578,
-      578,  374,  374,  374,  374,  374,  374,  378,  379,  380,
-      378,  378,  378,  378,  378,  381,  351,  346,  345,  382,
-
-      382,  382,  382,  382,  468,  371,  470,  470,  470,  470,
-      470,  470,  470,  470,  320,  423,  240,  202,  202,  265,
-      507,  382,  382,  382,  382,  382,  382,  242,  164,  388,
-      388,  388,  388,  388,  388,  388,  388,  335,  242,  164,
-      389,  389,  389,  389,  389,  389,  389,  389,  390,  164,
-      309,  308,  391,  391,  391,  391,  391,  468,  390,  471,
-      471,  471,  471,  471,  472,  469,  469,  306,  503,  459,
-      504,  505,  506,  305,  391,  391,  391,  391,  391,  391,
-      164,  395,  396,  397,  395,  395,  395,  395,  395,  459,
-      304,  459,  460,  398,  398,  398,  398,  398,  432,  432,
-
-      432,  432,  432,  432,  432,  432,  525,  525,  525,  525,
-      525,  526,  303,   76,  509,  398,  398,  398,  398,  398,
-      398,  364,  365,  365,  365,  365,  365,  365,  365,  365,
-      479,  479,  479,  479,  479,  479,  479,  479,  598,  371,
-      478,  478,  478,  478,  478,  478,  478,  478,  302,  477,
-      514,  514,  514,  301,   76,  364,  365,  365,  365,  365,
-      365,  365,  365,  365,  487,  488,  489,  487,  487,  487,
-      487,  487,  433,  598,  434,  434,  434,  434,  434,  434,
-      434,  434,   76,  477,  300,  299,  281,  240,   76,  371,
-      202,  421,  421,  421,  421,  421,  421,  421,  421,  373,
-
-      371,  371,  422,  422,  422,  422,  422,  422,  422,  422,
-      423,  477,  277,  202,  424,  424,  424,  424,  424,  433,
-      371,  434,  434,  434,  434,  434,  434,  434,  434,  598,
-      522,  598,  598,  598,  100,  265,  424,  424,  424,  424,
-      424,  424,  428,  429,  430,  428,  428,  428,  428,  428,
-      431,  267,  265,  266,  432,  432,  432,  432,  432,  433,
-      265,  434,  434,  434,  434,  434,  434,  515,  516,  517,
-      515,  515,  515,  515,  515,  507,  432,  432,  432,  432,
-      432,  432,  242,  164,  440,  440,  440,  440,  440,  440,
-      440,  440,  390,  242,  164,  441,  441,  441,  441,  441,
-
-      441,  441,  441,  242,  164,  456,   80,  442,  442,  442,
-      442,  442,  263,  390,  262,  567,   80,  598,  499,  510,
-      511,  512,  510,  510,  510,  510,  510,  522,  579,  442,
-      442,  442,  442,  442,  442,  461,  371,  462,  462,  462,
-      462,  462,  462,  462,  462,  261,  522,  260,  259,  258,
-      468,   76,  469,  469,  469,  469,  469,  469,  469,  469,
-      468,   94,  469,  469,  469,  469,  469,  469,  202,   76,
-      461,  240,  463,  463,  463,  463,  463,  463,  463,  463,
-      468,  202,  469,  469,  469,  469,  469,  469,  469,  469,
-      486,  486,  486,  486,  486,  486,  486,  486,  562,  562,
-
-      562,  562,  562,  563,   76,  461,  100,  464,  464,  464,
-      464,  464,  465,  466,  466,  524,  524,  524,  524,  524,
-      524,  524,  524,  598,   80,  523,  523,  523,  523,  523,
-      523,  523,  523,  585,  585,  585,  585,  585,  585,   76,
-      461,  190,  467,  467,  467,  462,  462,  462,  462,  462,
-      164,  531,  531,  531,  531,  531,  531,  531,  531,  164,
-      532,  532,  532,  532,  532,  532,  532,  532,  503,  228,
-      504,  505,  506,  225,   76,  371,  224,  475,  475,  475,
-      475,  475,  475,  475,  475,  423,  371,  223,  476,  476,
-      476,  476,  476,  476,  476,  476,  477,  222,  221,  219,
-
-      478,  478,  478,  478,  478,  164,  533,  533,  533,  533,
-      533,  534,  531,  531,  507,  598,  218,  504,  505,  506,
-      217,  216,  478,  478,  478,  478,  478,  478,  482,  483,
-      484,  482,  482,  482,  482,  482,  485,  215,  214,  213,
-      486,  486,  486,  486,  486,  598,  212,  598,  598,  506,
-      544,  100,   92,  545,  545,  545,  545,  545,  545,  545,
-      545,  507,  486,  486,  486,  486,  486,  486,  242,  164,
-      492,  492,  492,  492,  492,  492,  492,  492,  461,   80,
-      466,  466,  466,  466,  466,  466,  466,  466,  502,  502,
-       80,  507,  502,  598,  190,  598,  598,  598,  145,  146,
-
-      140,  140,  132,  188,  502,  502,  502,  508,  508,  126,
-      126,  508,   76,  461,  181,  466,  466,  466,  466,  466,
-      466,  466,  466,  508,  508,  508,  513,  513,  513,  513,
-      513,  513,  513,  513,  180,  179,  178,  177,  175,  509,
-      164,  531,  531,  531,  531,  531,  531,   76,  461,  174,
-      466,  466,  466,  466,  466,  466,  513,  513,   76,  551,
-      169,  552,  552,  552,  552,  552,  552,  552,  552,  551,
-      168,  553,  553,  553,  553,  553,  553,  553,  553,  100,
-       75,  100,   76,  461,  157,  513,  513,  513,  513,  513,
-      513,  513,  513,  551,   88,  554,  554,  554,  554,  554,
-
-      555,  552,  552,  530,  530,  530,  530,  530,  530,  530,
-      530,   80,   78,   77,   76,  146,  140,   76,  371,  132,
-      520,  520,  520,  520,  520,  520,  520,  520,  477,  371,
-      126,  521,  521,  521,  521,  521,  521,  521,  521,  522,
-      122,  121,  120,  523,  523,  523,  523,  523,  561,  561,
-      561,  561,  561,  561,  561,  561,  164,  531,  531,  531,
-      531,  531,  531,  531,  531,  523,  523,  523,  523,  523,
-      523,  527,  528,  529,  527,  527,  527,  527,  527,  119,
-      118,  107,  106,  530,  530,  530,  530,  530,  598,  105,
-      560,  560,  560,  560,  560,  560,  560,  560,  104,  103,
-
-      100,   88,   78,   77,   76,  530,  530,  530,  530,  530,
-      530,  546,  598,  547,  547,  547,  547,  547,  547,  547,
-      547,  164,  531,  531,  531,  531,  531,  531,  531,  531,
-      545,  545,  545,  545,  545,  545,  545,  545,  598,  598,
-      598,  598,  598,  598,  598,   76,  546,  598,  548,  548,
-      548,  548,  548,  548,  548,  548,  545,  545,  545,  545,
-      545,  545,  545,  545,  568,  569,  570,  568,  568,  568,
-      568,  568,  546,  598,  547,  547,  547,  547,  547,  547,
-       76,  546,  598,  549,  549,  549,  549,  549,  550,  547,
-      547,  598,  598,  598,  598,  598,   76,  571,  572,  573,
-
-      571,  571,  571,  571,  571,  551,   76,  552,  552,  552,
-      552,  552,  552,  552,  552,   76,  371,  598,  558,  558,
-      558,  558,  558,  558,  558,  558,  522,  371,  598,  559,
-      559,  559,  559,  559,  559,  559,  559,  598,  598,  598,
-      598,  560,  560,  560,  560,  560,  551,  598,  552,  552,
-      552,  552,  552,  552,  552,  552,  595,  595,  595,  595,
-      595,  595,  598,  560,  560,  560,  560,  560,  560,  546,
-      598,  547,  547,  547,  547,  547,  547,  547,  547,  551,
-      598,  552,  552,  552,  552,  552,  552,  371,   76,  576,
-      576,  576,  576,  576,  576,  576,  576,  598,  598,  598,
-
-      598,  598,  598,   76,  546,  598,  547,  547,  547,  547,
-      547,  547,  547,  547,  585,  585,  585,  585,  585,  585,
-      585,  585,  586,  586,  586,  586,  586,  586,  586,  586,
-      587,  587,  587,  587,  587,  588,  585,  585,   76,  580,
-      598,  581,  581,  581,  581,  581,  581,  581,  581,  598,
-      598,  598,  592,  593,  594,  592,  592,  592,  592,  592,
-      580,  598,  581,  581,  581,  581,  581,  581,  598,  598,
-      598,  598,  598,   76,  580,  598,  582,  582,  582,  582,
-      582,  582,  582,  582,   76,  585,  585,  585,  585,  585,
-      585,  585,  585,  598,   76,  585,  585,  585,  585,  585,
-
-      585,  585,  585,  598,  598,  598,  598,  598,   76,  580,
-      598,  583,  583,  583,  583,  583,  584,  581,  581,  598,
-      598,  598,  595,  595,  595,  595,  595,  595,  595,  595,
-      592,  592,  592,  592,  592,  592,  592,  592,  598,  598,
-      598,  598,  598,   76,  580,  598,  581,  581,  581,  581,
-      581,  581,  581,  581,   76,  598,  598,  598,  598,  598,
-      598,  598,   76,  596,  596,  596,  596,  596,  597,  595,
-      595,  598,  598,  598,  598,  598,  598,  598,   76,  580,
-      598,  581,  581,  581,  581,  581,  581,  581,  581,  598,
-      598,  598,  598,  598,  598,   76,  595,  595,  595,  595,
-
-      595,  595,  595,  595,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,   76,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,   76,   54,
-       54,   54,   54,   54,   54,   54,   54,   54,   54,   54,
-       54,   54,   54,   54,   54,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
-       31,   63,   63,   63,   63,   63,   63,   63,   63,   63,
-       63,   63,   63,   63,   63,   63,   63,   70,   70,   70,
-       70,   70,   70,   70,   70,   70,   70,   70,   70,   70,
-       70,   70,   70,   75,  598,  598,  598,  598,  598,  598,
-
-      598,   75,   75,   75,  598,  598,   75,   75,   75,   79,
-       79,   79,   79,   79,   79,   79,   79,   79,   79,   79,
-       79,   79,   79,   79,   79,   83,  598,  598,  598,  598,
-       83,  598,  598,   83,   83,   83,   83,  598,   83,   83,
-       83,   87,  598,  598,  598,  598,  598,  598,  598,   87,
-       87,   87,  598,  598,   87,   87,   87,   89,  598,  598,
-       89,   89,  598,   89,  598,   89,   89,   89,  598,  598,
-       89,   89,   89,   99,   99,  598,  598,  598,   99,  127,
-      598,  598,  127,  127,  598,  127,  598,  127,  127,  127,
-      598,  598,  127,  127,  127,  131,  598,  598,  131,  131,
-
-      598,  131,  598,  131,  131,  131,  598,  131,  598,  131,
-      131,  139,  598,  598,  139,  598,  598,  139,  598,  139,
-      139,  139,  139,  598,  139,  139,  139,  143,  143,  143,
-      143,  143,  143,  143,  143,  143,  143,  143,  143,  143,
-      143,  143,  143,  145,  145,  598,  145,  598,  145,  145,
-      145,  145,  145,  145,  145,  145,  145,  145,  145,  151,
-      151,  151,  151,  151,  151,  151,  151,  151,  151,  151,
-      151,  151,  151,  151,  151,  152,  152,  598,  152,  152,
-      152,  152,  152,  152,  152,  152,  152,  152,  152,  152,
-      152,  155,  598,  598,  598,  598,  155,  598,  598,  155,
-
-      155,  155,  598,  598,  155,  155,  155,   90,  598,  598,
-       90,   90,  598,   90,  598,   90,   90,   90,  598,  598,
-       90,   90,   90,  163,  163,  598,  598,  598,  163,  165,
-      165,  165,  598,  598,  598,  165,  128,  598,  598,  128,
-      128,  598,  128,  598,  128,  128,  128,  598,  598,  128,
-      128,  128,  191,  191,  191,  191,  191,  191,  191,  191,
-      191,  191,  191,  191,  191,  191,  191,  191,  198,  198,
-      598,  598,  598,  198,  204,  204,  204,  598,  598,  598,
-      204,  234,  234,  598,  598,  598,  234,  235,  235,  598,
-      598,  598,  235,  239,  239,  598,  598,  598,  239,  241,
-
-      241,  241,  598,  598,  598,  241,  277,  277,  598,  598,
-      598,  277,  279,  279,  598,  598,  598,  279,  280,  280,
-      598,  598,  598,  280,  282,  282,  282,  598,  598,  598,
-      282,  286,  286,  286,  286,  598,  598,  598,  286,  317,
-      317,  598,  598,  598,  317,  318,  318,  598,  598,  598,
-      318,  319,  319,  598,  598,  598,  319,  331,  331,  331,
-      598,  598,  598,  331,  332,  332,  332,  332,  598,  598,
-      598,  332,  369,  369,  598,  598,  598,  369,  370,  370,
-      598,  598,  598,  370,  386,  386,  386,  598,  598,  598,
-      386,  387,  387,  387,  387,  598,  598,  598,  387,  416,
-
-      416,  598,  598,  598,  416,  420,  598,  420,  420,  598,
-      598,  598,  420,  438,  438,  438,  598,  598,  598,  438,
-      439,  439,  439,  439,  598,  598,  598,  439,  473,  473,
-      598,  598,  598,  473,  474,  598,  474,  474,  598,  598,
-      598,  474,  490,  490,  490,  598,  598,  598,  490,  491,
-      491,  491,  598,  598,  598,  598,  491,  502,  502,  598,
-      502,  502,  502,  598,  598,  502,  502,  502,  598,  598,
-      502,  502,  502,  508,  508,  598,  508,  508,  508,  598,
-      598,  508,  508,  508,  598,  598,  508,  508,  508,  518,
-      518,  598,  598,  598,  518,  519,  598,  519,  519,  598,
-
-      598,  598,  519,  535,  535,  598,  598,  598,  598,  535,
-      541,  541,  541,  541,  541,  541,  541,  541,  541,  541,
-      541,  541,  541,  541,  541,  541,  556,  556,  598,  598,
-      598,  556,  557,  598,  557,  557,  598,  598,  598,  557,
-      574,  574,  598,  598,  598,  574,  575,  598,  575,  598,
-      598,  598,  598,  575,  590,  590,  590,  590,  590,  590,
-      590,  590,  590,  590,  590,  590,  590,  590,  590,  590,
-       13,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598
-    } ;
-
-static yyconst short int yy_chk[3737] =
-    {   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,    1,    1,    1,    2,    3,    4,   41,    2,
-        3,    4,   11,   11,   11,   11,    3,    4,   53,    3,
-        4,   49,   61,   61,   71,   41,    5,    5,    5,   72,
-        5,   49,   20,    2,    2,   53,    5,    2,  117,   65,
-
-      595,    6,    6,    6,    2,    6,   67,    2,    5,    5,
-       20,    6,   12,   12,   12,   12,   25,   25,   11,  118,
-       25,   25,   65,    6,    6,   69,   69,    3,    4,   67,
-       71,  118,    5,   72,   20,   85,  108,  108,   25,   27,
-       27,   27,   27,   27,   27,   27,   27,    6,    7,    7,
-        7,   42,    7,   74,   74,  117,   74,  590,   12,  100,
-       25,   28,   28,   28,   28,   28,   28,   40,  100,   40,
-       40,   40,   40,   40,   40,   40,   40,   85,  187,   42,
-       42,  123,  108,   42,   98,   98,   98,   98,   98,   98,
-       42,  123,  187,   42,    7,    7,    7,    7,    7,    7,
-
-        7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
-        7,    7,    8,    8,    8,   50,    8,  579,   50,   50,
-       50,   50,   50,   50,   50,   50,   81,   81,   81,   81,
-       81,   81,   81,   81,   82,   82,   82,   82,   82,   82,
-       82,   82,   84,  119,  121,   84,   84,   84,   84,   84,
-       84,   84,   84,  133,  133,  186,  121,  186,    8,    8,
-        8,    8,    8,    8,    8,    8,    8,    8,    8,    8,
-        8,    8,    8,    8,    8,    8,    9,    9,    9,    9,
-        9,  137,  137,  110,  119,    9,    9,    9,  110,  120,
-      500,   52,   52,  576,   83,   52,   52,   89,   89,    9,
-
-      130,   89,   89,  122,  120,  130,   59,   59,   59,  122,
-       59,  147,   83,   52,   59,  148,   59,  144,  144,   89,
-      149,  149,    9,   10,   10,   10,   10,   10,   59,   59,
-      182,  193,   10,   10,   10,   52,   83,   86,  457,   86,
-       86,   89,  165,   86,   86,  105,   10,   86,  185,  500,
-      105,  165,   59,  105,  176,  105,  270,  147,  197,  148,
-       86,   86,  155,  144,  185,  193,  270,  176,  189,   10,
-       19,   92,   92,   92,   92,   92,   92,   92,   92,  182,
-       19,  189,  197,   19,   19,   19,   19,   19,   19,   19,
-       19,   26,  457,   26,   26,   26,   26,   26,   26,   26,
-
-       26,   26,  212,   92,  155,   26,   26,   26,   26,   26,
-       96,   96,   96,   96,   96,   96,   96,   96,  183,  201,
-      201,  201,  574,  183,  212,   26,  204,   26,   26,   26,
-       26,   26,   26,   32,  140,  204,  213,  140,  140,   32,
-      213,  560,   32,   32,  140,   32,   32,   32,   32,   32,
-       32,   32,   32,   32,   32,   32,   32,  140,  360,   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,   32,   32,   32,   32,   32,   34,   34,
-
-       34,   34,   34,   34,   34,   34,   34,  227,  227,  360,
-       34,   34,   34,   34,   34,   97,   97,   97,   97,   97,
-       97,   97,   97,  559,  196,  111,  196,  196,  196,  196,
-      196,  196,   34,   34,   34,   34,   34,   34,   39,   39,
-       39,   39,   39,  220,   39,   39,  157,  264,   39,  220,
-      157,  229,  264,  111,  111,  226,  157,  111,  196,  230,
-       39,   39,   39,   43,  111,  230,  229,  111,  157,  157,
-      127,  127,  557,   43,  127,  127,   43,   43,   43,   43,
-       43,   43,   43,   43,  125,  125,  125,  125,  125,  125,
-      125,  125,  127,  136,  136,  136,  136,  136,  136,  136,
-
-      136,  153,  153,  153,  153,  153,  153,  153,  153,  310,
-      226,  302,  556,  268,  127,  302,  228,   43,   60,  154,
-      154,  154,  154,  154,  154,  154,  154,  269,   60,  254,
-      301,   60,   60,   60,   60,   60,   60,   60,   60,   76,
-      228,   76,   76,   76,  241,   76,   76,  269,  311,   76,
-      188,  254,  301,  241,  188,  243,  243,  228,  311,  310,
-      188,   76,   76,   76,   88,  243,   88,   88,   88,  552,
-       88,   88,  188,  188,   88,  268,  192,  192,  192,  192,
-      192,  192,  192,  192,  245,  245,   88,   88,   88,   91,
-      362,   91,   91,   91,  245,   91,   91,  377,  377,   91,
-
-      156,  541,  156,  156,  271,  362,  156,  156,  192,  271,
-      156,   91,   91,   91,   93,   93,   93,   93,   93,   93,
-       93,   93,  156,  156,  156,  539,   93,   93,   93,   93,
-       93,  200,  200,  200,  200,  200,  200,  200,  200,  200,
-      205,  205,  205,  205,  205,  205,  205,  205,   93,   93,
-       93,   93,   93,   93,  101,  101,  101,  101,  101,  101,
-      101,  101,  409,  305,  409,  273,  101,  101,  101,  101,
-      101,  207,  207,  207,  207,  207,  207,  207,  207,  208,
-      208,  208,  208,  208,  208,  305,  282,  365,  101,  101,
-      101,  101,  101,  101,  129,  282,  129,  129,  129,  273,
-
-      129,  129,  535,  210,  129,  210,  210,  210,  210,  210,
-      210,  210,  210,  427,  427,  531,  129,  129,  129,  158,
-      365,  158,  158,  158,  158,  158,  158,  158,  158,  236,
-      236,  236,  236,  236,  236,  236,  236,  236,  242,  242,
-      242,  242,  242,  242,  242,  242,  251,  251,  251,  251,
-      251,  251,  519,  158,  159,  518,  159,  159,  159,  159,
-      159,  159,  159,  159,  244,  244,  244,  244,  244,  244,
-      244,  244,  248,  248,  248,  248,  248,  248,  248,  248,
-      501,  286,  248,  499,  408,  408,  306,  498,  159,  160,
-      286,  160,  160,  160,  160,  160,  160,  160,  160,  250,
-
-      250,  250,  250,  250,  250,  250,  250,  253,  306,  253,
-      253,  253,  253,  253,  253,  253,  253,  296,  296,  296,
-      296,  296,  296,  160,  161,  307,  161,  161,  161,  161,
-      161,  161,  161,  161,  307,  408,  312,  347,  161,  161,
-      161,  161,  161,  272,  272,  272,  272,  272,  272,  272,
-      272,  276,  312,  276,  276,  276,  276,  276,  276,  347,
-      161,  161,  161,  161,  161,  161,  164,  164,  164,  164,
-      164,  164,  164,  164,  164,  272,  441,  441,  164,  164,
-      164,  164,  164,  462,  283,  276,  283,  283,  283,  283,
-      283,  283,  283,  283,  323,  323,  323,  323,  323,  323,
-
-      164,  164,  164,  164,  164,  164,  166,  166,  166,  166,
-      166,  166,  166,  166,  166,  166,  313,  462,  353,  166,
-      166,  166,  166,  166,  284,  313,  284,  284,  284,  284,
-      284,  284,  284,  284,  342,  342,  342,  342,  342,  342,
-      353,  166,  166,  166,  166,  166,  166,  167,  167,  167,
-      167,  167,  167,  167,  167,  287,  287,  497,  355,  167,
-      167,  167,  167,  167,  285,  287,  285,  285,  285,  285,
-      285,  285,  285,  285,  442,  442,  445,  445,  288,  288,
-      355,  167,  167,  167,  167,  167,  167,  194,  288,  194,
-      194,  194,  194,  194,  194,  194,  194,  289,  289,  289,
-
-      289,  289,  289,  289,  289,  290,  290,  293,  293,  293,
-      293,  293,  293,  293,  293,  290,  496,  293,  481,  481,
-      491,  194,  195,  474,  195,  195,  195,  195,  195,  195,
-      195,  195,  295,  295,  295,  295,  295,  295,  295,  295,
-      298,  331,  298,  298,  298,  298,  298,  298,  298,  298,
-      331,  473,  357,  363,  492,  492,  195,  206,  206,  206,
-      206,  206,  206,  206,  206,  206,  206,  206,  357,  363,
-      403,  206,  206,  206,  206,  206,  320,  320,  320,  320,
-      320,  320,  320,  320,  322,  322,  322,  322,  322,  322,
-      322,  322,  403,  206,  206,  206,  206,  206,  206,  209,
-
-      209,  209,  209,  209,  209,  209,  209,  209,  209,  332,
-      469,  404,  209,  209,  209,  209,  209,  325,  332,  325,
-      325,  325,  325,  325,  325,  325,  325,  526,  526,  543,
-      543,  333,  333,  404,  209,  209,  209,  209,  209,  209,
-      231,  333,  231,  231,  231,  231,  231,  231,  231,  231,
-      326,  326,  326,  326,  326,  326,  326,  326,  328,  361,
-      328,  328,  328,  328,  328,  328,  328,  328,  361,  467,
-      547,  467,  467,  467,  231,  232,  372,  232,  232,  232,
-      232,  232,  232,  232,  232,  329,  372,  329,  329,  329,
-      329,  329,  329,  329,  329,  330,  374,  330,  330,  330,
-
-      330,  330,  330,  467,  547,  454,  374,  563,  563,  232,
-      233,  449,  233,  233,  233,  233,  233,  233,  233,  233,
-      334,  334,  335,  335,  335,  335,  335,  335,  335,  335,
-      334,  336,  336,  339,  339,  339,  339,  339,  339,  339,
-      339,  336,  448,  339,  233,  246,  246,  246,  246,  246,
-      246,  246,  246,  246,  246,  246,  249,  249,  249,  249,
-      249,  249,  249,  249,  249,  249,  249,  447,  458,  446,
-      249,  249,  249,  249,  249,  341,  341,  341,  341,  341,
-      341,  341,  341,  458,  368,  368,  368,  368,  368,  368,
-      368,  446,  249,  249,  249,  249,  249,  249,  252,  252,
-
-      252,  252,  252,  252,  252,  252,  252,  252,  611,  611,
-      450,  252,  252,  252,  252,  252,  344,  368,  344,  344,
-      344,  344,  344,  344,  344,  344,  380,  380,  380,  380,
-      380,  380,  450,  252,  252,  252,  252,  252,  252,  274,
-      386,  274,  274,  274,  274,  274,  274,  274,  274,  386,
-      452,  434,  364,  364,  364,  364,  364,  364,  364,  364,
-      371,  371,  371,  371,  371,  371,  371,  371,  420,  416,
-      661,  411,  452,  274,  275,  661,  275,  275,  275,  275,
-      275,  275,  275,  275,  364,  373,  373,  373,  373,  373,
-      373,  373,  373,  379,  379,  379,  379,  379,  379,  379,
-
-      379,  397,  397,  397,  397,  397,  397,  407,  275,  281,
-      281,  281,  281,  281,  281,  281,  281,  281,  387,  406,
-      493,  281,  281,  281,  281,  281,  382,  387,  382,  382,
-      382,  382,  382,  382,  382,  382,  430,  430,  430,  430,
-      430,  430,  493,  281,  281,  281,  281,  281,  281,  291,
-      291,  291,  291,  291,  291,  291,  291,  291,  291,  291,
-      294,  294,  294,  294,  294,  294,  294,  294,  294,  294,
-      294,  455,  405,  495,  294,  294,  294,  294,  294,  383,
-      421,  383,  383,  383,  383,  383,  383,  383,  383,  402,
-      421,  455,  536,  455,  455,  495,  294,  294,  294,  294,
-
-      294,  294,  297,  297,  297,  297,  297,  297,  297,  297,
-      297,  297,  538,  564,  536,  297,  297,  297,  297,  297,
-      384,  422,  384,  384,  384,  384,  384,  384,  384,  384,
-      401,  422,  400,  581,  538,  564,  399,  297,  297,  297,
-      297,  297,  297,  314,  314,  314,  314,  314,  314,  314,
-      314,  314,  385,  370,  385,  385,  385,  385,  385,  385,
-      385,  385,  388,  388,  389,  389,  438,  581,  369,  359,
-      358,  352,  388,  351,  389,  438,  314,  315,  315,  315,
-      315,  315,  315,  315,  315,  315,  390,  390,  390,  390,
-      390,  390,  390,  390,  391,  391,  394,  394,  394,  394,
-
-      394,  394,  394,  394,  391,  350,  394,  349,  346,  345,
-      315,  316,  316,  316,  316,  316,  316,  316,  316,  316,
-      396,  396,  396,  396,  396,  396,  396,  396,  398,  424,
-      398,  398,  398,  398,  398,  398,  398,  398,  327,  424,
-      319,  318,  317,  309,  316,  321,  308,  321,  321,  321,
-      321,  321,  321,  321,  321,  321,  439,  566,  577,  321,
-      321,  321,  321,  321,  417,  439,  417,  417,  417,  417,
-      417,  417,  417,  417,  459,  304,  459,  459,  459,  566,
-      577,  321,  321,  321,  321,  321,  321,  324,  324,  324,
-      324,  324,  324,  324,  324,  324,  303,  300,  299,  324,
-
-      324,  324,  324,  324,  418,  475,  418,  418,  418,  418,
-      418,  418,  418,  418,  280,  475,  279,  278,  277,  267,
-      459,  324,  324,  324,  324,  324,  324,  337,  337,  337,
-      337,  337,  337,  337,  337,  337,  337,  337,  340,  340,
-      340,  340,  340,  340,  340,  340,  340,  340,  340,  490,
-      266,  265,  340,  340,  340,  340,  340,  419,  490,  419,
-      419,  419,  419,  419,  419,  419,  419,  263,  460,  410,
-      460,  460,  460,  262,  340,  340,  340,  340,  340,  340,
-      343,  343,  343,  343,  343,  343,  343,  343,  343,  410,
-      261,  410,  410,  343,  343,  343,  343,  343,  423,  423,
-
-      423,  423,  423,  423,  423,  423,  484,  484,  484,  484,
-      484,  484,  260,  410,  460,  343,  343,  343,  343,  343,
-      343,  366,  366,  366,  366,  366,  366,  366,  366,  366,
-      429,  429,  429,  429,  429,  429,  429,  429,  432,  476,
-      432,  432,  432,  432,  432,  432,  432,  432,  259,  476,
-      514,  514,  514,  258,  366,  367,  367,  367,  367,  367,
-      367,  367,  367,  367,  433,  433,  433,  433,  433,  433,
-      433,  433,  435,  478,  435,  435,  435,  435,  435,  435,
-      435,  435,  514,  478,  257,  256,  240,  239,  367,  375,
-      238,  375,  375,  375,  375,  375,  375,  375,  375,  375,
-
-      378,  520,  378,  378,  378,  378,  378,  378,  378,  378,
-      378,  520,  237,  235,  378,  378,  378,  378,  378,  436,
-      521,  436,  436,  436,  436,  436,  436,  436,  436,  502,
-      521,  502,  502,  502,  234,  225,  378,  378,  378,  378,
-      378,  378,  381,  381,  381,  381,  381,  381,  381,  381,
-      381,  224,  223,  222,  381,  381,  381,  381,  381,  437,
-      221,  437,  437,  437,  437,  437,  437,  468,  468,  468,
-      468,  468,  468,  468,  468,  502,  381,  381,  381,  381,
-      381,  381,  392,  392,  392,  392,  392,  392,  392,  392,
-      392,  392,  392,  395,  395,  395,  395,  395,  395,  395,
-
-      395,  395,  395,  440,  440,  456,  456,  395,  395,  395,
-      395,  395,  219,  440,  218,  567,  567,  523,  456,  461,
-      461,  461,  461,  461,  461,  461,  461,  523,  567,  395,
-      395,  395,  395,  395,  395,  412,  558,  412,  412,  412,
-      412,  412,  412,  412,  412,  217,  558,  216,  215,  214,
-      470,  461,  470,  470,  470,  470,  470,  470,  470,  470,
-      472,  211,  472,  472,  472,  472,  472,  472,  203,  412,
-      413,  202,  413,  413,  413,  413,  413,  413,  413,  413,
-      471,  199,  471,  471,  471,  471,  471,  471,  471,  471,
-      477,  477,  477,  477,  477,  477,  477,  477,  529,  529,
-
-      529,  529,  529,  529,  413,  414,  198,  414,  414,  414,
-      414,  414,  414,  414,  414,  483,  483,  483,  483,  483,
-      483,  483,  483,  486,  191,  486,  486,  486,  486,  486,
-      486,  486,  486,  588,  588,  588,  588,  588,  588,  414,
-      415,  190,  415,  415,  415,  415,  415,  415,  415,  415,
-      487,  487,  487,  487,  487,  487,  487,  487,  487,  488,
-      488,  488,  488,  488,  488,  488,  488,  488,  503,  184,
-      503,  503,  503,  181,  415,  425,  180,  425,  425,  425,
-      425,  425,  425,  425,  425,  425,  428,  179,  428,  428,
-      428,  428,  428,  428,  428,  428,  428,  178,  177,  175,
-
-      428,  428,  428,  428,  428,  489,  489,  489,  489,  489,
-      489,  489,  489,  489,  503,  504,  174,  504,  504,  504,
-      173,  172,  428,  428,  428,  428,  428,  428,  431,  431,
-      431,  431,  431,  431,  431,  431,  431,  171,  170,  169,
-      431,  431,  431,  431,  431,  505,  168,  505,  505,  505,
-      506,  163,  162,  506,  506,  506,  506,  506,  506,  506,
-      506,  504,  431,  431,  431,  431,  431,  431,  443,  443,
-      443,  443,  443,  443,  443,  443,  443,  443,  463,  152,
-      463,  463,  463,  463,  463,  463,  463,  463,  507,  507,
-      151,  505,  507,  508,  150,  508,  508,  508,  146,  145,
-
-      143,  139,  132,  128,  507,  507,  507,  509,  509,  126,
-      124,  509,  463,  464,  116,  464,  464,  464,  464,  464,
-      464,  464,  464,  509,  509,  509,  513,  513,  513,  513,
-      513,  513,  513,  513,  115,  114,  113,  112,  107,  508,
-      534,  534,  534,  534,  534,  534,  534,  464,  465,  106,
-      465,  465,  465,  465,  465,  465,  465,  465,  513,  515,
-      104,  515,  515,  515,  515,  515,  515,  515,  515,  516,
-      103,  516,  516,  516,  516,  516,  516,  516,  516,   99,
-       95,   94,  465,  466,   90,  466,  466,  466,  466,  466,
-      466,  466,  466,  517,   87,  517,  517,  517,  517,  517,
-
-      517,  517,  517,  522,  522,  522,  522,  522,  522,  522,
-      522,   79,   78,   77,   75,   70,   63,  466,  479,   56,
-      479,  479,  479,  479,  479,  479,  479,  479,  479,  482,
-       51,  482,  482,  482,  482,  482,  482,  482,  482,  482,
-       48,   47,   46,  482,  482,  482,  482,  482,  528,  528,
-      528,  528,  528,  528,  528,  528,  532,  532,  532,  532,
-      532,  532,  532,  532,  532,  482,  482,  482,  482,  482,
-      482,  485,  485,  485,  485,  485,  485,  485,  485,   45,
-       44,   38,   37,  485,  485,  485,  485,  485,  530,   36,
-      530,  530,  530,  530,  530,  530,  530,  530,   35,   33,
-
-       29,   23,   17,   15,   14,  485,  485,  485,  485,  485,
-      485,  510,   13,  510,  510,  510,  510,  510,  510,  510,
-      510,  533,  533,  533,  533,  533,  533,  533,  533,  533,
-      544,  544,  544,  544,  544,  544,  544,  544,    0,    0,
-        0,    0,    0,    0,    0,  510,  511,    0,  511,  511,
-      511,  511,  511,  511,  511,  511,  545,  545,  545,  545,
-      545,  545,  545,  545,  546,  546,  546,  546,  546,  546,
-      546,  546,  550,    0,  550,  550,  550,  550,  550,  550,
-      511,  512,    0,  512,  512,  512,  512,  512,  512,  512,
-      512,    0,    0,    0,    0,    0,  546,  551,  551,  551,
-
-      551,  551,  551,  551,  551,  553,  550,  553,  553,  553,
-      553,  553,  553,  553,  553,  512,  524,    0,  524,  524,
-      524,  524,  524,  524,  524,  524,  524,  527,    0,  527,
-      527,  527,  527,  527,  527,  527,  527,    0,    0,    0,
-        0,  527,  527,  527,  527,  527,  554,    0,  554,  554,
-      554,  554,  554,  554,  554,  554,  597,  597,  597,  597,
-      597,  597,    0,  527,  527,  527,  527,  527,  527,  548,
-        0,  548,  548,  548,  548,  548,  548,  548,  548,  555,
-        0,  555,  555,  555,  555,  555,  555,  561,  597,  561,
-      561,  561,  561,  561,  561,  561,  561,    0,    0,    0,
-
-        0,    0,    0,  548,  549,    0,  549,  549,  549,  549,
-      549,  549,  549,  549,  571,  571,  571,  571,  571,  571,
-      571,  571,  572,  572,  572,  572,  572,  572,  572,  572,
-      573,  573,  573,  573,  573,  573,  573,  573,  549,  568,
-        0,  568,  568,  568,  568,  568,  568,  568,  568,    0,
-        0,    0,  580,  580,  580,  580,  580,  580,  580,  580,
-      584,    0,  584,  584,  584,  584,  584,  584,    0,    0,
-        0,    0,    0,  568,  569,    0,  569,  569,  569,  569,
-      569,  569,  569,  569,  580,  586,  586,  586,  586,  586,
-      586,  586,  586,    0,  584,  587,  587,  587,  587,  587,
-
-      587,  587,  587,    0,    0,    0,    0,    0,  569,  570,
-        0,  570,  570,  570,  570,  570,  570,  570,  570,    0,
-        0,    0,  592,  592,  592,  592,  592,  592,  592,  592,
-      593,  593,  593,  593,  593,  593,  593,  593,    0,    0,
-        0,    0,    0,  570,  582,    0,  582,  582,  582,  582,
-      582,  582,  582,  582,  592,    0,    0,    0,    0,    0,
-        0,    0,  593,  594,  594,  594,  594,  594,  594,  594,
-      594,    0,    0,    0,    0,    0,    0,    0,  582,  583,
-        0,  583,  583,  583,  583,  583,  583,  583,  583,    0,
-        0,    0,    0,    0,    0,  594,  596,  596,  596,  596,
-
-      596,  596,  596,  596,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,  583,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,    0,    0,  596,  599,
-      599,  599,  599,  599,  599,  599,  599,  599,  599,  599,
-      599,  599,  599,  599,  599,  600,  600,  600,  600,  600,
-      600,  600,  600,  600,  600,  600,  600,  600,  600,  600,
-      600,  601,  601,  601,  601,  601,  601,  601,  601,  601,
-      601,  601,  601,  601,  601,  601,  601,  602,  602,  602,
-      602,  602,  602,  602,  602,  602,  602,  602,  602,  602,
-      602,  602,  602,  603,    0,    0,    0,    0,    0,    0,
-
-        0,  603,  603,  603,    0,    0,  603,  603,  603,  604,
-      604,  604,  604,  604,  604,  604,  604,  604,  604,  604,
-      604,  604,  604,  604,  604,  605,    0,    0,    0,    0,
-      605,    0,    0,  605,  605,  605,  605,    0,  605,  605,
-      605,  606,    0,    0,    0,    0,    0,    0,    0,  606,
-      606,  606,    0,    0,  606,  606,  606,  607,    0,    0,
-      607,  607,    0,  607,    0,  607,  607,  607,    0,    0,
-      607,  607,  607,  608,  608,    0,    0,    0,  608,  609,
-        0,    0,  609,  609,    0,  609,    0,  609,  609,  609,
-        0,    0,  609,  609,  609,  610,    0,    0,  610,  610,
-
-        0,  610,    0,  610,  610,  610,    0,  610,    0,  610,
-      610,  612,    0,    0,  612,    0,    0,  612,    0,  612,
-      612,  612,  612,    0,  612,  612,  612,  613,  613,  613,
-      613,  613,  613,  613,  613,  613,  613,  613,  613,  613,
-      613,  613,  613,  614,  614,    0,  614,    0,  614,  614,
-      614,  614,  614,  614,  614,  614,  614,  614,  614,  615,
-      615,  615,  615,  615,  615,  615,  615,  615,  615,  615,
-      615,  615,  615,  615,  615,  616,  616,    0,  616,  616,
-      616,  616,  616,  616,  616,  616,  616,  616,  616,  616,
-      616,  617,    0,    0,    0,    0,  617,    0,    0,  617,
-
-      617,  617,    0,    0,  617,  617,  617,  618,    0,    0,
-      618,  618,    0,  618,    0,  618,  618,  618,    0,    0,
-      618,  618,  618,  619,  619,    0,    0,    0,  619,  620,
-      620,  620,    0,    0,    0,  620,  621,    0,    0,  621,
-      621,    0,  621,    0,  621,  621,  621,    0,    0,  621,
-      621,  621,  622,  622,  622,  622,  622,  622,  622,  622,
-      622,  622,  622,  622,  622,  622,  622,  622,  623,  623,
-        0,    0,    0,  623,  624,  624,  624,    0,    0,    0,
-      624,  625,  625,    0,    0,    0,  625,  626,  626,    0,
-        0,    0,  626,  627,  627,    0,    0,    0,  627,  628,
-
-      628,  628,    0,    0,    0,  628,  629,  629,    0,    0,
-        0,  629,  630,  630,    0,    0,    0,  630,  631,  631,
-        0,    0,    0,  631,  632,  632,  632,    0,    0,    0,
-      632,  633,  633,  633,  633,    0,    0,    0,  633,  634,
-      634,    0,    0,    0,  634,  635,  635,    0,    0,    0,
-      635,  636,  636,    0,    0,    0,  636,  637,  637,  637,
-        0,    0,    0,  637,  638,  638,  638,  638,    0,    0,
-        0,  638,  639,  639,    0,    0,    0,  639,  640,  640,
-        0,    0,    0,  640,  641,  641,  641,    0,    0,    0,
-      641,  642,  642,  642,  642,    0,    0,    0,  642,  643,
-
-      643,    0,    0,    0,  643,  644,    0,  644,  644,    0,
-        0,    0,  644,  645,  645,  645,    0,    0,    0,  645,
-      646,  646,  646,  646,    0,    0,    0,  646,  647,  647,
-        0,    0,    0,  647,  648,    0,  648,  648,    0,    0,
-        0,  648,  649,  649,  649,    0,    0,    0,  649,  650,
-      650,  650,    0,    0,    0,    0,  650,  651,  651,    0,
-      651,  651,  651,    0,    0,  651,  651,  651,    0,    0,
-      651,  651,  651,  652,  652,    0,  652,  652,  652,    0,
-        0,  652,  652,  652,    0,    0,  652,  652,  652,  653,
-      653,    0,    0,    0,  653,  654,    0,  654,  654,    0,
-
-        0,    0,  654,  655,  655,    0,    0,    0,    0,  655,
-      656,  656,  656,  656,  656,  656,  656,  656,  656,  656,
-      656,  656,  656,  656,  656,  656,  657,  657,    0,    0,
-        0,  657,  658,    0,  658,  658,    0,    0,    0,  658,
-      659,  659,    0,    0,    0,  659,  660,    0,  660,    0,
-        0,    0,    0,  660,  662,  662,  662,  662,  662,  662,
-      662,  662,  662,  662,  662,  662,  662,  662,  662,  662,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598,  598,  598,  598,  598,
-      598,  598,  598,  598,  598,  598
-    } ;
-
-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-2010
- *     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 <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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_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 */
-#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 <errno.h>
-#include <ctype.h>
-#include "sudo.h"
-#include "parse.h"
-#include "toke.h"
-#include <gram.h>
-
-extern YYSTYPE yylval;
-extern int parse_error;
-int sudolineno;
-char *sudoers;
-
-static int continued, prev_state, sawspace;
-
-static int _push_include       __P((char *, int));
-static int pop_include         __P((void));
-static char *parse_include     __P((char *));
-
-#define fill(a, b)             fill_txt(a, b, 0)
-
-#define        push_include(_p)        (_push_include((_p), FALSE))
-#define        push_includedir(_p)     (_push_include((_p), TRUE))
-
-#ifdef TRACELEXER
-#define LEXTRACE(msg)  fputs(msg, stderr)
-#else
-#define LEXTRACE(msg)
-#endif
-#define YY_NO_INPUT 1
-#define YY_NO_UNPUT 1
-#define GOTDEFS 1
-
-#define GOTCMND 2
-
-#define STARTDEFS 3
-
-#define INDEFS 4
-
-#define INSTR 5
-
-#line 1511 "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 120 "toke.l"
-
-#line 1667 "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 >= 599 )
-                                       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] != 3671 );
-
-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 121 "toke.l"
-{
-                           LEXTRACE(", ");
-                           return ',';
-                       }                       /* return ',' */
-       YY_BREAK
-case 2:
-YY_RULE_SETUP
-#line 126 "toke.l"
-BEGIN STARTDEFS;
-       YY_BREAK
-case 3:
-YY_RULE_SETUP
-#line 128 "toke.l"
-{
-                           BEGIN INDEFS;
-                           LEXTRACE("DEFVAR ");
-                           if (!fill(yytext, yyleng))
-                               yyterminate();
-                           return DEFVAR;
-                       }
-       YY_BREAK
-
-case 4:
-YY_RULE_SETUP
-#line 137 "toke.l"
-{
-                           BEGIN STARTDEFS;
-                           LEXTRACE(", ");
-                           return ',';
-                       }                       /* return ',' */
-       YY_BREAK
-case 5:
-YY_RULE_SETUP
-#line 143 "toke.l"
-{
-                           LEXTRACE("= ");
-                           return '=';
-                       }                       /* return '=' */
-       YY_BREAK
-case 6:
-YY_RULE_SETUP
-#line 148 "toke.l"
-{
-                           LEXTRACE("+= ");
-                           return '+';
-                       }                       /* return '+' */
-       YY_BREAK
-case 7:
-YY_RULE_SETUP
-#line 153 "toke.l"
-{
-                           LEXTRACE("-= ");
-                           return '-';
-                       }                       /* return '-' */
-       YY_BREAK
-case 8:
-YY_RULE_SETUP
-#line 158 "toke.l"
-{
-                           LEXTRACE("BEGINSTR ");
-                           yylval.string = NULL;
-                           prev_state = YY_START;
-                           BEGIN INSTR;
-                       }
-       YY_BREAK
-case 9:
-YY_RULE_SETUP
-#line 165 "toke.l"
-{
-                           LEXTRACE("WORD(2) ");
-                           if (!fill(yytext, yyleng))
-                               yyterminate();
-                           return WORD;
-                       }
-       YY_BREAK
-
-
-case 10:
-YY_RULE_SETUP
-#line 174 "toke.l"
-{
-                           /* Line continuation char followed by newline. */
-                           ++sudolineno;
-                           continued = TRUE;
-                       }
-       YY_BREAK
-case 11:
-YY_RULE_SETUP
-#line 180 "toke.l"
-{
-                           LEXTRACE("ENDSTR ");
-                           BEGIN prev_state;
-
-                           if (yylval.string == NULL) {
-                               LEXTRACE("ERROR "); /* empty string */
-                               return ERROR;
-                           }
-                           if (prev_state == INITIAL) {
-                               switch (yylval.string[0]) {
-                               case '%':
-                                   if (yylval.string[1] == '\0' ||
-                                       (yylval.string[1] == ':' &&
-                                       yylval.string[2] == '\0')) {
-                                       LEXTRACE("ERROR "); /* empty group */
-                                       return ERROR;
-                                   }
-                                   LEXTRACE("USERGROUP ");
-                                   return USERGROUP;
-                               case '+':
-                                   if (yylval.string[1] == '\0') {
-                                       LEXTRACE("ERROR "); /* empty netgroup */
-                                       return ERROR;
-                                   }
-                                   LEXTRACE("NETGROUP ");
-                                   return NETGROUP;
-                               }
-                           }
-                           LEXTRACE("WORD(4) ");
-                           return WORD;
-                       }
-       YY_BREAK
-case 12:
-YY_RULE_SETUP
-#line 212 "toke.l"
-{
-                           LEXTRACE("BACKSLASH ");
-                           if (!append(yytext, yyleng))
-                               yyterminate();
-                       }
-       YY_BREAK
-case 13:
-YY_RULE_SETUP
-#line 218 "toke.l"
-{
-                           LEXTRACE("STRBODY ");
-                           if (!append(yytext, yyleng))
-                               yyterminate();
-                       }
-       YY_BREAK
-
-
-case 14:
-YY_RULE_SETUP
-#line 226 "toke.l"
-{
-                           /* quoted fnmatch glob char, pass verbatim */
-                           LEXTRACE("QUOTEDCHAR ");
-                           if (!fill_args(yytext, 2, sawspace))
-                               yyterminate();
-                           sawspace = FALSE;
-                       }
-       YY_BREAK
-case 15:
-YY_RULE_SETUP
-#line 234 "toke.l"
-{
-                           /* quoted sudoers special char, strip backslash */
-                           LEXTRACE("QUOTEDCHAR ");
-                           if (!fill_args(yytext + 1, 1, sawspace))
-                               yyterminate();
-                           sawspace = FALSE;
-                       }
-       YY_BREAK
-case 16:
-YY_RULE_SETUP
-#line 242 "toke.l"
-{
-                           BEGIN INITIAL;
-                           yyless(0);
-                           return COMMAND;
-                       }                       /* end of command line args */
-       YY_BREAK
-case 17:
-YY_RULE_SETUP
-#line 248 "toke.l"
-{
-                           LEXTRACE("ARG ");
-                           if (!fill_args(yytext, yyleng, sawspace))
-                               yyterminate();
-                           sawspace = FALSE;
-                       }                       /* a command line arg */
-       YY_BREAK
-
-case 18:
-YY_RULE_SETUP
-#line 256 "toke.l"
-{
-                           char *path;
-
-                           if (continued) {
-                               LEXTRACE("ERROR ");
-                               return ERROR;
-                           }
-
-                           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 19:
-YY_RULE_SETUP
-#line 274 "toke.l"
-{
-                           char *path;
-
-                           if (continued) {
-                               LEXTRACE("ERROR ");
-                               return ERROR;
-                           }
-
-                           if ((path = parse_include(yytext)) == NULL)
-                               yyterminate();
-
-                           LEXTRACE("INCLUDEDIR\n");
-
-                           /*
-                            * Push current buffer and switch to include file.
-                            * We simply ignore empty directories.
-                            */
-                           if (!push_includedir(path) && parse_error)
-                               yyterminate();
-                       }
-       YY_BREAK
-case 20:
-YY_RULE_SETUP
-#line 295 "toke.l"
-{
-                           char deftype;
-                           int n;
-
-                           if (continued) {
-                               LEXTRACE("ERROR ");
-                               return ERROR;
-                           }
-
-                           for (n = 0; isblank((unsigned char)yytext[n]); n++)
-                               continue;
-                           n += sizeof("Defaults") - 1;
-                           if ((deftype = yytext[n++]) != '\0') {
-                               while (isblank((unsigned char)yytext[n]))
-                                   n++;
-                           }
-                           BEGIN GOTDEFS;
-                           switch (deftype) {
-                               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 21:
-YY_RULE_SETUP
-#line 335 "toke.l"
-{
-                           int n;
-
-                           if (continued) {
-                               LEXTRACE("ERROR ");
-                               return ERROR;
-                           }
-
-                           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 22:
-YY_RULE_SETUP
-#line 361 "toke.l"
-{
-                               /* cmnd does not require passwd for this user */
-                               LEXTRACE("NOPASSWD ");
-                               return NOPASSWD;
-                       }
-       YY_BREAK
-case 23:
-YY_RULE_SETUP
-#line 367 "toke.l"
-{
-                               /* cmnd requires passwd for this user */
-                               LEXTRACE("PASSWD ");
-                               return PASSWD;
-                       }
-       YY_BREAK
-case 24:
-YY_RULE_SETUP
-#line 373 "toke.l"
-{
-                               LEXTRACE("NOEXEC ");
-                               return NOEXEC;
-                       }
-       YY_BREAK
-case 25:
-YY_RULE_SETUP
-#line 378 "toke.l"
-{
-                               LEXTRACE("EXEC ");
-                               return EXEC;
-                       }
-       YY_BREAK
-case 26:
-YY_RULE_SETUP
-#line 383 "toke.l"
-{
-                               LEXTRACE("SETENV ");
-                               return SETENV;
-                       }
-       YY_BREAK
-case 27:
-YY_RULE_SETUP
-#line 388 "toke.l"
-{
-                               LEXTRACE("NOSETENV ");
-                               return NOSETENV;
-                       }
-       YY_BREAK
-case 28:
-YY_RULE_SETUP
-#line 393 "toke.l"
-{
-                               LEXTRACE("LOG_OUTPUT ");
-                               return LOG_OUTPUT;
-                       }
-       YY_BREAK
-case 29:
-YY_RULE_SETUP
-#line 398 "toke.l"
-{
-                               LEXTRACE("NOLOG_OUTPUT ");
-                               return NOLOG_OUTPUT;
-                       }
-       YY_BREAK
-case 30:
-YY_RULE_SETUP
-#line 403 "toke.l"
-{
-                               LEXTRACE("LOG_INPUT ");
-                               return LOG_INPUT;
-                       }
-       YY_BREAK
-case 31:
-YY_RULE_SETUP
-#line 408 "toke.l"
-{
-                               LEXTRACE("NOLOG_INPUT ");
-                               return NOLOG_INPUT;
-                       }
-       YY_BREAK
-case 32:
-YY_RULE_SETUP
-#line 413 "toke.l"
-{
-                           /* empty group or netgroup */
-                           LEXTRACE("ERROR ");
-                           return ERROR;
-                       }
-       YY_BREAK
-case 33:
-YY_RULE_SETUP
-#line 419 "toke.l"
-{
-                           /* netgroup */
-                           if (!fill(yytext, yyleng))
-                               yyterminate();
-                           LEXTRACE("NETGROUP ");
-                           return NETGROUP;
-                       }
-       YY_BREAK
-case 34:
-YY_RULE_SETUP
-#line 427 "toke.l"
-{
-                           /* group */
-                           if (!fill(yytext, yyleng))
-                               yyterminate();
-                           LEXTRACE("USERGROUP ");
-                           return USERGROUP;
-                       }
-       YY_BREAK
-case 35:
-YY_RULE_SETUP
-#line 435 "toke.l"
-{
-                           if (!fill(yytext, yyleng))
-                               yyterminate();
-                           LEXTRACE("NTWKADDR ");
-                           return NTWKADDR;
-                       }
-       YY_BREAK
-case 36:
-YY_RULE_SETUP
-#line 442 "toke.l"
-{
-                           if (!fill(yytext, yyleng))
-                               yyterminate();
-                           LEXTRACE("NTWKADDR ");
-                           return NTWKADDR;
-                       }
-       YY_BREAK
-case 37:
-YY_RULE_SETUP
-#line 449 "toke.l"
-{
-                           if (!ipv6_valid(yytext)) {
-                               LEXTRACE("ERROR ");
-                               return ERROR;
-                           }
-                           if (!fill(yytext, yyleng))
-                               yyterminate();
-                           LEXTRACE("NTWKADDR ");
-                           return NTWKADDR;
-                       }
-       YY_BREAK
-case 38:
-YY_RULE_SETUP
-#line 460 "toke.l"
-{
-                           if (!ipv6_valid(yytext)) {
-                               LEXTRACE("ERROR ");
-                               return ERROR;
-                           }
-                           if (!fill(yytext, yyleng))
-                               yyterminate();
-                           LEXTRACE("NTWKADDR ");
-                           return NTWKADDR;
-                       }
-       YY_BREAK
-case 39:
-YY_RULE_SETUP
-#line 471 "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 40:
-YY_RULE_SETUP
-#line 493 "toke.l"
-{
-                           /* no command args allowed for Defaults!/path */
-                           if (!fill_cmnd(yytext, yyleng))
-                               yyterminate();
-                           LEXTRACE("COMMAND ");
-                           return COMMAND;
-                       }
-       YY_BREAK
-case 41:
-YY_RULE_SETUP
-#line 501 "toke.l"
-{
-                           BEGIN GOTCMND;
-                           LEXTRACE("COMMAND ");
-                           if (!fill_cmnd(yytext, yyleng))
-                               yyterminate();
-                       }                       /* sudo -e */
-       YY_BREAK
-case 42:
-YY_RULE_SETUP
-#line 508 "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 43:
-YY_RULE_SETUP
-#line 523 "toke.l"
-{
-                           LEXTRACE("BEGINSTR ");
-                           yylval.string = NULL;
-                           prev_state = YY_START;
-                           BEGIN INSTR;
-                       }
-       YY_BREAK
-case 44:
-YY_RULE_SETUP
-#line 530 "toke.l"
-{
-                           /* a word */
-                           if (!fill(yytext, yyleng))
-                               yyterminate();
-                           LEXTRACE("WORD(5) ");
-                           return WORD;
-                       }
-       YY_BREAK
-case 45:
-YY_RULE_SETUP
-#line 538 "toke.l"
-{
-                           LEXTRACE("( ");
-                           return '(';
-                       }
-       YY_BREAK
-case 46:
-YY_RULE_SETUP
-#line 543 "toke.l"
-{
-                           LEXTRACE(") ");
-                           return ')';
-                       }
-       YY_BREAK
-case 47:
-YY_RULE_SETUP
-#line 548 "toke.l"
-{
-                           LEXTRACE(", ");
-                           return ',';
-                       }                       /* return ',' */
-       YY_BREAK
-case 48:
-YY_RULE_SETUP
-#line 553 "toke.l"
-{
-                           LEXTRACE("= ");
-                           return '=';
-                       }                       /* return '=' */
-       YY_BREAK
-case 49:
-YY_RULE_SETUP
-#line 558 "toke.l"
-{
-                           LEXTRACE(": ");
-                           return ':';
-                       }                       /* return ':' */
-       YY_BREAK
-case 50:
-YY_RULE_SETUP
-#line 563 "toke.l"
-{
-                           if (yyleng & 1) {
-                               LEXTRACE("!");
-                               return '!';     /* return '!' */
-                           }
-                       }
-       YY_BREAK
-case 51:
-YY_RULE_SETUP
-#line 570 "toke.l"
-{
-                           if (YY_START == INSTR) {
-                               LEXTRACE("ERROR ");
-                               return ERROR;   /* line break in string */
-                           }
-                           BEGIN INITIAL;
-                           ++sudolineno;
-                           continued = FALSE;
-                           LEXTRACE("\n");
-                           return COMMENT;
-                       }                       /* return newline */
-       YY_BREAK
-case 52:
-YY_RULE_SETUP
-#line 582 "toke.l"
-{                      /* throw away space/tabs */
-                           sawspace = TRUE;    /* but remember for fill_args */
-                       }
-       YY_BREAK
-case 53:
-YY_RULE_SETUP
-#line 586 "toke.l"
-{
-                           sawspace = TRUE;    /* remember for fill_args */
-                           ++sudolineno;
-                           continued = TRUE;
-                       }                       /* throw away EOL after \ */
-       YY_BREAK
-case 54:
-YY_RULE_SETUP
-#line 592 "toke.l"
-{
-                           BEGIN INITIAL;
-                           ++sudolineno;
-                           continued = FALSE;
-                           LEXTRACE("#\n");
-                           return COMMENT;
-                       }                       /* comment, not uid/gid */
-       YY_BREAK
-case 55:
-YY_RULE_SETUP
-#line 600 "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 605 "toke.l"
-{
-                           if (YY_START != INITIAL) {
-                               BEGIN INITIAL;
-                               LEXTRACE("ERROR ");
-                               return ERROR;
-                           }
-                           if (!pop_include())
-                               yyterminate();
-                       }
-       YY_BREAK
-case 56:
-YY_RULE_SETUP
-#line 615 "toke.l"
-ECHO;
-       YY_BREAK
-#line 2422 "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 >= 599 )
-                               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 >= 599 )
-                       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 == 598);
-
-       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 */
-
-
-#ifndef YY_NO_INPUT
-#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;
-       }
-#endif /* ifndef YY_NO_INPUT */
-
-
-#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 615 "toke.l"
-
-struct path_list {
-    char *path;
-    struct path_list *next;
-};
-
-struct include_stack {
-    YY_BUFFER_STATE bs;
-    char *path;
-    struct path_list *more; /* more files in case of includedir */
-    int lineno;
-    int keepopen;
-};
-
-static int
-pl_compare(v1, v2)
-    const void *v1;
-    const void *v2;
-{
-    const struct path_list * const *p1 = v1;
-    const struct path_list * const *p2 = v2;
-
-    return strcmp((*p1)->path, (*p2)->path);
-}
-
-static char *
-switch_dir(stack, dirpath)
-    struct include_stack *stack;
-    char *dirpath;
-{
-    DIR *dir;
-    int i, count = 0;
-    char *path = NULL;
-    struct dirent *dent;
-    struct stat sb;
-    struct path_list *pl, *first = NULL;
-    struct path_list **sorted = NULL;
-
-    if (!(dir = opendir(dirpath))) {
-       if (errno != ENOENT) {
-           char *errbuf;
-           if (asprintf(&errbuf, "%s: %s", dirpath, strerror(errno)) != -1) {
-               yyerror(errbuf);
-               free(errbuf);
-           } else {
-               yyerror("unable to allocate memory");
-           }
-       }
-       goto done;
-    }
-    while ((dent = readdir(dir))) {
-       /* Ignore files that end in '~' or have a '.' in them. */
-       if (dent->d_name[0] == '\0' || dent->d_name[NAMLEN(dent) - 1] == '~'
-           || strchr(dent->d_name, '.') != NULL) {
-           continue;
-       }
-       if (asprintf(&path, "%s/%s", dirpath, dent->d_name) == -1) {
-           closedir(dir);
-           goto bad;
-       }
-       if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)) {
-           efree(path);
-           path = NULL;
-           continue;
-       }
-       pl = malloc(sizeof(*pl));
-       if (pl == NULL)
-           goto bad;
-       pl->path = path;
-       pl->next = first;
-       first = pl;
-       count++;
-    }
-    closedir(dir);
-
-    if (count == 0)
-       goto done;
-
-    /* Sort the list as an array. */
-    sorted = malloc(sizeof(*sorted) * count);
-    if (sorted == NULL)
-       goto bad;
-    pl = first;
-    for (i = 0; i < count; i++) {
-       sorted[i] = pl;
-       pl = pl->next;
-    }
-    qsort(sorted, count, sizeof(*sorted), pl_compare);
-
-    /* Apply sorting to the list. */
-    first = sorted[0];
-    sorted[count - 1]->next = NULL;
-    for (i = 1; i < count; i++)
-       sorted[i - 1]->next = sorted[i];
-    efree(sorted);
-
-    /* Pull out the first element for parsing, leave the rest for later. */
-    if (count) {
-       path = first->path;
-       pl = first->next;
-       efree(first);
-       stack->more = pl;
-    } else {
-       path = NULL;
-    }
-done:
-    efree(dirpath);
-    return path;
-bad:
-    while (first != NULL) {
-       pl = first;
-       first = pl->next;
-       free(pl->path);
-       free(pl);
-    }
-    efree(sorted);
-    efree(dirpath);
-    efree(path);
-    return NULL;
-}
-
-#define MAX_SUDOERS_DEPTH      128
-#define SUDOERS_STACK_INCREMENT        16
-
-static size_t istacksize, idepth;
-static struct include_stack *istack;
-static int keepopen;
-
-void
-init_lexer()
-{
-    struct path_list *pl;
-
-    while (idepth) {
-       idepth--;
-       while ((pl = istack[idepth].more) != NULL) {
-           istack[idepth].more = pl->next;
-           efree(pl->path);
-           efree(pl);
-       }
-       efree(istack[idepth].path);
-       if (idepth && !istack[idepth].keepopen)
-           fclose(istack[idepth].bs->yy_input_file);
-       yy_delete_buffer(istack[idepth].bs);
-    }
-    efree(istack);
-    istack = NULL;
-    istacksize = idepth = 0;
-    sudolineno = 1;
-    keepopen = FALSE;
-    sawspace = FALSE;
-    continued = FALSE;
-    prev_state = INITIAL;
-}
-
-static int
-_push_include(path, isdir)
-    char *path;
-    int isdir;
-{
-    struct path_list *pl;
-    FILE *fp;
-
-    /* push current state onto stack */
-    if (idepth >= istacksize) {
-       if (idepth > MAX_SUDOERS_DEPTH) {
-           yyerror("too many levels of includes");
-           return FALSE;
-       }
-       istacksize += SUDOERS_STACK_INCREMENT;
-       istack = (struct include_stack *) realloc(istack,
-           sizeof(*istack) * istacksize);
-       if (istack == NULL) {
-           yyerror("unable to allocate memory");
-           return FALSE;
-       }
-    }
-    if (isdir) {
-       if (!(path = switch_dir(&istack[idepth], path))) {
-           /* switch_dir() called yyerror() for us */
-           return FALSE;
-       }
-       while ((fp = open_sudoers(path, FALSE, &keepopen)) == NULL) {
-           /* Unable to open path in includedir, go to next one, if any. */
-           efree(path);
-           if ((pl = istack[idepth].more) == NULL)
-               return FALSE;
-           path = pl->path;
-           istack[idepth].more = pl->next;
-           efree(pl);
-       }
-    } else {
-       if ((fp = open_sudoers(path, TRUE, &keepopen)) == NULL) {
-           char *errbuf;
-           if (asprintf(&errbuf, "%s: %s", path, strerror(errno)) != -1) {
-               yyerror(errbuf);
-               free(errbuf);
-           } else {
-               yyerror("unable to allocate memory");
-           }
-           return FALSE;
-       }
-       istack[idepth].more = NULL;
-    }
-    /* Push the old (current) file and open the new one. */
-    istack[idepth].path = sudoers; /* push old path */
-    istack[idepth].bs = YY_CURRENT_BUFFER;
-    istack[idepth].lineno = sudolineno;
-    istack[idepth].keepopen = keepopen;
-    idepth++;
-    sudolineno = 1;
-    sudoers = path;
-    yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
-
-    return TRUE;
-}
-
-static int
-pop_include()
-{
-    struct path_list *pl;
-    FILE *fp;
-
-    if (idepth == 0)
-       return FALSE;
-
-    if (!keepopen)
-       fclose(YY_CURRENT_BUFFER->yy_input_file);
-    yy_delete_buffer(YY_CURRENT_BUFFER);
-    /* If we are in an include dir, move to the next file. */
-    while ((pl = istack[idepth - 1].more) != NULL) {
-       fp = open_sudoers(pl->path, FALSE, &keepopen);
-       if (fp != NULL) {
-           istack[idepth - 1].more = pl->next;
-           efree(sudoers);
-           sudoers = pl->path;
-           sudolineno = 1;
-           yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
-           efree(pl);
-           break;
-       }
-       /* Unable to open path in include dir, go to next one. */
-       istack[idepth - 1].more = pl->next;
-       efree(pl->path);
-       efree(pl);
-    }
-    /* If no path list, just pop the last dir on the stack. */
-    if (pl == NULL) {
-       idepth--;
-       yy_switch_to_buffer(istack[idepth].bs);
-       efree(sudoers);
-       sudoers = istack[idepth].path;
-       sudolineno = istack[idepth].lineno;
-       keepopen = istack[idepth].keepopen;
-    }
-    return TRUE;
-}
-
-static char *
-parse_include(base)
-    char *base;
-{
-    char *cp, *ep, *path;
-    int len = 0, subst = 0;
-    size_t shost_len = 0;
-
-    /* Pull out path from #include line. */
-    cp = base + sizeof("#include");
-    if (*cp == 'i')
-       cp += 3; /* includedir */
-    while (isblank((unsigned char) *cp))
-       cp++;
-    ep = cp;
-    while (*ep != '\0' && !isspace((unsigned char) *ep)) {
-       if (ep[0] == '%' && ep[1] == 'h') {
-           shost_len = strlen(user_shost);
-           len += shost_len - 2;
-           subst = 1;
-       }
-       ep++;
-    }
-
-    /* Make a copy of path and return it. */
-    len += (int)(ep - cp);
-    if ((path = malloc(len + 1)) == NULL)
-       yyerror("unable to allocate memory");
-    if (subst) {
-       /* substitute for %h */
-       char *pp = path;
-       while (cp < ep) {
-           if (cp[0] == '%' && cp[1] == 'h') {
-               memcpy(pp, user_shost, shost_len);
-               pp += shost_len;
-               cp += 2;
-               continue;
-           }
-           *pp++ = *cp++;
-       }
-       *pp = '\0';
-    } else {
-       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;
-}
diff --git a/toke.h b/toke.h
deleted file mode 100644 (file)
index 75e9495..0000000
--- a/toke.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2011 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.
- */
-
-#ifndef _SUDO_TOKE_H
-#define _SUDO_TOKE_H
-
-int append     __P((char *, int));
-int fill_args  __P((char *, int, int));
-int fill_cmnd  __P((char *, int));
-int fill_txt   __P((char *, int, int));
-int ipv6_valid __P((const char *s));
-void yyerror   __P((const char *));
-
-/* realloc() to size + COMMANDARGINC to make room for command args */
-#define COMMANDARGINC   64
-
-#endif /* _SUDO_TOKE_H */
diff --git a/toke.l b/toke.l
deleted file mode 100644 (file)
index 05ea663..0000000
--- a/toke.l
+++ /dev/null
@@ -1,924 +0,0 @@
-%{
-/*
- * Copyright (c) 1996, 1998-2005, 2007-2010
- *     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 <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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_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 */
-#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 <errno.h>
-#include <ctype.h>
-#include "sudo.h"
-#include "parse.h"
-#include "toke.h"
-#include <gram.h>
-
-extern YYSTYPE yylval;
-extern int parse_error;
-int sudolineno;
-char *sudoers;
-
-static int continued, prev_state, sawspace;
-
-static int _push_include       __P((char *, int));
-static int pop_include         __P((void));
-static char *parse_include     __P((char *));
-
-#define fill(a, b)             fill_txt(a, b, 0)
-
-#define        push_include(_p)        (_push_include((_p), FALSE))
-#define        push_includedir(_p)     (_push_include((_p), TRUE))
-
-#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 noinput
-%option nounput
-%option noyywrap
-
-%s     GOTDEFS
-%x     GOTCMND
-%x     STARTDEFS
-%x     INDEFS
-%x     INSTR
-
-%%
-<GOTDEFS>[[:blank:]]*,[[:blank:]]* {
-                           LEXTRACE(", ");
-                           return ',';
-                       }                       /* return ',' */
-
-<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;
-                           prev_state = YY_START;
-                           BEGIN INSTR;
-                       }
-
-    {ENVAR}            {
-                           LEXTRACE("WORD(2) ");
-                           if (!fill(yytext, yyleng))
-                               yyterminate();
-                           return WORD;
-                       }
-}
-
-<INSTR>{
-    \\[[:blank:]]*\n[[:blank:]]*       {
-                           /* Line continuation char followed by newline. */
-                           ++sudolineno;
-                           continued = TRUE;
-                       }
-
-    \"                 {
-                           LEXTRACE("ENDSTR ");
-                           BEGIN prev_state;
-
-                           if (yylval.string == NULL) {
-                               LEXTRACE("ERROR "); /* empty string */
-                               return ERROR;
-                           }
-                           if (prev_state == INITIAL) {
-                               switch (yylval.string[0]) {
-                               case '%':
-                                   if (yylval.string[1] == '\0' ||
-                                       (yylval.string[1] == ':' &&
-                                       yylval.string[2] == '\0')) {
-                                       LEXTRACE("ERROR "); /* empty group */
-                                       return ERROR;
-                                   }
-                                   LEXTRACE("USERGROUP ");
-                                   return USERGROUP;
-                               case '+':
-                                   if (yylval.string[1] == '\0') {
-                                       LEXTRACE("ERROR "); /* empty netgroup */
-                                       return ERROR;
-                                   }
-                                   LEXTRACE("NETGROUP ");
-                                   return NETGROUP;
-                               }
-                           }
-                           LEXTRACE("WORD(4) ");
-                           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 (continued) {
-                               LEXTRACE("ERROR ");
-                               return ERROR;
-                           }
-
-                           if ((path = parse_include(yytext)) == NULL)
-                               yyterminate();
-
-                           LEXTRACE("INCLUDE\n");
-
-                           /* Push current buffer and switch to include file */
-                           if (!push_include(path))
-                               yyterminate();
-                       }
-
-<INITIAL>^#includedir[[:blank:]]+\/.*\n {
-                           char *path;
-
-                           if (continued) {
-                               LEXTRACE("ERROR ");
-                               return ERROR;
-                           }
-
-                           if ((path = parse_include(yytext)) == NULL)
-                               yyterminate();
-
-                           LEXTRACE("INCLUDEDIR\n");
-
-                           /*
-                            * Push current buffer and switch to include file.
-                            * We simply ignore empty directories.
-                            */
-                           if (!push_includedir(path) && parse_error)
-                               yyterminate();
-                       }
-
-<INITIAL>^[[:blank:]]*Defaults([:@>\!][[:blank:]]*\!*\"?({ID}|{WORD}))? {
-                           char deftype;
-                           int n;
-
-                           if (continued) {
-                               LEXTRACE("ERROR ");
-                               return ERROR;
-                           }
-
-                           for (n = 0; isblank((unsigned char)yytext[n]); n++)
-                               continue;
-                           n += sizeof("Defaults") - 1;
-                           if ((deftype = yytext[n++]) != '\0') {
-                               while (isblank((unsigned char)yytext[n]))
-                                   n++;
-                           }
-                           BEGIN GOTDEFS;
-                           switch (deftype) {
-                               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;
-
-                           if (continued) {
-                               LEXTRACE("ERROR ");
-                               return ERROR;
-                           }
-
-                           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;
-                       }
-
-LOG_OUTPUT[[:blank:]]*:        {
-                               LEXTRACE("LOG_OUTPUT ");
-                               return LOG_OUTPUT;
-                       }
-
-NOLOG_OUTPUT[[:blank:]]*:      {
-                               LEXTRACE("NOLOG_OUTPUT ");
-                               return NOLOG_OUTPUT;
-                       }
-
-LOG_INPUT[[:blank:]]*: {
-                               LEXTRACE("LOG_INPUT ");
-                               return LOG_INPUT;
-                       }
-
-NOLOG_INPUT[[:blank:]]*:       {
-                               LEXTRACE("NOLOG_INPUT ");
-                               return NOLOG_INPUT;
-                       }
-
-<INITIAL,GOTDEFS>(\+|\%|\%:) {
-                           /* empty group or netgroup */
-                           LEXTRACE("ERROR ");
-                           return ERROR;
-                       }
-
-\+{WORD}               {
-                           /* netgroup */
-                           if (!fill(yytext, yyleng))
-                               yyterminate();
-                           LEXTRACE("NETGROUP ");
-                           return NETGROUP;
-                       }
-
-\%:?({WORD}|{ID})      {
-                           /* 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>\" {
-                           LEXTRACE("BEGINSTR ");
-                           yylval.string = NULL;
-                           prev_state = YY_START;
-                           BEGIN INSTR;
-                       }
-
-<INITIAL,GOTDEFS>({ID}|{WORD}) {
-                           /* a word */
-                           if (!fill(yytext, yyleng))
-                               yyterminate();
-                           LEXTRACE("WORD(5) ");
-                           return WORD;
-                       }
-
-\(                     {
-                           LEXTRACE("( ");
-                           return '(';
-                       }
-
-\)                     {
-                           LEXTRACE(") ");
-                           return ')';
-                       }
-
-,                      {
-                           LEXTRACE(", ");
-                           return ',';
-                       }                       /* return ',' */
-
-=                      {
-                           LEXTRACE("= ");
-                           return '=';
-                       }                       /* return '=' */
-
-:                      {
-                           LEXTRACE(": ");
-                           return ':';
-                       }                       /* return ':' */
-
-<*>!+                  {
-                           if (yyleng & 1) {
-                               LEXTRACE("!");
-                               return '!';     /* return '!' */
-                           }
-                       }
-
-<*>\n                  {
-                           if (YY_START == INSTR) {
-                               LEXTRACE("ERROR ");
-                               return ERROR;   /* line break in string */
-                           }
-                           BEGIN INITIAL;
-                           ++sudolineno;
-                           continued = FALSE;
-                           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;
-                           continued = TRUE;
-                       }                       /* throw away EOL after \ */
-
-<INITIAL,STARTDEFS,INDEFS>#(-[^\n0-9].*|[^\n0-9-].*)?\n        {
-                           BEGIN INITIAL;
-                           ++sudolineno;
-                           continued = FALSE;
-                           LEXTRACE("#\n");
-                           return COMMENT;
-                       }                       /* comment, not uid/gid */
-
-<*>.                   {
-                           LEXTRACE("ERROR ");
-                           return ERROR;
-                       }       /* parse error */
-
-<*><<EOF>>             {
-                           if (YY_START != INITIAL) {
-                               BEGIN INITIAL;
-                               LEXTRACE("ERROR ");
-                               return ERROR;
-                           }
-                           if (!pop_include())
-                               yyterminate();
-                       }
-
-%%
-struct path_list {
-    char *path;
-    struct path_list *next;
-};
-
-struct include_stack {
-    YY_BUFFER_STATE bs;
-    char *path;
-    struct path_list *more; /* more files in case of includedir */
-    int lineno;
-    int keepopen;
-};
-
-static int
-pl_compare(v1, v2)
-    const void *v1;
-    const void *v2;
-{
-    const struct path_list * const *p1 = v1;
-    const struct path_list * const *p2 = v2;
-
-    return strcmp((*p1)->path, (*p2)->path);
-}
-
-static char *
-switch_dir(stack, dirpath)
-    struct include_stack *stack;
-    char *dirpath;
-{
-    DIR *dir;
-    int i, count = 0;
-    char *path = NULL;
-    struct dirent *dent;
-    struct stat sb;
-    struct path_list *pl, *first = NULL;
-    struct path_list **sorted = NULL;
-
-    if (!(dir = opendir(dirpath))) {
-       if (errno != ENOENT) {
-           char *errbuf;
-           if (asprintf(&errbuf, "%s: %s", dirpath, strerror(errno)) != -1) {
-               yyerror(errbuf);
-               free(errbuf);
-           } else {
-               yyerror("unable to allocate memory");
-           }
-       }
-       goto done;
-    }
-    while ((dent = readdir(dir))) {
-       /* Ignore files that end in '~' or have a '.' in them. */
-       if (dent->d_name[0] == '\0' || dent->d_name[NAMLEN(dent) - 1] == '~'
-           || strchr(dent->d_name, '.') != NULL) {
-           continue;
-       }
-       if (asprintf(&path, "%s/%s", dirpath, dent->d_name) == -1) {
-           closedir(dir);
-           goto bad;
-       }
-       if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)) {
-           efree(path);
-           path = NULL;
-           continue;
-       }
-       pl = malloc(sizeof(*pl));
-       if (pl == NULL)
-           goto bad;
-       pl->path = path;
-       pl->next = first;
-       first = pl;
-       count++;
-    }
-    closedir(dir);
-
-    if (count == 0)
-       goto done;
-
-    /* Sort the list as an array. */
-    sorted = malloc(sizeof(*sorted) * count);
-    if (sorted == NULL)
-       goto bad;
-    pl = first;
-    for (i = 0; i < count; i++) {
-       sorted[i] = pl;
-       pl = pl->next;
-    }
-    qsort(sorted, count, sizeof(*sorted), pl_compare);
-
-    /* Apply sorting to the list. */
-    first = sorted[0];
-    sorted[count - 1]->next = NULL;
-    for (i = 1; i < count; i++)
-       sorted[i - 1]->next = sorted[i];
-    efree(sorted);
-
-    /* Pull out the first element for parsing, leave the rest for later. */
-    if (count) {
-       path = first->path;
-       pl = first->next;
-       efree(first);
-       stack->more = pl;
-    } else {
-       path = NULL;
-    }
-done:
-    efree(dirpath);
-    return path;
-bad:
-    while (first != NULL) {
-       pl = first;
-       first = pl->next;
-       free(pl->path);
-       free(pl);
-    }
-    efree(sorted);
-    efree(dirpath);
-    efree(path);
-    return NULL;
-}
-
-#define MAX_SUDOERS_DEPTH      128
-#define SUDOERS_STACK_INCREMENT        16
-
-static size_t istacksize, idepth;
-static struct include_stack *istack;
-static int keepopen;
-
-void
-init_lexer()
-{
-    struct path_list *pl;
-
-    while (idepth) {
-       idepth--;
-       while ((pl = istack[idepth].more) != NULL) {
-           istack[idepth].more = pl->next;
-           efree(pl->path);
-           efree(pl);
-       }
-       efree(istack[idepth].path);
-       if (idepth && !istack[idepth].keepopen)
-           fclose(istack[idepth].bs->yy_input_file);
-       yy_delete_buffer(istack[idepth].bs);
-    }
-    efree(istack);
-    istack = NULL;
-    istacksize = idepth = 0;
-    sudolineno = 1;
-    keepopen = FALSE;
-    sawspace = FALSE;
-    continued = FALSE;
-    prev_state = INITIAL;
-}
-
-static int
-_push_include(path, isdir)
-    char *path;
-    int isdir;
-{
-    struct path_list *pl;
-    FILE *fp;
-
-    /* push current state onto stack */
-    if (idepth >= istacksize) {
-       if (idepth > MAX_SUDOERS_DEPTH) {
-           yyerror("too many levels of includes");
-           return FALSE;
-       }
-       istacksize += SUDOERS_STACK_INCREMENT;
-       istack = (struct include_stack *) realloc(istack,
-           sizeof(*istack) * istacksize);
-       if (istack == NULL) {
-           yyerror("unable to allocate memory");
-           return FALSE;
-       }
-    }
-    if (isdir) {
-       if (!(path = switch_dir(&istack[idepth], path))) {
-           /* switch_dir() called yyerror() for us */
-           return FALSE;
-       }
-       while ((fp = open_sudoers(path, FALSE, &keepopen)) == NULL) {
-           /* Unable to open path in includedir, go to next one, if any. */
-           efree(path);
-           if ((pl = istack[idepth].more) == NULL)
-               return FALSE;
-           path = pl->path;
-           istack[idepth].more = pl->next;
-           efree(pl);
-       }
-    } else {
-       if ((fp = open_sudoers(path, TRUE, &keepopen)) == NULL) {
-           char *errbuf;
-           if (asprintf(&errbuf, "%s: %s", path, strerror(errno)) != -1) {
-               yyerror(errbuf);
-               free(errbuf);
-           } else {
-               yyerror("unable to allocate memory");
-           }
-           return FALSE;
-       }
-       istack[idepth].more = NULL;
-    }
-    /* Push the old (current) file and open the new one. */
-    istack[idepth].path = sudoers; /* push old path */
-    istack[idepth].bs = YY_CURRENT_BUFFER;
-    istack[idepth].lineno = sudolineno;
-    istack[idepth].keepopen = keepopen;
-    idepth++;
-    sudolineno = 1;
-    sudoers = path;
-    yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
-
-    return TRUE;
-}
-
-static int
-pop_include()
-{
-    struct path_list *pl;
-    FILE *fp;
-
-    if (idepth == 0)
-       return FALSE;
-
-    if (!keepopen)
-       fclose(YY_CURRENT_BUFFER->yy_input_file);
-    yy_delete_buffer(YY_CURRENT_BUFFER);
-    /* If we are in an include dir, move to the next file. */
-    while ((pl = istack[idepth - 1].more) != NULL) {
-       fp = open_sudoers(pl->path, FALSE, &keepopen);
-       if (fp != NULL) {
-           istack[idepth - 1].more = pl->next;
-           efree(sudoers);
-           sudoers = pl->path;
-           sudolineno = 1;
-           yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
-           efree(pl);
-           break;
-       }
-       /* Unable to open path in include dir, go to next one. */
-       istack[idepth - 1].more = pl->next;
-       efree(pl->path);
-       efree(pl);
-    }
-    /* If no path list, just pop the last dir on the stack. */
-    if (pl == NULL) {
-       idepth--;
-       yy_switch_to_buffer(istack[idepth].bs);
-       efree(sudoers);
-       sudoers = istack[idepth].path;
-       sudolineno = istack[idepth].lineno;
-       keepopen = istack[idepth].keepopen;
-    }
-    return TRUE;
-}
-
-static char *
-parse_include(base)
-    char *base;
-{
-    char *cp, *ep, *path;
-    int len = 0, subst = 0;
-    size_t shost_len = 0;
-
-    /* Pull out path from #include line. */
-    cp = base + sizeof("#include");
-    if (*cp == 'i')
-       cp += 3; /* includedir */
-    while (isblank((unsigned char) *cp))
-       cp++;
-    ep = cp;
-    while (*ep != '\0' && !isspace((unsigned char) *ep)) {
-       if (ep[0] == '%' && ep[1] == 'h') {
-           shost_len = strlen(user_shost);
-           len += shost_len - 2;
-           subst = 1;
-       }
-       ep++;
-    }
-
-    /* Make a copy of path and return it. */
-    len += (int)(ep - cp);
-    if ((path = malloc(len + 1)) == NULL)
-       yyerror("unable to allocate memory");
-    if (subst) {
-       /* substitute for %h */
-       char *pp = path;
-       while (cp < ep) {
-           if (cp[0] == '%' && cp[1] == 'h') {
-               memcpy(pp, user_shost, shost_len);
-               pp += shost_len;
-               cp += 2;
-               continue;
-           }
-           *pp++ = *cp++;
-       }
-       *pp = '\0';
-    } else {
-       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;
-}
diff --git a/toke_util.c b/toke_util.c
deleted file mode 100644 (file)
index 99e7552..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-2005, 2007-2011
- *     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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_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 "toke.h"
-#include <gram.h>
-
-static int arg_len = 0;
-static int arg_size = 0;
-
-static unsigned char
-hexchar(s)
-    const char *s;
-{
-    int i;
-    int result = 0;
-
-    s += 2; /* skip \\x */
-    for (i = 0; i < 2; i++) {
-       switch (*s) {
-       case 'A':
-       case 'a':
-           result += 10;
-           break;
-       case 'B':
-       case 'b':
-           result += 11;
-           break;
-       case 'C':
-       case 'c':
-           result += 12;
-           break;
-       case 'D':
-       case 'd':
-           result += 13;
-           break;
-       case 'E':
-       case 'e':
-           result += 14;
-           break;
-       case 'F':
-       case 'f':
-           result += 15;
-           break;
-       default:
-           result += *s - '0';
-           break;
-       }
-       if (i == 0) {
-           result *= 16;
-           s++;
-       }
-    }
-    return (unsigned char)result;
-}
-
-int
-fill_txt(src, len, olen)
-    char *src;
-    int len, olen;
-{
-    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;
-    while (len--) {
-       if (*src == '\\' && len) {
-           if (src[1] == 'x' && len >= 3 && 
-               isxdigit((unsigned char) src[2]) &&
-               isxdigit((unsigned char) src[3])) {
-               *dst++ = hexchar(src);
-               src += 4;
-               len -= 3;
-           } else {
-               src++;
-               len--;
-               *dst++ = *src++;
-           }
-       } else {
-           *dst++ = *src++;
-       }
-    }
-    *dst = '\0';
-    return TRUE;
-}
-
-int
-append(src, len)
-    char *src;
-    int len;
-{
-    int olen = 0;
-
-    if (yylval.string != NULL)
-       olen = strlen(yylval.string);
-
-    return fill_txt(src, len, olen);
-}
-
-#define SPECIAL(c) \
-    ((c) == ',' || (c) == ':' || (c) == '=' || (c) == ' ' || (c) == '\t' || (c) == '#')
-
-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;
-}
-
-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;
-}
-
-/*
- * 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.
- */
-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
deleted file mode 100644 (file)
index 5b38298..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (c) 2005, 2008, 2010 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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#include <fcntl.h>
-#include <limits.h>
-
-#include "tsgetgrpw.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
-setpwfile(file)
-    const char *file;
-{
-    pwfile = file;
-    if (pwf != NULL)
-       endpwent();
-}
-
-void
-setpwent()
-{
-    if (pwf == NULL) {
-       pwf = fopen(pwfile, "r");
-       if (pwf != NULL)
-           fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
-    } else {
-       rewind(pwf);
-    }
-    pw_stayopen = 1;
-}
-
-void
-endpwent()
-{
-    if (pwf != NULL) {
-       fclose(pwf);
-       pwf = NULL;
-    }
-    pw_stayopen = 0;
-}
-
-struct passwd *
-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 *
-getpwnam(name)
-    const char *name;
-{
-    struct passwd *pw;
-
-    if (pwf == NULL) {
-       if ((pwf = fopen(pwfile, "r")) == NULL)
-           return NULL;
-       fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
-    } else {
-       rewind(pwf);
-    }
-    while ((pw = getpwent()) != NULL) {
-       if (strcmp(pw->pw_name, name) == 0)
-           break;
-    }
-    if (!pw_stayopen) {
-       fclose(pwf);
-       pwf = NULL;
-    }
-    return pw;
-}
-
-struct passwd *
-getpwuid(uid)
-    uid_t uid;
-{
-    struct passwd *pw;
-
-    if (pwf == NULL) {
-       if ((pwf = fopen(pwfile, "r")) == NULL)
-           return NULL;
-       fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
-    } else {
-       rewind(pwf);
-    }
-    while ((pw = getpwent()) != NULL) {
-       if (pw->pw_uid == uid)
-           break;
-    }
-    if (!pw_stayopen) {
-       fclose(pwf);
-       pwf = NULL;
-    }
-    return pw;
-}
-
-void
-setgrfile(file)
-    const char *file;
-{
-    grfile = file;
-    if (grf != NULL)
-       endgrent();
-}
-
-void
-setgrent()
-{
-    if (grf == NULL) {
-       grf = fopen(grfile, "r");
-       if (grf != NULL)
-           fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
-    } else {
-       rewind(grf);
-    }
-    gr_stayopen = 1;
-}
-
-void
-endgrent()
-{
-    if (grf != NULL) {
-       fclose(grf);
-       grf = NULL;
-    }
-    gr_stayopen = 0;
-}
-
-struct group *
-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 *
-getgrnam(name)
-    const char *name;
-{
-    struct group *gr;
-
-    if (grf == NULL) {
-       if ((grf = fopen(grfile, "r")) == NULL)
-           return NULL;
-       fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
-    } else {
-       rewind(grf);
-    }
-    while ((gr = getgrent()) != NULL) {
-       if (strcmp(gr->gr_name, name) == 0)
-           break;
-    }
-    if (!gr_stayopen) {
-       fclose(grf);
-       grf = NULL;
-    }
-    return gr;
-}
-
-struct group *
-getgrgid(gid)
-    gid_t gid;
-{
-    struct group *gr;
-
-    if (grf == NULL) {
-       if ((grf = fopen(grfile, "r")) == NULL)
-           return NULL;
-       fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
-    } else {
-       rewind(grf);
-    }
-    while ((gr = getgrent()) != NULL) {
-       if (gr->gr_gid == gid)
-           break;
-    }
-    if (!gr_stayopen) {
-       fclose(grf);
-       grf = NULL;
-    }
-    return gr;
-}
diff --git a/utimes.c b/utimes.c
deleted file mode 100644 (file)
index 5ff4379..0000000
--- a/utimes.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <stdio.h>
-#if TIME_WITH_SYS_TIME
-# include <time.h>
-#endif
-
-#ifdef HAVE_UTIME_H
-# include <utime.h>
-#else
-# include "emul/utime.h"
-#endif
-
-#include "missing.h"
-
-#ifndef HAVE_UTIMES
-/*
- * Emulate utimes() via utime()
- */
-int
-utimes(file, times)
-    const char *file;
-    const struct timeval *times;
-{
-    if (times != NULL) {
-       struct utimbuf utb;
-
-       utb.actime = (time_t)(times[0].tv_sec + times[0].tv_usec / 1000000);
-       utb.modtime = (time_t)(times[1].tv_sec + times[1].tv_usec / 1000000);
-       return utime(file, &utb);
-    } else
-       return utime(file, NULL);
-}
-#endif /* !HAVE_UTIMES */
-
-#ifdef HAVE_FUTIME
-/*
- * Emulate futimes() via futime()
- */
-int
-futimes(fd, times)
-    int fd;
-    const struct timeval *times;
-{
-    if (times != NULL) {
-       struct utimbuf utb;
-
-       utb.actime = (time_t)(times[0].tv_sec + times[0].tv_usec / 1000000);
-       utb.modtime = (time_t)(times[1].tv_sec + times[1].tv_usec / 1000000);
-       return futime(fd, &utb);
-    } else
-       return futime(fd, NULL);
-}
-#endif /* HAVE_FUTIME */
diff --git a/vasgroups.c b/vasgroups.c
deleted file mode 100644 (file)
index 0ba33e1..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * (c) 2006 Quest Software, Inc.  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. Neither the name of Quest Software, Inc. 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 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 <stdlib.h>
-#include <sys/types.h>
-#include <pwd.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <dlfcn.h>
-
-#include <vas.h>
-
-#include "missing.h"
-#include "logging.h"
-#include "nonunix.h"
-#include "sudo.h"
-#include "parse.h"
-
-
-/* Pseudo-boolean types */
-#undef TRUE
-#undef FALSE
-#define FALSE 0
-#define TRUE  1
-
-
-static vas_ctx_t *sudo_vas_ctx;
-static vas_id_t  *sudo_vas_id;
-/* Don't use VAS_NAME_FLAG_NO_CACHE or lookups just won't work.
- * -tedp, 2006-08-29 */
-static const int update_flags = 0;
-static int sudo_vas_available = 0;
-static char *err_msg = NULL;
-static void *libvas_handle = NULL;
-
-/* libvas functions */
-static vas_err_t       (*v_ctx_alloc) (vas_ctx_t **ctx);
-static void            (*v_ctx_free) (vas_ctx_t *ctx);
-static vas_err_t       (*v_id_alloc) (vas_ctx_t *ctx, const char *name, vas_id_t **id);
-static void            (*v_id_free) (vas_ctx_t *ctx, vas_id_t *id);
-static vas_err_t       (*v_id_establish_cred_keytab) (vas_ctx_t *ctx, vas_id_t *id, int credflags, const char *keytab);
-static vas_err_t       (*v_user_init) (vas_ctx_t *ctx, vas_id_t *id, const char *name, int flags, vas_user_t **user);
-static void            (*v_user_free) (vas_ctx_t *ctx, vas_user_t *user);
-static vas_err_t       (*v_group_init) (vas_ctx_t *ctx, vas_id_t *id, const char *name, int flags, vas_group_t **group);
-static void            (*v_group_free) (vas_ctx_t *ctx, vas_group_t *group);
-static vas_err_t       (*v_user_is_member) (vas_ctx_t *ctx, vas_id_t *id, vas_user_t *user, vas_group_t *group);
-static const char*     (*v_err_get_string) (vas_ctx_t *ctx, int with_cause);
-
-
-static int     resolve_vas_funcs(void);
-
-
-/**
- * Whether nonunix group lookups are available.
- * @return 1 if available, 0 if not.
- */
-int
-sudo_nonunix_groupcheck_available(void)
-{
-    return sudo_vas_available;
-}
-
-
-/**
- * Check if the user is in the group
- * @param group group name which can be in DOMAIN\sam format or just the group
- *              name
- * @param user user name
- * @param pwd (unused)
- * @return 1 if user is a member of the group, 0 if not (or error occurred)
- */
-int
-sudo_nonunix_groupcheck( const char* group, const char* user, const struct passwd* pwd )
-{
-    static int          error_cause_shown = FALSE;
-    int                 rval = FALSE;
-    vas_err_t           vaserr;
-    vas_user_t*         vas_user = NULL;
-    vas_group_t*        vas_group = NULL;
-
-    if (!sudo_vas_available) {
-       if (error_cause_shown == FALSE) {
-           /* Produce the saved error reason */
-           warningx("Non-unix group checking unavailable: %s",
-                   err_msg ? err_msg
-                   : "(unknown cause)");
-           error_cause_shown = TRUE;
-       }
-       return 0;
-    }
-
-    /* resolve the user and group. The user will be a real Unix account name,
-     * while the group may be a unix name, or any group name accepted by
-     * vas_name_to_dn, which means any of:
-     * - Group Name
-     * - Group Name@FULLY.QUALIFIED.DOMAIN
-     * - CN=sudoers,CN=Users,DC=rcdev,DC=vintela,DC=com
-     * - S-1-2-34-5678901234-5678901234-5678901234-567
-     *
-     * XXX - we may get non-VAS user accounts here. You can add local users to an
-     * Active Directory group through override files. Should we handle that case?
-     * */
-    if( (vaserr = v_user_init( sudo_vas_ctx, sudo_vas_id, user, update_flags, &vas_user )) != VAS_ERR_SUCCESS ) {
-       if (vaserr == VAS_ERR_NOT_FOUND) {
-            /* No such user in AD. Probably a local user. */
-           vaserr = VAS_ERR_SUCCESS;
-       }
-        goto FINISHED;
-    }
-        
-    if( (vaserr = v_group_init( sudo_vas_ctx, sudo_vas_id, group, update_flags, &vas_group )) != VAS_ERR_SUCCESS ) {
-        goto FINISHED;
-    }
-
-    /* do the membership check */
-    if( (vaserr = v_user_is_member( sudo_vas_ctx, sudo_vas_id, vas_user, vas_group )) == VAS_ERR_SUCCESS ) {
-        rval = TRUE;
-    }
-    else if (vaserr == VAS_ERR_NOT_FOUND) {
-       /* fake the vaserr code so no error is triggered */
-       vaserr = VAS_ERR_SUCCESS;
-    }
-
-
-FINISHED: /* cleanups */
-    if (vaserr != VAS_ERR_SUCCESS && vaserr != VAS_ERR_NOT_FOUND ) {
-       warningx("Error while checking group membership "
-               "for user \"%s\", group \"%s\", error: %s%s.", user, group,
-               v_err_get_string(sudo_vas_ctx, 1),
-               /* A helpful hint if there seems to be a non-FQDN as the domain */
-               (strchr(group, '@') && !strchr(group, '.'))
-                ? "\nMake sure the fully qualified domain name is specified"
-                : "");
-    }
-    if( vas_group )              v_group_free( sudo_vas_ctx, vas_group );
-    if( vas_user )              v_user_free( sudo_vas_ctx, vas_user );
-
-    return rval;
-}
-
-
-static void
-set_err_msg(const char *msg, ...) {
-    va_list ap;
-
-    if (!msg) /* assert */
-       return;
-
-    if (err_msg)
-       free(err_msg);
-
-    va_start(ap, msg);
-
-    if (vasprintf(&err_msg, msg, ap) == -1)
-       err_msg = NULL;
-       
-    va_end(ap);
-}
-
-
-/**
- * Initialise nonunix_groupcheck state.
- */
-void
-sudo_nonunix_groupcheck_init(void)
-{
-    vas_err_t vaserr;
-    void *libvas;
-
-    if (err_msg) {
-       free(err_msg);
-       err_msg = NULL;
-    }
-
-    libvas = dlopen(LIBVAS_SO, RTLD_LAZY);
-    if (!libvas) {
-       set_err_msg("dlopen() failed: %s", dlerror());
-       return;
-    }
-
-    libvas_handle = libvas;
-
-    if (resolve_vas_funcs() != 0)
-       return;
-
-    if (VAS_ERR_SUCCESS == (vaserr = v_ctx_alloc(&sudo_vas_ctx))) {
-
-       if (VAS_ERR_SUCCESS == (vaserr = v_id_alloc(sudo_vas_ctx, "host/", &sudo_vas_id))) {
-       
-           if (update_flags & VAS_NAME_FLAG_NO_LDAP) {
-               sudo_vas_available = 1;
-               return; /* OK */
-           } else { /* Get a keytab */
-               if ((vaserr = v_id_establish_cred_keytab( sudo_vas_ctx,
-                                                   sudo_vas_id,
-                                                     VAS_ID_FLAG_USE_MEMORY_CCACHE
-                                                   | VAS_ID_FLAG_KEEP_COPY_OF_CRED
-                                                   | VAS_ID_FLAG_NO_INITIAL_TGT,
-                                                   NULL )) == VAS_ERR_SUCCESS) {
-                   sudo_vas_available = 1;
-                   return; /* OK */
-               }
-
-               if (!err_msg)
-                   set_err_msg("unable to establish creds: %s",
-                           v_err_get_string(sudo_vas_ctx, 1));
-           }
-
-           v_id_free(sudo_vas_ctx, sudo_vas_id);
-           sudo_vas_id = NULL;
-       }
-
-       /* This is the last opportunity to get an error message from libvas */
-       if (!err_msg)
-           set_err_msg("Error initializing non-unix group checking: %s",
-                   v_err_get_string(sudo_vas_ctx, 1));
-
-       v_ctx_free(sudo_vas_ctx);
-       sudo_vas_ctx = NULL;
-    }
-
-    if (!err_msg)
-       set_err_msg("Failed to get a libvas handle for non-unix group checking (unknown cause)");
-
-    sudo_vas_available = 0;
-}
-
-
-/**
- * Clean up nonunix_groupcheck state.
- */
-void
-sudo_nonunix_groupcheck_cleanup()
-{
-    if (err_msg) {
-       free(err_msg);
-       err_msg = NULL;
-    }
-
-    if (sudo_vas_available) {
-       v_id_free(sudo_vas_ctx, sudo_vas_id);
-       sudo_vas_id = NULL;
-
-       v_ctx_free(sudo_vas_ctx);
-       sudo_vas_ctx = NULL;
-
-       sudo_vas_available = FALSE;
-    }
-
-    if (libvas_handle) {
-       if (dlclose(libvas_handle) != 0)
-           warningx("dlclose() failed: %s", dlerror());
-       libvas_handle = NULL;
-    }
-}
-
-#define RESOLVE_OR_ERR(fptr, sym) \
-    do { \
-       void *_fptr = dlsym(libvas_handle, (sym)); \
-       if (!_fptr) { \
-           set_err_msg("dlsym() failed: %s", dlerror()); \
-           return -1; \
-       } \
-       fptr = _fptr; \
-    } while (0)
-
-
-/**
- * Resolve all the libvas functions.
- * Returns -1 and sets err_msg if something went wrong, or 0 on success.
- */
-int
-resolve_vas_funcs(void)
-{
-    if (!libvas_handle) /* assert */
-       return -1;
-
-    RESOLVE_OR_ERR(v_ctx_alloc,        "vas_ctx_alloc");
-    RESOLVE_OR_ERR(v_ctx_free, "vas_ctx_free");
-    RESOLVE_OR_ERR(v_id_alloc, "vas_id_alloc");
-    RESOLVE_OR_ERR(v_id_free,  "vas_id_free");
-    RESOLVE_OR_ERR(v_id_establish_cred_keytab, "vas_id_establish_cred_keytab");
-    RESOLVE_OR_ERR(v_user_init,        "vas_user_init");
-    RESOLVE_OR_ERR(v_user_free,        "vas_user_free");
-    RESOLVE_OR_ERR(v_group_init,       "vas_group_init");
-    RESOLVE_OR_ERR(v_group_free,       "vas_group_free");
-    RESOLVE_OR_ERR(v_user_is_member,   "vas_user_is_member");
-    RESOLVE_OR_ERR(v_err_get_string,   "vas_err_get_string");
-
-    return 0;
-}
diff --git a/visudo.c b/visudo.c
deleted file mode 100644 (file)
index bc77377..0000000
--- a/visudo.c
+++ /dev/null
@@ -1,1214 +0,0 @@
-/*
- * Copyright (c) 1996, 1998-2005, 2007-2010
- *     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.
- */
-
-/*
- * Lock the sudoers file for safe editing (ala vipw) and check for parse errors.
- */
-
-#define _SUDO_MAIN
-
-#ifdef __TANDEM
-# include <floss.h>
-#endif
-
-#include <config.h>
-
-#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>
-#endif
-#include <sys/wait.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>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <ctype.h>
-#include <pwd.h>
-#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
-
-#include "sudo.h"
-#include "interfaces.h"
-#include "parse.h"
-#include "redblack.h"
-#include <gram.h>
-
-struct sudoersfile {
-    struct sudoersfile *prev, *next;
-    char *path;
-    char *tpath;
-    int fd;
-    int modified;
-    int doedit;
-};
-TQ_DECLARE(sudoersfile)
-
-/*
- * Function prototypes
- */
-static RETSIGTYPE quit         __P((int));
-static char *get_args          __P((char *));
-static char *get_editor                __P((char **));
-static void get_hostname       __P((void));
-static char whatnow            __P((void));
-static int check_aliases       __P((int, 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 print_selfref      __P((char *, int, int, int));
-static void print_undefined    __P((char *, int, int, int));
-static void setup_signals      __P((void));
-static void help               __P((void)) __attribute__((__noreturn__));
-static void usage              __P((int));
-
-extern void yyerror            __P((const char *));
-extern void yyrestart          __P((FILE *));
-
-/*
- * External globals exported by the parser
- */
-extern struct rbtree *aliases;
-extern FILE *yyin;
-extern char *sudoers, *errorfile;
-extern int errorlineno, parse_error;
-/* For getopt(3) */
-extern char *optarg;
-extern int optind;
-
-/*
- * Globals
- */
-int Argc;
-char **Argv;
-int num_interfaces;
-struct interface *interfaces;
-struct sudo_user sudo_user;
-struct passwd *list_pw;
-static struct sudoersfile_list sudoerslist;
-static struct rbtree *alias_freelist;
-
-int
-main(argc, argv)
-    int argc;
-    char **argv;
-{
-    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)
-       usage(1);
-
-    /*
-     * Arg handling.
-     */
-    checkonly = oldperms = quiet = strict = FALSE;
-    sudoers_path = _PATH_SUDOERS;
-    while ((ch = getopt(argc, argv, "Vcf:hsq")) != -1) {
-       switch (ch) {
-           case 'V':
-               (void) printf("%s version %s\n", getprogname(), PACKAGE_VERSION);
-               exit(0);
-           case 'c':
-               checkonly++;            /* check mode */
-               break;
-           case 'f':
-               sudoers_path = optarg;  /* sudoers file path */
-               oldperms = TRUE;
-               break;
-           case 'h':
-               help();
-               break;
-           case 's':
-               strict++;               /* strict mode */
-               break;
-           case 'q':
-               quiet++;                /* quiet mode */
-               break;
-           default:
-               usage(1);
-       }
-    }
-    argc -= optind;
-    argv += optind;
-    if (argc)
-       usage(1);
-
-    sudo_setpwent();
-    sudo_setgrent();
-
-    /* Mock up a fake sudo_user struct. */
-    user_cmnd = "";
-    if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL)
-       errorx(1, "you don't exist in the passwd database");
-    get_hostname();
-
-    /* Setup defaults data structures. */
-    init_defaults();
-
-    if (checkonly)
-       exit(check_syntax(sudoers_path, quiet, strict));
-
-    /*
-     * 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, TRUE, NULL)) == NULL) {
-       error(1, "%s", sudoers_path);
-    }
-    init_parser(sudoers_path, 0);
-    yyparse();
-    (void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER);
-
-    editor = get_editor(&args);
-
-    /* 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->doedit)
-           continue;
-       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 each sudoers file.
- * Returns TRUE on success, else FALSE.
- */
-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 timeval tv, tv1, tv2;       /* time before and after edit */
-    struct timeval 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 */
-
-#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;
-    mtim_get(&sb, &orig_mtim);
-
-    /* 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';
-               if (write(tfd, buf, 1) != 1)
-                   error(1, "write error");
-           }
-       }
-       (void) close(tfd);
-    }
-    (void) touch(-1, sp->tpath, &orig_mtim);
-
-    /* Find the length of the argument vector */
-    ac = 3 + (lineno > 0);
-    if (args) {
-        int wasblank;
-
-        ac++;
-        for (wasblank = FALSE, cp = args; *cp; cp++) {
-            if (isblank((unsigned char) *cp))
-                wasblank = TRUE;
-            else if (wasblank) {
-                wasblank = FALSE;
-                ac++;
-            }
-        }
-    }
-
-    /* Build up argument vector for the command */
-    av = emalloc2(ac, sizeof(char *));
-    if ((av[0] = strrchr(editor, '/')) != NULL)
-       av[0]++;
-    else
-       av[0] = editor;
-    ac = 1;
-    if (lineno > 0) {
-       (void) snprintf(linestr, sizeof(linestr), "+%d", lineno);
-       av[ac++] = linestr;
-    }
-    if (args) {
-       for ((cp = strtok(args, " \t")); cp; (cp = strtok(NULL, " \t")))
-           av[ac++] = cp;
-    }
-    av[ac++] = sp->tpath;
-    av[ac++] = NULL;
-
-    /*
-     * Do the edit:
-     *  We cannot check the editor's exit value against 0 since
-     *  XPG4 specifies that vi's exit value is a function of the
-     *  number of errors during editing (?!?!).
-     */
-    gettime(&tv1);
-    if (run_command(editor, av) != -1) {
-       gettime(&tv2);
-       /*
-        * Sanity checks.
-        */
-       if (stat(sp->tpath, &sb) < 0) {
-           warningx("cannot stat temporary file (%s), %s unchanged",
-               sp->tpath, sp->path);
-           return FALSE;
-       }
-       if (sb.st_size == 0 && orig_size != 0) {
-           warningx("zero length temporary file (%s), %s unchanged",
-               sp->tpath, sp->path);
-           sp->modified = TRUE;
-           return FALSE;
-       }
-    } else {
-       warningx("editor (%s) failed, %s unchanged", editor, sp->path);
-       return FALSE;
-    }
-
-    /* Set modified bit if use changed the file. */
-    modified = TRUE;
-    mtim_get(&sb, &tv);
-    if (orig_size == sb.st_size && timevalcmp(&orig_mtim, &tv, ==)) {
-       /*
-        * If mtime and size match but the user spent no measurable
-        * time in the editor we can't tell if the file was changed.
-        */
-       timevalsub(&tv1, &tv2);
-       if (timevalisset(&tv2))
-           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 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 files and do sanity checking
-     */
-    do {
-       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);
-
-       /* Clean slate for each parse */
-       init_defaults();
-       init_parser(sp->path, quiet);
-
-       /* Parse the sudoers temp file */
-       yyrestart(fp);
-       if (yyparse() && !parse_error) {
-           warningx("unabled to parse temporary file (%s), unknown error",
-               sp->tpath);
-           parse_error = TRUE;
-           errorfile = sp->path;
-       }
-       fclose(yyin);
-       if (!parse_error) {
-           if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER) ||
-               check_aliases(strict, quiet) != 0) {
-               parse_error = TRUE;
-               errorfile = sp->path;
-           }
-       }
-
-       /*
-        * Got an error, prompt the user for what to do now
-        */
-       if (parse_error) {
-           switch (whatnow()) {
-               case 'Q' :      parse_error = FALSE;    /* ignore parse error */
-                               break;
-               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 int
-install_sudoers(sp, oldperms)
-    struct sudoersfile *sp;
-    int oldperms;
-{
-    struct stat sb;
-
-    /*
-     * Change mode and ownership of temp file so when
-     * we move it to sp->path things are kosher.
-     */
-    if (oldperms) {
-       /* Use perms of the existing file.  */
-#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);
-       if (chown(sp->tpath, sb.st_uid, sb.st_gid) != 0) {
-           warning("unable to set (uid, gid) of %s to (%d, %d)",
-               sp->tpath, sb.st_uid, sb.st_gid);
-       }
-       if (chmod(sp->tpath, sb.st_mode & 0777) != 0) {
-           warning("unable to change mode of %s to 0%o", sp->tpath,
-               (sb.st_mode & 0777));
-       }
-    } else {
-       if (chown(sp->tpath, SUDOERS_UID, SUDOERS_GID) != 0) {
-           warning("unable to set (uid, gid) of %s to (%d, %d)",
-               sp->tpath, SUDOERS_UID, SUDOERS_GID);
-           return FALSE;
-       }
-       if (chmod(sp->tpath, SUDOERS_MODE) != 0) {
-           warning("unable to change mode of %s to 0%o", sp->tpath,
-               SUDOERS_MODE);
-           return FALSE;
-       }
-    }
-
-    /*
-     * Now that sp->tpath is sane (parses ok) it needs to be
-     * 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) {
-       efree(sp->tpath);
-       sp->tpath = NULL;
-    } else {
-       if (errno == EXDEV) {
-           char *av[4];
-           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 */
-           if ((av[0] = strrchr(_PATH_MV, '/')) != NULL)
-               av[0]++;
-           else
-               av[0] = _PATH_MV;
-           av[1] = sp->tpath;
-           av[2] = sp->path;
-           av[3] = NULL;
-
-           /* And run it... */
-           if (run_command(_PATH_MV, av)) {
-               warningx("command failed: '%s %s %s', %s unchanged",
-                   _PATH_MV, sp->tpath, sp->path, sp->path);
-               (void) unlink(sp->tpath);
-               efree(sp->tpath);
-               sp->tpath = NULL;
-               return FALSE;
-           }
-           efree(sp->tpath);
-           sp->tpath = NULL;
-       } else {
-           warning("error renaming %s, %s unchanged", sp->tpath, sp->path);
-           (void) unlink(sp->tpath);
-           return FALSE;
-       }
-    }
-    return TRUE;
-}
-
-/* STUB */
-void
-set_fqdn()
-{
-    return;
-}
-
-/* STUB */
-void
-init_envtables()
-{
-    return;
-}
-
-/* STUB */
-int
-user_is_exempt()
-{
-    return FALSE;
-}
-
-/* STUB */
-void
-sudo_setspent()
-{
-    return;
-}
-
-/* STUB */
-void
-sudo_endspent()
-{
-    return;
-}
-
-char *
-sudo_getepw(pw)
-    const struct passwd *pw;
-{
-    return pw->pw_passwd;
-}
-
-/*
- * Assuming a parse error occurred, prompt the user for what they want
- * to do now.  Returns the first letter of their choice.
- */
-static char
-whatnow()
-{
-    int choice, c;
-
-    for (;;) {
-       (void) fputs("What now? ", stdout);
-       choice = getchar();
-       for (c = choice; c != '\n' && c != EOF;)
-           c = getchar();
-
-       switch (choice) {
-           case EOF:
-               choice = 'x';
-               /* FALLTHROUGH */
-           case 'e':
-           case 'x':
-           case 'Q':
-               return choice;
-           default:
-               (void) puts("Options are:");
-               (void) puts("  (e)dit sudoers file again");
-               (void) puts("  e(x)it without saving changes to sudoers file");
-               (void) puts("  (Q)uit and save changes to sudoers file (DANGER!)\n");
-       }
-    }
-}
-
-/*
- * Install signal handlers for visudo.
- */
-static void
-setup_signals()
-{
-       sigaction_t sa;
-
-       /*
-        * Setup signal handlers to cleanup nicely.
-        */
-       zero_bytes(&sa, sizeof(sa));
-       sigemptyset(&sa.sa_mask);
-       sa.sa_flags = SA_RESTART;
-       sa.sa_handler = quit;
-       (void) sigaction(SIGTERM, &sa, NULL);
-       (void) sigaction(SIGHUP, &sa, NULL);
-       (void) sigaction(SIGINT, &sa, NULL);
-       (void) sigaction(SIGQUIT, &sa, NULL);
-}
-
-static int
-run_command(path, argv)
-    char *path;
-    char **argv;
-{
-    int status;
-    pid_t pid, rv;
-
-    switch (pid = fork()) {
-       case -1:
-           error(1, "unable to run %s", path);
-           break;      /* NOTREACHED */
-       case 0:
-           sudo_endpwent();
-           sudo_endgrent();
-           closefrom(STDERR_FILENO + 1);
-           execv(path, argv);
-           warning("unable to run %s", path);
-           _exit(127);
-           break;      /* NOTREACHED */
-    }
-
-    do {
-#ifdef sudo_waitpid
-       rv = sudo_waitpid(pid, &status, 0);
-#else
-       rv = wait(&status);
-#endif
-    } while (rv == -1 && errno == EINTR);
-
-    if (rv == -1 || !WIFEXITED(status))
-       return -1;
-    return WEXITSTATUS(status);
-}
-
-static int
-check_syntax(sudoers_path, quiet, strict)
-    char *sudoers_path;
-    int quiet;
-    int strict;
-{
-    struct stat sb;
-    int error;
-
-    if (strcmp(sudoers_path, "-") == 0) {
-       yyin = stdin;
-       sudoers_path = "stdin";
-    } else if ((yyin = fopen(sudoers_path, "r")) == NULL) {
-       if (!quiet)
-           warning("unable to open %s", sudoers_path);
-       exit(1);
-    }
-    init_parser(sudoers_path, quiet);
-    if (yyparse() && !parse_error) {
-       if (!quiet)
-           warningx("failed to parse %s file, unknown error", sudoers_path);
-       parse_error = TRUE;
-       errorfile = sudoers_path;
-    }
-    if (!parse_error && check_aliases(strict, quiet) != 0) {
-       parse_error = TRUE;
-       errorfile = sudoers_path;
-    }
-    error = parse_error;
-    if (!quiet) {
-       if (parse_error) {
-           if (errorlineno != -1)
-               (void) printf("parse error in %s near line %d\n", errorfile,
-                   errorlineno);
-           else
-               (void) printf("parse error in %s\n", errorfile);
-       } else {
-           (void) printf("%s: parsed OK\n", sudoers_path);
-       }
-    }
-    /* Check mode and owner in strict mode. */
-#ifdef HAVE_FSTAT
-    if (strict && yyin != stdin && fstat(fileno(yyin), &sb) == 0)
-#else
-    if (strict && yyin != stdin && stat(sudoers_path, &sb) == 0)
-#endif
-    {
-       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);
-           }
-       }
-    }
-
-    return error;
-}
-
-/*
- * 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, doedit, keepopen)
-    const char *path;
-    int doedit;
-    int *keepopen;
-{
-    struct sudoersfile *entry;
-    FILE *fp;
-
-    /* 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->prev = entry;
-       entry->next = NULL;
-       entry->fd = open(entry->path, O_RDWR | O_CREAT, SUDOERS_MODE);
-       entry->tpath = NULL;
-       entry->doedit = doedit;
-       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);
-       tq_append(&sudoerslist, entry);
-    } 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);
-           rewind(fp);
-       }
-    }
-    if (keepopen != NULL)
-       *keepopen = TRUE;
-    return fp;
-}
-
-static char *
-get_editor(args)
-    char **args;
-{
-    char *Editor, *EditorArgs, *EditorPath, *UserEditor, *UserEditorArgs;
-
-    /*
-     * Check VISUAL and EDITOR environment variables to see which editor
-     * the user wants to use (we may not end up using it though).
-     * If the path is not fully-qualified, make it so and check that
-     * the specified executable actually exists.
-     */
-    UserEditorArgs = NULL;
-    if ((UserEditor = getenv("VISUAL")) == NULL || *UserEditor == '\0')
-       UserEditor = getenv("EDITOR");
-    if (UserEditor && *UserEditor == '\0')
-       UserEditor = NULL;
-    else if (UserEditor) {
-       UserEditorArgs = get_args(UserEditor);
-       if (find_path(UserEditor, &Editor, NULL, getenv("PATH"), 0) == FOUND) {
-           UserEditor = Editor;
-       } else {
-           if (def_env_editor) {
-               /* If we are honoring $EDITOR this is a fatal error. */
-               errorx(1, "specified editor (%s) doesn't exist!", UserEditor);
-           } else {
-               /* Otherwise, just ignore $EDITOR. */
-               UserEditor = NULL;
-           }
-       }
-    }
-
-    /*
-     * See if we can use the user's choice of editors either because
-     * we allow any $EDITOR or because $EDITOR is in the allowable list.
-     */
-    Editor = EditorArgs = EditorPath = NULL;
-    if (def_env_editor && UserEditor) {
-       Editor = UserEditor;
-       EditorArgs = UserEditorArgs;
-    } else if (UserEditor) {
-       struct stat editor_sb;
-       struct stat user_editor_sb;
-       char *base, *userbase;
-
-       if (stat(UserEditor, &user_editor_sb) != 0) {
-           /* Should never happen since we already checked above. */
-           error(1, "unable to stat editor (%s)", UserEditor);
-       }
-       EditorPath = estrdup(def_editor);
-       Editor = strtok(EditorPath, ":");
-       do {
-           EditorArgs = get_args(Editor);
-           /*
-            * Both Editor and UserEditor should be fully qualified but
-            * check anyway...
-            */
-           if ((base = strrchr(Editor, '/')) == NULL)
-               continue;
-           if ((userbase = strrchr(UserEditor, '/')) == NULL) {
-               Editor = NULL;
-               break;
-           }
-           base++, userbase++;
-
-           /*
-            * We compare the basenames first and then use stat to match
-            * for sure.
-            */
-           if (strcmp(base, userbase) == 0) {
-               if (stat(Editor, &editor_sb) == 0 && S_ISREG(editor_sb.st_mode)
-                   && (editor_sb.st_mode & 0000111) &&
-                   editor_sb.st_dev == user_editor_sb.st_dev &&
-                   editor_sb.st_ino == user_editor_sb.st_ino)
-                   break;
-           }
-       } while ((Editor = strtok(NULL, ":")));
-    }
-
-    /*
-     * Can't use $EDITOR, try each element of def_editor until we
-     * find one that exists, is regular, and is executable.
-     */
-    if (Editor == NULL || *Editor == '\0') {
-       efree(EditorPath);
-       EditorPath = estrdup(def_editor);
-       Editor = strtok(EditorPath, ":");
-       do {
-           EditorArgs = get_args(Editor);
-           if (sudo_goodpath(Editor, NULL))
-               break;
-       } while ((Editor = strtok(NULL, ":")));
-
-       /* Bleah, none of the editors existed! */
-       if (Editor == NULL || *Editor == '\0')
-           errorx(1, "no editor found (editor path = %s)", def_editor);
-    }
-    *args = EditorArgs;
-    return Editor;
-}
-
-/*
- * Split out any command line arguments and return them.
- */
-static char *
-get_args(cmnd)
-    char *cmnd;
-{
-    char *args;
-
-    args = cmnd;
-    while (*args && !isblank((unsigned char) *args))
-       args++;
-    if (*args) {
-       *args++ = '\0';
-       while (*args && isblank((unsigned char) *args))
-           args++;
-    }
-    return *args ? args : NULL;
-}
-
-/*
- * Look up the hostname and set user_host and user_shost.
- */
-static void
-get_hostname()
-{
-    char *p, thost[MAXHOSTNAMELEN + 1];
-
-    if (gethostname(thost, sizeof(thost)) != 0) {
-       user_host = user_shost = "localhost";
-       return;
-    }
-    thost[sizeof(thost) - 1] = '\0';
-    user_host = estrdup(thost);
-
-    if ((p = strchr(user_host, '.'))) {
-       *p = '\0';
-       user_shost = estrdup(user_host);
-       *p = '.';
-    } else {
-       user_shost = user_host;
-    }
-}
-
-static int
-alias_remove_recursive(name, type, strict, quiet)
-    char *name;
-    int type;
-    int strict;
-    int quiet;
-{
-    struct member *m;
-    struct alias *a;
-    int error = 0;
-
-    if ((a = alias_find(name, type)) != NULL) {
-       tq_foreach_fwd(&a->members, m) {
-           if (m->type == ALIAS) {
-               if (strcmp(name, m->name) == 0) {
-                   print_selfref(m->name, type, strict, quiet);
-                   error = 1;
-               } else {
-                   if (!alias_remove_recursive(m->name, type, strict, quiet))
-                       error = 1;
-               }
-           }
-       }
-    }
-    alias_seqno++;
-    a = alias_remove(name, type);
-    if (a)
-       rbinsert(alias_freelist, a);
-    return error;
-}
-
-/*
- * Iterate through the sudoers datastructures looking for undefined
- * aliases or unused aliases.
- */
-static int
-check_aliases(strict, quiet)
-    int strict;
-    int quiet;
-{
-    struct cmndspec *cs;
-    struct member *m, *binding;
-    struct privilege *priv;
-    struct userspec *us;
-    struct defaults *d;
-    int atype, error = 0;
-
-    alias_freelist = rbcreate(alias_compare);
-
-    /* Forward check. */
-    tq_foreach_fwd(&userspecs, us) {
-       tq_foreach_fwd(&us->users, m) {
-           if (m->type == ALIAS) {
-               alias_seqno++;
-               if (alias_find(m->name, USERALIAS) == NULL) {
-                   print_undefined(m->name, USERALIAS, strict, quiet);
-                   error++;
-               }
-           }
-       }
-       tq_foreach_fwd(&us->privileges, priv) {
-           tq_foreach_fwd(&priv->hostlist, m) {
-               if (m->type == ALIAS) {
-                   alias_seqno++;
-                   if (alias_find(m->name, HOSTALIAS) == NULL) {
-                       print_undefined(m->name, HOSTALIAS, strict, quiet);
-                       error++;
-                   }
-               }
-           }
-           tq_foreach_fwd(&priv->cmndlist, cs) {
-               tq_foreach_fwd(&cs->runasuserlist, m) {
-                   if (m->type == ALIAS) {
-                       alias_seqno++;
-                       if (alias_find(m->name, RUNASALIAS) == NULL) {
-                           print_undefined(m->name, RUNASALIAS, strict, quiet);
-                           error++;
-                       }
-                   }
-               }
-               if ((m = cs->cmnd)->type == ALIAS) {
-                   alias_seqno++;
-                   if (alias_find(m->name, CMNDALIAS) == NULL) {
-                       print_undefined(m->name, CMNDALIAS, strict, quiet);
-                       error++;
-                   }
-               }
-           }
-       }
-    }
-
-    /* Reverse check (destructive) */
-    tq_foreach_fwd(&userspecs, us) {
-       tq_foreach_fwd(&us->users, m) {
-           if (m->type == ALIAS) {
-               if (!alias_remove_recursive(m->name, USERALIAS, strict, quiet))
-                   error++;
-           }
-       }
-       tq_foreach_fwd(&us->privileges, priv) {
-           tq_foreach_fwd(&priv->hostlist, m) {
-               if (m->type == ALIAS)
-                   if (!alias_remove_recursive(m->name, HOSTALIAS, strict,
-                       quiet))
-                       error++;
-           }
-           tq_foreach_fwd(&priv->cmndlist, cs) {
-               tq_foreach_fwd(&cs->runasuserlist, m) {
-                   if (m->type == ALIAS)
-                       if (!alias_remove_recursive(m->name, RUNASALIAS,
-                           strict, quiet))
-                           error++;
-               }
-               if ((m = cs->cmnd)->type == ALIAS)
-                   if (!alias_remove_recursive(m->name, CMNDALIAS, strict,
-                       quiet))
-                       error++;
-           }
-       }
-    }
-    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)
-                   if (!alias_remove_recursive(m->name, atype, strict, quiet))
-                       error++;
-           }
-       }
-    }
-    rbdestroy(alias_freelist, alias_free);
-
-    /* If all aliases were referenced we will have an empty tree. */
-    if (!no_aliases() && !quiet)
-       alias_apply(print_unused, strict ? "Error" : "Warning");
-
-    return strict ? error : 0;
-}
-
-static void
-print_undefined(name, type, strict, quiet)
-    char *name;
-    int type;
-    int strict;
-    int quiet;
-{
-    if (!quiet) {
-       warningx("%s: %s_Alias `%s' referenced but not defined",
-           strict ? "Error" : "Warning",
-           type == HOSTALIAS ? "Host" : type == CMNDALIAS ? "Cmnd" :
-           type == USERALIAS ? "User" : type == RUNASALIAS ? "Runas" :
-           "Unknown", name);
-    }
-}
-
-static void
-print_selfref(name, type, strict, quiet)
-    char *name;
-    int type;
-    int strict;
-    int quiet;
-{
-    if (!quiet) {
-       warningx("%s: %s_Alias `%s' references self",
-           strict ? "Error" : "Warning",
-           type == HOSTALIAS ? "Host" : type == CMNDALIAS ? "Cmnd" :
-           type == USERALIAS ? "User" : type == RUNASALIAS ? "Runas" :
-           "Unknown", name);
-    }
-}
-
-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;
-}
-
-/*
- * 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);
-    }
-    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"
-    if (write(STDERR_FILENO, getprogname(), strlen(getprogname())) == -1 ||
-       write(STDERR_FILENO, emsg, sizeof(emsg) - 1) == -1)
-       /* shut up glibc */;
-    _exit(signo);
-}
-
-static void
-usage(fatal)
-    int fatal;
-{
-    (void) fprintf(fatal ? stderr : stdout,
-       "usage: %s [-chqsV] [-f sudoers]\n", getprogname());
-    if (fatal)
-       exit(1);
-}
-
-static void
-help()
-{
-    (void) printf("%s - safely edit the sudoers file\n\n", getprogname());
-    usage(0);
-    (void) puts("\nOptions:");
-    (void) puts("  -c          check-only mode");
-    (void) puts("  -f sudoers  specify sudoers file location");
-    (void) puts("  -h          display help message and exit");
-    (void) puts("  -q          less verbose (quiet) syntax error messages");
-    (void) puts("  -s          strict syntax checking");
-    (void) puts("  -V          display version information and exit");
-    exit(0);
-}
diff --git a/visudo.cat b/visudo.cat
deleted file mode 100644 (file)
index ce7c1a3..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-
-
-
-VISUDO(1m)             MAINTENANCE COMMANDS            VISUDO(1m)
-
-
-N\bNA\bAM\bME\bE
-       visudo - edit the sudoers file
-
-S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS
-       v\bvi\bis\bsu\bud\bdo\bo [-\b-c\bch\bhq\bqs\bsV\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 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 one or more 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 "vi".  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_\b-_\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.
-
-       -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/_\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.  In c\bch\bhe\bec\bck\bk-\b-o\bon\bnl\bly\by mode only, the argument to
-                   -\b-f\bf may be "-", indicating that _\bs_\bu_\bd_\bo_\be_\br_\bs will be read from
-                   the standard input.
-
-
-
-
-1.7.6                     April  9, 2011                        1
-
-
-
-
-
-VISUDO(1m)             MAINTENANCE COMMANDS            VISUDO(1m)
-
-
-       -h          The -\b-h\bh (_\bh_\be_\bl_\bp) option causes v\bvi\bis\bsu\bud\bdo\bo to print a short help
-                   message to the standard output and exit.
-
-       -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 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 consider this a
-                   parse error.  Note that it is not possible to differentiate
-                   between an alias and a host name or user name 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.
-
-E\bEN\bNV\bVI\bIR\bRO\bON\bNM\bME\bEN\bNT\bT
-       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/_\be_\bt_\bc_\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.
-           Someone else is currently editing the _\bs_\bu_\bd_\bo_\be_\br_\bs file.
-
-       /etc/sudoers.tmp: Permission denied
-           You didn't run v\bvi\bis\bsu\bud\bdo\bo as root.
-
-       Can't find you in the passwd database
-           Your userid does not appear in the system passwd file.
-
-       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 host name 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: 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.
-
-
-
-
-
-1.7.6                     April  9, 2011                        2
-
-
-
-
-
-VISUDO(1m)             MAINTENANCE COMMANDS            VISUDO(1m)
-
-
-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)
-
-A\bAU\bUT\bTH\bHO\bOR\bR
-       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
-
-       See the HISTORY file in the sudo distribution or visit
-       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.
-
-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/
-
-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.
-
-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 complete details.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-1.7.6                     April  9, 2011                        3
-
-
diff --git a/visudo.man.in b/visudo.man.in
deleted file mode 100644 (file)
index c8ee72e..0000000
+++ /dev/null
@@ -1,307 +0,0 @@
-.\" Copyright (c) 1996,1998-2005, 2007-2010
-.\"    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.
-.\" 
-.\" 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.
-.\" 
-.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.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 (.SS), 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 "VISUDO @mansectsu@"
-.TH VISUDO @mansectsu@ "April  9, 2011" "1.7.6" "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"
-.IX Header "SYNOPSIS"
-\&\fBvisudo\fR [\fB\-chqsV\fR] [\fB\-f\fR \fIsudoers\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBvisudo\fR edits the \fIsudoers\fR file in a safe fashion, analogous to
-\&\fIvipw\fR\|(@mansectsu@).  \fBvisudo\fR locks the \fIsudoers\fR file against multiple
-simultaneous edits, provides basic sanity checks, and checks
-for parse errors.  If the \fIsudoers\fR file is currently being
-edited you will receive a message to try again later.
-.PP
-There is a hard-coded list of one or more editors that \fBvisudo\fR will
-use set at compile-time that may be overridden via the \fIeditor\fR \fIsudoers\fR
-\&\f(CW\*(C`Default\*(C'\fR variable.  This list defaults to \f(CW"@editor@"\fR.  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\-env\-editor\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.
-.PP
-\&\fBvisudo\fR parses the \fIsudoers\fR file after the edit and will
-not save the changes if there is a syntax error.  Upon finding
-an error, \fBvisudo\fR will print a message stating the line number(s)
-where the error occurred and the user will receive the
-\&\*(L"What now?\*(R" prompt.  At this point the user may enter \*(L"e\*(R"
-to re-edit the \fIsudoers\fR file, \*(L"x\*(R" to exit without
-saving the changes, or \*(L"Q\*(R" to quit and save changes.  The
-\&\*(L"Q\*(R" option should be used with extreme care because if \fBvisudo\fR
-believes there to be a parse error, so will \fBsudo\fR and no one
-will be able to \fBsudo\fR again until the error is fixed.
-If \*(L"e\*(R" is typed to edit the  \fIsudoers\fR 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).
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-\&\fBvisudo\fR accepts the following command line options:
-.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
-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 \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
-is the specified \fIsudoers\fR file with \*(L".tmp\*(R" appended to it.
-In \fBcheck-only\fR mode only, the argument to \fB\-f\fR may be \*(L"\-\*(R",
-indicating that \fIsudoers\fR will be read from the standard input.
-.IP "\-h" 12
-.IX Item "-h"
-The \fB\-h\fR (\fIhelp\fR) option causes \fBvisudo\fR to print a short help message
-to the standard output and exit.
-.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 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 host name or user name that consists solely of uppercase
-letters, digits, and the underscore ('_') character.
-.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 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"
-Invoked by visudo as the editor to use
-.ie n .IP "\*(C`EDITOR\*(C'" 16
-.el .IP "\f(CW\*(C`EDITOR\*(C'\fR" 16
-.IX Item "EDITOR"
-Used by visudo if \s-1VISUAL\s0 is not set
-.SH "FILES"
-.IX Header "FILES"
-.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
-.ie n .IP "\fI@sysconfdir@/sudoers.tmp\fR" 24
-.el .IP "\fI@sysconfdir@/sudoers.tmp\fR" 24
-.IX Item "@sysconfdir@/sudoers.tmp"
-Lock file for visudo
-.SH "DIAGNOSTICS"
-.IX Header "DIAGNOSTICS"
-.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.
-.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: {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 host name 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)
-.SH "AUTHOR"
-.IX Header "AUTHOR"
-Many people have worked on \fIsudo\fR over the years; this version of
-\&\fBvisudo\fR was written by:
-.PP
-.Vb 1
-\& Todd Miller
-.Ve
-.PP
-See the \s-1HISTORY\s0 file in the sudo distribution or visit
-http://www.sudo.ws/sudo/history.html for more details.
-.SH "CAVEATS"
-.IX Header "CAVEATS"
-There is no easy way to prevent a user from gaining a root shell if 
-the editor used by \fBvisudo\fR allows shell escapes.
-.SH "BUGS"
-.IX Header "BUGS"
-If you feel you have found a bug in \fBvisudo\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"
-\&\fBvisudo\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/visudo.pod b/visudo.pod
deleted file mode 100644 (file)
index 708d954..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-Copyright (c) 1996,1998-2005, 2007-2010
-       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.
-
-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.
-
-=pod
-
-=head1 NAME
-
-visudo - edit the sudoers file
-
-=head1 SYNOPSIS
-
-B<visudo> [B<-chqsV>] [B<-f> I<sudoers>]
-
-=head1 DESCRIPTION
-
-B<visudo> edits the I<sudoers> file in a safe fashion, analogous to
-L<vipw(8)>.  B<visudo> locks the I<sudoers> file against multiple
-simultaneous edits, provides basic sanity checks, and checks
-for parse errors.  If the I<sudoers> file is currently being
-edited you will receive a message to try again later.
-
-There is a hard-coded list of one or more editors that B<visudo> will
-use set at compile-time that may be overridden via the I<editor> I<sudoers>
-C<Default> variable.  This list defaults to C<"@editor@">.  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-env-editor>
-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>.
-
-B<visudo> parses the I<sudoers> file after the edit and will
-not save the changes if there is a syntax error.  Upon finding
-an error, B<visudo> 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 I<sudoers> 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 B<visudo>
-believes there to be a parse error, so will B<sudo> and no one
-will be able to B<sudo> again until the error is fixed.
-If "e" is typed to edit the  I<sudoers> 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).
-
-=head1 OPTIONS
-
-B<visudo> accepts the following command line options:
-
-=over 12
-
-=item -c
-
-Enable B<check-only> mode.  The existing I<sudoers> file will be
-checked for syntax and a message will be printed to the
-standard output detailing the status of I<sudoers>.
-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 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,
-instead of the default, F<@sysconfdir@/sudoers>.  The lock file used
-is the specified I<sudoers> file with ".tmp" appended to it.
-In B<check-only> mode only, the argument to B<-f> may be "-",
-indicating that I<sudoers> will be read from the standard input.
-
-=item -h
-
-The B<-h> (I<help>) option causes B<visudo> to print a short help message
-to the standard output and exit.
-
-=item -q
-
-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> option.
-
-=item -s
-
-Enable B<strict> checking of the I<sudoers> file.  If an alias is
-used before it is defined, B<visudo> will consider this a parse
-error.  Note that it is not possible to differentiate between an
-alias and a host name or user name that consists solely of uppercase
-letters, digits, and the underscore ('_') character.
-
-=item -V
-
-The B<-V> (version) option causes B<visudo> to print its version number
-and exit.
-
-=back
-
-=head1 ENVIRONMENT
-
-The following environment variables may be consulted depending on
-the value of the I<editor> and I<env_editor> I<sudoers> variables:
-
-=over 16
-
-=item C<VISUAL>
-
-Invoked by visudo as the editor to use
-
-=item C<EDITOR>
-
-Used by visudo if VISUAL is not set
-
-=back
-
-=head1 FILES
-
-=over 24
-
-=item F<@sysconfdir@/sudoers>
-
-List of who can run what
-
-=item F<@sysconfdir@/sudoers.tmp>
-
-Lock file for visudo
-
-=back
-
-=head1 DIAGNOSTICS
-
-=over 4
-
-=item sudoers file busy, try again later.
-
-Someone else is currently editing the I<sudoers> file.
-
-=item @sysconfdir@/sudoers.tmp: Permission denied
-
-You didn't run B<visudo> as root.
-
-=item Can't find you in the passwd database
-
-Your userid does not appear in the system passwd file.
-
-=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 host name 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
-
-=head1 SEE ALSO
-
-L<vi(1)>, L<sudoers(5)>, L<sudo(8)>, L<vipw(8)>
-
-=head1 AUTHOR
-
-Many people have worked on I<sudo> over the years; this version of
-B<visudo> was written by:
-
- Todd Miller
-
-See the HISTORY file in the sudo distribution or visit
-http://www.sudo.ws/sudo/history.html for more details.
-
-=head1 CAVEATS
-
-There is no easy way to prevent a user from gaining a root shell if 
-the editor used by B<visudo> allows shell escapes.
-
-=head1 BUGS
-
-If you feel you have found a bug in B<visudo>, 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<visudo> 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.
diff --git a/zero_bytes.c b/zero_bytes.c
deleted file mode 100644 (file)
index bce0895..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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
- * 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 "missing.h"
-
-/*
- * Like bzero(3) but with a volatile pointer.  The hope is that
- * the compiler will not be able to optimize away this function.
- */
-void
-zero_bytes(v, n)
-    volatile void *v;
-    size_t n;
-{
-    volatile char *p, *ep;
-
-    for (p = v, ep = p + n; p < ep; p++)
-       *p = 0;
-    return;
-}
diff --git a/zlib/Makefile.in b/zlib/Makefile.in
new file mode 100644 (file)
index 0000000..469db66
--- /dev/null
@@ -0,0 +1,123 @@
+#
+# Copyright (c) 2011 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.
+#
+# @configure_input@
+#
+
+#### Start of system configuration section. ####
+
+srcdir = @srcdir@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Compiler & tools to use
+CC = @CC@
+LIBTOOL = @LIBTOOL@
+
+# C preprocessor flags
+CPPFLAGS = -I. -I$(srcdir)
+
+# Usually -O and/or -g
+CFLAGS = @CFLAGS@
+
+# OS dependent defines
+DEFS = @OSDEFS@
+
+#### End of system configuration section. ####
+
+SHELL = @SHELL@
+
+LTOBJS = adler32.lo compress.lo crc32.lo deflate.lo gzclose.lo gzlib.lo \
+        gzread.lo gzwrite.lo infback.lo inffast.lo inflate.lo inftrees.lo \
+        trees.lo uncompr.lo zutil.lo
+
+all: libz.la
+
+Makefile: $(srcdir)/Makefile.in
+       (cd $(top_builddir) && ./config.status --file zlib/Makefile)
+
+.SUFFIXES: .c .h .lo
+
+.c.lo:
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $<
+
+libz.la: $(LTOBJS)
+       $(LIBTOOL) --mode=link $(CC) -o $@ $(LTOBJS) -no-install
+
+# Dependencies
+adler32.lo: $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/adler32.c
+compress.lo: $(srcdir)/zlib.h ./zconf.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/compress.c
+crc32.lo: $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h $(srcdir)/crc32.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/crc32.c
+deflate.lo: $(srcdir)/deflate.h $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/deflate.c
+gzclose.lo: $(srcdir)/zlib.h ./zconf.h $(srcdir)/gzguts.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/gzclose.c
+gzlib.lo: $(srcdir)/zlib.h ./zconf.h $(srcdir)/gzguts.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/gzlib.c
+gzread.lo: $(srcdir)/zlib.h ./zconf.h $(srcdir)/gzguts.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/gzread.c
+gzwrite.lo: $(srcdir)/zlib.h ./zconf.h $(srcdir)/gzguts.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/gzwrite.c
+infback.lo: $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h $(srcdir)/inftrees.h $(srcdir)/inflate.h $(srcdir)/inffast.h $(srcdir)/inffixed.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/infback.c
+inffast.lo: $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h $(srcdir)/inftrees.h $(srcdir)/inflate.h $(srcdir)/inffast.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/inffast.c
+inflate.lo: $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h $(srcdir)/inftrees.h $(srcdir)/inflate.h $(srcdir)/inffast.h $(srcdir)/inffixed.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/inflate.c
+inftrees.lo: $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h $(srcdir)/inftrees.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/inftrees.c
+trees.lo: $(srcdir)/deflate.h $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h $(srcdir)/trees.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/trees.c
+uncompr.lo: $(srcdir)/zlib.h ./zconf.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/uncompr.c
+zutil.lo: $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h
+       $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/zutil.c
+
+pre-install:
+
+install:
+
+install-dirs:
+
+install-binaries:
+
+install-includes:
+
+install-doc:
+
+install-plugin:
+
+uninstall:
+
+check:
+
+clean:
+       -$(LIBTOOL) --mode=clean rm -f *.lo *.o *.la *.a stamp-* core *.core core.*
+
+mostlyclean: clean
+
+distclean: clean
+       -rm -rf Makefile .libs zconf.h
+
+clobber: distclean
+
+realclean: distclean
+       rm -f TAGS tags
+
+cleandir: realclean